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:
parent
c4cf919204
commit
746c734a0c
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue