コード例 #1
0
    def _common_request(  # pylint: disable=too-many-locals
        self,
        args_name,
        traced_args,
        operation_name,
        original_func,
        instance,
        args,
        kwargs,
    ):

        endpoint_name = getattr(instance, "host").split(".")[0]

        with self._tracer.start_as_current_span(
                "{}.command".format(endpoint_name),
                kind=SpanKind.CONSUMER,
        ) as span:
            if args:
                http_method = args[0]
                span.resource = Resource(
                    attributes={
                        "endpoint": endpoint_name,
                        "http_method": http_method.lower(),
                    })
            else:
                span.resource = Resource(
                    attributes={"endpoint": endpoint_name})

            # Original func returns a boto.connection.HTTPResponse object
            result = original_func(*args, **kwargs)

            if span.is_recording():
                add_span_arg_tags(
                    span,
                    endpoint_name,
                    args,
                    args_name,
                    traced_args,
                )

                # Obtaining region name
                region_name = _get_instance_region_name(instance)

                meta = {
                    "aws.agent": "boto",
                    "aws.operation": operation_name,
                }
                if region_name:
                    meta["aws.region"] = region_name

                for key, value in meta.items():
                    span.set_attribute(key, value)

                span.set_attribute("http.status_code",
                                   getattr(result, "status"))
                span.set_attribute("http.method", getattr(result, "_method"))

            return result
コード例 #2
0
    def _patched_api_call(self, original_func, instance, args, kwargs):
        if context_api.get_value("suppress_instrumentation"):
            return original_func(*args, **kwargs)

        endpoint_name = deep_getattr(instance, "_endpoint._endpoint_prefix")

        with self._tracer.start_as_current_span(
            "{}.command".format(endpoint_name), kind=SpanKind.CONSUMER,
        ) as span:

            operation = None
            if args and span.is_recording():
                operation = args[0]
                span.resource = Resource(
                    attributes={
                        "endpoint": endpoint_name,
                        "operation": operation.lower(),
                    }
                )

            else:
                span.resource = Resource(
                    attributes={"endpoint": endpoint_name}
                )

            add_span_arg_tags(
                span,
                endpoint_name,
                args,
                ("action", "params", "path", "verb"),
                {"params", "path", "verb"},
            )

            if span.is_recording():
                region_name = deep_getattr(instance, "meta.region_name")

                meta = {
                    "aws.agent": "botocore",
                    "aws.operation": operation,
                    "aws.region": region_name,
                }
                for key, value in meta.items():
                    span.set_attribute(key, value)

            result = original_func(*args, **kwargs)

            if span.is_recording():
                span.set_attribute(
                    "http.status_code",
                    result["ResponseMetadata"]["HTTPStatusCode"],
                )
                span.set_attribute(
                    "retry_attempts",
                    result["ResponseMetadata"]["RetryAttempts"],
                )

            return result
コード例 #3
0
    def test_to_json(self):
        context = trace_api.SpanContext(
            trace_id=0x000000000000000000000000DEADBEEF,
            span_id=0x00000000DEADBEF0,
            is_remote=False,
            trace_flags=trace_api.TraceFlags(trace_api.TraceFlags.SAMPLED),
        )
        span = trace._Span("span-name", context)
        span.resource = Resource({})

        self.assertEqual(
            span.to_json(),
            """{
    "name": "span-name",
    "context": {
        "trace_id": "0x000000000000000000000000deadbeef",
        "span_id": "0x00000000deadbef0",
        "trace_state": "{}"
    },
    "kind": "SpanKind.INTERNAL",
    "parent_id": null,
    "start_time": null,
    "end_time": null,
    "attributes": {},
    "events": [],
    "links": [],
    "resource": {}
}""",
        )
        self.assertEqual(
            span.to_json(indent=None),
            '{"name": "span-name", "context": {"trace_id": "0x000000000000000000000000deadbeef", "span_id": "0x00000000deadbef0", "trace_state": "{}"}, "kind": "SpanKind.INTERNAL", "parent_id": null, "start_time": null, "end_time": null, "attributes": {}, "events": [], "links": [], "resource": {}}',
        )
    def test_service_name_fallback(self):
        context = trace_api.SpanContext(
            trace_id=0x000000000000000000000000DEADBEEF,
            span_id=0x34BF92DEEFC58C92,
            is_remote=False,
            trace_flags=trace_api.TraceFlags(trace_api.TraceFlags.SAMPLED),
        )
        trace_api.get_tracer_provider().sampler = sampling.TraceIdRatioBased(
            0.5)

        resource_with_default_name = Resource(
            attributes={
                "key_resource": "some_resource",
                "service.name": "unknown_service",
            })

        span = trace._Span(
            name="sampled",
            context=context,
            parent=None,
            resource=resource_with_default_name,
        )
        span.start()
        span.end()

        # pylint: disable=protected-access
        exporter = datadog.DatadogSpanExporter(service="fallback_service_name")
        datadog_spans = [
            span.to_dict() for span in exporter._translate_to_datadog([span])
        ]

        self.assertEqual(len(datadog_spans), 1)

        span = datadog_spans[0]
        self.assertEqual(span["service"], "fallback_service_name")
コード例 #5
0
def get_span_with_dropped_attributes_events_links():
    attributes = {}
    for index in range(130):
        attributes[f"key{index}"] = [f"value{index}"]
    links = []
    for index in range(129):
        links.append(
            trace_api.Link(
                trace_sdk._Span(
                    name=f"span{index}",
                    context=trace_api.INVALID_SPAN_CONTEXT,
                    attributes=attributes,
                ).get_span_context(),
                attributes=attributes,
            ))

    tracer = new_tracer(
        span_limits=trace_sdk.SpanLimits(),
        resource=Resource(attributes=attributes),
    )
    with tracer.start_as_current_span("span",
                                      links=links,
                                      attributes=attributes) as span:
        for index in range(131):
            span.add_event(f"event{index}", attributes=attributes)
        return span
コード例 #6
0
    def test_export(self):
        """Test that agent and/or collector are invoked"""

        trace_api.set_tracer_provider(
            TracerProvider(
                resource=Resource.create({SERVICE_NAME: "text_export"})))

        exporter = jaeger_exporter.JaegerExporter(agent_host_name="localhost",
                                                  agent_port=6318)

        # just agent is configured now
        agent_client_mock = mock.Mock(spec=jaeger_exporter.AgentClientUDP)
        # pylint: disable=protected-access
        exporter._agent_client = agent_client_mock

        exporter.export((self._test_span, ))
        self.assertEqual(agent_client_mock.emit.call_count, 1)

        # add also a collector and test that both are called
        collector_mock = mock.Mock(spec=jaeger_exporter.Collector)
        # pylint: disable=protected-access
        exporter._collector = collector_mock

        exporter.export((self._test_span, ))
        self.assertEqual(agent_client_mock.emit.call_count, 1)
        self.assertEqual(collector_mock.submit.call_count, 1)
コード例 #7
0
 def test_export_span_service_name(self):
     trace_api.set_tracer_provider(
         TracerProvider(
             resource=Resource.create({SERVICE_NAME: "text_export"})))
     exporter = jaeger_exporter.JaegerExporter(agent_host_name="localhost",
                                               agent_port=6318)
     agent_client_mock = mock.Mock(spec=jaeger_exporter.AgentClientUDP)
     exporter._agent_client = agent_client_mock
     resource = Resource.create({SERVICE_NAME: "test"})
     span = trace._Span("test_span",
                        context=self.context,
                        resource=resource)
     span.start()
     span.end()
     exporter.export([span])
     self.assertEqual(exporter.service_name, "test")
コード例 #8
0
    def test_export_protobuf_max_tag_length(self):
        service_name = "test-service"

        span_context = trace_api.SpanContext(
            0x0E0C63257DE34C926F9EFCD03927272E,
            0x04BF92DEEFC58C92,
            is_remote=False,
            trace_flags=TraceFlags(TraceFlags.SAMPLED),
        )

        span = trace._Span(
            name="test-span",
            context=span_context,
        )

        span.start()
        span.resource = Resource({})
        # added here to preserve order
        span.set_attribute("k1", "v" * 500)
        span.set_attribute("k2", "v" * 50)
        span.set_status(Status(StatusCode.ERROR, "Example description"))
        span.end()

        exporter = ZipkinSpanExporter(
            service_name,
            transport_format=TRANSPORT_FORMAT_PROTOBUF,
        )
        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export([span])
            self.assertEqual(SpanExportResult.SUCCESS, status)

        # pylint: disable=unsubscriptable-object
        kwargs = mock_post.call_args[1]
        actual_spans = zipkin_pb2.ListOfSpans.FromString(kwargs["data"])
        span_tags = actual_spans.spans[0].tags

        self.assertEqual(len(span_tags["k1"]), 128)
        self.assertEqual(len(span_tags["k2"]), 50)

        exporter = ZipkinSpanExporter(
            service_name,
            transport_format=TRANSPORT_FORMAT_PROTOBUF,
            max_tag_value_length=2,
        )
        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export([span])
            self.assertEqual(SpanExportResult.SUCCESS, status)

        # pylint: disable=unsubscriptable-object
        kwargs = mock_post.call_args[1]
        actual_spans = zipkin_pb2.ListOfSpans.FromString(kwargs["data"])
        span_tags = actual_spans.spans[0].tags

        self.assertEqual(len(span_tags["k1"]), 2)
        self.assertEqual(len(span_tags["k2"]), 2)
コード例 #9
0
    def test_max_tag_value_length(self):
        span = trace._Span(
            name="span",
            resource=Resource(attributes={
                "key_resource":
                "some_resource some_resource some_more_resource"
            }),
            context=trace_api.SpanContext(
                trace_id=0x000000000000000000000000DEADBEEF,
                span_id=0x00000000DEADBEF0,
                is_remote=False,
            ),
        )

        span.start()
        span.set_attribute("key_bool", False)
        span.set_attribute("key_string", "hello_world hello_world hello_world")
        span.set_attribute("key_float", 111.22)
        span.set_attribute("key_int", 1100)
        span.set_attribute("key_tuple", ("tuple_element", "tuple_element2"))
        span.end()

        translate = Translate([span])

        # does not truncate by default
        # pylint: disable=protected-access
        spans = translate._translate(pb_translator.ProtobufTranslator("svc"))
        tags_by_keys = {
            tag.key: tag.v_str
            for tag in spans[0].tags
            if tag.v_type == model_pb2.ValueType.STRING
        }
        self.assertEqual("hello_world hello_world hello_world",
                         tags_by_keys["key_string"])
        self.assertEqual("('tuple_element', 'tuple_element2')",
                         tags_by_keys["key_tuple"])
        self.assertEqual(
            "some_resource some_resource some_more_resource",
            tags_by_keys["key_resource"],
        )

        # truncates when max_tag_value_length is passed
        # pylint: disable=protected-access
        spans = translate._translate(
            pb_translator.ProtobufTranslator("svc", max_tag_value_length=5))
        tags_by_keys = {
            tag.key: tag.v_str
            for tag in spans[0].tags
            if tag.v_type == model_pb2.ValueType.STRING
        }
        self.assertEqual("hello", tags_by_keys["key_string"])
        self.assertEqual("('tup", tags_by_keys["key_tuple"])
        self.assertEqual("some_", tags_by_keys["key_resource"])
