Skip to content

Commit 9fd4ccd

Browse files
hectorhdzgc24t
authored andcommitted
Adding pymongo integration (open-telemetry#232)
1 parent e95a115 commit 9fd4ccd

File tree

8 files changed

+417
-2
lines changed

8 files changed

+417
-2
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
OpenTelemetry pymongo integration
2+
=================================
3+
4+
The integration with MongoDB supports the `pymongo`_ library and is specified
5+
to ``trace_integration`` using ``'pymongo'``.
6+
7+
.. _pymongo: https://pypi.org/project/pymongo
8+
9+
Usage
10+
-----
11+
12+
.. code:: python
13+
14+
from pymongo import MongoClient
15+
from opentelemetry.trace import tracer
16+
from opentelemetry.trace.ext.pymongo import trace_integration
17+
18+
trace_integration(tracer())
19+
client = MongoClient()
20+
db = client["MongoDB_Database"]
21+
collection = db["MongoDB_Collection"]
22+
collection.find_one()
23+
24+
References
25+
----------
26+
27+
* `OpenTelemetry Project <https://opentelemetry.io/>`_
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Copyright 2019, 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-pymongo
17+
description = OpenTelemetry pymongo integration
18+
long_description = file: README.rst
19+
long_description_content_type = text/x-rst
20+
author = OpenTelemetry Authors
21+
author_email = cncf-opentelemetry-contributors@lists.cncf.io
22+
url = https://github.com/open-telemetry/opentelemetry-python/ext/opentelemetry-ext-pymongo
23+
platforms = any
24+
license = Apache-2.0
25+
classifiers =
26+
Development Status :: 3 - Alpha
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.4
32+
Programming Language :: Python :: 3.5
33+
Programming Language :: Python :: 3.6
34+
Programming Language :: Python :: 3.7
35+
36+
[options]
37+
python_requires = >=3.4
38+
package_dir=
39+
=src
40+
packages=find_namespace:
41+
install_requires =
42+
opentelemetry-api >= 0.3.dev0
43+
pymongo ~= 3.1
44+
45+
[options.packages.find]
46+
where = src
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright 2019, 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", "pymongo", "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: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Copyright 2019, 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+
"""
16+
The opentelemetry-ext-pymongo package allows tracing commands made by the
17+
pymongo library.
18+
"""
19+
20+
from pymongo import monitoring
21+
22+
from opentelemetry.trace import SpanKind
23+
from opentelemetry.trace.status import Status, StatusCanonicalCode
24+
25+
DATABASE_TYPE = "mongodb"
26+
COMMAND_ATTRIBUTES = ["filter", "sort", "skip", "limit", "pipeline"]
27+
28+
29+
def trace_integration(tracer=None):
30+
"""Integrate with pymongo to trace it using event listener.
31+
https://api.mongodb.com/python/current/api/pymongo/monitoring.html
32+
"""
33+
34+
monitoring.register(CommandTracer(tracer))
35+
36+
37+
class CommandTracer(monitoring.CommandListener):
38+
def __init__(self, tracer):
39+
if tracer is None:
40+
raise ValueError("The tracer is not provided.")
41+
self._tracer = tracer
42+
self._span_dict = {}
43+
44+
def started(self, event: monitoring.CommandStartedEvent):
45+
command = event.command.get(event.command_name, "")
46+
name = DATABASE_TYPE + "." + event.command_name
47+
statement = event.command_name
48+
if command:
49+
name += "." + command
50+
statement += " " + command
51+
52+
try:
53+
span = self._tracer.start_span(name, kind=SpanKind.CLIENT)
54+
span.set_attribute("component", DATABASE_TYPE)
55+
span.set_attribute("db.type", DATABASE_TYPE)
56+
span.set_attribute("db.instance", event.database_name)
57+
span.set_attribute("db.statement", statement)
58+
if event.connection_id is not None:
59+
span.set_attribute("peer.hostname", event.connection_id[0])
60+
span.set_attribute("peer.port", event.connection_id[1])
61+
62+
# pymongo specific, not specified by spec
63+
span.set_attribute("db.mongo.operation_id", event.operation_id)
64+
span.set_attribute("db.mongo.request_id", event.request_id)
65+
66+
for attr in COMMAND_ATTRIBUTES:
67+
_attr = event.command.get(attr)
68+
if _attr is not None:
69+
span.set_attribute("db.mongo." + attr, str(_attr))
70+
71+
# Add Span to dictionary
72+
self._span_dict[_get_span_dict_key(event)] = span
73+
except Exception as ex: # noqa pylint: disable=broad-except
74+
if span is not None:
75+
span.set_status(Status(StatusCanonicalCode.INTERNAL, str(ex)))
76+
span.end()
77+
self._remove_span(event)
78+
79+
def succeeded(self, event: monitoring.CommandSucceededEvent):
80+
span = self._get_span(event)
81+
if span is not None:
82+
span.set_attribute(
83+
"db.mongo.duration_micros", event.duration_micros
84+
)
85+
span.set_status(Status(StatusCanonicalCode.OK, event.reply))
86+
span.end()
87+
self._remove_span(event)
88+
89+
def failed(self, event: monitoring.CommandFailedEvent):
90+
span = self._get_span(event)
91+
if span is not None:
92+
span.set_attribute(
93+
"db.mongo.duration_micros", event.duration_micros
94+
)
95+
span.set_status(Status(StatusCanonicalCode.UNKNOWN, event.failure))
96+
span.end()
97+
self._remove_span(event)
98+
99+
def _get_span(self, event):
100+
return self._span_dict.get(_get_span_dict_key(event))
101+
102+
def _remove_span(self, event):
103+
self._span_dict.pop(_get_span_dict_key(event))
104+
105+
106+
def _get_span_dict_key(event):
107+
if event.connection_id is not None:
108+
return (event.request_id, event.connection_id)
109+
return event.request_id
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright 2019, 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+
__version__ = "0.3.dev0"

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

Whitespace-only changes.

0 commit comments

Comments
 (0)