def setUp(self): # create and save span to be used in tests context = trace_api.SpanContext( trace_id=0x000000000000000000000000DEADBEEF, span_id=0x00000000DEADBEF0, is_remote=False, ) self._test_span = trace._Span("test_span", context=context) self._test_span.start() self._test_span.end() # pylint: disable=protected-access Configuration._reset()
def test_span_delete(self): # ensure the helper removes properly a propagated Span @self.app.task def fn_task(): return 42 # propagate a Span task_id = "7c6731af-9533-40c3-83a9-25b58f0d837f" span = trace._Span("name", mock.Mock(spec=trace_api.SpanContext)) utils.attach_span(fn_task, task_id, span) # delete the Span utils.detach_span(fn_task, task_id) self.assertEqual(utils.retrieve_span(fn_task, task_id), (None, None))
def test_return_code(self): span = trace._Span("name", mock.Mock(spec=trace_api.SpanContext)) span_list = (span, ) memory_exporter = InMemorySpanExporter() ret = memory_exporter.export(span_list) self.assertEqual(ret, export.SpanExportResult.SUCCESS) memory_exporter.shutdown() # after shutdown export should fail ret = memory_exporter.export(span_list) self.assertEqual(ret, export.SpanExportResult.FAILURE)
def test_start_accepts_context(self): # pylint: disable=no-self-use span_processor = mock.Mock(spec=trace.SpanProcessor) span = trace._Span( "name", mock.Mock(spec=trace_api.SpanContext), span_processor=span_processor, ) context = Context() span.start(parent_context=context) span_processor.on_start.assert_called_once_with( span, parent_context=context )
def _create_start_and_end_span(name, span_processor): span = trace._Span( name, trace_api.SpanContext( 0xDEADBEEF, 0xDEADBEEF, is_remote=False, trace_flags=trace_api.TraceFlags(trace_api.TraceFlags.SAMPLED), ), span_processor=span_processor, ) span.start() span.end()
def test_export(self): # pylint: disable=no-self-use """Check that the console exporter prints spans.""" exporter = export.ConsoleSpanExporter() # Mocking stdout interferes with debugging and test reporting, mock on # the exporter instance instead. span = trace._Span("span name", trace_api.INVALID_SPAN_CONTEXT) with mock.patch.object(exporter, "out") as mock_stdout: exporter.export([span]) mock_stdout.write.assert_called_once_with(span.to_json() + os.linesep) self.assertEqual(mock_stdout.write.call_count, 1) self.assertEqual(mock_stdout.flush.call_count, 1)
def test_export_custom(self): # pylint: disable=no-self-use """Check that console exporter uses custom io, formatter.""" mock_span_str = mock.Mock(str) def formatter(span): # pylint: disable=unused-argument return mock_span_str mock_stdout = mock.Mock() exporter = export.ConsoleSpanExporter( out=mock_stdout, formatter=formatter ) exporter.export([trace._Span("span name", mock.Mock())]) mock_stdout.write.assert_called_once_with(mock_span_str)
def test_span_to_envelope_partA(self): exporter = self._exporter resource = resources.Resource({ "service.name": "testServiceName", "service.namespace": "testServiceNamespace", "service.instance.id": "testServiceInstanceId" }) context = SpanContext( trace_id=36873507687745823477771305566750195431, span_id=12030755672171557338, is_remote=False, ) test_span = trace._Span( name="test", context=context, resource=resource, attributes={"enduser.id": "testId"}, parent=context, ) test_span.start() test_span.end() envelope = exporter._span_to_envelope(test_span) self.assertEqual(envelope.instrumentation_key, "1234abcd-5678-4efa-8abc-1234567890ab") self.assertIsNotNone(envelope.tags) self.assertEqual(envelope.tags.get("ai.device.id"), azure_monitor_context["ai.device.id"]) self.assertEqual(envelope.tags.get("ai.device.locale"), azure_monitor_context["ai.device.locale"]) self.assertEqual(envelope.tags.get("ai.device.osVersion"), azure_monitor_context["ai.device.osVersion"]) self.assertEqual(envelope.tags.get("ai.device.type"), azure_monitor_context["ai.device.type"]) self.assertEqual(envelope.tags.get("ai.internal.sdkVersion"), azure_monitor_context["ai.internal.sdkVersion"]) self.assertEqual(envelope.tags.get("ai.cloud.role"), "testServiceNamespace.testServiceName") self.assertEqual(envelope.tags.get("ai.cloud.roleInstance"), "testServiceInstanceId") self.assertEqual(envelope.tags.get("ai.internal.nodeName"), "testServiceInstanceId") self.assertEqual(envelope.tags.get("ai.operation.id"), "{:032x}".format(context.trace_id)) self.assertEqual(envelope.tags.get("ai.user.id"), "testId") self.assertEqual(envelope.tags.get("ai.operation.parentId"), "{:016x}".format(context.span_id))
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), ) parent = trace._Span("parent-name", context, resource=Resource({})) span = trace._Span( "span-name", context, resource=Resource({}), parent=parent ) self.assertEqual( span.to_json(), """{ "name": "span-name", "context": { "trace_id": "0x000000000000000000000000deadbeef", "span_id": "0x00000000deadbef0", "trace_state": "[]" }, "kind": "SpanKind.INTERNAL", "parent_id": "0x00000000deadbef0", "start_time": null, "end_time": null, "status": { "status_code": "UNSET" }, "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": "0x00000000deadbef0", "start_time": null, "end_time": null, "status": {"status_code": "UNSET"}, "attributes": {}, "events": [], "links": [], "resource": {}}', )
def get_child_parent_new_carrier(old_carrier, propagator): ctx = propagator.extract(old_carrier) parent_span_context = trace_api.get_current_span(ctx).get_span_context() parent = trace._Span("parent", parent_span_context) child = trace._Span( "child", trace_api.SpanContext( parent_span_context.trace_id, id_generator.RandomIdGenerator().generate_span_id(), is_remote=False, trace_flags=parent_span_context.trace_flags, trace_state=parent_span_context.trace_state, ), parent=parent.get_span_context(), ) new_carrier = {} ctx = trace_api.set_span_in_context(child) propagator.inject(new_carrier, context=ctx) return child, parent, new_carrier
def test_context_propagation(self): """Test the propagation of Datadog headers.""" parent_context = get_current_span( FORMAT.extract( get_as_list, { FORMAT.TRACE_ID_KEY: self.serialized_trace_id, FORMAT.PARENT_ID_KEY: self.serialized_parent_id, FORMAT.SAMPLING_PRIORITY_KEY: str(constants.AUTO_KEEP), FORMAT.ORIGIN_KEY: self.serialized_origin, }, )).get_context() self.assertEqual(parent_context.trace_id, int(self.serialized_trace_id)) self.assertEqual(parent_context.span_id, int(self.serialized_parent_id)) self.assertEqual(parent_context.trace_flags, constants.AUTO_KEEP) self.assertEqual( parent_context.trace_state.get(constants.DD_ORIGIN), self.serialized_origin, ) self.assertTrue(parent_context.is_remote) child = trace._Span( "child", trace_api.SpanContext( parent_context.trace_id, trace_api.RandomIdsGenerator().generate_span_id(), is_remote=False, trace_flags=parent_context.trace_flags, trace_state=parent_context.trace_state, ), parent=parent_context, ) child_carrier = {} child_context = set_span_in_context(child) FORMAT.inject(dict.__setitem__, child_carrier, context=child_context) self.assertEqual(child_carrier[FORMAT.TRACE_ID_KEY], self.serialized_trace_id) self.assertEqual(child_carrier[FORMAT.PARENT_ID_KEY], str(child.context.span_id)) self.assertEqual( child_carrier[FORMAT.SAMPLING_PRIORITY_KEY], str(constants.AUTO_KEEP), ) self.assertEqual(child_carrier.get(FORMAT.ORIGIN_KEY), self.serialized_origin)
def get_child_parent_new_carrier(old_carrier): ctx = FORMAT.extract(carrier_getter, old_carrier) parent_span_context = trace_api.get_current_span(ctx).get_span_context() parent = trace._Span("parent", parent_span_context) child = trace._Span( "child", trace_api.SpanContext( parent_span_context.trace_id, ids_generator.RandomIdsGenerator().generate_span_id(), is_remote=False, trace_flags=parent_span_context.trace_flags, trace_state=parent_span_context.trace_state, ), parent=parent.get_span_context(), ) new_carrier = {} ctx = trace_api.set_span_in_context(child) FORMAT.inject(dict.__setitem__, new_carrier, context=ctx) return child, parent, new_carrier
def test_export_span_service_name(self, mock_post): mock_post.return_value = MockResponse(200) resource = Resource.create({SERVICE_NAME: "test"}) context = trace.SpanContext( trace_id=0x000000000000000000000000DEADBEEF, span_id=0x00000000DEADBEF0, is_remote=False, ) span = _Span("test_span", context=context, resource=resource) span.start() span.end() exporter = ZipkinExporter() exporter.export([span]) self.assertEqual(exporter.local_node.service_name, "test")
def setUp(self): tracer_provider = TracerProvider() self.exporter = OTLPSpanExporter(insecure=True) tracer_provider.add_span_processor( SimpleExportSpanProcessor(self.exporter)) self.tracer = tracer_provider.get_tracer(__name__) self.server = server(ThreadPoolExecutor(max_workers=10)) self.server.add_insecure_port("[::]:55680") self.server.start() event_mock = Mock( **{ "timestamp": 1591240820506462784, "attributes": OrderedDict([("a", 1), ("b", False)]), }) type(event_mock).name = PropertyMock(return_value="a") self.span = _Span( "a", context=Mock( **{ "trace_state": OrderedDict([("a", "b"), ("c", "d")]), "span_id": 10217189687419569865, "trace_id": 67545097771067222548457157018666467027, }), resource=SDKResource(OrderedDict([("a", 1), ("b", False)])), parent=Mock(**{"span_id": 12345}), attributes=OrderedDict([("a", 1), ("b", True)]), events=[event_mock], links=[ Mock( **{ "context.trace_id": 1, "context.span_id": 2, "attributes": OrderedDict([("a", 1), ("b", False)]), "kind": OTLPSpan.SpanKind.SPAN_KIND_INTERNAL, # pylint: disable=no-member }) ], instrumentation_info=InstrumentationInfo(name="name", version="version"), ) self.span.start() self.span.end() Configuration._reset() # pylint: disable=protected-access
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(ThriftTranslator()) tags_by_keys = { tag.key: tag.vStr for tag in spans[0].tags if tag.vType == 0 } 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(ThriftTranslator(max_tag_value_length=5)) tags_by_keys = { tag.key: tag.vStr for tag in spans[0].tags if tag.vType == 0 } self.assertEqual("hello", tags_by_keys["key_string"]) self.assertEqual("('tup", tags_by_keys["key_tuple"]) self.assertEqual("some_", tags_by_keys["key_resource"])
def test_origin(self): context = trace_api.SpanContext( trace_id=0x000000000000000000000000DEADBEEF, span_id=trace_api.INVALID_SPAN, is_remote=True, trace_state=trace_api.TraceState( {datadog.constants.DD_ORIGIN: "origin-service"} ), ) root_span = trace._Span(name="root", context=context, parent=None) child_span = trace._Span( name="child", context=context, parent=root_span ) root_span.start() child_span.start() child_span.end() root_span.end() # pylint: disable=protected-access exporter = datadog.DatadogSpanExporter() datadog_spans = [ span.to_dict() for span in exporter._translate_to_datadog([root_span, child_span]) ] self.assertEqual(len(datadog_spans), 2) actual = [ span["meta"].get(datadog.constants.DD_ORIGIN) if "meta" in span else None for span in datadog_spans ] expected = ["origin-service", None] self.assertListEqual(actual, expected)
def _create_span_with_status(status: SDKStatus): span = _Span( "a", context=Mock( **{ "trace_state": OrderedDict([("a", "b"), ("c", "d")]), "span_id": 10217189687419569865, "trace_id": 67545097771067222548457157018666467027, }), parent=Mock(**{"span_id": 12345}), instrumentation_info=InstrumentationInfo(name="name", version="version"), ) span.set_status(status) return span
def test_encode_id_zero_padding(self): 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 otel_span = trace._Span( name=TEST_SERVICE_NAME, context=trace_api.SpanContext( trace_id, span_id, is_remote=False, trace_flags=TraceFlags(TraceFlags.SAMPLED), ), parent=trace_api.SpanContext(trace_id, parent_id, is_remote=False), resource=trace.Resource({}), ) otel_span.start(start_time=start_time) otel_span.end(end_time=end_time) expected_output = [{ "traceId": format(trace_id, "032x"), "id": format(span_id, "016x"), "name": TEST_SERVICE_NAME, "timestamp": JsonV2Encoder._nsec_to_usec_round(start_time), "duration": JsonV2Encoder._nsec_to_usec_round(duration), "localEndpoint": { "serviceName": TEST_SERVICE_NAME }, "kind": JsonV2Encoder.SPAN_KIND_MAP[SpanKind.INTERNAL], "debug": True, "parentId": format(parent_id, "016x"), }] self.assert_equal_encoded_spans( json.dumps(expected_output), JsonV2Encoder().serialize([otel_span], NodeEndpoint()), )
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)
def test_span_to_envelope_client_rpc(self): exporter = self._exporter start_time = 1575494316027613500 end_time = start_time + 1001000000 # SpanKind.CLIENT rpc span = trace._Span( name="test", context=SpanContext( trace_id=36873507687745823477771305566750195431, span_id=12030755672171557337, is_remote=False, ), attributes={ "peer.service": "service", "rpc.system": "rpc", "rpc.service": "Test service", }, kind=SpanKind.CLIENT, ) span.start(start_time=start_time) span.end(end_time=end_time) span._status = Status(status_code=StatusCode.OK) envelope = exporter._span_to_envelope(span) self.assertEqual(envelope.name, "Microsoft.ApplicationInsights.RemoteDependency") self.assertEqual(envelope.time, "2019-12-04T21:18:36.027613Z") self.assertEqual(envelope.data.base_data.name, "test") self.assertEqual(envelope.data.base_data.id, "a6f5d48acb4d31d9") self.assertEqual(envelope.data.base_data.duration, "0.00:00:01.001") self.assertTrue(envelope.data.base_data.success) self.assertEqual(envelope.data.base_type, "RemoteDependencyData") self.assertEqual(envelope.data.base_data.type, "rpc.system") self.assertEqual(envelope.data.base_data.target, "service") # target span._attributes = { "rpc.system": "rpc", "rpc.service": "Test service", } envelope = exporter._span_to_envelope(span) self.assertEqual(envelope.data.base_data.target, "rpc") # TODO: data.data # self.assertEqual(envelope.data.base_data.data, "SELECT") self.assertEqual(envelope.data.base_data.result_code, "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")
def test_record_exception(self): span = trace._Span("name", mock.Mock(spec=trace_api.SpanContext)) try: raise ValueError("invalid") except ValueError as err: span.record_exception(err) exception_event = span.events[0] self.assertEqual("exception", exception_event.name) self.assertEqual("invalid", exception_event.attributes["exception.message"]) self.assertEqual("ValueError", exception_event.attributes["exception.type"]) self.assertIn( "ValueError: invalid", exception_event.attributes["exception.stacktrace"], )
def test_export(self): """Test that agent and/or collector are invoked""" # create and save span to be used in tests context = trace_api.SpanContext( trace_id=0x000000000000000000000000DEADBEEF, span_id=0x00000000DEADBEF0, is_remote=False, ) test_span = trace._Span("test_span", context=context) test_span.start() test_span.end() self.exporter.export((test_span, )) self.assertEqual(self.exporter.agent_writer.write.call_count, 1)
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)
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": {}}', )
def test_record_exception_escaped(self): span = trace._Span("name", mock.Mock(spec=trace_api.SpanContext)) try: raise RuntimeError("error") except RuntimeError as err: span.record_exception(exception=err, escaped=True) exception_event = span.events[0] self.assertEqual("exception", exception_event.name) self.assertEqual("error", exception_event.attributes["exception.message"]) self.assertEqual("RuntimeError", exception_event.attributes["exception.type"]) self.assertIn( "RuntimeError: error", exception_event.attributes["exception.stacktrace"], ) self.assertEqual("True", exception_event.attributes["exception.escaped"])
def test_export_not_retryable(self): exporter = self._exporter test_span = trace._Span( name="test", context=SpanContext( trace_id=36873507687745823477771305566750195431, span_id=12030755672171557338, is_remote=False, ), ) test_span.start() test_span.end() with mock.patch( "azure.monitor.opentelemetry.exporter.AzureMonitorTraceExporter._transmit" ) as transmit: # noqa: E501 transmit.return_value = ExportResult.FAILED_NOT_RETRYABLE result = exporter.export([test_span]) self.assertEqual(result, SpanExportResult.FAILURE)
def test_record_exception_with_timestamp(self): span = trace._Span("name", mock.Mock(spec=trace_api.SpanContext)) try: raise RuntimeError("error") except RuntimeError as err: timestamp = 1604238587112021089 span.record_exception(err, timestamp=timestamp) exception_event = span.events[0] self.assertEqual("exception", exception_event.name) self.assertEqual("error", exception_event.attributes["exception.message"]) self.assertEqual("RuntimeError", exception_event.attributes["exception.type"]) self.assertIn( "RuntimeError: error", exception_event.attributes["exception.stacktrace"], ) self.assertEqual(1604238587112021089, exception_event.timestamp)
def test_set_attributes_from_context(self): # it should extract only relevant keys context = { "correlation_id": "44b7f305", "delivery_info": {"eager": True}, "eta": "soon", "expires": "later", "hostname": "localhost", "id": "44b7f305", "reply_to": "44b7f305", "retries": 4, "timelimit": ("now", "later"), "custom_meta": "custom_value", "routing_key": "celery", } span = trace._Span("name", mock.Mock(spec=trace_api.SpanContext)) utils.set_attributes_from_context(span, context) self.assertEqual( span.attributes.get(SpanAttributes.MESSAGING_MESSAGE_ID), "44b7f305", ) self.assertEqual( span.attributes.get(SpanAttributes.MESSAGING_CONVERSATION_ID), "44b7f305", ) self.assertEqual( span.attributes.get(SpanAttributes.MESSAGING_DESTINATION), "celery" ) self.assertEqual( span.attributes["celery.delivery_info"], str({"eager": True}) ) self.assertEqual(span.attributes.get("celery.eta"), "soon") self.assertEqual(span.attributes.get("celery.expires"), "later") self.assertEqual(span.attributes.get("celery.hostname"), "localhost") self.assertEqual(span.attributes.get("celery.reply_to"), "44b7f305") self.assertEqual(span.attributes.get("celery.retries"), 4) self.assertEqual( span.attributes.get("celery.timelimit"), ("now", "later") ) self.assertNotIn("custom_meta", span.attributes)
def test_get_parent_id_from_span(self): parent_id = 0x00000000DEADBEF0 self.assertEqual( parent_id, self.get_encoder_default()._get_parent_id( trace._Span( name="test-span", context=trace_api.SpanContext( 0x000000000000000000000000DEADBEEF, 0x04BF92DEEFC58C92, is_remote=False, ), parent=trace_api.SpanContext( 0x0000000000000000000000AADEADBEEF, parent_id, is_remote=False, ), )), )