コード例 #10
0
    def test_constructor_by_environment_variables(self):
        #  pylint: disable=protected-access
        """Test the constructor using Environment Variables."""
        service = "my-opentelemetry-jaeger"

        agent_host_name = "opentelemetry.io"
        agent_port = "6831"

        collector_endpoint = "https://opentelemetry.io:15875"

        username = "******"
        password = "******"
        auth = (username, password)

        environ_patcher = mock.patch.dict(
            "os.environ",
            {
                OTEL_EXPORTER_JAEGER_AGENT_HOST: agent_host_name,
                OTEL_EXPORTER_JAEGER_AGENT_PORT: agent_port,
                OTEL_EXPORTER_JAEGER_ENDPOINT: collector_endpoint,
                OTEL_EXPORTER_JAEGER_USER: username,
                OTEL_EXPORTER_JAEGER_PASSWORD: password,
                OTEL_EXPORTER_JAEGER_TIMEOUT: "20",
            },
        )

        trace_api.set_tracer_provider(
            TracerProvider(resource=Resource.create(
                {SERVICE_NAME: "my-opentelemetry-jaeger"})))

        environ_patcher.start()
        exporter = jaeger_exporter.JaegerExporter()
        self.assertEqual(exporter.service_name, service)
        self.assertEqual(exporter.agent_host_name, agent_host_name)
        self.assertEqual(exporter.agent_port, int(agent_port))
        self.assertEqual(exporter._timeout, 20)
        self.assertTrue(exporter._collector_http_client is not None)
        self.assertEqual(exporter.collector_endpoint, collector_endpoint)
        self.assertEqual(exporter._collector_http_client.auth, auth)
        # property should not construct new object
        collector = exporter._collector_http_client
        self.assertEqual(exporter._collector_http_client, collector)
        # property should construct new object
        exporter._collector = None
        exporter.username = None
        exporter.password = None
        self.assertNotEqual(exporter._collector_http_client, collector)
        self.assertTrue(exporter._collector_http_client.auth is None)
        environ_patcher.stop()
コード例 #11
0
    def test_max_tag_length(self):
        service_name = "test-service"

        span_context = trace_api.SpanContext(
            0x0E0C63257DE34C926F9EFCD03927272E,
            0x04BF92DEEFC58C92,
            is_remote=False,
            trace_flags=TraceFlags(TraceFlags.SAMPLED),
        )

        span = trace._Span(
            name="test-span",
            context=span_context,
        )

        span.start()
        span.resource = Resource({})
        # added here to preserve order
        span.set_attribute("k1", "v" * 500)
        span.set_attribute("k2", "v" * 50)
        span.set_status(
            Status(StatusCanonicalCode.UNKNOWN, "Example description"))
        span.end()

        exporter = ZipkinSpanExporter(service_name)
        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export([span])
            self.assertEqual(SpanExportResult.SUCCESS, status)

        _, kwargs = mock_post.call_args  # pylint: disable=E0633

        tags = json.loads(kwargs["data"])[0]["tags"]
        self.assertEqual(len(tags["k1"]), 128)
        self.assertEqual(len(tags["k2"]), 50)

        exporter = ZipkinSpanExporter(service_name, max_tag_value_length=2)
        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export([span])
            self.assertEqual(SpanExportResult.SUCCESS, status)

        _, kwargs = mock_post.call_args  # pylint: disable=E0633
        tags = json.loads(kwargs["data"])[0]["tags"]
        self.assertEqual(len(tags["k1"]), 2)
        self.assertEqual(len(tags["k2"]), 2)
コード例 #12
0
    def setUp(self):
        # create and save span to be used in tests
        self.context = trace_api.SpanContext(
            trace_id=0x000000000000000000000000DEADBEEF,
            span_id=0x00000000DEADBEF0,
            is_remote=False,
        )

        self._test_span = trace._Span(
            "test_span",
            context=self.context,
            # Use a fixed version because a longer/shorter version number
            # might break tests that care about packet size.
            resource=Resource.create({"telemetry.sdk.version": "0.0.0.dev0"}),
        )
        self._test_span.start(start_time=1)
        self._test_span.end(end_time=3)
コード例 #13
0
 def test_attributes_to_json(self):
     context = trace_api.SpanContext(
         trace_id=0x000000000000000000000000DEADBEEF,
         span_id=0x00000000DEADBEF0,
         is_remote=False,
         trace_flags=trace_api.TraceFlags(trace_api.TraceFlags.SAMPLED),
     )
     span = trace._Span("span-name", context, resource=Resource({}))
     span.set_attribute("key", "value")
     span.add_event("event", {"key2": "value2"}, 123)
     date_str = ns_to_iso_str(123)
     self.assertEqual(
         span.to_json(indent=None),
         '{"name": "span-name", "context": {"trace_id": "0x000000000000000000000000deadbeef", "span_id": "0x00000000deadbef0", "trace_state": "[]"}, "kind": "SpanKind.INTERNAL", "parent_id": null, "start_time": null, "end_time": null, "status": {"status_code": "UNSET"}, "attributes": {"key": "value"}, "events": [{"name": "event", "timestamp": "'
         + date_str
         + '", "attributes": {"key2": "value2"}}], "links": [], "resource": {}}',
     )
コード例 #14
0
    def test_constructor_default(self):
        # pylint: disable=protected-access
        """Test the default values assigned by constructor."""
        service_name = "my-service-name"
        agent_host_name = "localhost"
        agent_port = 6831

        trace_api.set_tracer_provider(
            TracerProvider(
                resource=Resource.create({SERVICE_NAME: "my-service-name"})))

        exporter = jaeger_exporter.JaegerExporter()
        self.assertEqual(exporter.service_name, service_name)
        self.assertEqual(exporter.agent_host_name, agent_host_name)
        self.assertEqual(exporter.agent_port, agent_port)
        self.assertEqual(exporter.collector_endpoint, None)
        self.assertEqual(exporter.username, None)
        self.assertEqual(exporter.password, None)
        self.assertTrue(exporter._collector_http_client is None)
        self.assertTrue(exporter._agent_client is not None)
        self.assertIsNone(exporter._max_tag_value_length)
コード例 #15
0
    def test_constructor_explicit(self):
        # pylint: disable=protected-access
        """Test the constructor passing all the options."""
        service = "my-opentelemetry-jaeger"
        collector_endpoint = "https://opentelemetry.io:15875"

        agent_port = 14268
        agent_host_name = "opentelemetry.io"

        username = "******"
        password = "******"
        auth = (username, password)
        trace_api.set_tracer_provider(
            TracerProvider(resource=Resource.create(
                {SERVICE_NAME: "my-opentelemetry-jaeger"})))

        exporter = jaeger_exporter.JaegerExporter(
            agent_host_name=agent_host_name,
            agent_port=agent_port,
            collector_endpoint=collector_endpoint,
            username=username,
            password=password,
            max_tag_value_length=42,
        )
        self.assertEqual(exporter.service_name, service)
        self.assertEqual(exporter.agent_host_name, agent_host_name)
        self.assertEqual(exporter.agent_port, agent_port)
        self.assertTrue(exporter._collector_http_client is not None)
        self.assertEqual(exporter._collector_http_client.auth, auth)
        # property should not construct new object
        collector = exporter._collector_http_client
        self.assertEqual(exporter._collector_http_client, collector)
        # property should construct new object
        exporter._collector = None
        exporter.username = None
        exporter.password = None
        self.assertNotEqual(exporter._collector_http_client, collector)
        self.assertTrue(exporter._collector_http_client.auth is None)
        self.assertEqual(exporter._max_tag_value_length, 42)
コード例 #16
0
ファイル: app.py プロジェクト: okilker/ot-sample-app
async def fetch(session: aiohttp.ClientSession, url, payload):
    async with session.post(url, data=payload) as resp:
        return await resp.json()


async def make_booking(request):
    async with aiohttp.ClientSession() as session:
        results = await asyncio.gather(
            fetch(session,
                  os.getenv("PAY_SVC"),
                  payload={"card": request.json["card"]}),
            fetch(session,
                  os.getenv("RSV_SVC"),
                  payload={
                      "date": request.json["date"],
                      "name": request.json["name"]
                  }))

    print(results)
    return web.Response(body="success!", status=200)


app = web.Application()
app.add_routes([web.get('/booking', make_booking)])

if __name__ == '__main__':
    trace.set_tracer_provider(
        TracerProvider(resource=Resource({"service.name": "booking"})))
    trace.get_tracer_provider().add_span_processor(
        BatchExportSpanProcessor(OTLPSpanExporter(os.getenv("OTC_HOST"))))
    web.run_app(app, port=5000)
コード例 #17
0
    def test_translate_to_datadog(self):
        # pylint: disable=invalid-name
        self.maxDiff = None

        resource = Resource(
            attributes={
                "key_resource": "some_resource",
                "service.name": "resource_service_name",
            })

        resource_without_service = Resource(
            attributes={"conflicting_key": "conflicting_value"})

        span_names = ("test1", "test2", "test3")
        trace_id = 0x6E0C63257DE34C926F9EFCD03927272E
        trace_id_low = 0x6F9EFCD03927272E
        span_id = 0x34BF92DEEFC58C92
        parent_id = 0x1111111111111111
        other_id = 0x2222222222222222

        base_time = 683647322 * 10**9  # in ns
        start_times = (
            base_time,
            base_time + 150 * 10**6,
            base_time + 300 * 10**6,
        )
        durations = (50 * 10**6, 100 * 10**6, 200 * 10**6)
        end_times = (
            start_times[0] + durations[0],
            start_times[1] + durations[1],
            start_times[2] + durations[2],
        )

        span_context = trace_api.SpanContext(trace_id,
                                             span_id,
                                             is_remote=False)
        parent_span_context = trace_api.SpanContext(trace_id,
                                                    parent_id,
                                                    is_remote=False)
        other_context = trace_api.SpanContext(trace_id,
                                              other_id,
                                              is_remote=False)

        instrumentation_info = InstrumentationInfo(__name__, "0")

        otel_spans = [
            trace._Span(
                name=span_names[0],
                context=span_context,
                parent=parent_span_context,
                kind=trace_api.SpanKind.CLIENT,
                instrumentation_info=instrumentation_info,
                resource=Resource({}),
            ),
            trace._Span(
                name=span_names[1],
                context=parent_span_context,
                parent=None,
                instrumentation_info=instrumentation_info,
                resource=resource_without_service,
            ),
            trace._Span(
                name=span_names[2],
                context=other_context,
                parent=None,
                resource=resource,
            ),
        ]

        otel_spans[1].set_attribute("conflicting_key", "original_value")

        otel_spans[0].start(start_time=start_times[0])
        otel_spans[0].end(end_time=end_times[0])

        otel_spans[1].start(start_time=start_times[1])
        otel_spans[1].end(end_time=end_times[1])

        otel_spans[2].start(start_time=start_times[2])
        otel_spans[2].end(end_time=end_times[2])

        # pylint: disable=protected-access
        exporter = datadog.DatadogSpanExporter()
        datadog_spans = [
            span.to_dict()
            for span in exporter._translate_to_datadog(otel_spans)
        ]

        expected_spans = [
            dict(
                trace_id=trace_id_low,
                parent_id=parent_id,
                span_id=span_id,
                name="tests.test_datadog_exporter.CLIENT",
                resource=span_names[0],
                start=start_times[0],
                duration=durations[0],
                error=0,
                service="test-service",
                meta={
                    "env": "test",
                    "team": "testers"
                },
            ),
            dict(
                trace_id=trace_id_low,
                parent_id=0,
                span_id=parent_id,
                name="tests.test_datadog_exporter.INTERNAL",
                resource=span_names[1],
                start=start_times[1],
                duration=durations[1],
                error=0,
                service="test-service",
                meta={
                    "env": "test",
                    "team": "testers",
                    "version": "0.0.1",
                    "conflicting_key": "original_value",
                },
            ),
            dict(
                trace_id=trace_id_low,
                parent_id=0,
                span_id=other_id,
                name=span_names[2],
                resource=span_names[2],
                start=start_times[2],
                duration=durations[2],
                error=0,
                service="resource_service_name",
                meta={
                    "env": "test",
                    "team": "testers",
                    "version": "0.0.1",
                    "key_resource": "some_resource",
                },
            ),
        ]

        self.assertEqual(datadog_spans, expected_spans)
