コード例 #1
0
    def test_third_party_instrumentor(self, telemetry: TelemetryFixture):
        import requests
        from telemetry.api.listeners.span import LabelAttributes, InstrumentorSpanListener

        RequestsInstrumentor().instrument()

        telemetry.initialize()
        telemetry.add_span_processor(InstrumentorSpanListener(
            LabelAttributes('component', 'http.status_code', 'http.method'), 'requests'))

        responses.add_passthru('http://localhost:1234/does_not_exist')

        with telemetry.span('test_category', 'span1', attributes={TestAttributes.LABEL1: 'l1'}) as span:
            try:
                with requests.get('http://localhost:1234/does_not_exist') as response:
                    pass
            except:
                pass

        telemetry.collect()

        assert telemetry.get_value_recorder(name='trace.duration',
                                            labels={'component': 'http',
                                                    'http.method': 'GET',
                                                    TestAttributes.LABEL1.name: 'l1',
                                                    Attributes.TRACE_CATEGORY.name: 'requests',
                                                    Attributes.TRACE_NAME.name: 'requests.HTTP GET',
                                                    Attributes.TRACE_STATUS.name: 'ERROR'}).count == 1
コード例 #2
0
    def test_up_down_counter(self, telemetry: TelemetryFixture):
        telemetry.up_down_counter("category1", "counter1", 5)
        telemetry.up_down_counter("category1", "counter1", -10)

        telemetry.collect()

        assert telemetry.get_up_down_counter('category1.counter1').value == -5
コード例 #3
0
    def test_environment_attributes(self, monkeypatch,
                                    telemetry: TelemetryFixture):
        monkeypatch.setenv('METRICS_LABEL_label1', 'label1_value')
        monkeypatch.setenv('METRICS_LABEL_label2', 'label2_value')
        monkeypatch.setenv('METRICS_ATTRIBUTE_ATTRIB1', 'attrib1_value')
        monkeypatch.setenv('METRICS_ATTRIBUTE_ATTRIB2', 'attrib2_value')

        # need to initialize again after environment is updated
        telemetry.initialize()

        with telemetry.span("category1", 'span1') as span:
            logging.info("In span")

        telemetry.collect()

        assert len(
            telemetry.get_finished_spans(
                name_filter=lambda name: name == 'category1.span1',
                attribute_filter=lambda a: a.get('attrib1') == 'attrib1_value'
                and a.get('attrib2') == 'attrib2_value')) == 1

        assert telemetry.get_value_recorder('trace.duration',
                                            labels={
                                                Attributes.TRACE_CATEGORY.name:
                                                'category1',
                                                Attributes.TRACE_NAME.name:
                                                'category1.span1',
                                                Attributes.TRACE_STATUS.name:
                                                'OK',
                                                'label1': 'label1_value',
                                                'label2': 'label2_value'
                                            }).count == 1
コード例 #4
0
    def test_decorator_argument_labelging_none(self,
                                               telemetry: TelemetryFixture,
                                               caplog):
        telemetry.enable_log_record_capture(caplog)

        example = DecoratorExample()
        example.method_trace_custom(arg1='foo', arg2=None)

        telemetry.collect()

        assert telemetry.get_value_recorder(
            name='trace.duration',
            labels={
                'arg1': 'foo',
                'label1': 't1',
                Attributes.TRACE_STATUS.name: 'OK',
                Attributes.TRACE_CATEGORY.name: 'custom_category',
                Attributes.TRACE_NAME.name:
                'custom_category.method_trace_custom'
            }).count == 1

        rec = telemetry.caplog.get_record(
            lambda rec: rec['message'] == 'method_trace_custom log')

        assert rec['attributes']['label1'] == 't1'
        assert rec['attributes']['attrib1'] == 'a1'
        assert rec['attributes']['arg1'] == 'foo'
