From 867fd1c04ae883068da8114664fb342fd0f84af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Thu, 16 Apr 2020 08:22:55 -0500 Subject: [PATCH 1/9] tests/util: Create "create_tracer_provider" helper A helper to create a return a configured TracerProvider with a the span processor and the memory exporter --- .../util/src/opentelemetry/test/test_base.py | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/tests/util/src/opentelemetry/test/test_base.py b/tests/util/src/opentelemetry/test/test_base.py index 974cc894081..40eee296a3a 100644 --- a/tests/util/src/opentelemetry/test/test_base.py +++ b/tests/util/src/opentelemetry/test/test_base.py @@ -25,11 +25,9 @@ class TestBase(unittest.TestCase): @classmethod def setUpClass(cls): - cls.tracer_provider = TracerProvider() + result = cls.create_tracer_provider() + cls.tracer_provider, cls.memory_exporter = result trace_api.set_tracer_provider(cls.tracer_provider) - cls.memory_exporter = InMemorySpanExporter() - span_processor = export.SimpleExportSpanProcessor(cls.memory_exporter) - cls.tracer_provider.add_span_processor(span_processor) @classmethod def tearDownClass(cls): @@ -37,3 +35,23 @@ def tearDownClass(cls): def setUp(self): self.memory_exporter.clear() + + @staticmethod + def create_tracer_provider(**kwargs): + """Helper to create a configured tracer provider. + + Creates and configures a `TracerProvider` with a + `SimpleExportSpanProcessor` and a `InMemorySpanExporter`. + All the parameters passed are forwarded to the TracerProvider + constructor. + + Returns: + A list with the tracer provider in the first element and the + memory exporter in the second. + """ + tracer_provider = TracerProvider(**kwargs) + memory_exporter = InMemorySpanExporter() + span_processor = export.SimpleExportSpanProcessor(memory_exporter) + tracer_provider.add_span_processor(span_processor) + + return tracer_provider, memory_exporter From 6224f6e915e19ccc37773cfaeaa4f01c3af1b83d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Thu, 16 Apr 2020 10:21:53 -0500 Subject: [PATCH 2/9] ext/dbapi,mysql,psycopg2,pymongo: Receive TracerProvider instead of Tracer --- .../src/opentelemetry/ext/dbapi/__init__.py | 51 ++++++++++++++++--- .../tests/mysql/test_mysql_functional.py | 2 +- .../tests/postgres/test_psycopg_functional.py | 2 +- .../tests/pymongo/test_pymongo_functional.py | 2 +- .../src/opentelemetry/ext/mysql/__init__.py | 19 +++++-- .../tests/test_mysql_integration.py | 40 +++++++++++++-- .../opentelemetry/ext/psycopg2/__init__.py | 14 +++-- .../tests/test_psycopg2_integration.py | 4 +- .../src/opentelemetry/ext/pymongo/__init__.py | 16 ++++-- .../tests/test_pymongo.py | 2 +- 10 files changed, 121 insertions(+), 31 deletions(-) diff --git a/ext/opentelemetry-ext-dbapi/src/opentelemetry/ext/dbapi/__init__.py b/ext/opentelemetry-ext-dbapi/src/opentelemetry/ext/dbapi/__init__.py index ed4e93b9a39..3c693938dda 100644 --- a/ext/opentelemetry-ext-dbapi/src/opentelemetry/ext/dbapi/__init__.py +++ b/ext/opentelemetry-ext-dbapi/src/opentelemetry/ext/dbapi/__init__.py @@ -28,11 +28,11 @@ from opentelemetry.trace import TracerProvider trace.set_tracer_provider(TracerProvider()) - tracer = trace.get_tracer(__name__) + # Ex: mysql.connector - trace_integration(tracer, mysql.connector, "connect", "mysql", "sql") + trace_integration(mysql.connector, "connect", "mysql", "sql") # Ex: pyodbc - trace_integration(tracer, pyodbc, "Connection", "odbc", "sql") + trace_integration(pyodbc, "Connection", "odbc", "sql") API --- @@ -44,13 +44,52 @@ import wrapt -from opentelemetry.trace import SpanKind, Tracer +from opentelemetry.ext.dbapi.version import __version__ +from opentelemetry.trace import ( + SpanKind, + Tracer, + TracerProvider, + get_tracer_provider, +) from opentelemetry.trace.status import Status, StatusCanonicalCode logger = logging.getLogger(__name__) def trace_integration( + connect_module: typing.Callable[..., any], + connect_method_name: str, + database_component: str, + database_type: str = "", + connection_attributes: typing.Dict = None, + tracer_provider: typing.Optional[TracerProvider] = None, +): + """Integrate with DB API library. + https://www.python.org/dev/peps/pep-0249/ + + Args: + connect_module: Module name where connect method is available. + connect_method_name: The connect method name. + database_component: Database driver name or database name "JDBI", "jdbc", "odbc", "postgreSQL". + database_type: The Database type. For any SQL database, "sql". + connection_attributes: Attribute names for database, port, host and user in Connection object. + tracer_provider: The :class:`TracerProvider` to use. If ommited the current configured one is used. + """ + if tracer_provider is None: + tracer_provider = get_tracer_provider() + + tracer = tracer_provider.get_tracer(__name__, __version__) + wrap_connect( + tracer, + connect_module, + connect_method_name, + database_component, + database_type, + connection_attributes, + ) + + +def wrap_connect( tracer: Tracer, connect_module: typing.Callable[..., any], connect_method_name: str, @@ -71,7 +110,7 @@ def trace_integration( """ # pylint: disable=unused-argument - def wrap_connect( + def wrap_connect_( wrapped: typing.Callable[..., any], instance: typing.Any, args: typing.Tuple[any, any], @@ -87,7 +126,7 @@ def wrap_connect( try: wrapt.wrap_function_wrapper( - connect_module, connect_method_name, wrap_connect + connect_module, connect_method_name, wrap_connect_ ) except Exception as ex: # pylint: disable=broad-except logger.warning("Failed to integrate with DB API. %s", str(ex)) diff --git a/ext/opentelemetry-ext-docker-tests/tests/mysql/test_mysql_functional.py b/ext/opentelemetry-ext-docker-tests/tests/mysql/test_mysql_functional.py index c0790396b09..36fd7bf3d3c 100644 --- a/ext/opentelemetry-ext-docker-tests/tests/mysql/test_mysql_functional.py +++ b/ext/opentelemetry-ext-docker-tests/tests/mysql/test_mysql_functional.py @@ -35,7 +35,7 @@ def setUpClass(cls): cls._connection = None cls._cursor = None cls._tracer = cls.tracer_provider.get_tracer(__name__) - trace_integration(cls._tracer) + trace_integration(cls.tracer_provider) cls._connection = mysql.connector.connect( user=MYSQL_USER, password=MYSQL_PASSWORD, diff --git a/ext/opentelemetry-ext-docker-tests/tests/postgres/test_psycopg_functional.py b/ext/opentelemetry-ext-docker-tests/tests/postgres/test_psycopg_functional.py index a0ddfcae15b..c53baf81a62 100644 --- a/ext/opentelemetry-ext-docker-tests/tests/postgres/test_psycopg_functional.py +++ b/ext/opentelemetry-ext-docker-tests/tests/postgres/test_psycopg_functional.py @@ -35,7 +35,7 @@ def setUpClass(cls): cls._connection = None cls._cursor = None cls._tracer = cls.tracer_provider.get_tracer(__name__) - trace_integration(cls._tracer) + trace_integration(cls.tracer_provider) cls._connection = psycopg2.connect( dbname=POSTGRES_DB_NAME, user=POSTGRES_USER, diff --git a/ext/opentelemetry-ext-docker-tests/tests/pymongo/test_pymongo_functional.py b/ext/opentelemetry-ext-docker-tests/tests/pymongo/test_pymongo_functional.py index 6f6a728e519..567e0d86a0e 100644 --- a/ext/opentelemetry-ext-docker-tests/tests/pymongo/test_pymongo_functional.py +++ b/ext/opentelemetry-ext-docker-tests/tests/pymongo/test_pymongo_functional.py @@ -31,7 +31,7 @@ class TestFunctionalPymongo(TestBase): def setUpClass(cls): super().setUpClass() cls._tracer = cls.tracer_provider.get_tracer(__name__) - trace_integration(cls._tracer) + trace_integration(cls.tracer_provider) client = MongoClient( MONGODB_HOST, MONGODB_PORT, serverSelectionTimeoutMS=2000 ) diff --git a/ext/opentelemetry-ext-mysql/src/opentelemetry/ext/mysql/__init__.py b/ext/opentelemetry-ext-mysql/src/opentelemetry/ext/mysql/__init__.py index db799204e54..c2f0ce4993b 100644 --- a/ext/opentelemetry-ext-mysql/src/opentelemetry/ext/mysql/__init__.py +++ b/ext/opentelemetry-ext-mysql/src/opentelemetry/ext/mysql/__init__.py @@ -30,7 +30,7 @@ trace.set_tracer_provider(TracerProvider()) tracer = trace.get_tracer(__name__) - trace_integration(tracer) + trace_integration() cnx = mysql.connector.connect(database='MySQL_Database') cursor = cnx.cursor() cursor.execute("INSERT INTO test (testField) VALUES (123)" @@ -41,23 +41,32 @@ --- """ +import typing + import mysql.connector -from opentelemetry.ext.dbapi import trace_integration as db_integration -from opentelemetry.trace import Tracer +from opentelemetry.ext.dbapi import wrap_connect +from opentelemetry.ext.mysql.version import __version__ +from opentelemetry.trace import TracerProvider, get_tracer_provider -def trace_integration(tracer: Tracer): +def trace_integration(tracer_provider: typing.Optional[TracerProvider] = None): """Integrate with MySQL Connector/Python library. https://dev.mysql.com/doc/connector-python/en/ """ + + if tracer_provider is None: + tracer_provider = get_tracer_provider() + + tracer = tracer_provider.get_tracer(__name__, __version__) + connection_attributes = { "database": "database", "port": "server_port", "host": "server_host", "user": "user", } - db_integration( + wrap_connect( tracer, mysql.connector, "connect", diff --git a/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py b/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py index 150f9f51f99..699bfa1a59f 100644 --- a/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py +++ b/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py @@ -16,20 +16,50 @@ import mysql.connector -from opentelemetry.ext.mysql import trace_integration +import opentelemetry.ext.mysql +from opentelemetry.sdk import resources from opentelemetry.test.test_base import TestBase class TestMysqlIntegration(TestBase): def test_trace_integration(self): - tracer = self.tracer_provider.get_tracer(__name__) + with mock.patch("mysql.connector.connect") as mock_connect: + mock_connect.get.side_effect = mysql.connector.MySQLConnection() + opentelemetry.ext.mysql.trace_integration() + cnx = mysql.connector.connect(database="test") + cursor = cnx.cursor() + query = "SELECT * FROM test" + cursor.execute(query) + + spans_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans_list), 1) + span = spans_list[0] + # TODO: Add more tests? + + # check instrumentation name and version + self.assertEqual( + span.instrumentation_info.name, opentelemetry.ext.mysql.__name__, + ) + self.assertEqual( + span.instrumentation_info.version, + opentelemetry.ext.mysql.__version__, + ) + + def test_custom_tracer_provider(self): + resource = resources.Resource.create({}) + result = self.create_tracer_provider(resource=resource) + tracer_provider, exporter = result with mock.patch("mysql.connector.connect") as mock_connect: mock_connect.get.side_effect = mysql.connector.MySQLConnection() - trace_integration(tracer) + opentelemetry.ext.mysql.trace_integration(tracer_provider) cnx = mysql.connector.connect(database="test") cursor = cnx.cursor() query = "SELECT * FROM test" cursor.execute(query) - spans_list = self.memory_exporter.get_finished_spans() - self.assertEqual(len(spans_list), 1) + + span_list = exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + span = span_list[0] + + self.assertIs(span.resource, resource) diff --git a/ext/opentelemetry-ext-psycopg2/src/opentelemetry/ext/psycopg2/__init__.py b/ext/opentelemetry-ext-psycopg2/src/opentelemetry/ext/psycopg2/__init__.py index 13c990dfbc2..ed1c6e56d34 100644 --- a/ext/opentelemetry-ext-psycopg2/src/opentelemetry/ext/psycopg2/__init__.py +++ b/ext/opentelemetry-ext-psycopg2/src/opentelemetry/ext/psycopg2/__init__.py @@ -29,8 +29,8 @@ from opentelemetry.trace.ext.psycopg2 import trace_integration trace.set_tracer_provider(TracerProvider()) - tracer = trace.get_tracer(__name__) - trace_integration(tracer) + + trace_integration() cnx = psycopg2.connect(database='Database') cursor = cnx.cursor() cursor.execute("INSERT INTO test (testField) VALUES (123)") @@ -49,7 +49,8 @@ from psycopg2.sql import Composable from opentelemetry.ext.dbapi import DatabaseApiIntegration, TracedCursor -from opentelemetry.trace import Tracer +from opentelemetry.ext.psycopg2.version import __version__ +from opentelemetry.trace import Tracer, get_tracer_provider logger = logging.getLogger(__name__) @@ -57,11 +58,16 @@ DATABASE_TYPE = "sql" -def trace_integration(tracer): +def trace_integration(tracer_provider=None): """Integrate with PostgreSQL Psycopg library. Psycopg: http://initd.org/psycopg/ """ + if tracer_provider is None: + tracer_provider = get_tracer_provider() + + tracer = tracer_provider.get_tracer(__name__, __version__) + connection_attributes = { "database": "info.dbname", "port": "info.port", diff --git a/ext/opentelemetry-ext-psycopg2/tests/test_psycopg2_integration.py b/ext/opentelemetry-ext-psycopg2/tests/test_psycopg2_integration.py index a512ba4fa5c..b4724e308b0 100644 --- a/ext/opentelemetry-ext-psycopg2/tests/test_psycopg2_integration.py +++ b/ext/opentelemetry-ext-psycopg2/tests/test_psycopg2_integration.py @@ -17,14 +17,12 @@ import psycopg2 -from opentelemetry import trace as trace_api from opentelemetry.ext.psycopg2 import trace_integration class TestPostgresqlIntegration(unittest.TestCase): def test_trace_integration(self): - tracer = trace_api.DefaultTracer() with mock.patch("psycopg2.connect"): - trace_integration(tracer) + trace_integration() cnx = psycopg2.connect(database="test") self.assertIsNotNone(cnx.cursor_factory) diff --git a/ext/opentelemetry-ext-pymongo/src/opentelemetry/ext/pymongo/__init__.py b/ext/opentelemetry-ext-pymongo/src/opentelemetry/ext/pymongo/__init__.py index 9292b880526..cd7ec8f5892 100644 --- a/ext/opentelemetry-ext-pymongo/src/opentelemetry/ext/pymongo/__init__.py +++ b/ext/opentelemetry-ext-pymongo/src/opentelemetry/ext/pymongo/__init__.py @@ -42,25 +42,33 @@ from pymongo import monitoring -from opentelemetry.trace import SpanKind +from opentelemetry.ext.pymongo.version import __version__ +from opentelemetry.trace import SpanKind, get_tracer_provider from opentelemetry.trace.status import Status, StatusCanonicalCode DATABASE_TYPE = "mongodb" COMMAND_ATTRIBUTES = ["filter", "sort", "skip", "limit", "pipeline"] -def trace_integration(tracer=None): +def trace_integration(tracer_provider=None): """Integrate with pymongo to trace it using event listener. https://api.mongodb.com/python/current/api/pymongo/monitoring.html + + Args: + tracer_provider: The `TracerProvider` to use. If none is passed the + current configured one is used. """ + if tracer_provider is None: + tracer_provider = get_tracer_provider() + + tracer = tracer_provider.get_tracer(__name__, __version__) + monitoring.register(CommandTracer(tracer)) class CommandTracer(monitoring.CommandListener): def __init__(self, tracer): - if tracer is None: - raise ValueError("The tracer is not provided.") self._tracer = tracer self._span_dict = {} diff --git a/ext/opentelemetry-ext-pymongo/tests/test_pymongo.py b/ext/opentelemetry-ext-pymongo/tests/test_pymongo.py index 197c4d02666..d85b23bfc95 100644 --- a/ext/opentelemetry-ext-pymongo/tests/test_pymongo.py +++ b/ext/opentelemetry-ext-pymongo/tests/test_pymongo.py @@ -30,7 +30,7 @@ def test_trace_integration(self): "pymongo.monitoring.register", side_effect=mock_register ) with patch: - trace_integration(self.tracer) + trace_integration(self.tracer_provider) self.assertTrue(mock_register.called) From cf91cf92ed0adeff0c864bd3f94f339d76f9cc7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Fri, 17 Apr 2020 11:31:09 -0500 Subject: [PATCH 3/9] ext/grpc: Receive TracerProvider instead of Tracer --- .../grpc/hello_world_client.py | 3 +- .../grpc/hello_world_server.py | 3 +- .../grpc/route_guide_client.py | 3 +- .../grpc/route_guide_server.py | 3 +- .../src/opentelemetry/ext/grpc/__init__.py | 17 ++++++++-- .../tests/test_server_interceptor.py | 31 ++++++++++--------- 6 files changed, 36 insertions(+), 24 deletions(-) diff --git a/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/hello_world_client.py b/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/hello_world_client.py index 2f2351b9afc..7457c63148f 100755 --- a/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/hello_world_client.py +++ b/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/hello_world_client.py @@ -64,7 +64,6 @@ trace.get_tracer_provider().add_span_processor( SimpleExportSpanProcessor(ConsoleSpanExporter()) ) -tracer = trace.get_tracer(__name__) def run(): @@ -73,7 +72,7 @@ def run(): # of the code. with grpc.insecure_channel("localhost:50051") as channel: - channel = intercept_channel(channel, client_interceptor(tracer)) + channel = intercept_channel(channel, client_interceptor()) stub = helloworld_pb2_grpc.GreeterStub(channel) diff --git a/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/hello_world_server.py b/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/hello_world_server.py index 86dcd66527c..858426a4682 100755 --- a/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/hello_world_server.py +++ b/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/hello_world_server.py @@ -64,7 +64,6 @@ trace.get_tracer_provider().add_span_processor( SimpleExportSpanProcessor(ConsoleSpanExporter()) ) -tracer = trace.get_tracer(__name__) class Greeter(helloworld_pb2_grpc.GreeterServicer): @@ -75,7 +74,7 @@ def SayHello(self, request, context): def serve(): server = grpc.server(futures.ThreadPoolExecutor()) - server = intercept_server(server, server_interceptor(tracer)) + server = intercept_server(server, server_interceptor()) helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) server.add_insecure_port("[::]:50051") diff --git a/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/route_guide_client.py b/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/route_guide_client.py index 18391b4228c..d24875913d2 100755 --- a/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/route_guide_client.py +++ b/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/route_guide_client.py @@ -67,7 +67,6 @@ trace.get_tracer_provider().add_span_processor( SimpleExportSpanProcessor(ConsoleSpanExporter()) ) -tracer = trace.get_tracer(__name__) def make_route_note(message, latitude, longitude): @@ -154,7 +153,7 @@ def run(): # used in circumstances in which the with statement does not fit the needs # of the code. with grpc.insecure_channel("localhost:50051") as channel: - channel = intercept_channel(channel, client_interceptor(tracer)) + channel = intercept_channel(channel, client_interceptor()) stub = route_guide_pb2_grpc.RouteGuideStub(channel) diff --git a/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/route_guide_server.py b/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/route_guide_server.py index 9cd9db666e3..54a68b9f5a9 100755 --- a/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/route_guide_server.py +++ b/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/route_guide_server.py @@ -69,7 +69,6 @@ trace.get_tracer_provider().add_span_processor( SimpleExportSpanProcessor(ConsoleSpanExporter()) ) -tracer = trace.get_tracer(__name__) def get_feature(feature_db, point): @@ -164,7 +163,7 @@ def RouteChat(self, request_iterator, context): def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) - server = intercept_server(server, server_interceptor(tracer)) + server = intercept_server(server, server_interceptor()) route_guide_pb2_grpc.add_RouteGuideServicer_to_server( RouteGuideServicer(), server diff --git a/ext/opentelemetry-ext-grpc/src/opentelemetry/ext/grpc/__init__.py b/ext/opentelemetry-ext-grpc/src/opentelemetry/ext/grpc/__init__.py index 8807abcb1f2..b812781078b 100644 --- a/ext/opentelemetry-ext-grpc/src/opentelemetry/ext/grpc/__init__.py +++ b/ext/opentelemetry-ext-grpc/src/opentelemetry/ext/grpc/__init__.py @@ -17,8 +17,11 @@ # pylint:disable=no-name-in-module # pylint:disable=relative-beyond-top-level +from opentelemetry import trace +from opentelemetry.ext.grpc.version import __version__ -def client_interceptor(tracer): + +def client_interceptor(tracer_provider=None): """Create a gRPC client channel interceptor. Args: @@ -29,10 +32,15 @@ def client_interceptor(tracer): """ from . import _client + if tracer_provider is None: + tracer_provider = trace.get_tracer_provider() + + tracer = tracer_provider.get_tracer(__name__, __version__) + return _client.OpenTelemetryClientInterceptor(tracer) -def server_interceptor(tracer): +def server_interceptor(tracer_provider=None): """Create a gRPC server interceptor. Args: @@ -43,4 +51,9 @@ def server_interceptor(tracer): """ from . import _server + if tracer_provider is None: + tracer_provider = trace.get_tracer_provider() + + tracer = tracer_provider.get_tracer(__name__, __version__) + return _server.OpenTelemetryServerInterceptor(tracer) diff --git a/ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py b/ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py index 74ce9babab7..0b7cfa06f70 100644 --- a/ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py +++ b/ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py @@ -20,6 +20,7 @@ import grpc +import opentelemetry.ext.grpc from opentelemetry import trace from opentelemetry.ext.grpc import server_interceptor from opentelemetry.ext.grpc.grpcext import intercept_server @@ -48,15 +49,11 @@ def service(self, handler_call_details): class TestOpenTelemetryServerInterceptor(TestBase): - def setUp(self): - super().setUp() - self.tracer = self.tracer_provider.get_tracer(__name__) - def test_create_span(self): """Check that the interceptor wraps calls with spans server-side.""" # Intercept gRPC calls... - interceptor = server_interceptor(self.tracer) + interceptor = server_interceptor() # No-op RPC handler def handler(request, context): @@ -87,18 +84,26 @@ def handler(request, context): self.assertEqual(span.name, "") self.assertIs(span.kind, trace.SpanKind.SERVER) + self.assertEqual( + span.instrumentation_info.name, opentelemetry.ext.grpc.__name__, + ) + self.assertEqual( + span.instrumentation_info.version, + opentelemetry.ext.grpc.__version__, + ) + def test_span_lifetime(self): """Check that the span is active for the duration of the call.""" - tracer_provider = trace_sdk.TracerProvider() - tracer = tracer_provider.get_tracer(__name__) - interceptor = server_interceptor(tracer) + interceptor = server_interceptor() + tracer = trace.get_tracer(__name__) # To capture the current span at the time the handler is called active_span_in_handler = None def handler(request, context): nonlocal active_span_in_handler + # The current span is shared among all the tracers. active_span_in_handler = tracer.get_current_span() return b"" @@ -128,10 +133,9 @@ def handler(request, context): def test_sequential_server_spans(self): """Check that sequential RPCs get separate server spans.""" - tracer_provider = trace_sdk.TracerProvider() - tracer = tracer_provider.get_tracer(__name__) + tracer = trace.get_tracer(__name__) - interceptor = server_interceptor(tracer) + interceptor = server_interceptor() # Capture the currently active span in each thread active_spans_in_handler = [] @@ -176,10 +180,9 @@ def test_concurrent_server_spans(self): context. """ - tracer_provider = trace_sdk.TracerProvider() - tracer = tracer_provider.get_tracer(__name__) + tracer = trace.get_tracer(__name__) - interceptor = server_interceptor(tracer) + interceptor = server_interceptor() # Capture the currently active span in each thread active_spans_in_handler = [] From 0ee04590ef0cc5184700db4fa6f4dcd63b421df1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Tue, 21 Apr 2020 09:38:03 -0500 Subject: [PATCH 4/9] Create helper to check instrumentation info --- .../tests/test_server_interceptor.py | 9 ++------- .../tests/test_mysql_integration.py | 10 ++-------- tests/util/src/opentelemetry/test/test_base.py | 4 ++++ 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py b/ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py index 0b7cfa06f70..d966b43bedd 100644 --- a/ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py +++ b/ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py @@ -84,13 +84,8 @@ def handler(request, context): self.assertEqual(span.name, "") self.assertIs(span.kind, trace.SpanKind.SERVER) - self.assertEqual( - span.instrumentation_info.name, opentelemetry.ext.grpc.__name__, - ) - self.assertEqual( - span.instrumentation_info.version, - opentelemetry.ext.grpc.__version__, - ) + # Check version and name in span's instrumentation info + self.check_span_instrumentation_info(span, opentelemetry.ext.grpc) def test_span_lifetime(self): """Check that the span is active for the duration of the call.""" diff --git a/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py b/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py index 699bfa1a59f..2fa385765fd 100644 --- a/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py +++ b/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py @@ -36,14 +36,8 @@ def test_trace_integration(self): span = spans_list[0] # TODO: Add more tests? - # check instrumentation name and version - self.assertEqual( - span.instrumentation_info.name, opentelemetry.ext.mysql.__name__, - ) - self.assertEqual( - span.instrumentation_info.version, - opentelemetry.ext.mysql.__version__, - ) + # Check version and name in span's instrumentation info + self.check_span_instrumentation_info(span, opentelemetry.ext.mysql) def test_custom_tracer_provider(self): resource = resources.Resource.create({}) diff --git a/tests/util/src/opentelemetry/test/test_base.py b/tests/util/src/opentelemetry/test/test_base.py index 40eee296a3a..1fe591b09c6 100644 --- a/tests/util/src/opentelemetry/test/test_base.py +++ b/tests/util/src/opentelemetry/test/test_base.py @@ -36,6 +36,10 @@ def tearDownClass(cls): def setUp(self): self.memory_exporter.clear() + def check_span_instrumentation_info(self, span, module): + self.assertEqual(span.instrumentation_info.name, module.__name__) + self.assertEqual(span.instrumentation_info.version, module.__version__) + @staticmethod def create_tracer_provider(**kwargs): """Helper to create a configured tracer provider. From e060376fbf9539fd36a68630f2aeadecf566029b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Tue, 21 Apr 2020 09:40:22 -0500 Subject: [PATCH 5/9] Use local tracer provider for getting tracer --- ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py b/ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py index d966b43bedd..6c055c863c2 100644 --- a/ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py +++ b/ext/opentelemetry-ext-grpc/tests/test_server_interceptor.py @@ -91,7 +91,7 @@ def test_span_lifetime(self): """Check that the span is active for the duration of the call.""" interceptor = server_interceptor() - tracer = trace.get_tracer(__name__) + tracer = self.tracer_provider.get_tracer(__name__) # To capture the current span at the time the handler is called active_span_in_handler = None @@ -128,7 +128,7 @@ def handler(request, context): def test_sequential_server_spans(self): """Check that sequential RPCs get separate server spans.""" - tracer = trace.get_tracer(__name__) + tracer = self.tracer_provider.get_tracer(__name__) interceptor = server_interceptor() @@ -175,7 +175,7 @@ def test_concurrent_server_spans(self): context. """ - tracer = trace.get_tracer(__name__) + tracer = self.tracer_provider.get_tracer(__name__) interceptor = server_interceptor() From 81add8957de23e8eac55a14d341fe2342c71b1be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Tue, 21 Apr 2020 20:34:16 -0500 Subject: [PATCH 6/9] remove non relevant comment --- ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py b/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py index 2fa385765fd..39a70bc5516 100644 --- a/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py +++ b/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py @@ -34,7 +34,6 @@ def test_trace_integration(self): spans_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans_list), 1) span = spans_list[0] - # TODO: Add more tests? # Check version and name in span's instrumentation info self.check_span_instrumentation_info(span, opentelemetry.ext.mysql) From 92560cfb622c343a17a20e261322ea77d1a00908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Wed, 22 Apr 2020 15:53:00 -0500 Subject: [PATCH 7/9] api: Add tracer provider parameter to trace.get_tracer() --- .../src/opentelemetry/trace/__init__.py | 12 +++++++++--- opentelemetry-api/tests/trace/test_globals.py | 4 ++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index 773a3908ce1..c85770c1a34 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -677,14 +677,20 @@ def use_span( def get_tracer( - instrumenting_module_name: str, instrumenting_library_version: str = "" + instrumenting_module_name: str, + instrumenting_library_version: str = "", + tracer_provider: TracerProvider = None, ) -> "Tracer": """Returns a `Tracer` for use by the given instrumentation library. This function is a convenience wrapper for - opentelemetry.trace.get_tracer_provider().get_tracer + opentelemetry.trace.TracerProvider.get_tracer. + + If tracer_provider is ommited the current configured one is used. """ - return get_tracer_provider().get_tracer( + if tracer_provider is None: + tracer_provider = get_tracer_provider() + return tracer_provider.get_tracer( instrumenting_module_name, instrumenting_library_version ) diff --git a/opentelemetry-api/tests/trace/test_globals.py b/opentelemetry-api/tests/trace/test_globals.py index 2e0339b99dd..4f38f99ee86 100644 --- a/opentelemetry-api/tests/trace/test_globals.py +++ b/opentelemetry-api/tests/trace/test_globals.py @@ -16,3 +16,7 @@ def test_get_tracer(self): """trace.get_tracer should proxy to the global tracer provider.""" trace.get_tracer("foo", "var") self._mock_tracer_provider.get_tracer.assert_called_with("foo", "var") + + mock_provider = unittest.mock.Mock() + trace.get_tracer("foo", "var", mock_provider) + mock_provider.get_tracer.assert_called_with("foo", "var") From 6897dd145329a36d1a459c767d5726c3029e95a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Wed, 22 Apr 2020 15:53:17 -0500 Subject: [PATCH 8/9] ext: Use trace.get_tracer() --- .../src/opentelemetry/ext/dbapi/__init__.py | 13 +++---------- .../src/opentelemetry/ext/grpc/__init__.py | 10 ++-------- .../src/opentelemetry/ext/mysql/__init__.py | 8 ++------ .../src/opentelemetry/ext/psycopg2/__init__.py | 7 ++----- .../src/opentelemetry/ext/pymongo/__init__.py | 10 +++------- 5 files changed, 12 insertions(+), 36 deletions(-) diff --git a/ext/opentelemetry-ext-dbapi/src/opentelemetry/ext/dbapi/__init__.py b/ext/opentelemetry-ext-dbapi/src/opentelemetry/ext/dbapi/__init__.py index 3c693938dda..441434b1897 100644 --- a/ext/opentelemetry-ext-dbapi/src/opentelemetry/ext/dbapi/__init__.py +++ b/ext/opentelemetry-ext-dbapi/src/opentelemetry/ext/dbapi/__init__.py @@ -24,6 +24,7 @@ import mysql.connector import pyodbc + from opentelemetry import trace from opentelemetry.ext.dbapi import trace_integration from opentelemetry.trace import TracerProvider @@ -45,12 +46,7 @@ import wrapt from opentelemetry.ext.dbapi.version import __version__ -from opentelemetry.trace import ( - SpanKind, - Tracer, - TracerProvider, - get_tracer_provider, -) +from opentelemetry.trace import SpanKind, Tracer, TracerProvider, get_tracer from opentelemetry.trace.status import Status, StatusCanonicalCode logger = logging.getLogger(__name__) @@ -75,10 +71,7 @@ def trace_integration( connection_attributes: Attribute names for database, port, host and user in Connection object. tracer_provider: The :class:`TracerProvider` to use. If ommited the current configured one is used. """ - if tracer_provider is None: - tracer_provider = get_tracer_provider() - - tracer = tracer_provider.get_tracer(__name__, __version__) + tracer = get_tracer(__name__, __version__, tracer_provider) wrap_connect( tracer, connect_module, diff --git a/ext/opentelemetry-ext-grpc/src/opentelemetry/ext/grpc/__init__.py b/ext/opentelemetry-ext-grpc/src/opentelemetry/ext/grpc/__init__.py index b812781078b..0e9b19ef51b 100644 --- a/ext/opentelemetry-ext-grpc/src/opentelemetry/ext/grpc/__init__.py +++ b/ext/opentelemetry-ext-grpc/src/opentelemetry/ext/grpc/__init__.py @@ -32,10 +32,7 @@ def client_interceptor(tracer_provider=None): """ from . import _client - if tracer_provider is None: - tracer_provider = trace.get_tracer_provider() - - tracer = tracer_provider.get_tracer(__name__, __version__) + tracer = trace.get_tracer(__name__, __version__, tracer_provider) return _client.OpenTelemetryClientInterceptor(tracer) @@ -51,9 +48,6 @@ def server_interceptor(tracer_provider=None): """ from . import _server - if tracer_provider is None: - tracer_provider = trace.get_tracer_provider() - - tracer = tracer_provider.get_tracer(__name__, __version__) + tracer = trace.get_tracer(__name__, __version__, tracer_provider) return _server.OpenTelemetryServerInterceptor(tracer) diff --git a/ext/opentelemetry-ext-mysql/src/opentelemetry/ext/mysql/__init__.py b/ext/opentelemetry-ext-mysql/src/opentelemetry/ext/mysql/__init__.py index c3ed1d8abb8..2a8b2ab3a86 100644 --- a/ext/opentelemetry-ext-mysql/src/opentelemetry/ext/mysql/__init__.py +++ b/ext/opentelemetry-ext-mysql/src/opentelemetry/ext/mysql/__init__.py @@ -29,7 +29,6 @@ from opentelemetry.ext.mysql import trace_integration trace.set_tracer_provider(TracerProvider()) - tracer = trace.get_tracer(__name__) trace_integration() cnx = mysql.connector.connect(database='MySQL_Database') @@ -48,7 +47,7 @@ from opentelemetry.ext.dbapi import wrap_connect from opentelemetry.ext.mysql.version import __version__ -from opentelemetry.trace import TracerProvider, get_tracer_provider +from opentelemetry.trace import TracerProvider, get_tracer def trace_integration(tracer_provider: typing.Optional[TracerProvider] = None): @@ -56,10 +55,7 @@ def trace_integration(tracer_provider: typing.Optional[TracerProvider] = None): https://dev.mysql.com/doc/connector-python/en/ """ - if tracer_provider is None: - tracer_provider = get_tracer_provider() - - tracer = tracer_provider.get_tracer(__name__, __version__) + tracer = get_tracer(__name__, __version__, tracer_provider) connection_attributes = { "database": "database", diff --git a/ext/opentelemetry-ext-psycopg2/src/opentelemetry/ext/psycopg2/__init__.py b/ext/opentelemetry-ext-psycopg2/src/opentelemetry/ext/psycopg2/__init__.py index ed1c6e56d34..a0db2993ba7 100644 --- a/ext/opentelemetry-ext-psycopg2/src/opentelemetry/ext/psycopg2/__init__.py +++ b/ext/opentelemetry-ext-psycopg2/src/opentelemetry/ext/psycopg2/__init__.py @@ -50,7 +50,7 @@ from opentelemetry.ext.dbapi import DatabaseApiIntegration, TracedCursor from opentelemetry.ext.psycopg2.version import __version__ -from opentelemetry.trace import Tracer, get_tracer_provider +from opentelemetry.trace import Tracer, get_tracer logger = logging.getLogger(__name__) @@ -63,10 +63,7 @@ def trace_integration(tracer_provider=None): Psycopg: http://initd.org/psycopg/ """ - if tracer_provider is None: - tracer_provider = get_tracer_provider() - - tracer = tracer_provider.get_tracer(__name__, __version__) + tracer = get_tracer(__name__, __version__, tracer_provider) connection_attributes = { "database": "info.dbname", diff --git a/ext/opentelemetry-ext-pymongo/src/opentelemetry/ext/pymongo/__init__.py b/ext/opentelemetry-ext-pymongo/src/opentelemetry/ext/pymongo/__init__.py index 67a4388d633..b85bf423795 100644 --- a/ext/opentelemetry-ext-pymongo/src/opentelemetry/ext/pymongo/__init__.py +++ b/ext/opentelemetry-ext-pymongo/src/opentelemetry/ext/pymongo/__init__.py @@ -29,9 +29,8 @@ from opentelemetry.trace.ext.pymongo import trace_integration trace.set_tracer_provider(TracerProvider()) - tracer = trace.get_tracer(__name__) - trace_integration(tracer) + trace_integration() client = MongoClient() db = client["MongoDB_Database"] collection = db["MongoDB_Collection"] @@ -44,7 +43,7 @@ from pymongo import monitoring from opentelemetry.ext.pymongo.version import __version__ -from opentelemetry.trace import SpanKind, get_tracer_provider +from opentelemetry.trace import SpanKind, get_tracer from opentelemetry.trace.status import Status, StatusCanonicalCode DATABASE_TYPE = "mongodb" @@ -60,10 +59,7 @@ def trace_integration(tracer_provider=None): current configured one is used. """ - if tracer_provider is None: - tracer_provider = get_tracer_provider() - - tracer = tracer_provider.get_tracer(__name__, __version__) + tracer = get_tracer(__name__, __version__, tracer_provider) monitoring.register(CommandTracer(tracer)) From 3bb242ac2ef1a405e4b7a93382053e933d6f8633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Wed, 22 Apr 2020 16:16:18 -0500 Subject: [PATCH 9/9] fix type annotation --- opentelemetry-api/src/opentelemetry/trace/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index c85770c1a34..a4b18a3ddc5 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -679,7 +679,7 @@ def use_span( def get_tracer( instrumenting_module_name: str, instrumenting_library_version: str = "", - tracer_provider: TracerProvider = None, + tracer_provider: typing.Optional[TracerProvider] = None, ) -> "Tracer": """Returns a `Tracer` for use by the given instrumentation library.