コード例 #18
0
    def test_translate_to_jaeger(self):
        # pylint: disable=invalid-name
        self.maxDiff = None

        span_names = ("test1", "test2", "test3")
        trace_id = 0x6E0C63257DE34C926F9EFCD03927272E
        trace_id_high = 0x6E0C63257DE34C92
        trace_id_low = 0x6F9EFCD03927272E
        span_id = 0x34BF92DEEFC58C92
        parent_id = 0x1111111111111111
        other_id = 0x2222222222222222

        base_time = 683647322 * 10 ** 9  # in ns
        start_times = (
            base_time,
            base_time + 150 * 10 ** 6,
            base_time + 300 * 10 ** 6,
        )
        durations = (50 * 10 ** 6, 100 * 10 ** 6, 200 * 10 ** 6)
        end_times = (
            start_times[0] + durations[0],
            start_times[1] + durations[1],
            start_times[2] + durations[2],
        )

        span_context = trace_api.SpanContext(
            trace_id, span_id, is_remote=False
        )
        parent_span_context = trace_api.SpanContext(
            trace_id, parent_id, is_remote=False
        )
        other_context = trace_api.SpanContext(
            trace_id, other_id, is_remote=False
        )

        event_attributes = {
            "annotation_bool": True,
            "annotation_string": "annotation_test",
            "key_float": 0.3,
        }

        event_timestamp = base_time + 50 * 10 ** 6
        event = trace.Event(
            name="event0",
            timestamp=event_timestamp,
            attributes=event_attributes,
        )

        link_attributes = {"key_bool": True}

        link = trace_api.Link(
            context=other_context, attributes=link_attributes
        )

        default_tags = [
            jaeger.Tag(
                key="span.kind", vType=jaeger.TagType.STRING, vStr="internal",
            ),
        ]

        otel_spans = [
            trace._Span(
                name=span_names[0],
                context=span_context,
                parent=parent_span_context,
                events=(event,),
                links=(link,),
                kind=trace_api.SpanKind.CLIENT,
                resource=Resource(
                    attributes={"key_resource": "some_resource"}
                ),
            ),
            trace._Span(
                name=span_names[1],
                context=parent_span_context,
                parent=None,
                resource=Resource({}),
            ),
            trace._Span(
                name=span_names[2],
                context=other_context,
                parent=None,
                resource=Resource({}),
                instrumentation_info=InstrumentationInfo(
                    name="name", version="version"
                ),
            ),
        ]

        otel_spans[0].start(start_time=start_times[0])
        # added here to preserve order
        otel_spans[0].set_attribute("key_bool", False)
        otel_spans[0].set_attribute("key_string", "hello_world")
        otel_spans[0].set_attribute("key_float", 111.22)
        otel_spans[0].set_attribute("key_tuple", ("tuple_element",))
        otel_spans[0].set_status(
            Status(StatusCode.ERROR, "Example description")
        )
        otel_spans[0].end(end_time=end_times[0])

        otel_spans[1].start(start_time=start_times[1])
        otel_spans[1].end(end_time=end_times[1])

        otel_spans[2].start(start_time=start_times[2])
        otel_spans[2].set_status(Status(StatusCode.OK, "Example description"))
        otel_spans[2].end(end_time=end_times[2])

        translate = Translate(otel_spans)
        # pylint: disable=protected-access
        spans = translate._translate(ThriftTranslator())

        expected_spans = [
            jaeger.Span(
                operationName=span_names[0],
                traceIdHigh=trace_id_high,
                traceIdLow=trace_id_low,
                spanId=span_id,
                parentSpanId=parent_id,
                startTime=start_times[0] // 10 ** 3,
                duration=durations[0] // 10 ** 3,
                flags=0,
                tags=[
                    jaeger.Tag(
                        key="key_bool", vType=jaeger.TagType.BOOL, vBool=False
                    ),
                    jaeger.Tag(
                        key="key_string",
                        vType=jaeger.TagType.STRING,
                        vStr="hello_world",
                    ),
                    jaeger.Tag(
                        key="key_float",
                        vType=jaeger.TagType.DOUBLE,
                        vDouble=111.22,
                    ),
                    jaeger.Tag(
                        key="key_tuple",
                        vType=jaeger.TagType.STRING,
                        vStr="('tuple_element',)",
                    ),
                    jaeger.Tag(
                        key="key_resource",
                        vType=jaeger.TagType.STRING,
                        vStr="some_resource",
                    ),
                    jaeger.Tag(
                        key="otel.status_code",
                        vType=jaeger.TagType.STRING,
                        vStr="ERROR",
                    ),
                    jaeger.Tag(
                        key="otel.status_description",
                        vType=jaeger.TagType.STRING,
                        vStr="Example description",
                    ),
                    jaeger.Tag(
                        key="span.kind",
                        vType=jaeger.TagType.STRING,
                        vStr="client",
                    ),
                    jaeger.Tag(
                        key="error", vType=jaeger.TagType.BOOL, vBool=True
                    ),
                ],
                references=[
                    jaeger.SpanRef(
                        refType=jaeger.SpanRefType.FOLLOWS_FROM,
                        traceIdHigh=trace_id_high,
                        traceIdLow=trace_id_low,
                        spanId=other_id,
                    )
                ],
                logs=[
                    jaeger.Log(
                        timestamp=event_timestamp // 10 ** 3,
                        fields=[
                            jaeger.Tag(
                                key="annotation_bool",
                                vType=jaeger.TagType.BOOL,
                                vBool=True,
                            ),
                            jaeger.Tag(
                                key="annotation_string",
                                vType=jaeger.TagType.STRING,
                                vStr="annotation_test",
                            ),
                            jaeger.Tag(
                                key="key_float",
                                vType=jaeger.TagType.DOUBLE,
                                vDouble=0.3,
                            ),
                            jaeger.Tag(
                                key="message",
                                vType=jaeger.TagType.STRING,
                                vStr="event0",
                            ),
                        ],
                    )
                ],
            ),
            jaeger.Span(
                operationName=span_names[1],
                traceIdHigh=trace_id_high,
                traceIdLow=trace_id_low,
                spanId=parent_id,
                parentSpanId=0,
                startTime=start_times[1] // 10 ** 3,
                duration=durations[1] // 10 ** 3,
                flags=0,
                tags=default_tags,
            ),
            jaeger.Span(
                operationName=span_names[2],
                traceIdHigh=trace_id_high,
                traceIdLow=trace_id_low,
                spanId=other_id,
                parentSpanId=0,
                startTime=start_times[2] // 10 ** 3,
                duration=durations[2] // 10 ** 3,
                flags=0,
                tags=[
                    jaeger.Tag(
                        key="otel.status_code",
                        vType=jaeger.TagType.STRING,
                        vStr="OK",
                    ),
                    jaeger.Tag(
                        key="otel.status_description",
                        vType=jaeger.TagType.STRING,
                        vStr="Example description",
                    ),
                    jaeger.Tag(
                        key="span.kind",
                        vType=jaeger.TagType.STRING,
                        vStr="internal",
                    ),
                    jaeger.Tag(
                        key=jaeger_exporter.translate.NAME_KEY,
                        vType=jaeger.TagType.STRING,
                        vStr="name",
                    ),
                    jaeger.Tag(
                        key=jaeger_exporter.translate.VERSION_KEY,
                        vType=jaeger.TagType.STRING,
                        vStr="version",
                    ),
                ],
            ),
        ]

        # events are complicated to compare because order of fields
        # (attributes) in otel is not important but in jeager it is
        self.assertCountEqual(
            spans[0].logs[0].fields, expected_spans[0].logs[0].fields
        )
        # get rid of fields to be able to compare the whole spans
        spans[0].logs[0].fields = None
        expected_spans[0].logs[0].fields = None

        self.assertEqual(spans, expected_spans)