コード例 #5
0
    def test_instrumentors(self, telemetry: TelemetryFixture):
        telemetry.record_value("category1", "value1", 1)
        with telemetry.span("span_category1", "span1") as span:
            pass

        telemetry.collect()

        assert len(telemetry.get_metrics()) == 2
        assert len(
            telemetry.get_metrics(
                instrumentor_filter=lambda name: name == "default")) == 2
コード例 #6
0
    def test_decorator_invalid_argument_label(self,
                                              telemetry: TelemetryFixture,
                                              caplog):
        telemetry.enable_log_record_capture(caplog)

        example = DecoratorExample()
        example.method_invalid_argument_label(arg1='arg1_value')

        telemetry.collect()

        telemetry.caplog.assert_log_contains(
            "@trace decorator refers to an argument 'arg4' that was not found in the signature for DecoratorExample.method_invalid_argument_label",
            'WARNING')
コード例 #7
0
    def test_span_inheritance(self, telemetry: TelemetryFixture):
        with telemetry.span('test', 'span1', attributes={TestAttributes.ATTRIB1: 'attrib1', TestAttributes.LABEL1: 'label1'}) as span1:
            telemetry.counter('test', 'counter1')

            with telemetry.span('test', 'span2', attributes={TestAttributes.ATTRIB2: 'attrib2', TestAttributes.LABEL2: 'label2'}) as span2:
                telemetry.counter('test', 'counter2')

                with telemetry.span('test', 'span3') as span3:
                    span3.set_label('label3', 'label3')
                    span3.set_attribute('attrib3', 'attrib3')

                    telemetry.counter('test', 'counter3', labels={'counter_label': 'counter_label'})

                    assert span3.attributes == {'attrib1': 'attrib1',
                                                'attrib2': 'attrib2',
                                                'attrib3': 'attrib3',
                                                'label1': 'label1',
                                                'label2': 'label2',
                                                'label3': 'label3',
                                                Attributes.TRACE_ID.name: str(span3.context.trace_id),
                                                Attributes.TRACE_SPAN_ID.name: str(span3.context.span_id),
                                                Attributes.TRACE_IS_REMOTE.name: False,
                                                Attributes.TRACE_CATEGORY.name: 'test',
                                                Attributes.TRACE_NAME.name: 'test.span3'
                                                }

                    assert span3.labels == {Attributes.TRACE_CATEGORY.name: 'test',
                                            Attributes.TRACE_NAME.name: 'test.span3',
                                            'label1': 'label1',
                                            'label2': 'label2',
                                            'label3': 'label3'}

                    assert telemetry.current_span.qname == 'test.span3'
                    assert span3.qname == 'test.span3'

        telemetry.collect()

        assert telemetry.get_counter('test.counter1', labels={'label1': 'label1',
                                                              Attributes.TRACE_CATEGORY.name: 'test',
                                                              Attributes.TRACE_NAME.name: 'test.span1'}).value == 1
        assert telemetry.get_counter('test.counter2', labels={'label1': 'label1',
                                                              'label2': 'label2',
                                                              Attributes.TRACE_CATEGORY.name: 'test',
                                                              Attributes.TRACE_NAME.name: 'test.span2'}).value == 1
        assert telemetry.get_counter('test.counter3', labels={'label1': 'label1',
                                                              'label2': 'label2',
                                                              'label3': 'label3',
                                                              'counter_label': 'counter_label',
                                                              Attributes.TRACE_CATEGORY.name: 'test',
                                                              Attributes.TRACE_NAME.name: 'test.span3'}).value == 1
        assert len(telemetry.get_finished_spans()) == 3
