Skip to content

Commit

Permalink
ext/datadog: add environment variable configuration (#836)
Browse files Browse the repository at this point in the history
  • Loading branch information
majorgreys authored Jun 18, 2020
1 parent a7f0b75 commit 99cb046
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
USER_KEEP = 2
SAMPLE_RATE_METRIC_KEY = "_sample_rate"
SAMPLING_PRIORITY_KEY = "_sampling_priority_v1"
ENV_KEY = "env"
VERSION_KEY = "version"
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from opentelemetry.trace.status import StatusCanonicalCode

# pylint:disable=relative-beyond-top-level
from .constants import DD_ORIGIN, SAMPLE_RATE_METRIC_KEY
from .constants import DD_ORIGIN, ENV_KEY, SAMPLE_RATE_METRIC_KEY, VERSION_KEY

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -56,16 +56,24 @@ class DatadogSpanExporter(SpanExporter):
Args:
agent_url: The url of the Datadog Agent or use ``DD_TRACE_AGENT_URL`` environment variable
service: The service to be used for the application or use ``DD_SERVICE`` environment variable
service: The service name to be used for the application or use ``DD_SERVICE`` environment variable
env: Set the application’s environment or use ``DD_ENV`` environment variable
version: Set the application’s version or use ``DD_VERSION`` environment variable
tags: A list of default tags to be added to every span or use ``DD_TAGS`` environment variable
"""

def __init__(self, agent_url=None, service=None):
def __init__(
self, agent_url=None, service=None, env=None, version=None, tags=None
):
self.agent_url = (
agent_url
if agent_url
else os.environ.get("DD_TRACE_AGENT_URL", DEFAULT_AGENT_URL)
)
self.service = service if service else os.environ.get("DD_SERVICE")
self.service = service or os.environ.get("DD_SERVICE")
self.env = env or os.environ.get("DD_ENV")
self.version = version or os.environ.get("DD_VERSION")
self.tags = _parse_tags_str(tags or os.environ.get("DD_TAGS"))
self._agent_writer = None

@property
Expand Down Expand Up @@ -133,6 +141,17 @@ def _translate_to_datadog(self, spans):

datadog_span.set_tags(span.attributes)

# add configured env tag
if self.env is not None:
datadog_span.set_tag(ENV_KEY, self.env)

# add configured application version tag to only root span
if self.version is not None and parent_id == 0:
datadog_span.set_tag(VERSION_KEY, self.version)

# add configured global tags
datadog_span.set_tags(self.tags)

# add origin to root span
origin = _get_origin(span)
if origin and parent_id == 0:
Expand Down Expand Up @@ -230,3 +249,35 @@ def _get_sampling_rate(span):
and isinstance(span.sampler, trace_api.sampling.ProbabilitySampler)
else None
)


def _parse_tags_str(tags_str):
"""Parse a string of tags typically provided via environment variables.
The expected string is of the form::
"key1:value1,key2:value2"
:param tags_str: A string of the above form to parse tags from.
:return: A dict containing the tags that were parsed.
"""
parsed_tags = {}
if not tags_str:
return parsed_tags

for tag in tags_str.split(","):
try:
key, value = tag.split(":", 1)

# Validate the tag
if key == "" or value == "" or value.endswith(":"):
raise ValueError
except ValueError:
logger.error(
"Malformed tag in tag pair '%s' from tag string '%s'.",
tag,
tags_str,
)
else:
parsed_tags[key] = value

return parsed_tags
61 changes: 55 additions & 6 deletions ext/opentelemetry-ext-datadog/tests/test_datadog_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,26 +72,73 @@ def test_constructor_explicit(self):
"""Test the constructor passing all the options."""
agent_url = "http://localhost:8126"
exporter = datadog.DatadogSpanExporter(
agent_url=agent_url, service="explicit"
agent_url=agent_url, service="explicit",
)

self.assertEqual(exporter.agent_url, agent_url)
self.assertEqual(exporter.service, "explicit")
self.assertIsNotNone(exporter.agent_writer)
self.assertIsNone(exporter.env)
self.assertIsNone(exporter.version)
self.assertEqual(exporter.tags, {})

exporter = datadog.DatadogSpanExporter(
agent_url=agent_url,
service="explicit",
env="test",
version="0.0.1",
tags="",
)

self.assertEqual(exporter.agent_url, agent_url)
self.assertEqual(exporter.service, "explicit")
self.assertEqual(exporter.env, "test")
self.assertEqual(exporter.version, "0.0.1")
self.assertEqual(exporter.tags, {})

exporter = datadog.DatadogSpanExporter(
agent_url=agent_url,
service="explicit",
env="test",
version="0.0.1",
tags="team:testers,layer:app",
)

self.assertEqual(exporter.agent_url, agent_url)
self.assertEqual(exporter.service, "explicit")
self.assertEqual(exporter.env, "test")
self.assertEqual(exporter.version, "0.0.1")
self.assertEqual(exporter.tags, {"team": "testers", "layer": "app"})

@mock.patch.dict(
"os.environ",
{"DD_TRACE_AGENT_URL": "http://agent:8126", "DD_SERVICE": "environ"},
{
"DD_TRACE_AGENT_URL": "http://agent:8126",
"DD_SERVICE": "test-service",
"DD_ENV": "test",
"DD_VERSION": "0.0.1",
"DD_TAGS": "team:testers",
},
)
def test_constructor_environ(self):
exporter = datadog.DatadogSpanExporter()

self.assertEqual(exporter.agent_url, "http://agent:8126")
self.assertEqual(exporter.service, "environ")
self.assertEqual(exporter.service, "test-service")
self.assertEqual(exporter.env, "test")
self.assertEqual(exporter.version, "0.0.1")
self.assertEqual(exporter.tags, {"team": "testers"})
self.assertIsNotNone(exporter.agent_writer)

# pylint: disable=too-many-locals
@mock.patch.dict("os.environ", {"DD_SERVICE": "test-service"})
@mock.patch.dict(
"os.environ",
{
"DD_SERVICE": "test-service",
"DD_ENV": "test",
"DD_VERSION": "0.0.1",
"DD_TAGS": "team:testers",
},
)
def test_translate_to_datadog(self):
# pylint: disable=invalid-name
self.maxDiff = None
Expand Down Expand Up @@ -174,6 +221,7 @@ def test_translate_to_datadog(self):
duration=durations[0],
error=0,
service="test-service",
meta={"env": "test", "team": "testers"},
),
dict(
trace_id=trace_id_low,
Expand All @@ -185,6 +233,7 @@ def test_translate_to_datadog(self):
duration=durations[1],
error=0,
service="test-service",
meta={"env": "test", "team": "testers", "version": "0.0.1"},
),
dict(
trace_id=trace_id_low,
Expand All @@ -196,12 +245,12 @@ def test_translate_to_datadog(self):
duration=durations[2],
error=0,
service="test-service",
meta={"env": "test", "team": "testers", "version": "0.0.1"},
),
]

self.assertEqual(datadog_spans, expected_spans)

@mock.patch.dict("os.environ", {"DD_SERVICE": "test-service"})
def test_export(self):
"""Test that agent and/or collector are invoked"""
# create and save span to be used in tests
Expand Down

0 comments on commit 99cb046

Please sign in to comment.