コード例 #19
0
    def test_translate_to_jaeger(self):

        span_names = ("test1", "test2", "test3")
        trace_id = 0x6E0C63257DE34C926F9EFCD03927272E
        span_id = 0x34BF92DEEFC58C92
        parent_id = 0x1111111111111111
        other_id = 0x2222222222222222

        base_time = 683647322 * 10 ** 9  # in ns
        start_times = (
            base_time,
            base_time + 150 * 10 ** 6,
            base_time + 300 * 10 ** 6,
        )
        durations = (50 * 10 ** 6, 100 * 10 ** 6, 200 * 10 ** 6)
        end_times = (
            start_times[0] + durations[0],
            start_times[1] + durations[1],
            start_times[2] + durations[2],
        )

        span_context = trace_api.SpanContext(
            trace_id, span_id, is_remote=False
        )
        parent_span_context = trace_api.SpanContext(
            trace_id, parent_id, is_remote=False
        )
        other_context = trace_api.SpanContext(
            trace_id, other_id, is_remote=False
        )

        event_attributes = OrderedDict(
            [
                ("annotation_bool", True),
                ("annotation_string", "annotation_test"),
                ("key_float", 0.3),
            ]
        )

        event_timestamp = base_time + 50 * 10 ** 6
        # pylint:disable=protected-access
        event_timestamp_proto = pb_translator._proto_timestamp_from_epoch_nanos(
            event_timestamp
        )

        event = trace.Event(
            name="event0",
            timestamp=event_timestamp,
            attributes=event_attributes,
        )

        link_attributes = {"key_bool": True}

        link = trace_api.Link(
            context=other_context, attributes=link_attributes
        )

        default_tags = [
            model_pb2.KeyValue(
                key="span.kind",
                v_type=model_pb2.ValueType.STRING,
                v_str="internal",
            ),
        ]

        otel_spans = [
            trace._Span(
                name=span_names[0],
                context=span_context,
                parent=parent_span_context,
                events=(event,),
                links=(link,),
                kind=trace_api.SpanKind.CLIENT,
            ),
            trace._Span(
                name=span_names[1], context=parent_span_context, parent=None
            ),
            trace._Span(
                name=span_names[2], context=other_context, parent=None
            ),
        ]

        otel_spans[0].start(start_time=start_times[0])
        # added here to preserve order
        otel_spans[0].set_attribute("key_bool", False)
        otel_spans[0].set_attribute("key_string", "hello_world")
        otel_spans[0].set_attribute("key_float", 111.22)
        otel_spans[0].set_attribute("key_tuple", ("tuple_element",))
        otel_spans[0].resource = Resource(
            attributes={"key_resource": "some_resource"}
        )
        otel_spans[0].set_status(
            Status(StatusCode.ERROR, "Example description")
        )
        otel_spans[0].end(end_time=end_times[0])

        otel_spans[1].start(start_time=start_times[1])
        otel_spans[1].resource = Resource({})
        otel_spans[1].end(end_time=end_times[1])

        otel_spans[2].start(start_time=start_times[2])
        otel_spans[2].resource = Resource({})
        otel_spans[2].set_status(Status(StatusCode.OK, "Example description"))
        otel_spans[2].end(end_time=end_times[2])
        otel_spans[2].instrumentation_info = InstrumentationInfo(
            name="name", version="version"
        )

        translate = Translate(otel_spans)
        # pylint: disable=protected-access
        spans = translate._translate(pb_translator.ProtobufTranslator("svc"))

        span1_start_time = pb_translator._proto_timestamp_from_epoch_nanos(
            start_times[0]
        )
        span2_start_time = pb_translator._proto_timestamp_from_epoch_nanos(
            start_times[1]
        )
        span3_start_time = pb_translator._proto_timestamp_from_epoch_nanos(
            start_times[2]
        )

        span1_end_time = pb_translator._proto_timestamp_from_epoch_nanos(
            end_times[0]
        )
        span2_end_time = pb_translator._proto_timestamp_from_epoch_nanos(
            end_times[1]
        )
        span3_end_time = pb_translator._proto_timestamp_from_epoch_nanos(
            end_times[2]
        )

        span1_duration = pb_translator._duration_from_two_time_stamps(
            span1_start_time, span1_end_time
        )
        span2_duration = pb_translator._duration_from_two_time_stamps(
            span2_start_time, span2_end_time
        )
        span3_duration = pb_translator._duration_from_two_time_stamps(
            span3_start_time, span3_end_time
        )

        expected_spans = [
            model_pb2.Span(
                operation_name=span_names[0],
                trace_id=pb_translator._trace_id_to_bytes(trace_id),
                span_id=pb_translator._span_id_to_bytes(span_id),
                start_time=span1_start_time,
                duration=span1_duration,
                flags=0,
                tags=[
                    model_pb2.KeyValue(
                        key="key_bool",
                        v_type=model_pb2.ValueType.BOOL,
                        v_bool=False,
                    ),
                    model_pb2.KeyValue(
                        key="key_string",
                        v_type=model_pb2.ValueType.STRING,
                        v_str="hello_world",
                    ),
                    model_pb2.KeyValue(
                        key="key_float",
                        v_type=model_pb2.ValueType.FLOAT64,
                        v_float64=111.22,
                    ),
                    model_pb2.KeyValue(
                        key="key_tuple",
                        v_type=model_pb2.ValueType.STRING,
                        v_str="('tuple_element',)",
                    ),
                    model_pb2.KeyValue(
                        key="key_resource",
                        v_type=model_pb2.ValueType.STRING,
                        v_str="some_resource",
                    ),
                    model_pb2.KeyValue(
                        key="otel.status_code",
                        v_type=model_pb2.ValueType.STRING,
                        v_str="ERROR",
                    ),
                    model_pb2.KeyValue(
                        key="otel.status_description",
                        v_type=model_pb2.ValueType.STRING,
                        v_str="Example description",
                    ),
                    model_pb2.KeyValue(
                        key="span.kind",
                        v_type=model_pb2.ValueType.STRING,
                        v_str="client",
                    ),
                    model_pb2.KeyValue(
                        key="error",
                        v_type=model_pb2.ValueType.BOOL,
                        v_bool=True,
                    ),
                ],
                references=[
                    model_pb2.SpanRef(
                        ref_type=model_pb2.SpanRefType.FOLLOWS_FROM,
                        trace_id=pb_translator._trace_id_to_bytes(trace_id),
                        span_id=pb_translator._span_id_to_bytes(other_id),
                    )
                ],
                logs=[
                    model_pb2.Log(
                        timestamp=event_timestamp_proto,
                        fields=[
                            model_pb2.KeyValue(
                                key="annotation_bool",
                                v_type=model_pb2.ValueType.BOOL,
                                v_bool=True,
                            ),
                            model_pb2.KeyValue(
                                key="annotation_string",
                                v_type=model_pb2.ValueType.STRING,
                                v_str="annotation_test",
                            ),
                            model_pb2.KeyValue(
                                key="key_float",
                                v_type=model_pb2.ValueType.FLOAT64,
                                v_float64=0.3,
                            ),
                            model_pb2.KeyValue(
                                key="message",
                                v_type=model_pb2.ValueType.STRING,
                                v_str="event0",
                            ),
                        ],
                    )
                ],
                process=model_pb2.Process(
                    service_name="svc",
                    tags=[
                        model_pb2.KeyValue(
                            key="key_resource",
                            v_str="some_resource",
                            v_type=model_pb2.ValueType.STRING,
                        )
                    ],
                ),
            ),
            model_pb2.Span(
                operation_name=span_names[1],
                trace_id=pb_translator._trace_id_to_bytes(trace_id),
                span_id=pb_translator._span_id_to_bytes(parent_id),
                start_time=span2_start_time,
                duration=span2_duration,
                flags=0,
                tags=default_tags,
                process=model_pb2.Process(service_name="svc",),
            ),
            model_pb2.Span(
                operation_name=span_names[2],
                trace_id=pb_translator._trace_id_to_bytes(trace_id),
                span_id=pb_translator._span_id_to_bytes(other_id),
                start_time=span3_start_time,
                duration=span3_duration,
                flags=0,
                tags=[
                    model_pb2.KeyValue(
                        key="otel.status_code",
                        v_type=model_pb2.ValueType.STRING,
                        v_str="OK",
                    ),
                    model_pb2.KeyValue(
                        key="otel.status_description",
                        v_type=model_pb2.ValueType.STRING,
                        v_str="Example description",
                    ),
                    model_pb2.KeyValue(
                        key="span.kind",
                        v_type=model_pb2.ValueType.STRING,
                        v_str="internal",
                    ),
                    model_pb2.KeyValue(
                        key="otel.instrumentation_library.name",
                        v_type=model_pb2.ValueType.STRING,
                        v_str="name",
                    ),
                    model_pb2.KeyValue(
                        key="otel.instrumentation_library.version",
                        v_type=model_pb2.ValueType.STRING,
                        v_str="version",
                    ),
                ],
                process=model_pb2.Process(service_name="svc",),
            ),
        ]

        # events are complicated to compare because order of fields
        # (attributes) in otel is not important but in jeager it is
        # pylint: disable=no-member
        self.assertCountEqual(
            spans[0].logs[0].fields, expected_spans[0].logs[0].fields,
        )

        self.assertEqual(spans, expected_spans)
コード例 #20
0
    def test_export_protobuf(self):
        span_names = ("test1", "test2", "test3", "test4")
        trace_id = 0x6E0C63257DE34C926F9EFCD03927272E
        span_id = 0x34BF92DEEFC58C92
        parent_id = 0x1111111111111111
        other_id = 0x2222222222222222

        base_time = 683647322 * 10**9  # in ns
        start_times = (
            base_time,
            base_time + 150 * 10**6,
            base_time + 300 * 10**6,
            base_time + 400 * 10**6,
        )
        durations = (50 * 10**6, 100 * 10**6, 200 * 10**6, 300 * 10**6)
        end_times = (
            start_times[0] + durations[0],
            start_times[1] + durations[1],
            start_times[2] + durations[2],
            start_times[3] + durations[3],
        )

        span_context = trace_api.SpanContext(
            trace_id,
            span_id,
            is_remote=False,
            trace_flags=TraceFlags(TraceFlags.SAMPLED),
        )
        parent_span_context = trace_api.SpanContext(trace_id,
                                                    parent_id,
                                                    is_remote=False)
        other_context = trace_api.SpanContext(trace_id,
                                              other_id,
                                              is_remote=False)

        event_attributes = {
            "annotation_bool": True,
            "annotation_string": "annotation_test",
            "key_float": 0.3,
        }

        event_timestamp = base_time + 50 * 10**6
        event = trace.Event(
            name="event0",
            timestamp=event_timestamp,
            attributes=event_attributes,
        )

        link_attributes = {"key_bool": True}

        link = trace_api.Link(context=other_context,
                              attributes=link_attributes)

        otel_spans = [
            trace._Span(
                name=span_names[0],
                context=span_context,
                parent=parent_span_context,
                resource=Resource({}),
                events=(event, ),
                links=(link, ),
            ),
            trace._Span(
                name=span_names[1],
                context=parent_span_context,
                parent=None,
                resource=Resource(
                    attributes={"key_resource": "some_resource"}),
            ),
            trace._Span(
                name=span_names[2],
                context=other_context,
                parent=None,
                resource=Resource(
                    attributes={"key_resource": "some_resource"}),
            ),
            trace._Span(
                name=span_names[3],
                context=other_context,
                parent=None,
                resource=Resource({}),
                instrumentation_info=InstrumentationInfo(name="name",
                                                         version="version"),
            ),
        ]

        otel_spans[0].start(start_time=start_times[0])
        # added here to preserve order
        otel_spans[0].set_attribute("key_bool", False)
        otel_spans[0].set_attribute("key_string", "hello_world")
        otel_spans[0].set_attribute("key_float", 111.22)
        otel_spans[0].set_status(
            Status(StatusCode.ERROR, "Example description"))
        otel_spans[0].end(end_time=end_times[0])

        otel_spans[1].start(start_time=start_times[1])
        otel_spans[1].set_status(Status(StatusCode.OK))
        otel_spans[1].end(end_time=end_times[1])

        otel_spans[2].start(start_time=start_times[2])
        otel_spans[2].set_attribute("key_string", "hello_world")
        otel_spans[2].end(end_time=end_times[2])

        otel_spans[3].start(start_time=start_times[3])
        otel_spans[3].end(end_time=end_times[3])

        service_name = "test-service"
        local_endpoint = zipkin_pb2.Endpoint(service_name=service_name,
                                             port=9411)
        span_kind = SPAN_KIND_MAP_PROTOBUF[SpanKind.INTERNAL]

        expected_spans = zipkin_pb2.ListOfSpans(spans=[
            zipkin_pb2.Span(
                trace_id=trace_id.to_bytes(length=16,
                                           byteorder="big",
                                           signed=False),
                id=ZipkinSpanExporter.format_pbuf_span_id(span_id),
                name=span_names[0],
                timestamp=nsec_to_usec_round(start_times[0]),
                duration=nsec_to_usec_round(durations[0]),
                local_endpoint=local_endpoint,
                kind=span_kind,
                tags={
                    "key_bool": "false",
                    "key_string": "hello_world",
                    "key_float": "111.22",
                    "otel.status_code": "ERROR",
                    "error": "Example description",
                },
                debug=True,
                parent_id=ZipkinSpanExporter.format_pbuf_span_id(parent_id),
                annotations=[
                    zipkin_pb2.Annotation(
                        timestamp=nsec_to_usec_round(event_timestamp),
                        value=json.dumps({
                            "event0": {
                                "annotation_bool": True,
                                "annotation_string": "annotation_test",
                                "key_float": 0.3,
                            }
                        }),
                    ),
                ],
            ),
            zipkin_pb2.Span(
                trace_id=trace_id.to_bytes(length=16,
                                           byteorder="big",
                                           signed=False),
                id=ZipkinSpanExporter.format_pbuf_span_id(parent_id),
                name=span_names[1],
                timestamp=nsec_to_usec_round(start_times[1]),
                duration=nsec_to_usec_round(durations[1]),
                local_endpoint=local_endpoint,
                kind=span_kind,
                tags={
                    "key_resource": "some_resource",
                    "otel.status_code": "OK",
                },
            ),
            zipkin_pb2.Span(
                trace_id=trace_id.to_bytes(length=16,
                                           byteorder="big",
                                           signed=False),
                id=ZipkinSpanExporter.format_pbuf_span_id(other_id),
                name=span_names[2],
                timestamp=nsec_to_usec_round(start_times[2]),
                duration=nsec_to_usec_round(durations[2]),
                local_endpoint=local_endpoint,
                kind=span_kind,
                tags={
                    "key_string": "hello_world",
                    "key_resource": "some_resource",
                },
            ),
            zipkin_pb2.Span(
                trace_id=trace_id.to_bytes(length=16,
                                           byteorder="big",
                                           signed=False),
                id=ZipkinSpanExporter.format_pbuf_span_id(other_id),
                name=span_names[3],
                timestamp=nsec_to_usec_round(start_times[3]),
                duration=nsec_to_usec_round(durations[3]),
                local_endpoint=local_endpoint,
                kind=span_kind,
                tags={
                    NAME_KEY: "name",
                    VERSION_KEY: "version"
                },
            ),
        ], )

        exporter = ZipkinSpanExporter(
            service_name, transport_format=TRANSPORT_FORMAT_PROTOBUF)
        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export(otel_spans)
            self.assertEqual(SpanExportResult.SUCCESS, status)

        # pylint: disable=unsubscriptable-object
        kwargs = mock_post.call_args[1]

        self.assertEqual(kwargs["url"], "http://localhost:9411/api/v2/spans")
        self.assertEqual(kwargs["headers"]["Content-Type"],
                         "application/x-protobuf")
        self.assertEqual(zipkin_pb2.ListOfSpans.FromString(kwargs["data"]),
                         expected_spans)
