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-dbapi/src/opentelemetry/ext/dbapi/__init__.py b/ext/opentelemetry-ext-dbapi/src/opentelemetry/ext/dbapi/__init__.py index ed4e93b9a39..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,15 +24,16 @@ import mysql.connector import pyodbc + from opentelemetry import trace from opentelemetry.ext.dbapi import trace_integration 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 +45,44 @@ import wrapt -from opentelemetry.trace import SpanKind, Tracer +from opentelemetry.ext.dbapi.version import __version__ +from opentelemetry.trace import SpanKind, Tracer, TracerProvider, get_tracer 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. + """ + tracer = get_tracer(__name__, __version__, tracer_provider) + 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 +103,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 +119,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-grpc/src/opentelemetry/ext/grpc/__init__.py b/ext/opentelemetry-ext-grpc/src/opentelemetry/ext/grpc/__init__.py index 8807abcb1f2..0e9b19ef51b 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,12 @@ def client_interceptor(tracer): """ from . import _client + tracer = trace.get_tracer(__name__, __version__, tracer_provider) + return _client.OpenTelemetryClientInterceptor(tracer) -def server_interceptor(tracer): +def server_interceptor(tracer_provider=None): """Create a gRPC server interceptor. Args: @@ -43,4 +48,6 @@ def server_interceptor(tracer): """ from . import _server + tracer = trace.get_tracer(__name__, __version__, tracer_provider) + 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..6c055c863c2 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,21 @@ def handler(request, context): self.assertEqual(span.name, "") self.assertIs(span.kind, trace.SpanKind.SERVER) + # 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.""" - tracer_provider = trace_sdk.TracerProvider() - tracer = tracer_provider.get_tracer(__name__) - interceptor = server_interceptor(tracer) + interceptor = server_interceptor() + tracer = self.tracer_provider.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 +128,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 = self.tracer_provider.get_tracer(__name__) - interceptor = server_interceptor(tracer) + interceptor = server_interceptor() # Capture the currently active span in each thread active_spans_in_handler = [] @@ -176,10 +175,9 @@ def test_concurrent_server_spans(self): context. """ - tracer_provider = trace_sdk.TracerProvider() - tracer = tracer_provider.get_tracer(__name__) + tracer = self.tracer_provider.get_tracer(__name__) - interceptor = server_interceptor(tracer) + interceptor = server_interceptor() # Capture the currently active span in each thread active_spans_in_handler = [] 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 16b64655c70..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,9 +29,8 @@ from opentelemetry.ext.mysql import trace_integration 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)" @@ -42,23 +41,29 @@ --- """ +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 -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/ """ + + tracer = get_tracer(__name__, __version__, tracer_provider) + 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..39a70bc5516 100644 --- a/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py +++ b/ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py @@ -16,20 +16,43 @@ 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] + + # 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({}) + 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..a0db2993ba7 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 logger = logging.getLogger(__name__) @@ -57,11 +58,13 @@ DATABASE_TYPE = "sql" -def trace_integration(tracer): +def trace_integration(tracer_provider=None): """Integrate with PostgreSQL Psycopg library. Psycopg: http://initd.org/psycopg/ """ + tracer = get_tracer(__name__, __version__, tracer_provider) + 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 4ab87158beb..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"] @@ -43,25 +42,30 @@ from pymongo import monitoring -from opentelemetry.trace import SpanKind +from opentelemetry.ext.pymongo.version import __version__ +from opentelemetry.trace import SpanKind, get_tracer 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. """ + tracer = get_tracer(__name__, __version__, tracer_provider) + 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) diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index 773a3908ce1..a4b18a3ddc5 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: typing.Optional[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") diff --git a/tests/util/src/opentelemetry/test/test_base.py b/tests/util/src/opentelemetry/test/test_base.py index d35eef650a7..787439b1d76 100644 --- a/tests/util/src/opentelemetry/test/test_base.py +++ b/tests/util/src/opentelemetry/test/test_base.py @@ -24,12 +24,10 @@ class TestBase(unittest.TestCase): @classmethod def setUpClass(cls): - cls.tracer_provider = TracerProvider() cls.original_provider = trace_api.get_tracer_provider() + 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,27 @@ 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. + + 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