Skip to content

Commit e44f29b

Browse files
committed
feat: Add exporter to datadog
1 parent 7c2ceba commit e44f29b

File tree

10 files changed

+489
-0
lines changed

10 files changed

+489
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Datadog Exporter Example
2+
=======================
3+
4+
This example shows how to use OpenTelemetry to send tracing data to Datadog.
5+
6+
Installation
7+
------------
8+
9+
.. code-block:: sh
10+
11+
pip install opentelemetry-api
12+
pip install opentelemetry-sdk
13+
pip install opentelemetry-ext-datadog
14+
15+
Run the Example
16+
---------------
17+
18+
* Start Datadog Agent
19+
20+
.. code-block:: sh
21+
22+
docker run -d -v /var/run/docker.sock:/var/run/docker.sock:ro \
23+
-v /proc/:/host/proc/:ro \
24+
-v /sys/fs/cgroup/:/host/sys/fs/cgroup:ro \
25+
-p 127.0.0.1:8126:8126/tcp \
26+
-e DD_API_KEY="<DATADOG_API_KEY>" \
27+
-e DD_APM_ENABLED=true \
28+
datadog/agent:latest
29+
30+
* Run the example
31+
32+
.. code-block:: sh
33+
34+
python datadog_exporter.py
35+
36+
The traces will be available at http://datadoghq.com/.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright The OpenTelemetry Authors
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
import os
17+
18+
from opentelemetry import trace
19+
from opentelemetry.ext.datadog import DatadogSpanExporter
20+
from opentelemetry.sdk.trace import TracerProvider
21+
from opentelemetry.sdk.trace.export import BatchExportSpanProcessor
22+
23+
trace.set_tracer_provider(TracerProvider())
24+
tracer = trace.get_tracer(__name__)
25+
26+
exporter = DatadogSpanExporter(agent_url="http://localhost:8126")
27+
28+
span_processor = BatchExportSpanProcessor(exporter)
29+
trace.get_tracer_provider().add_span_processor(span_processor)
30+
31+
with tracer.start_as_current_span("foo"):
32+
with tracer.start_as_current_span("bar"):
33+
with tracer.start_as_current_span("baz"):
34+
print("Hello world from OpenTelemetry Python!")
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
OpenTelemetry Datadog Exporter
2+
==============================
3+
4+
This library allows to export tracing data to `Datadog <https://www.datadoghq.com/>`_.
5+
6+
Installation
7+
------------
8+
9+
.. code-block:: sh
10+
11+
pip install opentelemetry-ext-datadog
12+
13+
14+
.. _Datadog: https://www.datadoghq.com/
15+
.. _OpenTelemetry: https://github.com/open-telemetry/opentelemetry-python/
16+
17+
18+
References
19+
----------
20+
21+
* `Datadog <https://www.datadoghq.com/>`_
22+
* `OpenTelemetry Project <https://opentelemetry.io/>`_
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
[metadata]
16+
name = opentelemetry-ext-datadog
17+
description = Datadog Exporter for OpenTelemetry
18+
long_description = file: README.rst
19+
long_description_content_type = text/x-rst
20+
author = OpenTelemetry Authors
21+
author_email = [email protected]
22+
url = https://github.com/open-telemetry/opentelemetry-python/ext/opentelemetry-ext-datadog
23+
platforms = any
24+
license = Apache-2.0
25+
classifiers =
26+
Development Status :: 4 - Beta
27+
Intended Audience :: Developers
28+
License :: OSI Approved :: Apache Software License
29+
Programming Language :: Python
30+
Programming Language :: Python :: 3
31+
Programming Language :: Python :: 3.5
32+
Programming Language :: Python :: 3.6
33+
Programming Language :: Python :: 3.7
34+
Programming Language :: Python :: 3.8
35+
36+
[options]
37+
python_requires = >=3.5
38+
package_dir=
39+
=src
40+
packages=find_namespace:
41+
install_requires =
42+
opentelemetry-api
43+
opentelemetry-sdk
44+
ddtrace
45+
46+
[options.packages.find]
47+
where = src
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import os
15+
16+
import setuptools
17+
18+
BASE_DIR = os.path.dirname(__file__)
19+
VERSION_FILENAME = os.path.join(
20+
BASE_DIR, "src", "opentelemetry", "ext", "datadog", "version.py"
21+
)
22+
PACKAGE_INFO = {}
23+
with open(VERSION_FILENAME) as f:
24+
exec(f.read(), PACKAGE_INFO)
25+
26+
setuptools.setup(version=PACKAGE_INFO["__version__"])
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import logging
2+
import os
3+
from urllib.parse import urlparse
4+
5+
from ddtrace.encoding import MsgpackEncoder
6+
from ddtrace.internal.writer import AgentWriter
7+
from ddtrace.span import Span as DatadogSpan
8+
9+
import opentelemetry.trace as trace_api
10+
from opentelemetry.sdk.trace import Span
11+
from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
12+
from opentelemetry.trace.status import StatusCanonicalCode
13+
14+
log = logging.getLogger(__name__)
15+
16+
DEFAULT_AGENT_URL = "http://localhost:8126"
17+
18+
19+
class DatadogSpanExporter(SpanExporter):
20+
def __init__(self, agent_url=None, service=None):
21+
self.agent_url = (
22+
agent_url
23+
if agent_url
24+
else os.environ.get("DD_TRACE_AGENT_URL", DEFAULT_AGENT_URL)
25+
)
26+
self.service = service if service else os.environ.get("DD_SERVICE")
27+
self._agent_writer = None
28+
29+
@property
30+
def agent_writer(self):
31+
if self._agent_writer is None:
32+
url_parsed = urlparse(self.agent_url)
33+
if url_parsed.scheme in ("http", "https"):
34+
self._agent_writer = AgentWriter(
35+
hostname=url_parsed.hostname,
36+
port=url_parsed.port,
37+
https=url_parsed.scheme == "https",
38+
)
39+
elif url_parsed.scheme == "unix":
40+
self._agent_writer = AgentWriter(uds_path=url_parsed.path)
41+
else:
42+
raise ValueError(
43+
"Unknown scheme `%s` for agent URL" % url_parsed.scheme
44+
)
45+
return self._agent_writer
46+
47+
def export(self, spans):
48+
datadog_spans = self._translate_to_datadog(spans)
49+
50+
self.agent_writer.write(spans=datadog_spans)
51+
52+
return SpanExportResult.SUCCESS
53+
54+
def shutdown(self):
55+
if self.agent_writer.started:
56+
self.agent_writer.stop()
57+
self.agent_writer.join(self.agent_writer.exit_timeout)
58+
59+
def _translate_to_datadog(self, spans):
60+
datadog_spans = []
61+
62+
for span in spans:
63+
trace_id, parent_id, span_id = _get_trace_ids(span)
64+
65+
# datadog Span is initialized with a reference to the tracer which is
66+
# used to record the span when it is finished. We can skip ignore this
67+
# because we are not calling the finish method and explictly set the
68+
# duration.
69+
tracer = None
70+
71+
datadog_span = DatadogSpan(
72+
tracer,
73+
span.name,
74+
# set service name if root span
75+
service=self.service if parent_id == 0 else None,
76+
# TODO: Handle resource
77+
resource=span.name,
78+
trace_id=trace_id,
79+
span_id=span_id,
80+
parent_id=parent_id,
81+
)
82+
datadog_span.start_ns = span.start_time
83+
datadog_span.duration_ns = span.end_time - span.start_time
84+
datadog_span.error = (
85+
1
86+
if span.status.canonical_code is not StatusCanonicalCode.OK
87+
else 0
88+
)
89+
90+
# TODO: Add span type
91+
# TODO: Add span tags
92+
# TODO: Add exception info
93+
94+
datadog_spans.append(datadog_span)
95+
96+
return datadog_spans
97+
98+
99+
def _get_trace_ids(span):
100+
ctx = span.get_context()
101+
trace_id = ctx.trace_id
102+
span_id = ctx.span_id
103+
104+
if isinstance(span.parent, trace_api.Span):
105+
parent_id = span.parent.get_context().span_id
106+
elif isinstance(span.parent, trace_api.SpanContext):
107+
parent_id = span.parent.span_id
108+
else:
109+
parent_id = 0
110+
111+
trace_id = _convert_trace_id_uint64(trace_id)
112+
113+
return trace_id, parent_id, span_id
114+
115+
116+
def _convert_trace_id_uint64(otel_id):
117+
raw = otel_id.to_bytes(16, "big")
118+
return int.from_bytes(raw[8:], byteorder="big")
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright 2019, OpenCensus Authors
2+
# Copyright The OpenTelemetry Authors
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
__version__ = "0.7.dev0"

ext/opentelemetry-ext-datadog/tests/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)