コード例 #21
0
ファイル: app.py プロジェクト: girishgrover2008/ot-sample-app
@app.route('/book/<username>')
def hello_world(username):
    status = requests.post(os.getenv("BOOK_SVC"),
                           json={
                               "card":
                               "VISA",
                               "name":
                               username,
                               "date":
                               datetime.datetime.today().strftime('%Y-%m-%d')
                           })
    if status.ok:
        resp = status.json()
        return resp
    else:
        return 'bad request!', 400


if __name__ == '__main__':
    endpoint = "{}:{}".format(os.getenv("OTC_HOST"),
                              os.getenv("OTC_PORT", "55680"))
    print('OTC Collector endpoint set to {}'.format(endpoint))

    trace.set_tracer_provider(
        TracerProvider(resource=Resource({"service.name": "api"})))
    trace.get_tracer_provider().add_span_processor(
        BatchExportSpanProcessor(
            OTLPSpanExporter(endpoint=endpoint, insecure=True)))

    app.run(debug=True, host='0.0.0.0')
コード例 #22
0
    def test_export_json_zero_padding(self):
        """test that hex ids starting with 0
        are properly padded to 16 or 32 hex chars
        when exported
        """

        span_names = "testZeroes"
        trace_id = 0x0E0C63257DE34C926F9EFCD03927272E
        span_id = 0x04BF92DEEFC58C92
        parent_id = 0x0AAAAAAAAAAAAAAA

        start_time = 683647322 * 10**9  # in ns
        duration = 50 * 10**6
        end_time = start_time + duration

        span_context = trace_api.SpanContext(
            trace_id,
            span_id,
            is_remote=False,
            trace_flags=TraceFlags(TraceFlags.SAMPLED),
        )
        parent_span_context = trace_api.SpanContext(trace_id,
                                                    parent_id,
                                                    is_remote=False)

        otel_span = trace._Span(
            name=span_names[0],
            context=span_context,
            parent=parent_span_context,
            resource=Resource({}),
        )

        otel_span.start(start_time=start_time)
        otel_span.end(end_time=end_time)

        service_name = "test-service"
        local_endpoint = {"serviceName": service_name, "port": 9411}

        exporter = ZipkinSpanExporter(service_name)
        # Check traceId are properly lowercase 16 or 32 hex
        expected = [{
            "traceId": "0e0c63257de34c926f9efcd03927272e",
            "id": "04bf92deefc58c92",
            "name": span_names[0],
            "timestamp": start_time // 10**3,
            "duration": duration // 10**3,
            "localEndpoint": local_endpoint,
            "kind": SPAN_KIND_MAP_JSON[SpanKind.INTERNAL],
            "tags": {},
            "annotations": None,
            "debug": True,
            "parentId": "0aaaaaaaaaaaaaaa",
        }]

        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export([otel_span])
            self.assertEqual(SpanExportResult.SUCCESS, status)

        mock_post.assert_called_with(
            url="http://localhost:9411/api/v2/spans",
            data=json.dumps(expected),
            headers={"Content-Type": "application/json"},
        )
コード例 #23
0
    def test_export_json_max_tag_length(self):
        service_name = "test-service"

        span_context = trace_api.SpanContext(
            0x0E0C63257DE34C926F9EFCD03927272E,
            0x04BF92DEEFC58C92,
            is_remote=False,
            trace_flags=TraceFlags(TraceFlags.SAMPLED),
        )

        span = trace._Span(name="test-span",
                           context=span_context,
                           resource=Resource({}))

        span.start()
        # added here to preserve order
        span.set_attribute("string1", "v" * 500)
        span.set_attribute("string2", "v" * 50)
        span.set_attribute("list1", ["a"] * 25)
        span.set_attribute("list2", ["a"] * 10)
        span.set_attribute("list3", [2] * 25)
        span.set_attribute("list4", [2] * 10)
        span.set_attribute("list5", [True] * 25)
        span.set_attribute("list6", [True] * 10)
        span.set_attribute("tuple1", ("a", ) * 25)
        span.set_attribute("tuple2", ("a", ) * 10)
        span.set_attribute("tuple3", (2, ) * 25)
        span.set_attribute("tuple4", (2, ) * 10)
        span.set_attribute("tuple5", (True, ) * 25)
        span.set_attribute("tuple6", (True, ) * 10)
        span.set_attribute("range1", range(0, 25))
        span.set_attribute("range2", range(0, 10))
        span.set_attribute("empty_list", [])
        span.set_attribute("none_list", ["hello", None, "world"])

        span.set_status(Status(StatusCode.ERROR, "Example description"))
        span.end()

        exporter = ZipkinSpanExporter(service_name)
        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export([span])
            self.assertEqual(SpanExportResult.SUCCESS, status)

        _, kwargs = mock_post.call_args  # pylint: disable=E0633

        tags = json.loads(kwargs["data"])[0]["tags"]

        self.assertEqual(len(tags["string1"]), 128)
        self.assertEqual(len(tags["string2"]), 50)
        self.assertEqual(
            tags["list1"],
            '["a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a"]',
        )
        self.assertEqual(
            tags["list2"],
            '["a","a","a","a","a","a","a","a","a","a"]',
        )
        self.assertEqual(
            tags["list3"],
            '["2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2"]',
        )
        self.assertEqual(
            tags["list4"],
            '["2","2","2","2","2","2","2","2","2","2"]',
        )
        self.assertEqual(
            tags["list5"],
            '["true","true","true","true","true","true","true","true","true","true","true","true","true","true","true","true","true","true"]',
        )
        self.assertEqual(
            tags["list6"],
            '["true","true","true","true","true","true","true","true","true","true"]',
        )
        self.assertEqual(
            tags["tuple1"],
            '["a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a"]',
        )
        self.assertEqual(
            tags["tuple2"],
            '["a","a","a","a","a","a","a","a","a","a"]',
        )
        self.assertEqual(
            tags["tuple3"],
            '["2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2"]',
        )
        self.assertEqual(
            tags["tuple4"],
            '["2","2","2","2","2","2","2","2","2","2"]',
        )
        self.assertEqual(
            tags["tuple5"],
            '["true","true","true","true","true","true","true","true","true","true","true","true","true","true","true","true","true","true"]',
        )
        self.assertEqual(
            tags["tuple6"],
            '["true","true","true","true","true","true","true","true","true","true"]',
        )
        self.assertEqual(
            tags["range1"],
            '["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24"]',
        )
        self.assertEqual(
            tags["range2"],
            '["0","1","2","3","4","5","6","7","8","9"]',
        )
        self.assertEqual(
            tags["empty_list"],
            "[]",
        )
        self.assertEqual(
            tags["none_list"],
            '["hello",null,"world"]',
        )

        exporter = ZipkinSpanExporter(service_name, max_tag_value_length=2)
        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export([span])
            self.assertEqual(SpanExportResult.SUCCESS, status)

        _, kwargs = mock_post.call_args  # pylint: disable=E0633
        tags = json.loads(kwargs["data"])[0]["tags"]
        self.assertEqual(len(tags["string1"]), 2)
        self.assertEqual(len(tags["string2"]), 2)
        self.assertEqual(tags["list1"], "[]")
        self.assertEqual(tags["list2"], "[]")
        self.assertEqual(tags["list3"], "[]")
        self.assertEqual(tags["list4"], "[]")
        self.assertEqual(tags["list5"], "[]")
        self.assertEqual(tags["list6"], "[]")
        self.assertEqual(tags["tuple1"], "[]")
        self.assertEqual(tags["tuple2"], "[]")
        self.assertEqual(tags["tuple3"], "[]")
        self.assertEqual(tags["tuple4"], "[]")
        self.assertEqual(tags["tuple5"], "[]")
        self.assertEqual(tags["tuple6"], "[]")
        self.assertEqual(tags["range1"], "[]")
        self.assertEqual(tags["range2"], "[]")

        exporter = ZipkinSpanExporter(service_name, max_tag_value_length=5)
        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export([span])
            self.assertEqual(SpanExportResult.SUCCESS, status)

        _, kwargs = mock_post.call_args  # pylint: disable=E0633
        tags = json.loads(kwargs["data"])[0]["tags"]
        self.assertEqual(len(tags["string1"]), 5)
        self.assertEqual(len(tags["string2"]), 5)
        self.assertEqual(tags["list1"], '["a"]')
        self.assertEqual(tags["list2"], '["a"]')
        self.assertEqual(tags["list3"], '["2"]')
        self.assertEqual(tags["list4"], '["2"]')
        self.assertEqual(tags["list5"], "[]")
        self.assertEqual(tags["list6"], "[]")
        self.assertEqual(tags["tuple1"], '["a"]')
        self.assertEqual(tags["tuple2"], '["a"]')
        self.assertEqual(tags["tuple3"], '["2"]')
        self.assertEqual(tags["tuple4"], '["2"]')
        self.assertEqual(tags["tuple5"], "[]")
        self.assertEqual(tags["tuple6"], "[]")
        self.assertEqual(tags["range1"], '["0"]')
        self.assertEqual(tags["range2"], '["0"]')

        exporter = ZipkinSpanExporter(service_name, max_tag_value_length=9)
        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export([span])
            self.assertEqual(SpanExportResult.SUCCESS, status)

        _, kwargs = mock_post.call_args  # pylint: disable=E0633
        tags = json.loads(kwargs["data"])[0]["tags"]
        self.assertEqual(len(tags["string1"]), 9)
        self.assertEqual(len(tags["string2"]), 9)
        self.assertEqual(tags["list1"], '["a","a"]')
        self.assertEqual(tags["list2"], '["a","a"]')
        self.assertEqual(tags["list3"], '["2","2"]')
        self.assertEqual(tags["list4"], '["2","2"]')
        self.assertEqual(tags["list5"], '["true"]')
        self.assertEqual(tags["list6"], '["true"]')
        self.assertEqual(tags["tuple1"], '["a","a"]')
        self.assertEqual(tags["tuple2"], '["a","a"]')
        self.assertEqual(tags["tuple3"], '["2","2"]')
        self.assertEqual(tags["tuple4"], '["2","2"]')
        self.assertEqual(tags["tuple5"], '["true"]')
        self.assertEqual(tags["tuple6"], '["true"]')
        self.assertEqual(tags["range1"], '["0","1"]')
        self.assertEqual(tags["range2"], '["0","1"]')

        exporter = ZipkinSpanExporter(service_name, max_tag_value_length=10)
        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export([span])
            self.assertEqual(SpanExportResult.SUCCESS, status)

        _, kwargs = mock_post.call_args  # pylint: disable=E0633
        tags = json.loads(kwargs["data"])[0]["tags"]
        self.assertEqual(len(tags["string1"]), 10)
        self.assertEqual(len(tags["string2"]), 10)
        self.assertEqual(tags["list1"], '["a","a"]')
        self.assertEqual(tags["list2"], '["a","a"]')
        self.assertEqual(tags["list3"], '["2","2"]')
        self.assertEqual(tags["list4"], '["2","2"]')
        self.assertEqual(tags["list5"], '["true"]')
        self.assertEqual(tags["list6"], '["true"]')
        self.assertEqual(tags["tuple1"], '["a","a"]')
        self.assertEqual(tags["tuple2"], '["a","a"]')
        self.assertEqual(tags["tuple3"], '["2","2"]')
        self.assertEqual(tags["tuple4"], '["2","2"]')
        self.assertEqual(tags["tuple5"], '["true"]')
        self.assertEqual(tags["tuple6"], '["true"]')
        self.assertEqual(tags["range1"], '["0","1"]')
        self.assertEqual(tags["range2"], '["0","1"]')

        exporter = ZipkinSpanExporter(service_name, max_tag_value_length=11)
        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export([span])
            self.assertEqual(SpanExportResult.SUCCESS, status)

        _, kwargs = mock_post.call_args  # pylint: disable=E0633
        tags = json.loads(kwargs["data"])[0]["tags"]
        self.assertEqual(len(tags["string1"]), 11)
        self.assertEqual(len(tags["string2"]), 11)
        self.assertEqual(tags["list1"], '["a","a"]')
        self.assertEqual(tags["list2"], '["a","a"]')
        self.assertEqual(tags["list3"], '["2","2"]')
        self.assertEqual(tags["list4"], '["2","2"]')
        self.assertEqual(tags["list5"], '["true"]')
        self.assertEqual(tags["list6"], '["true"]')
        self.assertEqual(tags["tuple1"], '["a","a"]')
        self.assertEqual(tags["tuple2"], '["a","a"]')
        self.assertEqual(tags["tuple3"], '["2","2"]')
        self.assertEqual(tags["tuple4"], '["2","2"]')
        self.assertEqual(tags["tuple5"], '["true"]')
        self.assertEqual(tags["tuple6"], '["true"]')
        self.assertEqual(tags["range1"], '["0","1"]')
        self.assertEqual(tags["range2"], '["0","1"]')
