exporter/datadog: add support for resource labels and service.name (#1074)

* exporter/datadog: add support for resource labels and service.name
This commit is contained in:
Eric Mustin 2020-09-18 17:51:49 +02:00 committed by alrex
parent c4cf919204
commit 746c734a0c
4 changed files with 73 additions and 8 deletions

View File

@ -2,6 +2,8 @@
## Unreleased ## Unreleased
- Add support for span resource labels and service name
## Version 0.12b0 ## Version 0.12b0
Released 2020-08-14 Released 2020-08-14

View File

@ -6,3 +6,4 @@ SAMPLE_RATE_METRIC_KEY = "_sample_rate"
SAMPLING_PRIORITY_KEY = "_sampling_priority_v1" SAMPLING_PRIORITY_KEY = "_sampling_priority_v1"
ENV_KEY = "env" ENV_KEY = "env"
VERSION_KEY = "version" VERSION_KEY = "version"
SERVICE_NAME_TAG = "service.name"

View File

@ -26,7 +26,13 @@ from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
from opentelemetry.trace.status import StatusCanonicalCode from opentelemetry.trace.status import StatusCanonicalCode
# pylint:disable=relative-beyond-top-level # pylint:disable=relative-beyond-top-level
from .constants import DD_ORIGIN, ENV_KEY, SAMPLE_RATE_METRIC_KEY, VERSION_KEY from .constants import (
DD_ORIGIN,
ENV_KEY,
SAMPLE_RATE_METRIC_KEY,
SERVICE_NAME_TAG,
VERSION_KEY,
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -107,6 +113,7 @@ class DatadogSpanExporter(SpanExporter):
self.agent_writer.stop() self.agent_writer.stop()
self.agent_writer.join(self.agent_writer.exit_timeout) self.agent_writer.join(self.agent_writer.exit_timeout)
# pylint: disable=too-many-locals
def _translate_to_datadog(self, spans): def _translate_to_datadog(self, spans):
datadog_spans = [] datadog_spans = []
@ -119,10 +126,16 @@ class DatadogSpanExporter(SpanExporter):
# duration. # duration.
tracer = None tracer = None
# extract resource attributes to be used as tags as well as potential service name
[
resource_tags,
resource_service_name,
] = _extract_tags_from_resource(span.resource)
datadog_span = DatadogSpan( datadog_span = DatadogSpan(
tracer, tracer,
_get_span_name(span), _get_span_name(span),
service=self.service, service=resource_service_name or self.service,
resource=_get_resource(span), resource=_get_resource(span),
span_type=_get_span_type(span), span_type=_get_span_type(span),
trace_id=trace_id, trace_id=trace_id,
@ -140,7 +153,12 @@ class DatadogSpanExporter(SpanExporter):
datadog_span.set_tag("error.msg", exc_val) datadog_span.set_tag("error.msg", exc_val)
datadog_span.set_tag("error.type", exc_type) datadog_span.set_tag("error.type", exc_type)
datadog_span.set_tags(span.attributes) # combine resource attributes and span attributes, don't modify existing span attributes
combined_span_tags = {}
combined_span_tags.update(resource_tags)
combined_span_tags.update(span.attributes)
datadog_span.set_tags(combined_span_tags)
# add configured env tag # add configured env tag
if self.env is not None: if self.env is not None:
@ -282,3 +300,19 @@ def _parse_tags_str(tags_str):
parsed_tags[key] = value parsed_tags[key] = value
return parsed_tags return parsed_tags
def _extract_tags_from_resource(resource):
"""Parse tags from resource.attributes, except service.name which
has special significance within datadog"""
tags = {}
service_name = None
if not (resource and getattr(resource, "attributes", None)):
return [tags, service_name]
for attribute_key, attribute_value in resource.attributes.items():
if attribute_key == SERVICE_NAME_TAG:
service_name = attribute_value
else:
tags[attribute_key] = attribute_value
return [tags, service_name]

View File

@ -23,7 +23,7 @@ from ddtrace.internal.writer import AgentWriter
from opentelemetry import trace as trace_api from opentelemetry import trace as trace_api
from opentelemetry.exporter import datadog from opentelemetry.exporter import datadog
from opentelemetry.sdk import trace from opentelemetry.sdk import trace
from opentelemetry.sdk.trace import sampling from opentelemetry.sdk.trace import Resource, sampling
from opentelemetry.sdk.util.instrumentation import InstrumentationInfo from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
@ -144,6 +144,17 @@ class TestDatadogSpanExporter(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
self.maxDiff = None 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") span_names = ("test1", "test2", "test3")
trace_id = 0x6E0C63257DE34C926F9EFCD03927272E trace_id = 0x6E0C63257DE34C926F9EFCD03927272E
trace_id_low = 0x6F9EFCD03927272E trace_id_low = 0x6F9EFCD03927272E
@ -183,18 +194,25 @@ class TestDatadogSpanExporter(unittest.TestCase):
parent=parent_context, parent=parent_context,
kind=trace_api.SpanKind.CLIENT, kind=trace_api.SpanKind.CLIENT,
instrumentation_info=instrumentation_info, instrumentation_info=instrumentation_info,
resource=Resource({}),
), ),
trace.Span( trace.Span(
name=span_names[1], name=span_names[1],
context=parent_context, context=parent_context,
parent=None, parent=None,
instrumentation_info=instrumentation_info, instrumentation_info=instrumentation_info,
resource=resource_without_service,
), ),
trace.Span( trace.Span(
name=span_names[2], context=other_context, parent=None, 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].start(start_time=start_times[0])
otel_spans[0].end(end_time=end_times[0]) otel_spans[0].end(end_time=end_times[0])
@ -234,7 +252,12 @@ class TestDatadogSpanExporter(unittest.TestCase):
duration=durations[1], duration=durations[1],
error=0, error=0,
service="test-service", service="test-service",
meta={"env": "test", "team": "testers", "version": "0.0.1"}, meta={
"env": "test",
"team": "testers",
"version": "0.0.1",
"conflicting_key": "original_value",
},
), ),
dict( dict(
trace_id=trace_id_low, trace_id=trace_id_low,
@ -245,8 +268,13 @@ class TestDatadogSpanExporter(unittest.TestCase):
start=start_times[2], start=start_times[2],
duration=durations[2], duration=durations[2],
error=0, error=0,
service="test-service", service="resource_service_name",
meta={"env": "test", "team": "testers", "version": "0.0.1"}, meta={
"env": "test",
"team": "testers",
"version": "0.0.1",
"key_resource": "some_resource",
},
), ),
] ]