コード例 #8
0
    def test_decorator_default(self, telemetry: TelemetryFixture):
        example = DecoratorExample()
        example.method_trace_default(arg1='arg1_value')

        telemetry.collect()

        assert example.telemetry_category == 'tests.test_decorator.DecoratorExample'
        assert telemetry.get_value_recorder(
            'trace.duration',
            labels={
                Attributes.TRACE_CATEGORY.name:
                'tests.test_decorator.DecoratorExample',
                Attributes.TRACE_NAME.name:
                'tests.test_decorator.DecoratorExample.method_trace_default',
                Attributes.TRACE_STATUS.name: 'OK'
            }).count == 1
コード例 #9
0
    def test_decorator_complex_argument_label(self,
                                              telemetry: TelemetryFixture):
        example = DecoratorExample()
        example.method_complex_argument_label(arg1=ComplexValue('foo', 10))

        telemetry.collect()

        assert telemetry.get_value_recorder(
            name='trace.duration',
            labels={
                Attributes.TRACE_STATUS.name:
                'OK',
                Attributes.TRACE_CATEGORY.name:
                'tests.test_decorator.DecoratorExample',
                Attributes.TRACE_NAME.name:
                'tests.test_decorator.DecoratorExample.method_complex_argument_label'
            }).count == 1
コード例 #10
0
    def test_value_recorder(self, telemetry: TelemetryFixture):
        telemetry.record_value("category1", "value1", 1)

        telemetry.record_value("category1", "value2", 1.0)
        telemetry.record_value("category1", "value2", 1.2)
        telemetry.record_value("category1", "value2", 1.4)

        telemetry.collect()

        assert telemetry.get_value_recorder('category1.value1').count == 1
        assert telemetry.get_value_recorder('category1.value1').sum == 1
        assert telemetry.get_value_recorder('category1.value1').min == 1
        assert telemetry.get_value_recorder('category1.value1').max == 1

        assert telemetry.get_value_recorder('category1.value2').count == 3
        assert telemetry.get_value_recorder('category1.value2').sum == 3.6
        assert telemetry.get_value_recorder('category1.value2').min == 1.0
        assert telemetry.get_value_recorder('category1.value2').max == 1.4
コード例 #11
0
    def test_decorator_local_def(self, telemetry: TelemetryFixture):
        @trace(extractor=extract_args("arg"))
        def foo(arg: str):
            time.sleep(.1)
            return "value"

        foo('arg1')

        telemetry.collect()

        assert telemetry.get_value_recorder('trace.duration',
                                            labels={
                                                Attributes.TRACE_CATEGORY.name:
                                                'tests.test_decorator',
                                                Attributes.TRACE_NAME.name:
                                                'tests.test_decorator.foo',
                                                Attributes.TRACE_STATUS.name:
                                                'OK'
                                            }).count == 1
コード例 #12
0
    def test_counter(self, telemetry: TelemetryFixture):
        telemetry.counter("category1", "counter1", 1)
        telemetry.counter("category1", "counter2", 2)
        telemetry.counter("category1", "counter3", 2)
        telemetry.counter("category1", "counter3", 1)
        telemetry.counter("category1",
                          "counter4",
                          1,
                          labels={'label1': 'label1'})

        telemetry.collect()

        assert telemetry.get_counter('category1.counter1').value == 1
        assert telemetry.get_counter('category1.counter2').value == 2
        assert telemetry.get_counter('category1.counter3').value == 3
        assert telemetry.get_counter('category1.counter4',
                                     labels={
                                         'label1': 'label1'
                                     }).value == 1