コード例 #24
0
ファイル: configuration.py プロジェクト: ocelotl/otel-python
def configure_opentelemetry(
    access_token: str = _LS_ACCESS_TOKEN,
    span_endpoint: str = _OTEL_EXPORTER_OTLP_SPAN_ENDPOINT,
    metric_endpoint: str = _OTEL_EXPORTER_OTLP_METRIC_ENDPOINT,
    service_name: str = _LS_SERVICE_NAME,
    service_version: str = _LS_SERVICE_VERSION,
    propagator: list = _OTEL_PROPAGATORS,
    resource_labels: str = _OTEL_RESOURCE_LABELS,
    log_level: int = _OTEL_LOG_LEVEL,
    span_exporter_endpoint_insecure: bool = _OTEL_EXPORTER_OTLP_SPAN_INSECURE,
    metric_exporter_endpoint_insecure: bool = (
        _OTEL_EXPORTER_OTLP_METRIC_INSECURE
    ),
):
    """
    Configures OpenTelemetry with Lightstep environment variables

    This function works as a configuration layer that allows the Lightstep end
    user to use current environment variables seamlessly with OpenTelemetry. In
    this way, it is not needed to make any configuration changes to the
    environment before using OpenTelemetry. The configuration can be done via
    environment variables (prefixed with `LS`) or via arguments passed to this
    function. Each argument has a 1:1 correspondence with an environment
    variable, their description follows:

    Arguments:
        access_token (str): LS_ACCESS_TOKEN, the access token used to
            authenticate with the Lightstep satellite. This configuration value
            is mandatory.
        span_endpoint (str): OTEL_EXPORTER_OTLP_SPAN_ENDPOINT, the URL of the Lightstep
            satellite where the spans are to be exported. Defaults to
            `ingest.lightstep.com:443`.
        metric_endpoint (str): OTEL_EXPORTER_OTLP_METRIC_ENDPOINT, the URL of the metrics collector
            where the metrics are to be exported. Defaults to
            `ingest.lightstep.com:443/metrics`.
        service_name (str): LS_SERVICE_NAME, the name of the service that is
            used along with the access token to send spans to the Lighstep
            satellite. This configuration value is mandatory.
        service_version (str): LS_SERVICE_VERSION, the version of the service
            used to sernd spans to the Lightstep satellite. Defaults to
            `"unknown"`.
        propagator (list): OTEL_PROPAGATORS, a list of propagators to be used.
            Defaults to `["b3"]`.
        resource_labels (dict): OTEL_RESOURCE_LABELS, a dictionary of
            key value pairs used to instantiate the resouce of the tracer
            provider. Defaults to
            `{
                "service.name": _LS_SERVICE_NAME,
                "service.version": _LS_SERVICE_VERSION,
                "telemetry.sdk.language": "python",
                "telemetry.sdk.version": "0.9b0",
            }`
        log_level (int): OTEL_LOG_LEVEL, a boolean value that indicates the log
            level. Defaults to `logging.DEBUG`.
            information is to be printed. Defaults to `False`.
        span_exporter_endpoint_insecure (bool):
            OTEL_EXPORTER_OTLP_SPAN_INSECURE, a boolean value that indicates if
            an insecure channel is to be used to send spans to the satellite.
            Defaults to `False`.
        metric_exporter_endpoint_insecure (bool):
            OTEL_EXPORTER_OTLP_METRIC_INSECURE, a boolean value that indicates
            if an insecure channel is to be used to send spans to the
            satellite. Defaults to `False`.
    """

    basicConfig(level=log_level)

    _logger.debug("configuration")

    for key, value in {
        "access_token": access_token,
        "span_endpoint": span_endpoint,
        "metric_endpoint": metric_endpoint,
        "service_name": service_name,
        "service_version": service_version,
        "propagator": propagator,
        "resource_labels": resource_labels,
        "log_level": log_level,
        "span_exporter_endpoint_insecure": span_exporter_endpoint_insecure,
        "metric_exporter_endpoint_insecure": metric_exporter_endpoint_insecure,
    }.items():
        _logger.debug("%s: %s", key, value)

    if not _validate_service_name(service_name):

        message = (
            "Invalid configuration: service name missing. "
            "Set environment variable LS_SERVICE_NAME or call "
            "configure_opentelemetry with service_name defined"
        )
        _logger.error(message)
        raise InvalidConfigurationError(message)

    if access_token is None:
        if span_endpoint == _DEFAULT_OTEL_EXPORTER_OTLP_SPAN_ENDPOINT:
            message = (
                "Invalid configuration: token missing. "
                "Must be set to send data to {}. "
                "Set environment variable LS_ACCESS_TOKEN or call"
                "configure_opentelemetry with access_token defined"
            ).format(_OTEL_EXPORTER_OTLP_SPAN_ENDPOINT)
            _logger.error(message)
            raise InvalidConfigurationError(message)

    if not _validate_token(access_token):
        message = (
            "Invalid configuration: invalid token. "
            "Token must be a 32, 84 or 104 character long string."
        )
        _logger.error(message)
        raise InvalidConfigurationError(message)

    _logger.debug("configuring propagation")

    # FIXME use entry points (instead of a dictionary) to locate propagator
    # classes
    set_global_httptextformat(
        CompositeHTTPPropagator(
            [{"b3": B3Format}[propagator] for propagator in _OTEL_PROPAGATORS]
        )
    )

    _logger.debug("configuring tracing")

    metadata = None

    if _env.str("OPENTELEMETRY_PYTHON_TRACER_PROVIDER", None) is None:
        # FIXME now that new values can be set in the global configuration
        # object, check for this object having a tracer_provider attribute, if
        # not, set it to "sdk_tracer_provider" instead of using
        # set_tracer_provider, this in order to avoid having more than one
        # method of setting configuration.
        set_tracer_provider(TracerProvider())

    if access_token != "":
        metadata = (("lightstep-access-token", access_token),)

    credentials = ssl_channel_credentials()

    if span_exporter_endpoint_insecure:
        credentials = None

    # FIXME Do the same for metrics when the OTLPMetricsExporter is in
    # OpenTelemetry.
    get_tracer_provider().add_span_processor(
        BatchExportSpanProcessor(
            LightstepOTLPSpanExporter(
                endpoint=span_endpoint,
                credentials=credentials,
                metadata=metadata,
            )
        )
    )

    get_tracer_provider().resource = Resource(resource_labels)

    if log_level == DEBUG:
        get_tracer_provider().add_span_processor(
            BatchExportSpanProcessor(ConsoleSpanExporter())
        )
コード例 #25
0
    def test_export_json(self):
        span_names = ("test1", "test2", "test3", "test4")
        trace_id = 0x6E0C63257DE34C926F9EFCD03927272E
        span_id = 0x34BF92DEEFC58C92
        parent_id = 0x1111111111111111
        other_id = 0x2222222222222222

        base_time = 683647322 * 10**9  # in ns
        start_times = (
            base_time,
            base_time + 150 * 10**6,
            base_time + 300 * 10**6,
            base_time + 400 * 10**6,
        )
        durations = (50 * 10**6, 100 * 10**6, 200 * 10**6, 300 * 10**6)
        end_times = (
            start_times[0] + durations[0],
            start_times[1] + durations[1],
            start_times[2] + durations[2],
            start_times[3] + durations[3],
        )

        span_context = trace_api.SpanContext(
            trace_id,
            span_id,
            is_remote=False,
            trace_flags=TraceFlags(TraceFlags.SAMPLED),
        )
        parent_span_context = trace_api.SpanContext(trace_id,
                                                    parent_id,
                                                    is_remote=False)
        other_context = trace_api.SpanContext(trace_id,
                                              other_id,
                                              is_remote=False)

        event_attributes = {
            "annotation_bool": True,
            "annotation_string": "annotation_test",
            "key_float": 0.3,
        }

        event_timestamp = base_time + 50 * 10**6
        event = trace.Event(
            name="event0",
            timestamp=event_timestamp,
            attributes=event_attributes,
        )

        link_attributes = {"key_bool": True}

        link = trace_api.Link(context=other_context,
                              attributes=link_attributes)

        otel_spans = [
            trace._Span(
                name=span_names[0],
                context=span_context,
                parent=parent_span_context,
                events=(event, ),
                links=(link, ),
                resource=Resource({}),
            ),
            trace._Span(
                name=span_names[1],
                context=parent_span_context,
                parent=None,
                resource=Resource(
                    attributes={"key_resource": "some_resource"}),
            ),
            trace._Span(
                name=span_names[2],
                context=other_context,
                parent=None,
                resource=Resource(
                    attributes={"key_resource": "some_resource"}),
            ),
            trace._Span(
                name=span_names[3],
                context=other_context,
                parent=None,
                resource=Resource({}),
                instrumentation_info=InstrumentationInfo(name="name",
                                                         version="version"),
            ),
        ]

        otel_spans[0].start(start_time=start_times[0])
        # added here to preserve order
        otel_spans[0].set_attribute("key_bool", False)
        otel_spans[0].set_attribute("key_string", "hello_world")
        otel_spans[0].set_attribute("key_float", 111.22)
        otel_spans[0].set_status(
            Status(StatusCode.ERROR, "Example description"))
        otel_spans[0].end(end_time=end_times[0])

        otel_spans[1].start(start_time=start_times[1])
        otel_spans[1].end(end_time=end_times[1])

        otel_spans[2].start(start_time=start_times[2])
        otel_spans[2].set_attribute("key_string", "hello_world")
        otel_spans[2].end(end_time=end_times[2])

        otel_spans[3].start(start_time=start_times[3])
        otel_spans[3].end(end_time=end_times[3])

        service_name = "test-service"
        local_endpoint = {"serviceName": service_name, "port": 9411}
        span_kind = SPAN_KIND_MAP_JSON[SpanKind.INTERNAL]

        exporter = ZipkinSpanExporter(service_name)
        expected_spans = [
            {
                "traceId":
                format(trace_id, "x"),
                "id":
                format(span_id, "x"),
                "name":
                span_names[0],
                "timestamp":
                start_times[0] // 10**3,
                "duration":
                durations[0] // 10**3,
                "localEndpoint":
                local_endpoint,
                "kind":
                span_kind,
                "tags": {
                    "key_bool": "false",
                    "key_string": "hello_world",
                    "key_float": "111.22",
                    "otel.status_code": "ERROR",
                    "error": "Example description",
                },
                "debug":
                True,
                "parentId":
                format(parent_id, "x"),
                "annotations": [{
                    "timestamp": event_timestamp // 10**3,
                    "value": {
                        "event0": {
                            "annotation_bool": True,
                            "annotation_string": "annotation_test",
                            "key_float": 0.3,
                        }
                    },
                }],
            },
            {
                "traceId": format(trace_id, "x"),
                "id": format(parent_id, "x"),
                "name": span_names[1],
                "timestamp": start_times[1] // 10**3,
                "duration": durations[1] // 10**3,
                "localEndpoint": local_endpoint,
                "kind": span_kind,
                "tags": {
                    "key_resource": "some_resource"
                },
                "annotations": None,
            },
            {
                "traceId": format(trace_id, "x"),
                "id": format(other_id, "x"),
                "name": span_names[2],
                "timestamp": start_times[2] // 10**3,
                "duration": durations[2] // 10**3,
                "localEndpoint": local_endpoint,
                "kind": span_kind,
                "tags": {
                    "key_string": "hello_world",
                    "key_resource": "some_resource",
                },
                "annotations": None,
            },
            {
                "traceId": format(trace_id, "x"),
                "id": format(other_id, "x"),
                "name": span_names[3],
                "timestamp": start_times[3] // 10**3,
                "duration": durations[3] // 10**3,
                "localEndpoint": local_endpoint,
                "kind": span_kind,
                "tags": {
                    NAME_KEY: "name",
                    VERSION_KEY: "version"
                },
                "annotations": None,
            },
        ]

        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export(otel_spans)
            self.assertEqual(SpanExportResult.SUCCESS, status)

        # pylint: disable=unsubscriptable-object
        kwargs = mock_post.call_args[1]

        self.assertEqual(kwargs["url"], "http://localhost:9411/api/v2/spans")
        self.assertEqual(kwargs["headers"]["Content-Type"], "application/json")
        actual_spans = sorted(json.loads(kwargs["data"]),
                              key=lambda span: span["timestamp"])
        for expected, actual in zip(expected_spans, actual_spans):
            expected_annotations = expected.pop("annotations", None)
            actual_annotations = actual.pop("annotations", None)
            if actual_annotations:
                for annotation in actual_annotations:
                    annotation["value"] = json.loads(annotation["value"])
            self.assertEqual(expected, actual)
            self.assertEqual(expected_annotations, actual_annotations)
コード例 #26
0
    # create errors sometimes
    global counter
    counter += 1
    if counter % 3 == 0:
        error_request = requests.get("httpx2://www.invalidschema.com")

    name = request.json["name"]

    status = requests.post(os.getenv("ECHO_SVC"), json={"name": name})
    if status.ok:
        return jsonify({
            "data": f"Hello {name} from Delta Service!",
            "echo_response": status.json()
        })

    return jsonify({"data": f"Hello {name} from Delta Service!"})


if __name__ == '__main__':
    endpoint = "{}:{}".format(os.getenv("OTC_HOST"),
                              os.getenv("OTC_PORT", "55680"))
    print('OTC Collector endpoint set to {}'.format(endpoint))

    trace.set_tracer_provider(
        TracerProvider(resource=Resource({"service.name": "delta"})))
    trace.get_tracer_provider().add_span_processor(
        BatchExportSpanProcessor(
            OTLPSpanExporter(endpoint=endpoint, insecure=True)))

    app.run(debug=True, host='0.0.0.0')
コード例 #27
0
    def test_export(self):

        span_names = ("test1", "test2", "test3", "test4")
        trace_id = 0x6E0C63257DE34C926F9EFCD03927272E
        span_id = 0x34BF92DEEFC58C92
        parent_id = 0x1111111111111111
        other_id = 0x2222222222222222

        base_time = 683647322 * 10**9  # in ns
        start_times = (
            base_time,
            base_time + 150 * 10**6,
            base_time + 300 * 10**6,
            base_time + 400 * 10**6,
        )
        durations = (50 * 10**6, 100 * 10**6, 200 * 10**6, 300 * 10**6)
        end_times = (
            start_times[0] + durations[0],
            start_times[1] + durations[1],
            start_times[2] + durations[2],
            start_times[3] + durations[3],
        )

        span_context = trace_api.SpanContext(
            trace_id,
            span_id,
            is_remote=False,
            trace_flags=TraceFlags(TraceFlags.SAMPLED),
        )
        parent_context = trace_api.SpanContext(trace_id,
                                               parent_id,
                                               is_remote=False)
        other_context = trace_api.SpanContext(trace_id,
                                              other_id,
                                              is_remote=False)

        event_attributes = {
            "annotation_bool": True,
            "annotation_string": "annotation_test",
            "key_float": 0.3,
        }

        event_timestamp = base_time + 50 * 10**6
        event = trace.Event(
            name="event0",
            timestamp=event_timestamp,
            attributes=event_attributes,
        )

        link_attributes = {"key_bool": True}

        link = trace_api.Link(context=other_context,
                              attributes=link_attributes)

        otel_spans = [
            trace.Span(
                name=span_names[0],
                context=span_context,
                parent=parent_context,
                events=(event, ),
                links=(link, ),
            ),
            trace.Span(name=span_names[1], context=parent_context,
                       parent=None),
            trace.Span(name=span_names[2], context=other_context, parent=None),
            trace.Span(name=span_names[3], context=other_context, parent=None),
        ]

        otel_spans[0].start(start_time=start_times[0])
        otel_spans[0].resource = Resource({})
        # added here to preserve order
        otel_spans[0].set_attribute("key_bool", False)
        otel_spans[0].set_attribute("key_string", "hello_world")
        otel_spans[0].set_attribute("key_float", 111.22)
        otel_spans[0].set_status(
            Status(StatusCanonicalCode.UNKNOWN, "Example description"))
        otel_spans[0].end(end_time=end_times[0])

        otel_spans[1].start(start_time=start_times[1])
        otel_spans[1].resource = Resource(
            attributes={"key_resource": "some_resource"})
        otel_spans[1].end(end_time=end_times[1])

        otel_spans[2].start(start_time=start_times[2])
        otel_spans[2].set_attribute("key_string", "hello_world")
        otel_spans[2].resource = Resource(
            attributes={"key_resource": "some_resource"})
        otel_spans[2].end(end_time=end_times[2])

        otel_spans[3].start(start_time=start_times[3])
        otel_spans[3].resource = Resource({})
        otel_spans[3].end(end_time=end_times[3])
        otel_spans[3].instrumentation_info = InstrumentationInfo(
            name="name", version="version")

        service_name = "test-service"
        local_endpoint = {"serviceName": service_name, "port": 9411}

        exporter = ZipkinSpanExporter(service_name)
        expected = [
            {
                "traceId":
                format(trace_id, "x"),
                "id":
                format(span_id, "x"),
                "name":
                span_names[0],
                "timestamp":
                start_times[0] // 10**3,
                "duration":
                durations[0] // 10**3,
                "localEndpoint":
                local_endpoint,
                "kind":
                None,
                "tags": {
                    "key_bool": "False",
                    "key_string": "hello_world",
                    "key_float": "111.22",
                    "otel.status_code": "2",
                    "otel.status_description": "Example description",
                },
                "annotations": [{
                    "timestamp": event_timestamp // 10**3,
                    "value": "event0",
                }],
                "debug":
                True,
                "parentId":
                format(parent_id, "x"),
            },
            {
                "traceId": format(trace_id, "x"),
                "id": format(parent_id, "x"),
                "name": span_names[1],
                "timestamp": start_times[1] // 10**3,
                "duration": durations[1] // 10**3,
                "localEndpoint": local_endpoint,
                "kind": None,
                "tags": {
                    "key_resource": "some_resource",
                    "otel.status_code": "0",
                },
                "annotations": None,
            },
            {
                "traceId": format(trace_id, "x"),
                "id": format(other_id, "x"),
                "name": span_names[2],
                "timestamp": start_times[2] // 10**3,
                "duration": durations[2] // 10**3,
                "localEndpoint": local_endpoint,
                "kind": None,
                "tags": {
                    "key_string": "hello_world",
                    "key_resource": "some_resource",
                    "otel.status_code": "0",
                },
                "annotations": None,
            },
            {
                "traceId": format(trace_id, "x"),
                "id": format(other_id, "x"),
                "name": span_names[3],
                "timestamp": start_times[3] // 10**3,
                "duration": durations[3] // 10**3,
                "localEndpoint": local_endpoint,
                "kind": None,
                "tags": {
                    "otel.instrumentation_library.name": "name",
                    "otel.instrumentation_library.version": "version",
                    "otel.status_code": "0",
                },
                "annotations": None,
            },
        ]

        mock_post = MagicMock()
        with patch("requests.post", mock_post):
            mock_post.return_value = MockResponse(200)
            status = exporter.export(otel_spans)
            self.assertEqual(SpanExportResult.SUCCESS, status)

        mock_post.assert_called_with(
            url="http://localhost:9411/api/v2/spans",
            data=json.dumps(expected),
            headers={"Content-Type": "application/json"},
        )