コード例 #13
0
    def test_json_log_format(self, telemetry: TelemetryFixture, caplog):
        telemetry.enable_log_record_capture(caplog)

        example = ExampleClass()
        example.method1()

        telemetry.collect()
        method1_span = telemetry.get_finished_spans(name_filter=lambda name: name == 'tests.example.ExampleClass.method1')[0]
        method2_span = telemetry.get_finished_spans(name_filter=lambda name: name == 'tests.example.ExampleClass.method2')[0]

        log_record = telemetry.caplog.get_record(lambda l: l['message'] == 'method1 log')
        assert log_record['attributes'] == {TestAttributes.ATTRIB1.name: 'value1',
                                            TestAttributes.LABEL1.name: 'value1',
                                            Attributes.TRACE_ID.name: method1_span.context.trace_id,
                                            Attributes.TRACE_SPAN_ID.name: method1_span.context.span_id,
                                            Attributes.TRACE_IS_REMOTE.name: False,
                                            Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                            Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method1'}

        log_record = telemetry.caplog.get_record(lambda l: l['message'] == 'method2 log')
        assert log_record['attributes'] == {TestAttributes.ATTRIB1.name: 'value1',
                                            TestAttributes.ATTRIB2.name: 'value2',
                                            Attributes.TRACE_ID.name: method2_span.context.trace_id,
                                            Attributes.TRACE_SPAN_ID.name: method2_span.context.span_id,
                                            Attributes.TRACE_IS_REMOTE.name: False,
                                            Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                            Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method2',
                                            'label1': 'value1',
                                            'label2': 'value2'}

        telemetry.collect()

        assert example.telemetry_category == 'tests.example.ExampleClass'
        assert telemetry.get_value_recorder(name='trace.duration',
                                            labels={Attributes.TRACE_STATUS.name: 'OK', 'label1': 'value1',
                                                    Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                    Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method1'}).count == 1

        assert telemetry.get_value_recorder(name='trace.duration',
                                            labels={Attributes.TRACE_STATUS.name: 'OK', 'label1': 'value1', 'label2': 'value2',
                                                    Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                    Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method2'}).count == 1
        assert len(telemetry.get_value_recorders()) == 2
コード例 #14
0
    def test_environment_attributes_override(self, monkeypatch,
                                             telemetry: TelemetryFixture):
        monkeypatch.setenv('METRICS_LABEL_label1', 'label1_value')
        monkeypatch.setenv('METRICS_LABEL_label2', 'label2_value')
        monkeypatch.setenv('METRICS_ATTRIBUTE_ATTRIB1', 'attrib1_value')
        monkeypatch.setenv('METRICS_ATTRIBUTE_ATTRIB2', 'attrib2_value')

        # need to initialize again after environment is updated
        telemetry.initialize()

        # environment labels should win over any locally-specified labels to preserve ops behavior
        with telemetry.span("category1",
                            'span1',
                            attributes={
                                TestAttributes.ATTRIB1: 'attrib1_override',
                                TestAttributes.LABEL1: 'label1_value'
                            }) as span:
            pass

        telemetry.collect()

        spans = telemetry.get_finished_spans()
        assert len(
            telemetry.get_finished_spans(
                name_filter=lambda name: name == 'category1.span1',
                attribute_filter=lambda a: a.get('attrib1'
                                                 ) == 'attrib1_override')) == 1

        assert telemetry.get_value_recorder('trace.duration',
                                            labels={
                                                Attributes.TRACE_CATEGORY.name:
                                                'category1',
                                                Attributes.TRACE_NAME.name:
                                                'category1.span1',
                                                Attributes.TRACE_STATUS.name:
                                                'OK',
                                                TestAttributes.LABEL1.name:
                                                'label1_value',
                                                TestAttributes.LABEL2.name:
                                                'label2_value'
                                            }).count == 1

        Environment._clear()
コード例 #15
0
    def test_span_listener(self, telemetry: TelemetryFixture):
        from opentelemetry.sdk.trace import SpanProcessor
        class Customlabelger(SpanProcessor):
            def on_start(self, span: "Span", parent_context: Optional[context_api.Context] = None) -> None:
                wrapped = Span(span)
                wrapped.set_attribute('hostname', 'localhost')
                wrapped.set_label('env', 'test')

        telemetry.add_span_processor(Customlabelger())

        with telemetry.span("category1", "span1") as span:
            assert span.labels['env'] == 'test'

        telemetry.collect()

        assert telemetry.get_value_recorder(name='trace.duration',
                                            labels={'env': 'test',
                                                    Attributes.TRACE_CATEGORY.name: 'category1',
                                                    Attributes.TRACE_NAME.name: 'category1.span1',
                                                    Attributes.TRACE_STATUS.name: 'OK'}).count == 1
コード例 #16
0
    def test_labelger_empty(self, monkeypatch, telemetry: TelemetryFixture):
        # need to initialize again after environment is updated
        telemetry.initialize()

        with telemetry.span("category1", 'span1') as span:
            pass

        telemetry.collect()

        assert telemetry.get_value_recorder('trace.duration',
                                            labels={
                                                Attributes.TRACE_CATEGORY.name:
                                                'category1',
                                                Attributes.TRACE_NAME.name:
                                                'category1.span1',
                                                Attributes.TRACE_STATUS.name:
                                                'OK'
                                            }).count == 1

        Environment._clear()
コード例 #17
0
    def test_gauge(self, telemetry: TelemetryFixture):
        telemetry.gauge(
            "category1", "gauge1",
            lambda observer: observer.observe(10, {'label1': 'label1'}))
        telemetry.gauge(
            "category1", "gauge2",
            lambda observer: observer.observe(1.2, {'label1': 'label1'}))

        telemetry.collect()

        assert telemetry.get_gauge('category1.gauge1', {
            'label1': 'label1'
        }).count == 1
        assert telemetry.get_gauge('category1.gauge1', {
            'label1': 'label1'
        }).min == 10
        assert telemetry.get_gauge('category1.gauge1', {
            'label1': 'label1'
        }).max == 10
        assert telemetry.get_gauge('category1.gauge1', {
            'label1': 'label1'
        }).last == 10
        assert telemetry.get_gauge('category1.gauge1', {
            'label1': 'label1'
        }).sum == 10

        assert telemetry.get_gauge('category1.gauge2', {
            'label1': 'label1'
        }).count == 1
        assert telemetry.get_gauge('category1.gauge2', {
            'label1': 'label1'
        }).min == 1.2
        assert telemetry.get_gauge('category1.gauge2', {
            'label1': 'label1'
        }).max == 1.2
        assert telemetry.get_gauge('category1.gauge2', {
            'label1': 'label1'
        }).last == 1.2
        assert telemetry.get_gauge('category1.gauge2', {
            'label1': 'label1'
        }).sum == 1.2
コード例 #18
0
    def test_decorator_global_method(self, telemetry: TelemetryFixture,
                                     caplog):
        telemetry.enable_log_record_capture(caplog)

        global_method()

        telemetry.collect()

        assert telemetry.get_value_recorder('trace.duration',
                                            labels={
                                                Attributes.TRACE_CATEGORY.name:
                                                'tests.example',
                                                Attributes.TRACE_NAME.name:
                                                'tests.example.global_method',
                                                Attributes.TRACE_STATUS.name:
                                                'OK'
                                            }).count == 1

        log_record = telemetry.caplog.get_record(
            lambda l: l['message'] == 'global_method log')
        assert log_record['attributes']['trace.id']
コード例 #19
0
    def test_decorator_extractor_mapping(self, telemetry: TelemetryFixture):
        @trace(extractor=extract_args(arg1='arg1_renamed',
                                      arg2=Label('arg2_renamed'),
                                      arg3=Attribute,
                                      arg4=Label))
        def foo(arg1: str, arg2: str, arg3: str, arg4: str):
            time.sleep(.1)
            return "value"

        foo('arg1', 'arg2', 'arg3', 'arg4')

        telemetry.collect()

        assert telemetry.get_value_recorder('trace.duration',
                                            labels={
                                                Attributes.TRACE_CATEGORY.name:
                                                'tests.test_decorator',
                                                Attributes.TRACE_NAME.name:
                                                'tests.test_decorator.foo',
                                                Attributes.TRACE_STATUS.name:
                                                'OK',
                                                'arg2_renamed': 'arg2',
                                                'arg4': 'arg4'
                                            }).count == 1
コード例 #20
0
    def test_metrics_labelged_without_span(self, monkeypatch,
                                           telemetry: TelemetryFixture):
        monkeypatch.setenv('METRICS_LABEL_label1', 'label1_value')
        monkeypatch.setenv('METRICS_LABEL_label2', 'label2_value')
        monkeypatch.setenv('METRICS_ATTRIBUTE_ATTRIB1', 'attrib1_value')
        monkeypatch.setenv('METRICS_ATTRIBUTE_ATTRIB2', 'attrib2_value')

        # test that we include the environment labelger by default
        telemetry.initialize()

        # environment labels should win over any locally-specified labels to preserve ops behavior
        telemetry.counter('category1',
                          'counter1',
                          1,
                          labels={'label1': 'label1_override'})
        telemetry.collect()

        assert telemetry.get_counter('category1.counter1',
                                     labels={
                                         'label1': 'label1_value',
                                         'label2': 'label2_value'
                                     }).value == 1

        Environment._clear()
コード例 #21
0
    def test_http_server(self, monkeypatch, telemetry: TelemetryFixture):
        address = 'localhost:19102'
        monkeypatch.setenv('METRICS_EXPORTERS', 'prometheus')
        monkeypatch.setenv('METRICS_PROMETHEUS_PREFIX', 'test_prefix')
        monkeypatch.setenv('METRICS_INTERVAL', '5')
        monkeypatch.setenv('METRICS_PROMETHEUS_BIND_ADDRESS', address)

        telemetry.initialize()

        http = urllib3.PoolManager()

        with telemetry.span("category1",
                            "span1",
                            attributes={
                                TestAttributes.ATTRIB1: "attrib1",
                                TestAttributes.LABEL1: 'label1'
                            }) as span:
            time.sleep(.5)

        telemetry.counter("category1", "counter1", 2.0)

        def gauge(obv: Observer):
            obv.observe(1, {Attributes.ENV: 'test'})

        telemetry.gauge("category1", "gauge", gauge)

        # wait for Prometheus collection interval to pass (METRICS_INTERVAL)
        time.sleep(5)

        telemetry.collect()

        response = http.request('GET', 'http://localhost:19102/metrics')

        def fetch_metric(name: str, labels: dict = {}):
            response = http.request('GET', 'http://localhost:19102/metrics')
            lines = response.data.decode('utf8').split('\n')

            matches = list(
                filter(lambda line: not line.startswith("#") and name in line,
                       lines))
            if len(matches) == 0:
                pytest.fail(f"Metric not found: {name}")
            elif len(matches) == 1:
                return float(matches[0].split(' ')[1])
            else:
                pytest.fail(f"More than one match for metric: {name}")

        assert fetch_metric('test_prefix_trace_duration_count') == 1.0
        assert fetch_metric('test_prefix_trace_duration_sum') >= 500

        assert fetch_metric('test_prefix_category1_gauge') == 1.0

        # double-check that metrics continue to be returned on duplicate fetches
        assert fetch_metric('test_prefix_trace_duration_count') == 1.0
        assert fetch_metric('test_prefix_trace_duration_sum') >= 500

        with telemetry.span("category1",
                            "span1",
                            attributes={
                                TestAttributes.ATTRIB1: "attrib1",
                                TestAttributes.LABEL1: 'label1'
                            }) as span:
            time.sleep(.5)

        # wait for Prometheus collection interval to pass (METRICS_INTERVAL)
        time.sleep(2)

        telemetry.collect()

        assert fetch_metric('test_prefix_trace_duration_count') == 2.0
        assert fetch_metric('test_prefix_trace_duration_sum') >= 1000

        telemetry.shutdown()
コード例 #22
0
    def test_mixin(self, telemetry: TelemetryFixture, caplog):
        example = ExampleClass()
        example.method1()
        example.method2()
        try:
            example.error()  # raises exception
        except:
            pass

        telemetry.collect()

        assert example.telemetry_category == 'tests.example.ExampleClass'

        # method1 (direct)
        assert telemetry.get_counter('tests.example.ExampleClass.method1_counter').value == 1

        # method1 (direct, inside span)
        assert telemetry.get_counter('tests.example.ExampleClass.method1_counter_inside_span', labels={'label1': 'value1',
                                                                                                       Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                                                                       Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method1'}).value == 1

        # method2 (direct)
        assert telemetry.get_counter('tests.example.ExampleClass.method2_counter').value == 1

        # method2 (direct, inside span)
        assert telemetry.get_counter('tests.example.ExampleClass.method2_counter_inside_span',
                                     labels={'label2': 'value2',
                                             Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                             Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method2'}).value == 1  # method2 (inside span)

        # method2 (indirect)
        assert telemetry.get_counter('tests.example.ExampleClass.method2_counter', labels={'label1': 'value1',
                                                                                           Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                                                           Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method1'}).value == 1

        # method2 (indirect, inside span)
        assert telemetry.get_counter('tests.example.ExampleClass.method2_counter_inside_span',
                                     labels={'label1': 'value1', 'label2': 'value2',
                                             Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                             Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method2'}).value == 1

        assert len(telemetry.get_counters()) == 7

        # method1 (direct)
        assert telemetry.get_value_recorder('trace.duration',
                                            labels={'label1': 'value1',
                                                    Attributes.TRACE_STATUS.name: 'OK',
                                                    Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                    Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method1'}).count == 1

        assert telemetry.get_value_recorder('trace.duration',
                                            labels={'label1': 'value1',
                                                    Attributes.TRACE_STATUS.name: 'OK',
                                                    Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                    Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method1'}).sum >= 100
        assert telemetry.get_value_recorder('trace.duration',
                                            labels={'label1': 'value1',
                                                    Attributes.TRACE_STATUS.name: 'OK',
                                                    Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                    Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method1'}).min >= 100
        assert telemetry.get_value_recorder('trace.duration',
                                            labels={'label1': 'value1',
                                                    Attributes.TRACE_STATUS.name: 'OK',
                                                    Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                    Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method1'}).max >= 100

        # method2 (direct)
        assert telemetry.get_value_recorder('trace.duration',
                                            labels={'label2': 'value2',
                                                    Attributes.TRACE_STATUS.name: 'OK',
                                                    Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                    Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method2'}).count == 1
        assert telemetry.get_value_recorder('trace.duration',
                                            labels={'label2': 'value2',
                                                    Attributes.TRACE_STATUS.name: 'OK',
                                                    Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                    Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method2'}).sum >= 100
        assert telemetry.get_value_recorder('trace.duration',
                                            labels={'label2': 'value2',
                                                    Attributes.TRACE_STATUS.name: 'OK',
                                                    Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                    Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method2'}).min >= 100
        assert telemetry.get_value_recorder('trace.duration',
                                            labels={'label2': 'value2',
                                                    Attributes.TRACE_STATUS.name: 'OK',
                                                    Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                    Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method2'}).max >= 100

        # method2 (indirect)
        assert telemetry.get_value_recorder('trace.duration',
                                            labels={'label1': 'value1',
                                                    'label2': 'value2',
                                                    Attributes.TRACE_STATUS.name: 'OK',
                                                    Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                    Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.method2'}).count == 1

        # error (direct)
        assert telemetry.get_value_recorder('trace.duration',
                                            labels={Attributes.TRACE_STATUS.name: 'ERROR',
                                                    Attributes.TRACE_CATEGORY.name: 'tests.example.ExampleClass',
                                                    Attributes.TRACE_NAME.name: 'tests.example.ExampleClass.error'}).count == 1

        assert len(telemetry.get_value_recorders()) == 4