コード例 #28
0
def configure_opentelemetry(
    access_token: str = _LS_ACCESS_TOKEN,
    span_exporter_endpoint: str = _OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
    service_name: str = _LS_SERVICE_NAME,
    service_version: str = _LS_SERVICE_VERSION,
    propagators: str = _OTEL_PROPAGATORS,
    resource_attributes: str = _OTEL_RESOURCE_ATTRIBUTES,
    log_level: str = _OTEL_LOG_LEVEL,
    span_exporter_insecure: bool = _OTEL_EXPORTER_OTLP_TRACES_INSECURE,
    _auto_instrumented: bool = False,
):
    # pylint: disable=too-many-locals
    # pylint: disable=too-many-statements
    """
    Configures OpenTelemetry with Lightstep environment variables

    This function works as a configuration layer that allows the Lightstep end
    user to use current environment variables seamlessly with OpenTelemetry. In
    this way, it is not needed to make any configuration changes to the
    environment before using OpenTelemetry. The configuration can be done via
    environment variables (prefixed with `LS`) or via arguments passed to this
    function. Each argument has a 1:1 correspondence with an environment
    variable, their description follows:

    Arguments:
        access_token (str): LS_ACCESS_TOKEN, the access token used to
            authenticate with the Lightstep satellite. This configuration value
            is mandatory.
        span_exporter_endpoint (str): OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, the URL of the Lightstep
            satellite where the spans are to be exported. Defaults to
            `ingest.lightstep.com:443`.
        service_name (str): LS_SERVICE_NAME, the name of the service that is
            used along with the access token to send spans to the Lighstep
            satellite. This configuration value is mandatory.
        service_version (str): LS_SERVICE_VERSION, the version of the service
            used to sernd spans to the Lightstep satellite. Defaults to `None`.
        propagators (str): OTEL_PROPAGATORS, a list of propagators to be used.
            The list is specified as a comma-separated string of values, for
            example: `a,b,c,d,e,f`. Defaults to `b3`.
        resource_attributes (str): OTEL_RESOURCE_ATTRIBUTES, a dictionary of
            key value pairs used to instantiate the resouce of the tracer
            provider. The dictionary is specified as a string of
            comma-separated `key=value` pairs. For example: `a=1,b=2,c=3`.
            Defaults to
            `telemetry.sdk.language=python,telemetry.sdk.version=X` where `X`
            is the version of this package.
        log_level (str): OTEL_LOG_LEVEL, one of:

            - `NOTSET` (0)
            - `DEBUG` (10)
            - `INFO` (20)
            - `WARNING` (30)
            - `ERROR` (40)
            - `CRITICAL` (50)

            Defaults to `logging.ERROR`.
        span_exporter_insecure (bool):
            OTEL_EXPORTER_OTLP_TRACES_INSECURE, a boolean value that indicates if
            an insecure channel is to be used to send spans to the satellite.
            Defaults to `False`.
    """

    log_levels = {
        "NOTSET": NOTSET,
        "DEBUG": DEBUG,
        "INFO": INFO,
        "WARNING": WARNING,
        "ERROR": ERROR,
        "CRITICAL": CRITICAL,
    }

    # No environment variable is passed here as the first argument since what
    # is intended here is just to parse the value of the already obtained value
    # of the environment variables OTEL_PROPAGATORS and
    # OTEL_RESOURCE_ATTRIBUTES into a list and a dictionary. This is not done
    # at the attribute declaration to avoid having mutable objects as default
    # arguments.
    propagators = _env.list("", propagators)
    resource_attributes = _env.dict("", resource_attributes)

    log_level = log_level.upper()

    if log_level not in log_levels.keys():

        message = (
            "Invalid configuration: invalid log_level value."
            "It must be one of {}.".format(", ".join(log_levels.keys()))
        )
        _logger.error(message)
        raise InvalidConfigurationError(message)

    log_level = log_levels[log_level]

    basicConfig(level=log_level)

    _logger.debug("configuration")

    if not _validate_service_name(service_name):

        message = (
            "Invalid configuration: service name missing. "
            "Set environment variable LS_SERVICE_NAME"
        )

        if not _auto_instrumented:
            message += (
                " or call configure_opentelemetry with service_name defined"
            )
        _logger.error(message)
        raise InvalidConfigurationError(message)

    resource_attributes["service.name"] = service_name

    logged_attributes = {
        "access_token": access_token,
        "span_exporter_endpoint": span_exporter_endpoint,
        "service_name": service_name,
        "propagators": propagators,
        "resource_attributes": resource_attributes,
        "log_level": getLevelName(log_level),
        "span_exporter_insecure": span_exporter_insecure,
    }

    if service_version is not None:
        resource_attributes["service.version"] = service_version
        logged_attributes["service_version"] = service_version

    for key, value in logged_attributes.items():
        _logger.debug("%s: %s", key, value)

    if access_token is None:
        if (
            span_exporter_endpoint
            == _DEFAULT_OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
        ):
            message = (
                "Invalid configuration: token missing. "
                "Must be set to send data to {}. "
                "Set environment variable LS_ACCESS_TOKEN"
            ).format(_OTEL_EXPORTER_OTLP_TRACES_ENDPOINT)
            if not _auto_instrumented:
                message += " or call configure_opentelemetry with access_token defined"
            _logger.error(message)
            raise InvalidConfigurationError(message)

    if access_token is not None and not _validate_token(access_token):
        message = (
            "Invalid configuration: invalid token. "
            "Token must be a 32, 84 or 104 character long string."
        )
        _logger.error(message)
        raise InvalidConfigurationError(message)

    _logger.debug("configuring propagation")

    # FIXME use entry points (instead of a dictionary) to locate propagator
    # classes
    set_global_textmap(
        CompositeHTTPPropagator(
            [
                {
                    "b3": B3Format(),
                    "baggage": BaggagePropagator(),
                    "tracecontext": TraceContextTextMapPropagator(),
                }[propagator]
                for propagator in propagators
            ]
        )
    )

    headers = None

    if access_token != "":
        headers = (("lightstep-access-token", access_token),)

    _logger.debug("configuring tracing")

    credentials = _common_configuration(
        set_tracer_provider,
        TracerProvider,
        "OTEL_PYTHON_TRACER_PROVIDER",
        span_exporter_insecure,
    )

    get_tracer_provider().add_span_processor(
        BatchExportSpanProcessor(
            LightstepOTLPSpanExporter(
                endpoint=span_exporter_endpoint,
                credentials=credentials,
                headers=headers,
            )
        )
    )

    if _ATTRIBUTE_HOST_NAME not in resource_attributes.keys() or not (
        resource_attributes[_ATTRIBUTE_HOST_NAME]
    ):

        no_hostname_message = (
            "set it with the environment variable OTEL_RESOURCE_ATTRIBUTES or "
            'with the resource_attributes argument. Use "host.name" as key '
            "in both cases."
        )
        try:
            hostname = gethostname()
            if not hostname:
                _logger.warning("Hostname is empty, %s", no_hostname_message)
            else:
                resource_attributes[_ATTRIBUTE_HOST_NAME] = hostname
        # pylint: disable=broad-except
        except Exception:
            _logger.exception(
                "Unable to get hostname, %s", no_hostname_message
            )

    get_tracer_provider().resource = Resource(resource_attributes)

    if log_level <= DEBUG:
        get_tracer_provider().add_span_processor(
            BatchExportSpanProcessor(ConsoleSpanExporter())
        )
コード例 #29
0
from opentelemetry import metrics
from opentelemetry.sdk.metrics.export import ConsoleMetricsExporter
from opentelemetry.exporter.otlp.metrics_exporter import OTLPMetricsExporter

app = Flask("api")


@app.route('/book/<username>')
def hello_world(username):
    status = requests.post(os.getenv("BOOK_SVC"), json={
        "card": "VISA",
        "name": username,
        "date": datetime.datetime.today().strftime('%Y-%m-%d')
    })
    if status.ok:
        resp = status.json()
        return resp
    else:
        return 'bad request!', 400


if __name__ == '__main__':
    resource = Resource({"service.name": "gateway"})

    trace.get_tracer_provider().resource = resource
    trace.get_tracer_provider().add_span_processor(BatchExportSpanProcessor(OTLPSpanExporter(os.getenv("OTC_HOST"))))

    metrics.get_meter_provider().resource = resource
    metrics.get_meter_provider().start_pipeline(RequestsInstrumentor().meter, ConsoleMetricsExporter(), 1)

    app.run(debug=True, host='0.0.0.0')
コード例 #30
0
from flask import jsonify, Flask, request
import os
import argparse

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider, Resource
from opentelemetry.sdk.trace.export import BatchExportSpanProcessor
from opentelemetry.exporter.otlp.trace_exporter import OTLPSpanExporter

app = Flask("payments")


@app.route("/process", methods=["POST"])
def process_card():
    return jsonify({"status": "charged {} $abc".format(request.json["card"])})


if __name__ == '__main__':
    trace.set_tracer_provider(
        TracerProvider(resource=Resource({"service.name": "payments"})))
    trace.get_tracer_provider().add_span_processor(
        BatchExportSpanProcessor(OTLPSpanExporter(os.getenv("OTC_HOST"))))
    app.run(debug=True, host='0.0.0.0')