From 8406e2e7894bd3832b33fd78124e4bc0b871f790 Mon Sep 17 00:00:00 2001 From: Tammy Baylis <96076570+tammy-baylis-swi@users.noreply.github.com> Date: Mon, 13 Jan 2025 01:40:43 -0800 Subject: [PATCH 01/12] DB drivers: db.statement inclusion of sqlcomment as opt-in (#3121) * db-api opt-in for enable_attribute_commenter * Refactor db-api traced_execution * Changelog * Update comment * psycopg(2), mysqlclient, pymysql support enable_attribute_commenter * Changelog --- CHANGELOG.md | 8 ++ .../instrumentation/mysqlclient/__init__.py | 26 ++++ .../tests/test_mysqlclient_integration.py | 116 ++++++++++++++++++ .../instrumentation/psycopg/__init__.py | 26 ++++ .../instrumentation/psycopg2/__init__.py | 24 ++++ .../instrumentation/pymysql/__init__.py | 26 ++++ .../tests/test_pymysql_integration.py | 112 +++++++++++++++++ 7 files changed, 338 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 438f9c787e..2c4e76aaf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3115](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3115)) +### Breaking changes + +- `opentelemetry-instrumentation-dbapi` including sqlcomment in `db.statement` span attribute value is now opt-in + ([#3115](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3115)) +- `opentelemetry-instrumentation-psycopg2`, `opentelemetry-instrumentation-psycopg`, `opentelemetry-instrumentation-mysqlclient`, `opentelemetry-instrumentation-pymysql`: including sqlcomment in `db.statement` span attribute value is now opt-in + ([#3121](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3121)) + + ## Version 1.29.0/0.50b0 (2024-12-11) ### Added diff --git a/instrumentation/opentelemetry-instrumentation-mysqlclient/src/opentelemetry/instrumentation/mysqlclient/__init__.py b/instrumentation/opentelemetry-instrumentation-mysqlclient/src/opentelemetry/instrumentation/mysqlclient/__init__.py index e1c07096fa..10c2b23a40 100644 --- a/instrumentation/opentelemetry-instrumentation-mysqlclient/src/opentelemetry/instrumentation/mysqlclient/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-mysqlclient/src/opentelemetry/instrumentation/mysqlclient/__init__.py @@ -126,6 +126,26 @@ :: Enabling this flag will add traceparent values /*traceparent='00-03afa25236b8cd948fa853d67038ac79-405ff022e8247c46-01'*/ +SQLComment in span attribute +**************************** +If sqlcommenter is enabled, you can optionally configure MySQLClient instrumentation to append sqlcomment to query span attribute for convenience of your platform. + +.. code:: python + + from opentelemetry.instrumentation.mysqlclient import MySQLClientInstrumentor + + MySQLClientInstrumentor().instrument( + enable_commenter=True, + enable_attribute_commenter=True, + ) + + +For example, +:: + + Invoking cursor.execute("select * from auth_users") will lead to sql query "select * from auth_users" but when SQLCommenter and attribute_commenter are enabled + the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" for both server query and `db.statement` span attribute. + API --- """ @@ -159,6 +179,9 @@ def _instrument(self, **kwargs): # pylint: disable=no-self-use tracer_provider = kwargs.get("tracer_provider") enable_sqlcommenter = kwargs.get("enable_commenter", False) commenter_options = kwargs.get("commenter_options", {}) + enable_attribute_commenter = kwargs.get( + "enable_attribute_commenter", False + ) dbapi.wrap_connect( __name__, @@ -170,6 +193,7 @@ def _instrument(self, **kwargs): # pylint: disable=no-self-use tracer_provider=tracer_provider, enable_commenter=enable_sqlcommenter, commenter_options=commenter_options, + enable_attribute_commenter=enable_attribute_commenter, ) def _uninstrument(self, **kwargs): # pylint: disable=no-self-use @@ -182,6 +206,7 @@ def instrument_connection( tracer_provider=None, enable_commenter=None, commenter_options=None, + enable_attribute_commenter=None, ): """Enable instrumentation in a mysqlclient connection. @@ -220,6 +245,7 @@ def instrument_connection( enable_commenter=enable_commenter, commenter_options=commenter_options, connect_module=MySQLdb, + enable_attribute_commenter=enable_attribute_commenter, ) @staticmethod diff --git a/instrumentation/opentelemetry-instrumentation-mysqlclient/tests/test_mysqlclient_integration.py b/instrumentation/opentelemetry-instrumentation-mysqlclient/tests/test_mysqlclient_integration.py index ae221f68f4..e2b1e41aa3 100644 --- a/instrumentation/opentelemetry-instrumentation-mysqlclient/tests/test_mysqlclient_integration.py +++ b/instrumentation/opentelemetry-instrumentation-mysqlclient/tests/test_mysqlclient_integration.py @@ -19,6 +19,7 @@ import opentelemetry.instrumentation.mysqlclient from opentelemetry.instrumentation.mysqlclient import MySQLClientInstrumentor from opentelemetry.sdk import resources +from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.test.test_base import TestBase @@ -110,12 +111,14 @@ def test_instrument_connection_enable_commenter_dbapi_kwargs( cnx, enable_commenter=True, commenter_options={"foo": True}, + enable_attribute_commenter=True, ) cursor = cnx.cursor() cursor.execute("Select 1;") kwargs = mock_instrument_connection.call_args[1] self.assertEqual(kwargs["enable_commenter"], True) self.assertEqual(kwargs["commenter_options"], {"foo": True}) + self.assertEqual(kwargs["enable_attribute_commenter"], True) def test_instrument_connection_with_dbapi_sqlcomment_enabled(self): mock_connect_module = mock.MagicMock( @@ -150,6 +153,51 @@ def test_instrument_connection_with_dbapi_sqlcomment_enabled(self): mock_cursor.execute.call_args[0][0], f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", ) + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + "Select 1;", + ) + + def test_instrument_connection_with_dbapi_sqlcomment_enabled_stmt_enabled( + self, + ): + mock_connect_module = mock.MagicMock( + __name__="MySQLdb", + threadsafety="123", + apilevel="123", + paramstyle="test", + ) + mock_connect_module._mysql.get_client_info.return_value = "foobaz" + mock_cursor = mock_connect_module.connect().cursor() + mock_connection = mock.MagicMock() + mock_connection.cursor.return_value = mock_cursor + + with mock.patch( + "opentelemetry.instrumentation.mysqlclient.MySQLdb", + mock_connect_module, + ), mock.patch( + "opentelemetry.instrumentation.dbapi.util_version", + return_value="foobar", + ): + cnx_proxy = MySQLClientInstrumentor().instrument_connection( + mock_connection, + enable_commenter=True, + enable_attribute_commenter=True, + ) + cnx_proxy.cursor().execute("Select 1;") + + spans_list = self.memory_exporter.get_finished_spans() + span = spans_list[0] + span_id = format(span.get_span_context().span_id, "016x") + trace_id = format(span.get_span_context().trace_id, "032x") + self.assertEqual( + mock_cursor.execute.call_args[0][0], + f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", + ) + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", + ) def test_instrument_connection_with_dbapi_sqlcomment_enabled_with_options( self, @@ -191,6 +239,10 @@ def test_instrument_connection_with_dbapi_sqlcomment_enabled_with_options( mock_cursor.execute.call_args[0][0], f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_threadsafety='123',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", ) + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + "Select 1;", + ) def test_instrument_connection_with_dbapi_sqlcomment_not_enabled_default( self, @@ -221,6 +273,12 @@ def test_instrument_connection_with_dbapi_sqlcomment_not_enabled_default( mock_cursor.execute.call_args[0][0], "Select 1;", ) + spans_list = self.memory_exporter.get_finished_spans() + span = spans_list[0] + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + "Select 1;", + ) @mock.patch("opentelemetry.instrumentation.dbapi.wrap_connect") @mock.patch("MySQLdb.connect") @@ -233,10 +291,12 @@ def test_instrument_enable_commenter_dbapi_kwargs( MySQLClientInstrumentor()._instrument( enable_commenter=True, commenter_options={"foo": True}, + enable_attribute_commenter=True, ) kwargs = mock_wrap_connect.call_args[1] self.assertEqual(kwargs["enable_commenter"], True) self.assertEqual(kwargs["commenter_options"], {"foo": True}) + self.assertEqual(kwargs["enable_attribute_commenter"], True) def test_instrument_with_dbapi_sqlcomment_enabled( self, @@ -274,6 +334,52 @@ def test_instrument_with_dbapi_sqlcomment_enabled( mock_cursor.execute.call_args[0][0], f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", ) + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + "Select 1;", + ) + + def test_instrument_with_dbapi_sqlcomment_enabled_stmt_enabled( + self, + ): + mock_connect_module = mock.MagicMock( + __name__="MySQLdb", + threadsafety="123", + apilevel="123", + paramstyle="test", + ) + mock_connect_module._mysql.get_client_info.return_value = "foobaz" + mock_cursor = mock_connect_module.connect().cursor() + mock_connection = mock.MagicMock() + mock_connection.cursor.return_value = mock_cursor + + with mock.patch( + "opentelemetry.instrumentation.mysqlclient.MySQLdb", + mock_connect_module, + ), mock.patch( + "opentelemetry.instrumentation.dbapi.util_version", + return_value="foobar", + ): + MySQLClientInstrumentor()._instrument( + enable_commenter=True, + enable_attribute_commenter=True, + ) + cnx = mock_connect_module.connect(database="test") + cursor = cnx.cursor() + cursor.execute("Select 1;") + + spans_list = self.memory_exporter.get_finished_spans() + span = spans_list[0] + span_id = format(span.get_span_context().span_id, "016x") + trace_id = format(span.get_span_context().trace_id, "032x") + self.assertEqual( + mock_cursor.execute.call_args[0][0], + f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", + ) + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", + ) def test_instrument_with_dbapi_sqlcomment_enabled_with_options( self, @@ -316,6 +422,10 @@ def test_instrument_with_dbapi_sqlcomment_enabled_with_options( mock_cursor.execute.call_args[0][0], f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_threadsafety='123',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", ) + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + "Select 1;", + ) def test_instrument_with_dbapi_sqlcomment_not_enabled_default( self, @@ -346,6 +456,12 @@ def test_instrument_with_dbapi_sqlcomment_not_enabled_default( mock_cursor.execute.call_args[0][0], "Select 1;", ) + spans_list = self.memory_exporter.get_finished_spans() + span = spans_list[0] + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + "Select 1;", + ) @mock.patch("MySQLdb.connect") # pylint: disable=unused-argument diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py index 8c608b7655..81390ed48f 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py @@ -80,6 +80,26 @@ :: Enabling this flag will add traceparent values /*traceparent='00-03afa25236b8cd948fa853d67038ac79-405ff022e8247c46-01'*/ +SQLComment in span attribute +**************************** +If sqlcommenter is enabled, you can optionally configure psycopg instrumentation to append sqlcomment to query span attribute for convenience of your platform. + +.. code:: python + + from opentelemetry.instrumentation.psycopg import PsycopgInstrumentor + + PsycopgInstrumentor().instrument( + enable_commenter=True, + enable_attribute_commenter=True, + ) + + +For example, +:: + + Invoking cursor.execute("select * from auth_users") will lead to postgresql query "select * from auth_users" but when SQLCommenter and attribute_commenter are enabled + the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" for both server query and `db.statement` span attribute. + Usage ----- @@ -159,6 +179,9 @@ def _instrument(self, **kwargs): tracer_provider = kwargs.get("tracer_provider") enable_sqlcommenter = kwargs.get("enable_commenter", False) commenter_options = kwargs.get("commenter_options", {}) + enable_attribute_commenter = kwargs.get( + "enable_attribute_commenter", False + ) dbapi.wrap_connect( __name__, psycopg, @@ -170,6 +193,7 @@ def _instrument(self, **kwargs): db_api_integration_factory=DatabaseApiIntegration, enable_commenter=enable_sqlcommenter, commenter_options=commenter_options, + enable_attribute_commenter=enable_attribute_commenter, ) dbapi.wrap_connect( @@ -183,6 +207,7 @@ def _instrument(self, **kwargs): db_api_integration_factory=DatabaseApiIntegration, enable_commenter=enable_sqlcommenter, commenter_options=commenter_options, + enable_attribute_commenter=enable_attribute_commenter, ) dbapi.wrap_connect( __name__, @@ -195,6 +220,7 @@ def _instrument(self, **kwargs): db_api_integration_factory=DatabaseApiAsyncIntegration, enable_commenter=enable_sqlcommenter, commenter_options=commenter_options, + enable_attribute_commenter=enable_attribute_commenter, ) def _uninstrument(self, **kwargs): diff --git a/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py b/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py index a811f4285a..f03ad1de0d 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py @@ -80,6 +80,26 @@ :: Enabling this flag will add traceparent values /*traceparent='00-03afa25236b8cd948fa853d67038ac79-405ff022e8247c46-01'*/ +SQLComment in span attribute +**************************** +If sqlcommenter is enabled, you can optionally configure psycopg2 instrumentation to append sqlcomment to query span attribute for convenience of your platform. + +.. code:: python + + from opentelemetry.instrumentation.psycopg2 import Psycopg2Instrumentor + + Psycopg2Instrumentor().instrument( + enable_commenter=True, + enable_attribute_commenter=True, + ) + + +For example, +:: + + Invoking cursor.execute("select * from auth_users") will lead to postgresql query "select * from auth_users" but when SQLCommenter and attribute_commenter are enabled + the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" for both server query and `db.statement` span attribute. + Usage ----- @@ -156,6 +176,9 @@ def _instrument(self, **kwargs): tracer_provider = kwargs.get("tracer_provider") enable_sqlcommenter = kwargs.get("enable_commenter", False) commenter_options = kwargs.get("commenter_options", {}) + enable_attribute_commenter = kwargs.get( + "enable_attribute_commenter", False + ) dbapi.wrap_connect( __name__, psycopg2, @@ -167,6 +190,7 @@ def _instrument(self, **kwargs): db_api_integration_factory=DatabaseApiIntegration, enable_commenter=enable_sqlcommenter, commenter_options=commenter_options, + enable_attribute_commenter=enable_attribute_commenter, ) def _uninstrument(self, **kwargs): diff --git a/instrumentation/opentelemetry-instrumentation-pymysql/src/opentelemetry/instrumentation/pymysql/__init__.py b/instrumentation/opentelemetry-instrumentation-pymysql/src/opentelemetry/instrumentation/pymysql/__init__.py index 54c614f745..24e5c34062 100644 --- a/instrumentation/opentelemetry-instrumentation-pymysql/src/opentelemetry/instrumentation/pymysql/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pymysql/src/opentelemetry/instrumentation/pymysql/__init__.py @@ -128,6 +128,26 @@ :: Enabling this flag will add traceparent values /*traceparent='00-03afa25236b8cd948fa853d67038ac79-405ff022e8247c46-01'*/ +SQLComment in span attribute +**************************** +If sqlcommenter is enabled, you can optionally configure PyMySQL instrumentation to append sqlcomment to query span attribute for convenience of your platform. + +.. code:: python + + from opentelemetry.instrumentation.pymysql import PyMySQLInstrumentor + + PyMySQLInstrumentor().instrument( + enable_commenter=True, + enable_attribute_commenter=True, + ) + + +For example, +:: + + Invoking cursor.execute("select * from auth_users") will lead to sql query "select * from auth_users" but when SQLCommenter and attribute_commenter are enabled + the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" for both server query and `db.statement` span attribute. + API --- """ @@ -161,6 +181,9 @@ def _instrument(self, **kwargs): # pylint: disable=no-self-use tracer_provider = kwargs.get("tracer_provider") enable_sqlcommenter = kwargs.get("enable_commenter", False) commenter_options = kwargs.get("commenter_options", {}) + enable_attribute_commenter = kwargs.get( + "enable_attribute_commenter", False + ) dbapi.wrap_connect( __name__, @@ -172,6 +195,7 @@ def _instrument(self, **kwargs): # pylint: disable=no-self-use tracer_provider=tracer_provider, enable_commenter=enable_sqlcommenter, commenter_options=commenter_options, + enable_attribute_commenter=enable_attribute_commenter, ) def _uninstrument(self, **kwargs): # pylint: disable=no-self-use @@ -184,6 +208,7 @@ def instrument_connection( tracer_provider=None, enable_commenter=None, commenter_options=None, + enable_attribute_commenter=None, ): """Enable instrumentation in a PyMySQL connection. @@ -216,6 +241,7 @@ def instrument_connection( enable_commenter=enable_commenter, commenter_options=commenter_options, connect_module=pymysql, + enable_attribute_commenter=enable_attribute_commenter, ) @staticmethod diff --git a/instrumentation/opentelemetry-instrumentation-pymysql/tests/test_pymysql_integration.py b/instrumentation/opentelemetry-instrumentation-pymysql/tests/test_pymysql_integration.py index 82294236f0..ea59e5df7b 100644 --- a/instrumentation/opentelemetry-instrumentation-pymysql/tests/test_pymysql_integration.py +++ b/instrumentation/opentelemetry-instrumentation-pymysql/tests/test_pymysql_integration.py @@ -20,6 +20,7 @@ from opentelemetry import trace as trace_api from opentelemetry.instrumentation.pymysql import PyMySQLInstrumentor from opentelemetry.sdk import resources +from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.test.test_base import TestBase @@ -125,12 +126,14 @@ def test_instrument_connection_enable_commenter_dbapi_kwargs( cnx, enable_commenter=True, commenter_options={"foo": True}, + enable_attribute_commenter=True, ) cursor = cnx.cursor() cursor.execute("SELECT * FROM test") kwargs = mock_instrument_connection.call_args[1] self.assertEqual(kwargs["enable_commenter"], True) self.assertEqual(kwargs["commenter_options"], {"foo": True}) + self.assertEqual(kwargs["enable_attribute_commenter"], True) def test_instrument_connection_with_dbapi_sqlcomment_enabled(self): mock_connect_module = mock.MagicMock( @@ -163,6 +166,49 @@ def test_instrument_connection_with_dbapi_sqlcomment_enabled(self): mock_cursor.execute.call_args[0][0], f"Select 1 /*db_driver='pymysql%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", ) + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + "Select 1;", + ) + + def test_instrument_connection_with_dbapi_sqlcomment_enabled_stmt_enabled( + self, + ): + mock_connect_module = mock.MagicMock( + __name__="pymysql", + __version__="foobar", + threadsafety="123", + apilevel="123", + paramstyle="test", + ) + mock_connect_module.get_client_info.return_value = "foobaz" + mock_cursor = mock_connect_module.connect().cursor() + mock_connection = mock.MagicMock() + mock_connection.cursor.return_value = mock_cursor + + with mock.patch( + "opentelemetry.instrumentation.pymysql.pymysql", + mock_connect_module, + ): + cnx_proxy = PyMySQLInstrumentor().instrument_connection( + mock_connection, + enable_commenter=True, + enable_attribute_commenter=True, + ) + cnx_proxy.cursor().execute("Select 1;") + + spans_list = self.memory_exporter.get_finished_spans() + span = spans_list[0] + span_id = format(span.get_span_context().span_id, "016x") + trace_id = format(span.get_span_context().trace_id, "032x") + self.assertEqual( + mock_cursor.execute.call_args[0][0], + f"Select 1 /*db_driver='pymysql%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", + ) + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + f"Select 1 /*db_driver='pymysql%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", + ) def test_instrument_connection_with_dbapi_sqlcomment_enabled_with_options( self, @@ -202,6 +248,10 @@ def test_instrument_connection_with_dbapi_sqlcomment_enabled_with_options( mock_cursor.execute.call_args[0][0], f"Select 1 /*db_driver='pymysql%%3Afoobar',dbapi_threadsafety='123',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", ) + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + "Select 1;", + ) def test_instrument_connection_with_dbapi_sqlcomment_not_enabled_default( self, @@ -230,6 +280,12 @@ def test_instrument_connection_with_dbapi_sqlcomment_not_enabled_default( mock_cursor.execute.call_args[0][0], "Select 1;", ) + spans_list = self.memory_exporter.get_finished_spans() + span = spans_list[0] + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + "Select 1;", + ) @mock.patch("opentelemetry.instrumentation.dbapi.wrap_connect") @mock.patch("pymysql.connect") @@ -242,10 +298,12 @@ def test_instrument_enable_commenter_dbapi_kwargs( PyMySQLInstrumentor()._instrument( enable_commenter=True, commenter_options={"foo": True}, + enable_attribute_commenter=True, ) kwargs = mock_wrap_connect.call_args[1] self.assertEqual(kwargs["enable_commenter"], True) self.assertEqual(kwargs["commenter_options"], {"foo": True}) + self.assertEqual(kwargs["enable_attribute_commenter"], True) def test_instrument_with_dbapi_sqlcomment_enabled( self, @@ -281,6 +339,50 @@ def test_instrument_with_dbapi_sqlcomment_enabled( mock_cursor.execute.call_args[0][0], f"Select 1 /*db_driver='pymysql%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", ) + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + "Select 1;", + ) + + def test_instrument_with_dbapi_sqlcomment_enabled_stmt_enabled( + self, + ): + mock_connect_module = mock.MagicMock( + __name__="pymysql", + __version__="foobar", + threadsafety="123", + apilevel="123", + paramstyle="test", + ) + mock_connect_module.get_client_info.return_value = "foobaz" + mock_cursor = mock_connect_module.connect().cursor() + mock_connection = mock.MagicMock() + mock_connection.cursor.return_value = mock_cursor + + with mock.patch( + "opentelemetry.instrumentation.pymysql.pymysql", + mock_connect_module, + ): + PyMySQLInstrumentor()._instrument( + enable_commenter=True, + enable_attribute_commenter=True, + ) + cnx = mock_connect_module.connect(database="test") + cursor = cnx.cursor() + cursor.execute("Select 1;") + + spans_list = self.memory_exporter.get_finished_spans() + span = spans_list[0] + span_id = format(span.get_span_context().span_id, "016x") + trace_id = format(span.get_span_context().trace_id, "032x") + self.assertEqual( + mock_cursor.execute.call_args[0][0], + f"Select 1 /*db_driver='pymysql%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", + ) + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + f"Select 1 /*db_driver='pymysql%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", + ) def test_instrument_with_dbapi_sqlcomment_enabled_with_options( self, @@ -321,6 +423,10 @@ def test_instrument_with_dbapi_sqlcomment_enabled_with_options( mock_cursor.execute.call_args[0][0], f"Select 1 /*db_driver='pymysql%%3Afoobar',dbapi_threadsafety='123',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;", ) + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + "Select 1;", + ) def test_instrument_with_dbapi_sqlcomment_not_enabled_default( self, @@ -349,6 +455,12 @@ def test_instrument_with_dbapi_sqlcomment_not_enabled_default( mock_cursor.execute.call_args[0][0], "Select 1;", ) + spans_list = self.memory_exporter.get_finished_spans() + span = spans_list[0] + self.assertEqual( + span.attributes[SpanAttributes.DB_STATEMENT], + "Select 1;", + ) @mock.patch("pymysql.connect") # pylint: disable=unused-argument From 406707b2bd322b6fe5819a6123b0deee1c6f21d1 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Mon, 13 Jan 2025 17:20:33 +0000 Subject: [PATCH 02/12] Add type checker (#3116) --- .github/workflows/misc_0.yml | 18 ++++++++ dev-requirements.txt | 2 +- .../instrumentation/threading/__init__.py | 45 +++++++++++++++---- pyproject.toml | 16 +++++++ tox.ini | 12 ++++- 5 files changed, 82 insertions(+), 11 deletions(-) diff --git a/.github/workflows/misc_0.yml b/.github/workflows/misc_0.yml index 1148f85abd..422669b86f 100644 --- a/.github/workflows/misc_0.yml +++ b/.github/workflows/misc_0.yml @@ -152,3 +152,21 @@ jobs: - name: Run tests run: tox -e ruff + + typecheck: + name: typecheck + runs-on: ubuntu-latest + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install tox + run: pip install tox + + - name: Run tests + run: tox -e typecheck diff --git a/dev-requirements.txt b/dev-requirements.txt index 2668677cc5..46ba31346e 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,6 +1,6 @@ pylint==3.0.2 httpretty==1.1.4 -mypy==0.931 +pyright==v1.1.390 sphinx==7.1.2 sphinx-rtd-theme==2.0.0rc4 sphinx-autodoc-typehints==1.25.2 diff --git a/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/__init__.py b/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/__init__.py index be1eec139e..9488e3ce47 100644 --- a/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/__init__.py @@ -35,17 +35,29 @@ run method or the executor's worker thread." """ +from __future__ import annotations + import threading from concurrent import futures -from typing import Collection +from typing import TYPE_CHECKING, Any, Callable, Collection -from wrapt import wrap_function_wrapper +from wrapt import ( + wrap_function_wrapper, # type: ignore[reportUnknownVariableType] +) from opentelemetry import context from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.threading.package import _instruments from opentelemetry.instrumentation.utils import unwrap +if TYPE_CHECKING: + from typing import Protocol, TypeVar + + R = TypeVar("R") + + class HasOtelContext(Protocol): + _otel_context: context.Context + class ThreadingInstrumentor(BaseInstrumentor): __WRAPPER_START_METHOD = "start" @@ -55,12 +67,12 @@ class ThreadingInstrumentor(BaseInstrumentor): def instrumentation_dependencies(self) -> Collection[str]: return _instruments - def _instrument(self, **kwargs): + def _instrument(self, **kwargs: Any): self._instrument_thread() self._instrument_timer() self._instrument_thread_pool() - def _uninstrument(self, **kwargs): + def _uninstrument(self, **kwargs: Any): self._uninstrument_thread() self._uninstrument_timer() self._uninstrument_thread_pool() @@ -117,12 +129,22 @@ def _uninstrument_thread_pool(): ) @staticmethod - def __wrap_threading_start(call_wrapped, instance, args, kwargs): + def __wrap_threading_start( + call_wrapped: Callable[[], None], + instance: HasOtelContext, + args: ..., + kwargs: ..., + ) -> None: instance._otel_context = context.get_current() return call_wrapped(*args, **kwargs) @staticmethod - def __wrap_threading_run(call_wrapped, instance, args, kwargs): + def __wrap_threading_run( + call_wrapped: Callable[..., R], + instance: HasOtelContext, + args: tuple[Any, ...], + kwargs: dict[str, Any], + ) -> R: token = None try: token = context.attach(instance._otel_context) @@ -131,12 +153,17 @@ def __wrap_threading_run(call_wrapped, instance, args, kwargs): context.detach(token) @staticmethod - def __wrap_thread_pool_submit(call_wrapped, instance, args, kwargs): + def __wrap_thread_pool_submit( + call_wrapped: Callable[..., R], + instance: futures.ThreadPoolExecutor, + args: tuple[Callable[..., Any], ...], + kwargs: dict[str, Any], + ) -> R: # obtain the original function and wrapped kwargs original_func = args[0] otel_context = context.get_current() - def wrapped_func(*func_args, **func_kwargs): + def wrapped_func(*func_args: Any, **func_kwargs: Any) -> R: token = None try: token = context.attach(otel_context) @@ -145,5 +172,5 @@ def wrapped_func(*func_args, **func_kwargs): context.detach(token) # replace the original function with the wrapped function - new_args = (wrapped_func,) + args[1:] + new_args: tuple[Callable[..., Any], ...] = (wrapped_func,) + args[1:] return call_wrapped(*new_args, **kwargs) diff --git a/pyproject.toml b/pyproject.toml index fd5ee5716f..6ba2e933c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,3 +39,19 @@ known-third-party = [ "opencensus", ] +# https://github.com/microsoft/pyright/blob/main/docs/configuration.md#type-check-rule-overrides +[tool.pyright] +typeCheckingMode = "strict" +reportUnnecessaryTypeIgnoreComment = true +reportMissingTypeStubs = false +pythonVersion = "3.8" +reportPrivateUsage = false # Ignore private attributes added by instrumentation packages. +# Add progressively instrumentation packages here. +include = [ + "instrumentation/opentelemetry-instrumentation-threading/**/*.py" +] +# We should also add type hints to the test suite - It helps on finding bugs. +# We are excluding for now because it's easier, and more important to add to the instrumentation packages. +exclude = [ + "instrumentation/opentelemetry-instrumentation-threading/tests/**", +] diff --git a/tox.ini b/tox.ini index 2f1c0a577e..feeda77702 100644 --- a/tox.ini +++ b/tox.ini @@ -404,6 +404,7 @@ envlist = generate-workflows shellcheck ruff + typecheck [testenv] test_deps = @@ -677,7 +678,6 @@ deps = util-http: -r {toxinidir}/util/opentelemetry-util-http/test-requirements.txt util-http: {toxinidir}/util/opentelemetry-util-http ; FIXME: add coverage testing - ; FIXME: add mypy testing allowlist_externals = sh @@ -986,3 +986,13 @@ deps = pre-commit commands = pre-commit run --color=always --all-files {posargs} + +[testenv:typecheck] +deps = + -c {toxinidir}/dev-requirements.txt + pyright + {[testenv]test_deps} + {toxinidir}/opentelemetry-instrumentation + {toxinidir}/util/opentelemetry-util-http +commands = + pyright From b7e7d0cbe58e5e525c330b4d3a38e831da588f8e Mon Sep 17 00:00:00 2001 From: Filip Nikolovski Date: Mon, 13 Jan 2025 20:49:22 +0100 Subject: [PATCH 03/12] Implement new HTTP semantic convention opt-in for Falcon (#2790) --- CHANGELOG.md | 2 + instrumentation/README.md | 2 +- .../instrumentation/falcon/__init__.py | 150 +++++--- .../instrumentation/falcon/package.py | 2 + .../tests/test_falcon.py | 350 +++++++++++++++--- 5 files changed, 406 insertions(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c4e76aaf8..0848cf9f7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3133](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3133)) - `opentelemetry-instrumentation-falcon` add support version to v4 ([#3086](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3086)) +- `opentelemetry-instrumentation-falcon` Implement new HTTP semantic convention opt-in for Falcon + ([#2790](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2790)) - `opentelemetry-instrumentation-wsgi` always record span status code to have it available in metrics ([#3148](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3148)) - add support to Python 3.13 diff --git a/instrumentation/README.md b/instrumentation/README.md index d1b383d5a6..75341dad9a 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -20,7 +20,7 @@ | [opentelemetry-instrumentation-dbapi](./opentelemetry-instrumentation-dbapi) | dbapi | No | experimental | [opentelemetry-instrumentation-django](./opentelemetry-instrumentation-django) | django >= 1.10 | Yes | experimental | [opentelemetry-instrumentation-elasticsearch](./opentelemetry-instrumentation-elasticsearch) | elasticsearch >= 6.0 | No | experimental -| [opentelemetry-instrumentation-falcon](./opentelemetry-instrumentation-falcon) | falcon >= 1.4.1, < 5.0.0 | Yes | experimental +| [opentelemetry-instrumentation-falcon](./opentelemetry-instrumentation-falcon) | falcon >= 1.4.1, < 5.0.0 | Yes | migration | [opentelemetry-instrumentation-fastapi](./opentelemetry-instrumentation-fastapi) | fastapi ~= 0.58 | Yes | migration | [opentelemetry-instrumentation-flask](./opentelemetry-instrumentation-flask) | flask >= 1.0 | Yes | migration | [opentelemetry-instrumentation-grpc](./opentelemetry-instrumentation-grpc) | grpcio >= 1.42.0 | No | experimental diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index 1037f98f5f..2b26c55cb1 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -193,6 +193,14 @@ def response_hook(span, req, resp): import opentelemetry.instrumentation.wsgi as otel_wsgi from opentelemetry import context, trace +from opentelemetry.instrumentation._semconv import ( + _get_schema_url, + _OpenTelemetrySemanticConventionStability, + _OpenTelemetryStabilitySignalType, + _report_new, + _report_old, + _StabilityMode, +) from opentelemetry.instrumentation.falcon.package import _instruments from opentelemetry.instrumentation.falcon.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor @@ -203,18 +211,22 @@ def response_hook(span, req, resp): from opentelemetry.instrumentation.utils import ( _start_internal_or_server_span, extract_attributes_from_object, - http_status_to_status_code, ) from opentelemetry.metrics import get_meter +from opentelemetry.semconv.attributes.http_attributes import ( + HTTP_ROUTE, +) from opentelemetry.semconv.metrics import MetricInstruments -from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.trace.status import Status, StatusCode +from opentelemetry.semconv.metrics.http_metrics import ( + HTTP_SERVER_REQUEST_DURATION, +) from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs _logger = getLogger(__name__) _ENVIRON_STARTTIME_KEY = "opentelemetry-falcon.starttime_key" _ENVIRON_SPAN_KEY = "opentelemetry-falcon.span_key" +_ENVIRON_REQ_ATTRS = "opentelemetry-falcon.req_attrs" _ENVIRON_ACTIVATION_KEY = "opentelemetry-falcon.activation_key" _ENVIRON_TOKEN = "opentelemetry-falcon.token" _ENVIRON_EXC = "opentelemetry-falcon.exc" @@ -243,6 +255,10 @@ class _InstrumentedFalconAPI(getattr(falcon, _instrument_app)): def __init__(self, *args, **kwargs): otel_opts = kwargs.pop("_otel_opts", {}) + self._sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode( + _OpenTelemetryStabilitySignalType.HTTP, + ) + # inject trace middleware self._middlewares_list = kwargs.pop("middleware", []) if self._middlewares_list is None: @@ -257,19 +273,30 @@ def __init__(self, *args, **kwargs): __name__, __version__, tracer_provider, - schema_url="https://opentelemetry.io/schemas/1.11.0", + schema_url=_get_schema_url(self._sem_conv_opt_in_mode), ) self._otel_meter = get_meter( __name__, __version__, meter_provider, - schema_url="https://opentelemetry.io/schemas/1.11.0", - ) - self.duration_histogram = self._otel_meter.create_histogram( - name=MetricInstruments.HTTP_SERVER_DURATION, - unit="ms", - description="Measures the duration of inbound HTTP requests.", + schema_url=_get_schema_url(self._sem_conv_opt_in_mode), ) + + self.duration_histogram_old = None + if _report_old(self._sem_conv_opt_in_mode): + self.duration_histogram_old = self._otel_meter.create_histogram( + name=MetricInstruments.HTTP_SERVER_DURATION, + unit="ms", + description="Measures the duration of inbound HTTP requests.", + ) + self.duration_histogram_new = None + if _report_new(self._sem_conv_opt_in_mode): + self.duration_histogram_new = self._otel_meter.create_histogram( + name=HTTP_SERVER_REQUEST_DURATION, + description="Duration of HTTP server requests.", + unit="s", + ) + self.active_requests_counter = self._otel_meter.create_up_down_counter( name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, unit="requests", @@ -283,6 +310,7 @@ def __init__(self, *args, **kwargs): ), otel_opts.pop("request_hook", None), otel_opts.pop("response_hook", None), + self._sem_conv_opt_in_mode, ) self._middlewares_list.insert(0, trace_middleware) kwargs["middleware"] = self._middlewares_list @@ -343,11 +371,14 @@ def __call__(self, env, start_response): context_carrier=env, context_getter=otel_wsgi.wsgi_getter, ) - attributes = otel_wsgi.collect_request_attributes(env) + attributes = otel_wsgi.collect_request_attributes( + env, self._sem_conv_opt_in_mode + ) active_requests_count_attrs = ( - otel_wsgi._parse_active_request_count_attrs(attributes) + otel_wsgi._parse_active_request_count_attrs( + attributes, self._sem_conv_opt_in_mode + ) ) - duration_attrs = otel_wsgi._parse_duration_attrs(attributes) self.active_requests_counter.add(1, active_requests_count_attrs) if span.is_recording(): @@ -364,6 +395,7 @@ def __call__(self, env, start_response): activation.__enter__() env[_ENVIRON_SPAN_KEY] = span env[_ENVIRON_ACTIVATION_KEY] = activation + env[_ENVIRON_REQ_ATTRS] = attributes exception = None def _start_response(status, response_headers, *args, **kwargs): @@ -379,12 +411,22 @@ def _start_response(status, response_headers, *args, **kwargs): exception = exc raise finally: - if span.is_recording(): - duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = ( - span.attributes.get(SpanAttributes.HTTP_STATUS_CODE) + duration_s = default_timer() - start + if self.duration_histogram_old: + duration_attrs = otel_wsgi._parse_duration_attrs( + attributes, _StabilityMode.DEFAULT + ) + self.duration_histogram_old.record( + max(round(duration_s * 1000), 0), duration_attrs + ) + if self.duration_histogram_new: + duration_attrs = otel_wsgi._parse_duration_attrs( + attributes, _StabilityMode.HTTP + ) + self.duration_histogram_new.record( + max(duration_s, 0), duration_attrs ) - duration = max(round((default_timer() - start) * 1000), 0) - self.duration_histogram.record(duration, duration_attrs) + self.active_requests_counter.add(-1, active_requests_count_attrs) if exception is None: activation.__exit__(None, None, None) @@ -407,11 +449,13 @@ def __init__( traced_request_attrs=None, request_hook=None, response_hook=None, + sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT, ): self.tracer = tracer self._traced_request_attrs = traced_request_attrs self._request_hook = request_hook self._response_hook = response_hook + self._sem_conv_opt_in_mode = sem_conv_opt_in_mode def process_request(self, req, resp): span = req.env.get(_ENVIRON_SPAN_KEY) @@ -437,58 +481,60 @@ def process_resource(self, req, resp, resource, params): def process_response(self, req, resp, resource, req_succeeded=None): # pylint:disable=R0201,R0912 span = req.env.get(_ENVIRON_SPAN_KEY) + req_attrs = req.env.get(_ENVIRON_REQ_ATTRS) - if not span or not span.is_recording(): + if not span: return status = resp.status - reason = None if resource is None: - status = "404" - reason = "NotFound" + status = falcon.HTTP_404 else: + exc_type, exc = None, None if _ENVIRON_EXC in req.env: exc = req.env[_ENVIRON_EXC] exc_type = type(exc) - else: - exc_type, exc = None, None + if exc_type and not req_succeeded: if "HTTPNotFound" in exc_type.__name__: - status = "404" - reason = "NotFound" + status = falcon.HTTP_404 + elif isinstance(exc, (falcon.HTTPError, falcon.HTTPStatus)): + try: + if _falcon_version > 2: + status = falcon.code_to_http_status(exc.status) + else: + status = exc.status + except ValueError: + status = falcon.HTTP_500 else: - status = "500" - reason = f"{exc_type.__name__}: {exc}" + status = falcon.HTTP_500 + + # Falcon 1 does not support response headers. So + # send an empty dict. + response_headers = {} + if _falcon_version > 1: + response_headers = resp.headers + + otel_wsgi.add_response_attributes( + span, + status, + response_headers, + req_attrs, + self._sem_conv_opt_in_mode, + ) - status = status.split(" ")[0] + if ( + _report_new(self._sem_conv_opt_in_mode) + and req.uri_template + and req_attrs is not None + ): + req_attrs[HTTP_ROUTE] = req.uri_template try: - status_code = int(status) - span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, status_code) - otel_status_code = http_status_to_status_code( - status_code, server_span=True - ) - - # set the description only when the status code is ERROR - if otel_status_code is not StatusCode.ERROR: - reason = None - - span.set_status( - Status( - status_code=otel_status_code, - description=reason, - ) - ) - - # Falcon 1 does not support response headers. So - # send an empty dict. - response_headers = {} - if _falcon_version > 1: - response_headers = resp.headers - if span.is_recording() and span.kind == trace.SpanKind.SERVER: # Check if low-cardinality route is available as per semantic-conventions if req.uri_template: span.update_name(f"{req.method} {req.uri_template}") + span.set_attribute(HTTP_ROUTE, req.uri_template) else: span.update_name(f"{req.method}") diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/package.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/package.py index 440a6e25f2..74651ddc42 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/package.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/package.py @@ -16,3 +16,5 @@ _instruments = ("falcon >= 1.4.1, < 5.0.0",) _supports_metrics = True + +_semconv_status = "migration" diff --git a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py index f940deb34e..48cbdbe3f8 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py @@ -22,7 +22,11 @@ from opentelemetry import trace from opentelemetry.instrumentation._semconv import ( + OTEL_SEMCONV_STABILITY_OPT_IN, + _OpenTelemetrySemanticConventionStability, + _server_active_requests_count_attrs_new, _server_active_requests_count_attrs_old, + _server_duration_attrs_new, _server_duration_attrs_old, ) from opentelemetry.instrumentation.falcon import FalconInstrumentor @@ -36,6 +40,24 @@ NumberDataPoint, ) from opentelemetry.sdk.resources import Resource +from opentelemetry.semconv.attributes.client_attributes import ( + CLIENT_PORT, +) +from opentelemetry.semconv.attributes.http_attributes import ( + HTTP_REQUEST_METHOD, + HTTP_RESPONSE_STATUS_CODE, +) +from opentelemetry.semconv.attributes.network_attributes import ( + NETWORK_PROTOCOL_VERSION, +) +from opentelemetry.semconv.attributes.server_attributes import ( + SERVER_ADDRESS, + SERVER_PORT, +) +from opentelemetry.semconv.attributes.url_attributes import ( + URL_PATH, + URL_SCHEME, +) from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.test.test_base import TestBase from opentelemetry.test.wsgitestutil import WsgiTestBase @@ -52,10 +74,33 @@ "http.server.active_requests", "http.server.duration", ] + _recommended_attrs = { + "http.server.active_requests": _server_active_requests_count_attrs_new + + _server_active_requests_count_attrs_old, + "http.server.duration": _server_duration_attrs_new + + _server_duration_attrs_old, +} + +_recommended_metrics_attrs_old = { "http.server.active_requests": _server_active_requests_count_attrs_old, "http.server.duration": _server_duration_attrs_old, } +_recommended_metrics_attrs_new = { + "http.server.active_requests": _server_active_requests_count_attrs_new, + "http.server.request.duration": _server_duration_attrs_new, +} +_server_active_requests_count_attrs_both = ( + _server_active_requests_count_attrs_old +) +_server_active_requests_count_attrs_both.extend( + _server_active_requests_count_attrs_new +) +_recommended_metrics_attrs_both = { + "http.server.active_requests": _server_active_requests_count_attrs_both, + "http.server.duration": _server_duration_attrs_old, + "http.server.request.duration": _server_duration_attrs_new, +} _parsed_falcon_version = package_version.parse(_falcon_version) @@ -63,13 +108,26 @@ class TestFalconBase(TestBase): def setUp(self): super().setUp() + + test_name = "" + if hasattr(self, "_testMethodName"): + test_name = self._testMethodName + sem_conv_mode = "default" + if "new_semconv" in test_name: + sem_conv_mode = "http" + elif "both_semconv" in test_name: + sem_conv_mode = "http/dup" + self.env_patch = patch.dict( "os.environ", { "OTEL_PYTHON_FALCON_EXCLUDED_URLS": "ping", "OTEL_PYTHON_FALCON_TRACED_REQUEST_ATTRS": "query_string", + OTEL_SEMCONV_STABILITY_OPT_IN: sem_conv_mode, }, ) + + _OpenTelemetrySemanticConventionStability._initialized = False self.env_patch.start() FalconInstrumentor().instrument( @@ -95,26 +153,63 @@ def tearDown(self): self.env_patch.stop() +# pylint: disable=too-many-public-methods class TestFalconInstrumentation(TestFalconBase, WsgiTestBase): def test_get(self): self._test_method("GET") + def test_get_new_semconv(self): + self._test_method("GET", old_semconv=False, new_semconv=True) + + def test_get_both_semconv(self): + self._test_method("GET", old_semconv=True, new_semconv=True) + def test_post(self): self._test_method("POST") + def test_post_new_semconv(self): + self._test_method("POST", old_semconv=False, new_semconv=True) + + def test_post_both_semconv(self): + self._test_method("POST", old_semconv=True, new_semconv=True) + def test_patch(self): self._test_method("PATCH") + def test_patch_new_semconv(self): + self._test_method("PATCH", old_semconv=False, new_semconv=True) + + def test_patch_both_semconv(self): + self._test_method("PATCH", old_semconv=True, new_semconv=True) + def test_put(self): self._test_method("PUT") + def test_put_new_semconv(self): + self._test_method("PUT", old_semconv=False, new_semconv=True) + + def test_put_both_semconv(self): + self._test_method("PUT", old_semconv=True, new_semconv=True) + def test_delete(self): self._test_method("DELETE") + def test_delete_new_semconv(self): + self._test_method("DELETE", old_semconv=False, new_semconv=True) + + def test_delete_both_semconv(self): + self._test_method("DELETE", old_semconv=True, new_semconv=True) + def test_head(self): self._test_method("HEAD") - def _test_method(self, method): + def test_head_new_semconv(self): + self._test_method("HEAD", old_semconv=False, new_semconv=True) + + def test_head_both_semconv(self): + self._test_method("HEAD", old_semconv=True, new_semconv=True) + + def _test_method(self, method, old_semconv=True, new_semconv=False): self.client().simulate_request(method=method, path="/hello") spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1) @@ -125,23 +220,42 @@ def _test_method(self, method): span.status.description, None, ) - self.assertSpanHasAttributes( - span, - { - SpanAttributes.HTTP_METHOD: method, - SpanAttributes.HTTP_SERVER_NAME: "falconframework.org", - SpanAttributes.HTTP_SCHEME: "http", - SpanAttributes.NET_HOST_PORT: 80, - SpanAttributes.HTTP_HOST: "falconframework.org", - SpanAttributes.HTTP_TARGET: "/" - if self._has_fixed_http_target - else "/hello", - SpanAttributes.NET_PEER_PORT: 65133, - SpanAttributes.HTTP_FLAVOR: "1.1", - "falcon.resource": "HelloWorldResource", - SpanAttributes.HTTP_STATUS_CODE: 201, - }, - ) + + expected_attributes = {} + expected_attributes_old = { + SpanAttributes.HTTP_METHOD: method, + SpanAttributes.HTTP_SERVER_NAME: "falconframework.org", + SpanAttributes.HTTP_SCHEME: "http", + SpanAttributes.NET_HOST_PORT: 80, + SpanAttributes.HTTP_HOST: "falconframework.org", + SpanAttributes.HTTP_TARGET: "/" + if self._has_fixed_http_target + else "/hello", + SpanAttributes.NET_PEER_PORT: 65133, + SpanAttributes.HTTP_FLAVOR: "1.1", + "falcon.resource": "HelloWorldResource", + SpanAttributes.HTTP_STATUS_CODE: 201, + SpanAttributes.HTTP_ROUTE: "/hello", + } + expected_attributes_new = { + HTTP_REQUEST_METHOD: method, + SERVER_ADDRESS: "falconframework.org", + URL_SCHEME: "http", + SERVER_PORT: 80, + URL_PATH: "/" if self._has_fixed_http_target else "/hello", + CLIENT_PORT: 65133, + NETWORK_PROTOCOL_VERSION: "1.1", + "falcon.resource": "HelloWorldResource", + HTTP_RESPONSE_STATUS_CODE: 201, + SpanAttributes.HTTP_ROUTE: "/hello", + } + + if old_semconv: + expected_attributes.update(expected_attributes_old) + if new_semconv: + expected_attributes.update(expected_attributes_new) + + self.assertSpanHasAttributes(span, expected_attributes) # In falcon<3, NET_PEER_IP is always set by default to 127.0.0.1 # In falcon>=3, NET_PEER_IP is not set to anything by default # https://github.com/falconry/falcon/blob/5233d0abed977d9dab78ebadf305f5abe2eef07c/falcon/testing/helpers.py#L1168-L1172 # noqa @@ -193,10 +307,16 @@ def test_500(self): self.assertEqual(span.name, "GET /error") self.assertFalse(span.status.is_ok) self.assertEqual(span.status.status_code, StatusCode.ERROR) - self.assertEqual( - span.status.description, - "NameError: name 'non_existent_var' is not defined", - ) + + _parsed_falcon_version = package_version.parse(_falcon_version) + if _parsed_falcon_version < package_version.parse("3.0.0"): + self.assertEqual( + span.status.description, + "NameError: name 'non_existent_var' is not defined", + ) + else: + self.assertEqual(span.status.description, None) + self.assertSpanHasAttributes( span, { @@ -211,6 +331,7 @@ def test_500(self): SpanAttributes.NET_PEER_PORT: 65133, SpanAttributes.HTTP_FLAVOR: "1.1", SpanAttributes.HTTP_STATUS_CODE: 500, + SpanAttributes.HTTP_ROUTE: "/error", }, ) # In falcon<3, NET_PEER_IP is always set by default to 127.0.0.1 @@ -221,6 +342,47 @@ def test_500(self): span.attributes[SpanAttributes.NET_PEER_IP], "127.0.0.1" ) + def test_url_template_new_semconv(self): + self.client().simulate_get("/user/123") + spans = self.memory_exporter.get_finished_spans() + metrics_list = self.memory_metrics_reader.get_metrics_data() + + self.assertEqual(len(spans), 1) + self.assertTrue(len(metrics_list.resource_metrics) != 0) + span = spans[0] + self.assertEqual(span.name, "GET /user/{user_id}") + self.assertEqual(span.status.status_code, StatusCode.UNSET) + self.assertEqual( + span.status.description, + None, + ) + self.assertSpanHasAttributes( + span, + { + HTTP_REQUEST_METHOD: "GET", + SERVER_ADDRESS: "falconframework.org", + URL_SCHEME: "http", + SERVER_PORT: 80, + URL_PATH: "/" if self._has_fixed_http_target else "/user/123", + CLIENT_PORT: 65133, + NETWORK_PROTOCOL_VERSION: "1.1", + "falcon.resource": "UserResource", + HTTP_RESPONSE_STATUS_CODE: 200, + SpanAttributes.HTTP_ROUTE: "/user/{user_id}", + }, + ) + + for resource_metric in metrics_list.resource_metrics: + for scope_metric in resource_metric.scope_metrics: + for metric in scope_metric.metrics: + if metric.name == "http.server.request.duration": + data_points = list(metric.data.data_points) + for point in data_points: + self.assertIn( + "http.route", + point.attributes, + ) + def test_url_template(self): self.client().simulate_get("/user/123") spans = self.memory_exporter.get_finished_spans() @@ -247,6 +409,7 @@ def test_url_template(self): SpanAttributes.HTTP_FLAVOR: "1.1", "falcon.resource": "UserResource", SpanAttributes.HTTP_STATUS_CODE: 200, + SpanAttributes.HTTP_ROUTE: "/user/{user_id}", }, ) @@ -305,6 +468,27 @@ def test_traced_not_recording(self): self.assertFalse(mock_span.set_attribute.called) self.assertFalse(mock_span.set_status.called) + metrics_list = self.memory_metrics_reader.get_metrics_data() + self.assertTrue(len(metrics_list.resource_metrics) != 0) + + for resource_metric in metrics_list.resource_metrics: + for scope_metric in resource_metric.scope_metrics: + for metric in scope_metric.metrics: + data_points = list(metric.data.data_points) + self.assertEqual(len(data_points), 1) + for point in list(metric.data.data_points): + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 1) + if isinstance(point, NumberDataPoint): + self.assertEqual(point.value, 0) + for attr in point.attributes: + self.assertIn( + attr, + _recommended_metrics_attrs_old[ + metric.name + ], + ) + def test_uninstrument_after_instrument(self): self.client().simulate_get(path="/hello") spans = self.memory_exporter.get_finished_spans() @@ -345,47 +529,119 @@ def test_falcon_metrics(self): ) self.assertTrue(number_data_point_seen and histogram_data_point_seen) + def test_falcon_metric_values_new_semconv(self): + number_data_point_seen = False + histogram_data_point_seen = False + + start = default_timer() + self.client().simulate_get("/hello/756") + duration = max(default_timer() - start, 0) + + metrics_list = self.memory_metrics_reader.get_metrics_data() + for resource_metric in metrics_list.resource_metrics: + for scope_metric in resource_metric.scope_metrics: + for metric in scope_metric.metrics: + data_points = list(metric.data.data_points) + self.assertEqual(len(data_points), 1) + for point in data_points: + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 1) + histogram_data_point_seen = True + self.assertAlmostEqual( + duration, point.sum, delta=10 + ) + if isinstance(point, NumberDataPoint): + self.assertEqual(point.value, 0) + number_data_point_seen = True + for attr in point.attributes: + self.assertIn( + attr, + _recommended_metrics_attrs_new[metric.name], + ) + + self.assertTrue(number_data_point_seen and histogram_data_point_seen) + + def test_falcon_metric_values_both_semconv(self): + number_data_point_seen = False + histogram_data_point_seen = False + + start = default_timer() + self.client().simulate_get("/hello/756") + duration_s = default_timer() - start + + metrics_list = self.memory_metrics_reader.get_metrics_data() + + # pylint: disable=too-many-nested-blocks + for resource_metric in metrics_list.resource_metrics: + for scope_metric in resource_metric.scope_metrics: + for metric in scope_metric.metrics: + if metric.unit == "ms": + self.assertEqual(metric.name, "http.server.duration") + elif metric.unit == "s": + self.assertEqual( + metric.name, "http.server.request.duration" + ) + else: + self.assertEqual( + metric.name, "http.server.active_requests" + ) + data_points = list(metric.data.data_points) + self.assertEqual(len(data_points), 1) + for point in data_points: + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 1) + if metric.unit == "ms": + self.assertAlmostEqual( + max(round(duration_s * 1000), 0), + point.sum, + delta=10, + ) + elif metric.unit == "s": + self.assertAlmostEqual( + max(duration_s, 0), point.sum, delta=10 + ) + histogram_data_point_seen = True + if isinstance(point, NumberDataPoint): + self.assertEqual(point.value, 0) + number_data_point_seen = True + for attr in point.attributes: + self.assertIn( + attr, + _recommended_metrics_attrs_both[metric.name], + ) + self.assertTrue(number_data_point_seen and histogram_data_point_seen) + def test_falcon_metric_values(self): - expected_duration_attributes = { - "http.method": "GET", - "http.host": "falconframework.org", - "http.scheme": "http", - "http.flavor": "1.1", - "http.server_name": "falconframework.org", - "net.host.port": 80, - "net.host.name": "falconframework.org", - "http.status_code": 404, - } - expected_requests_count_attributes = { - "http.method": "GET", - "http.host": "falconframework.org", - "http.scheme": "http", - "http.flavor": "1.1", - "http.server_name": "falconframework.org", - } + number_data_point_seen = False + histogram_data_point_seen = False + start = default_timer() self.client().simulate_get("/hello/756") duration = max(round((default_timer() - start) * 1000), 0) + metrics_list = self.memory_metrics_reader.get_metrics_data() for resource_metric in metrics_list.resource_metrics: for scope_metric in resource_metric.scope_metrics: for metric in scope_metric.metrics: + data_points = list(metric.data.data_points) + self.assertEqual(len(data_points), 1) for point in list(metric.data.data_points): if isinstance(point, HistogramDataPoint): - self.assertDictEqual( - expected_duration_attributes, - dict(point.attributes), - ) self.assertEqual(point.count, 1) + histogram_data_point_seen = True self.assertAlmostEqual( duration, point.sum, delta=10 ) if isinstance(point, NumberDataPoint): - self.assertDictEqual( - expected_requests_count_attributes, - dict(point.attributes), - ) self.assertEqual(point.value, 0) + number_data_point_seen = True + for attr in point.attributes: + self.assertIn( + attr, + _recommended_metrics_attrs_old[metric.name], + ) + + self.assertTrue(number_data_point_seen and histogram_data_point_seen) def test_metric_uninstrument(self): self.client().simulate_request(method="POST", path="/hello/756") From 5219242eafa5dff08fb2ff855860d6772a43364b Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Mon, 13 Jan 2025 21:32:16 +0000 Subject: [PATCH 04/12] Support PEP 561 to `opentelemetry-instrumentation-wsgi` (#3129) --- CHANGELOG.md | 2 + .../instrumentation/wsgi/__init__.py | 124 +++++++++++------- .../instrumentation/wsgi/package.py | 3 +- .../instrumentation/wsgi/py.typed | 0 .../src/opentelemetry/util/http/__init__.py | 10 +- 5 files changed, 87 insertions(+), 52 deletions(-) create mode 100644 instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/py.typed diff --git a/CHANGELOG.md b/CHANGELOG.md index 0848cf9f7a..ea1a44b574 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3148](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3148)) - add support to Python 3.13 ([#3134](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3134)) +- `opentelemetry-opentelemetry-wsgi` Add `py.typed` file to enable PEP 561 + ([#3129](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3129)) - `opentelemetry-util-http` Add `py.typed` file to enable PEP 561 ([#3127](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3127)) diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py index bd3b2d18db..a0a2ce9a35 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py @@ -97,15 +97,22 @@ def GET(self): .. code-block:: python + from wsgiref.types import WSGIEnvironment, StartResponse + from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware + + def app(environ: WSGIEnvironment, start_response: StartResponse): + start_response("200 OK", [("Content-Type", "text/plain"), ("Content-Length", "13")]) + return [b"Hello, World!"] + def request_hook(span: Span, environ: WSGIEnvironment): if span and span.is_recording(): span.set_attribute("custom_user_attribute_from_request_hook", "some-value") - def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_headers: List): + def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_headers: list[tuple[str, str]]): if span and span.is_recording(): span.set_attribute("custom_user_attribute_from_response_hook", "some-value") - OpenTelemetryMiddleware(request_hook=request_hook, response_hook=response_hook) + OpenTelemetryMiddleware(app, request_hook=request_hook, response_hook=response_hook) Capture HTTP request and response headers ***************************************** @@ -207,10 +214,12 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he --- """ +from __future__ import annotations + import functools -import typing import wsgiref.util as wsgiref_util from timeit import default_timer +from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, TypeVar, cast from opentelemetry import context, trace from opentelemetry.instrumentation._semconv import ( @@ -240,7 +249,7 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he ) from opentelemetry.instrumentation.utils import _start_internal_or_server_span from opentelemetry.instrumentation.wsgi.version import __version__ -from opentelemetry.metrics import get_meter +from opentelemetry.metrics import MeterProvider, get_meter from opentelemetry.propagators.textmap import Getter from opentelemetry.semconv.attributes.error_attributes import ERROR_TYPE from opentelemetry.semconv.metrics import MetricInstruments @@ -248,6 +257,7 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he HTTP_SERVER_REQUEST_DURATION, ) from opentelemetry.semconv.trace import SpanAttributes +from opentelemetry.trace import TracerProvider from opentelemetry.trace.status import Status, StatusCode from opentelemetry.util.http import ( OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS, @@ -262,15 +272,23 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he sanitize_method, ) +if TYPE_CHECKING: + from wsgiref.types import StartResponse, WSGIApplication, WSGIEnvironment + + +T = TypeVar("T") +RequestHook = Callable[[trace.Span, "WSGIEnvironment"], None] +ResponseHook = Callable[ + [trace.Span, "WSGIEnvironment", str, "list[tuple[str, str]]"], None +] + _HTTP_VERSION_PREFIX = "HTTP/" _CARRIER_KEY_PREFIX = "HTTP_" _CARRIER_KEY_PREFIX_LEN = len(_CARRIER_KEY_PREFIX) -class WSGIGetter(Getter[dict]): - def get( - self, carrier: dict, key: str - ) -> typing.Optional[typing.List[str]]: +class WSGIGetter(Getter[Dict[str, Any]]): + def get(self, carrier: dict[str, Any], key: str) -> list[str] | None: """Getter implementation to retrieve a HTTP header value from the PEP3333-conforming WSGI environ @@ -287,7 +305,7 @@ def get( return [value] return None - def keys(self, carrier): + def keys(self, carrier: dict[str, Any]): return [ key[_CARRIER_KEY_PREFIX_LEN:].lower().replace("_", "-") for key in carrier @@ -298,26 +316,19 @@ def keys(self, carrier): wsgi_getter = WSGIGetter() -def setifnotnone(dic, key, value): - if value is not None: - dic[key] = value - - # pylint: disable=too-many-branches - - def collect_request_attributes( - environ, - sem_conv_opt_in_mode=_StabilityMode.DEFAULT, + environ: WSGIEnvironment, + sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT, ): """Collects HTTP request attributes from the PEP3333-conforming WSGI environ and returns a dictionary to be used as span creation attributes. """ - result = {} + result: dict[str, str | None] = {} _set_http_method( result, environ.get("REQUEST_METHOD", ""), - sanitize_method(environ.get("REQUEST_METHOD", "")), + sanitize_method(cast(str, environ.get("REQUEST_METHOD", ""))), sem_conv_opt_in_mode, ) # old semconv v1.12.0 @@ -385,7 +396,7 @@ def collect_request_attributes( return result -def collect_custom_request_headers_attributes(environ): +def collect_custom_request_headers_attributes(environ: WSGIEnvironment): """Returns custom HTTP request headers which are configured by the user from the PEP3333-conforming WSGI environ to be used as span creation attributes as described in the specification https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-request-and-response-headers @@ -411,7 +422,9 @@ def collect_custom_request_headers_attributes(environ): ) -def collect_custom_response_headers_attributes(response_headers): +def collect_custom_response_headers_attributes( + response_headers: list[tuple[str, str]], +): """Returns custom HTTP response headers which are configured by the user from the PEP3333-conforming WSGI environ as described in the specification https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-request-and-response-headers @@ -422,7 +435,7 @@ def collect_custom_response_headers_attributes(response_headers): OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS ) ) - response_headers_dict = {} + response_headers_dict: dict[str, str] = {} if response_headers: for key, val in response_headers: key = key.lower() @@ -440,7 +453,8 @@ def collect_custom_response_headers_attributes(response_headers): ) -def _parse_status_code(resp_status): +# TODO: Used only on the `opentelemetry-instrumentation-pyramid` package - It can be moved there. +def _parse_status_code(resp_status: str) -> int | None: status_code, _ = resp_status.split(" ", 1) try: return int(status_code) @@ -449,7 +463,7 @@ def _parse_status_code(resp_status): def _parse_active_request_count_attrs( - req_attrs, sem_conv_opt_in_mode=_StabilityMode.DEFAULT + req_attrs, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT ): return _filter_semconv_active_request_count_attr( req_attrs, @@ -460,7 +474,8 @@ def _parse_active_request_count_attrs( def _parse_duration_attrs( - req_attrs, sem_conv_opt_in_mode=_StabilityMode.DEFAULT + req_attrs: dict[str, str | None], + sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT, ): return _filter_semconv_duration_attrs( req_attrs, @@ -471,11 +486,11 @@ def _parse_duration_attrs( def add_response_attributes( - span, - start_response_status, - response_headers, - duration_attrs=None, - sem_conv_opt_in_mode=_StabilityMode.DEFAULT, + span: trace.Span, + start_response_status: str, + response_headers: list[tuple[str, str]], + duration_attrs: dict[str, str | None] | None = None, + sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT, ): # pylint: disable=unused-argument """Adds HTTP response attributes to span using the arguments passed to a PEP3333-conforming start_response callable. @@ -497,7 +512,7 @@ def add_response_attributes( ) -def get_default_span_name(environ): +def get_default_span_name(environ: WSGIEnvironment) -> str: """ Default span name is the HTTP method and URL path, or just the method. https://github.com/open-telemetry/opentelemetry-specification/pull/3165 @@ -508,10 +523,12 @@ def get_default_span_name(environ): Returns: The span name. """ - method = sanitize_method(environ.get("REQUEST_METHOD", "").strip()) + method = sanitize_method( + cast(str, environ.get("REQUEST_METHOD", "")).strip() + ) if method == "_OTHER": return "HTTP" - path = environ.get("PATH_INFO", "").strip() + path = cast(str, environ.get("PATH_INFO", "")).strip() if method and path: return f"{method} {path}" return method @@ -538,11 +555,11 @@ class OpenTelemetryMiddleware: def __init__( self, - wsgi, - request_hook=None, - response_hook=None, - tracer_provider=None, - meter_provider=None, + wsgi: WSGIApplication, + request_hook: RequestHook | None = None, + response_hook: ResponseHook | None = None, + tracer_provider: TracerProvider | None = None, + meter_provider: MeterProvider | None = None, ): # initialize semantic conventions opt-in if needed _OpenTelemetrySemanticConventionStability._initialize() @@ -589,14 +606,19 @@ def __init__( @staticmethod def _create_start_response( - span, - start_response, - response_hook, - duration_attrs, - sem_conv_opt_in_mode, + span: trace.Span, + start_response: StartResponse, + response_hook: Callable[[str, list[tuple[str, str]]], None] | None, + duration_attrs: dict[str, str | None], + sem_conv_opt_in_mode: _StabilityMode, ): @functools.wraps(start_response) - def _start_response(status, response_headers, *args, **kwargs): + def _start_response( + status: str, + response_headers: list[tuple[str, str]], + *args: Any, + **kwargs: Any, + ): add_response_attributes( span, status, @@ -617,7 +639,9 @@ def _start_response(status, response_headers, *args, **kwargs): return _start_response # pylint: disable=too-many-branches - def __call__(self, environ, start_response): + def __call__( + self, environ: WSGIEnvironment, start_response: StartResponse + ): """The WSGI application Args: @@ -699,7 +723,9 @@ def __call__(self, environ, start_response): # Put this in a subfunction to not delay the call to the wrapped # WSGI application (instrumentation should change the application # behavior as little as possible). -def _end_span_after_iterating(iterable, span, token): +def _end_span_after_iterating( + iterable: Iterable[T], span: trace.Span, token: object +) -> Iterable[T]: try: with trace.use_span(span): yield from iterable @@ -713,10 +739,8 @@ def _end_span_after_iterating(iterable, span, token): # TODO: inherit from opentelemetry.instrumentation.propagators.Setter - - class ResponsePropagationSetter: - def set(self, carrier, key, value): # pylint: disable=no-self-use + def set(self, carrier: list[tuple[str, T]], key: str, value: T): # pylint: disable=no-self-use carrier.append((key, value)) diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/package.py b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/package.py index 1bb8350a06..2dbb19055f 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/package.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/package.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations -_instruments = tuple() +_instruments: tuple[str, ...] = tuple() _supports_metrics = True diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/py.typed b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/py.typed new file mode 100644 index 0000000000..e69de29bb2 diff --git a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py index c7dd9f7b06..71a6403a7d 100644 --- a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py +++ b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py @@ -19,7 +19,7 @@ from re import IGNORECASE as RE_IGNORECASE from re import compile as re_compile from re import search -from typing import Callable, Iterable +from typing import Callable, Iterable, overload from urllib.parse import urlparse, urlunparse from opentelemetry.semconv.trace import SpanAttributes @@ -191,6 +191,14 @@ def normalise_response_header_name(header: str) -> str: return f"http.response.header.{key}" +@overload +def sanitize_method(method: str) -> str: ... + + +@overload +def sanitize_method(method: None) -> None: ... + + def sanitize_method(method: str | None) -> str | None: if method is None: return None From c59b514cdadfe062c69f8e055d7c1aa4b56dc92e Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:42:32 -0500 Subject: [PATCH 05/12] Fix component owner workflow permissions (#3165) --- .github/workflows/component-owners.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/component-owners.yml b/.github/workflows/component-owners.yml index 824e39c370..f0068701f7 100644 --- a/.github/workflows/component-owners.yml +++ b/.github/workflows/component-owners.yml @@ -10,6 +10,10 @@ jobs: run_self: runs-on: ubuntu-latest name: Auto Assign Owners + permissions: + contents: read # to read changed files + issues: write # to read/write issue assignees + pull-requests: write # to read/write PR reviewers # Don't fail tests if this workflow fails. Some pending issues: # - https://github.com/dyladan/component-owners/issues/8 continue-on-error: true From e54256ddb7d5ef5b40ffff0f594d1f77a6c757ce Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Tue, 14 Jan 2025 16:28:11 +0000 Subject: [PATCH 06/12] Support PEP 561 to `opentelemetry-instrumentation-urllib` (#3131) * Support PEP 561 to `opentelemetry-instrumentation-urllib` * add future --------- Co-authored-by: Riccardo Magliocchetti --- CHANGELOG.md | 2 + .../instrumentation/urllib/__init__.py | 54 +++++++++++-------- .../instrumentation/urllib/package.py | 3 +- .../instrumentation/urllib/py.typed | 0 .../instrumentation/urllib/version.py | 2 - 5 files changed, 36 insertions(+), 25 deletions(-) create mode 100644 instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/py.typed diff --git a/CHANGELOG.md b/CHANGELOG.md index ea1a44b574..6e40e73270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3100](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3100)) - Add support to database stability opt-in in `_semconv` utilities and add tests ([#3111](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3111)) +- `opentelemetry-instrumentation-urllib` Add `py.typed` file to enable PEP 561 + ([#3131](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3131)) - `opentelemetry-opentelemetry-pymongo` Add `py.typed` file to enable PEP 561 ([#3136](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3136)) - `opentelemetry-opentelemetry-requests` Add `py.typed` file to enable PEP 561 diff --git a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py index 9fe9996ba4..a80e6d0700 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py @@ -43,17 +43,24 @@ .. code:: python - # `request_obj` is an instance of urllib.request.Request - def request_hook(span, request_obj): + from http.client import HTTPResponse + from urllib.request import Request + + from opentelemetry.instrumentation.urllib import URLLibInstrumentor + from opentelemetry.trace import Span + + + def request_hook(span: Span, request: Request): pass - # `request_obj` is an instance of urllib.request.Request - # `response` is an instance of http.client.HTTPResponse - def response_hook(span, request_obj, response) + + def response_hook(span: Span, request: Request, response: HTTPResponse): pass - URLLibInstrumentor.instrument( - request_hook=request_hook, response_hook=response_hook) + + URLLibInstrumentor().instrument( + request_hook=request_hook, + response_hook=response_hook ) Exclude lists @@ -74,12 +81,14 @@ def response_hook(span, request_obj, response) --- """ +from __future__ import annotations + import functools import types import typing from http import client from timeit import default_timer -from typing import Collection, Dict +from typing import Any, Collection from urllib.request import ( # pylint: disable=no-name-in-module,import-error OpenerDirector, Request, @@ -107,7 +116,7 @@ def response_hook(span, request_obj, response) is_http_instrumentation_enabled, suppress_http_instrumentation, ) -from opentelemetry.metrics import Histogram, get_meter +from opentelemetry.metrics import Histogram, Meter, get_meter from opentelemetry.propagate import inject from opentelemetry.semconv._incubating.metrics.http_metrics import ( HTTP_CLIENT_REQUEST_BODY_SIZE, @@ -121,7 +130,7 @@ def response_hook(span, request_obj, response) HTTP_CLIENT_REQUEST_DURATION, ) from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.trace import Span, SpanKind, get_tracer +from opentelemetry.trace import Span, SpanKind, Tracer, get_tracer from opentelemetry.util.http import ( ExcludeList, get_excluded_urls, @@ -129,6 +138,7 @@ def response_hook(span, request_obj, response) remove_url_credentials, sanitize_method, ) +from opentelemetry.util.types import Attributes _excluded_urls_from_env = get_excluded_urls("URLLIB") @@ -146,7 +156,7 @@ class URLLibInstrumentor(BaseInstrumentor): def instrumentation_dependencies(self) -> Collection[str]: return _instruments - def _instrument(self, **kwargs): + def _instrument(self, **kwargs: Any): """Instruments urllib module Args: @@ -194,7 +204,7 @@ def _instrument(self, **kwargs): sem_conv_opt_in_mode=sem_conv_opt_in_mode, ) - def _uninstrument(self, **kwargs): + def _uninstrument(self, **kwargs: Any): _uninstrument() def uninstrument_opener(self, opener: OpenerDirector): # pylint: disable=no-self-use @@ -204,11 +214,11 @@ def uninstrument_opener(self, opener: OpenerDirector): # pylint: disable=no-sel # pylint: disable=too-many-statements def _instrument( - tracer, - histograms: Dict[str, Histogram], + tracer: Tracer, + histograms: dict[str, Histogram], request_hook: _RequestHookT = None, response_hook: _ResponseHookT = None, - excluded_urls: ExcludeList = None, + excluded_urls: ExcludeList | None = None, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT, ): """Enables tracing of all requests calls that go through @@ -345,7 +355,7 @@ def _uninstrument(): _uninstrument_from(OpenerDirector) -def _uninstrument_from(instr_root, restore_as_bound_func=False): +def _uninstrument_from(instr_root, restore_as_bound_func: bool = False): instr_func_name = "open" instr_func = getattr(instr_root, instr_func_name) if not getattr( @@ -371,7 +381,7 @@ def _get_span_name(method: str) -> str: def _set_status_code_attribute( span: Span, status_code: int, - metric_attributes: dict = None, + metric_attributes: dict[str, Any] | None = None, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT, ) -> None: status_code_str = str(status_code) @@ -394,8 +404,8 @@ def _set_status_code_attribute( def _create_client_histograms( - meter, sem_conv_opt_in_mode=_StabilityMode.DEFAULT -) -> Dict[str, Histogram]: + meter: Meter, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT +) -> dict[str, Histogram]: histograms = {} if _report_old(sem_conv_opt_in_mode): histograms[MetricInstruments.HTTP_CLIENT_DURATION] = ( @@ -436,9 +446,9 @@ def _create_client_histograms( def _record_histograms( - histograms: Dict[str, Histogram], - metric_attributes_old: dict, - metric_attributes_new: dict, + histograms: dict[str, Histogram], + metric_attributes_old: Attributes, + metric_attributes_new: Attributes, request_size: int, response_size: int, duration_s: float, diff --git a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/package.py b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/package.py index 1bb8350a06..2dbb19055f 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/package.py +++ b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/package.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations -_instruments = tuple() +_instruments: tuple[str, ...] = tuple() _supports_metrics = True diff --git a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/py.typed b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/py.typed new file mode 100644 index 0000000000..e69de29bb2 diff --git a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/version.py b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/version.py index c3c9026f93..6e2923f0db 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/version.py +++ b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/version.py @@ -13,5 +13,3 @@ # limitations under the License. __version__ = "0.51b0.dev" - -_instruments = tuple() From 52871b82b6afc3545609d3740620a6c4d4edf7ab Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Tue, 14 Jan 2025 17:27:35 +0000 Subject: [PATCH 07/12] Add type hints to HTTPX (#3098) --- .../instrumentation/httpx/__init__.py | 143 +++++++++--------- .../instrumentation/httpx/py.typed | 0 2 files changed, 73 insertions(+), 70 deletions(-) create mode 100644 instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/py.typed diff --git a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py index 27bb3d639d..ba4e5b4fd4 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py @@ -230,15 +230,13 @@ async def async_response_hook(span, request, response): NETWORK_PEER_ADDRESS, NETWORK_PEER_PORT, ) -from opentelemetry.trace import SpanKind, TracerProvider, get_tracer +from opentelemetry.trace import SpanKind, Tracer, TracerProvider, get_tracer from opentelemetry.trace.span import Span from opentelemetry.trace.status import StatusCode from opentelemetry.util.http import remove_url_credentials, sanitize_method _logger = logging.getLogger(__name__) -URL = typing.Tuple[bytes, bytes, typing.Optional[int], bytes] -Headers = typing.List[typing.Tuple[bytes, bytes]] RequestHook = typing.Callable[[Span, "RequestInfo"], None] ResponseHook = typing.Callable[[Span, "RequestInfo", "ResponseInfo"], None] AsyncRequestHook = typing.Callable[ @@ -253,17 +251,15 @@ class RequestInfo(typing.NamedTuple): method: bytes url: httpx.URL headers: httpx.Headers | None - stream: typing.Optional[ - typing.Union[httpx.SyncByteStream, httpx.AsyncByteStream] - ] - extensions: typing.Optional[dict] + stream: httpx.SyncByteStream | httpx.AsyncByteStream | None + extensions: dict[str, typing.Any] | None class ResponseInfo(typing.NamedTuple): status_code: int headers: httpx.Headers | None - stream: typing.Iterable[bytes] - extensions: typing.Optional[dict] + stream: httpx.SyncByteStream | httpx.AsyncByteStream + extensions: dict[str, typing.Any] | None def _get_default_span_name(method: str) -> str: @@ -274,11 +270,19 @@ def _get_default_span_name(method: str) -> str: return method -def _prepare_headers(headers: typing.Optional[Headers]) -> httpx.Headers: +def _prepare_headers(headers: httpx.Headers | None) -> httpx.Headers: return httpx.Headers(headers) -def _extract_parameters(args, kwargs): +def _extract_parameters( + args: tuple[typing.Any, ...], kwargs: dict[str, typing.Any] +) -> tuple[ + bytes, + httpx.URL, + httpx.Headers | None, + httpx.SyncByteStream | httpx.AsyncByteStream | None, + dict[str, typing.Any], +]: if isinstance(args[0], httpx.Request): # In httpx >= 0.20.0, handle_request receives a Request object request: httpx.Request = args[0] @@ -311,10 +315,15 @@ def _inject_propagation_headers(headers, args, kwargs): def _extract_response( - response: typing.Union[ - httpx.Response, typing.Tuple[int, Headers, httpx.SyncByteStream, dict] - ], -) -> typing.Tuple[int, Headers, httpx.SyncByteStream, dict, str]: + response: httpx.Response + | tuple[int, httpx.Headers, httpx.SyncByteStream, dict[str, typing.Any]], +) -> tuple[ + int, + httpx.Headers, + httpx.SyncByteStream | httpx.AsyncByteStream, + dict[str, typing.Any], + str, +]: if isinstance(response, httpx.Response): status_code = response.status_code headers = response.headers @@ -331,8 +340,8 @@ def _extract_response( def _apply_request_client_attributes_to_span( - span_attributes: dict, - url: typing.Union[str, URL, httpx.URL], + span_attributes: dict[str, typing.Any], + url: str | httpx.URL, method_original: str, semconv: _StabilityMode, ): @@ -407,9 +416,9 @@ class SyncOpenTelemetryTransport(httpx.BaseTransport): def __init__( self, transport: httpx.BaseTransport, - tracer_provider: typing.Optional[TracerProvider] = None, - request_hook: typing.Optional[RequestHook] = None, - response_hook: typing.Optional[ResponseHook] = None, + tracer_provider: TracerProvider | None = None, + request_hook: RequestHook | None = None, + response_hook: ResponseHook | None = None, ): _OpenTelemetrySemanticConventionStability._initialize() self._sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode( @@ -426,27 +435,27 @@ def __init__( self._request_hook = request_hook self._response_hook = response_hook - def __enter__(self) -> "SyncOpenTelemetryTransport": + def __enter__(self) -> SyncOpenTelemetryTransport: self._transport.__enter__() return self def __exit__( self, - exc_type: typing.Optional[typing.Type[BaseException]] = None, - exc_value: typing.Optional[BaseException] = None, - traceback: typing.Optional[TracebackType] = None, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: TracebackType | None = None, ) -> None: self._transport.__exit__(exc_type, exc_value, traceback) # pylint: disable=R0914 def handle_request( self, - *args, - **kwargs, - ) -> typing.Union[ - typing.Tuple[int, "Headers", httpx.SyncByteStream, dict], - httpx.Response, - ]: + *args: typing.Any, + **kwargs: typing.Any, + ) -> ( + tuple[int, httpx.Headers, httpx.SyncByteStream, dict[str, typing.Any]] + | httpx.Response + ): """Add request info to span.""" if not is_http_instrumentation_enabled(): return self._transport.handle_request(*args, **kwargs) @@ -532,9 +541,9 @@ class AsyncOpenTelemetryTransport(httpx.AsyncBaseTransport): def __init__( self, transport: httpx.AsyncBaseTransport, - tracer_provider: typing.Optional[TracerProvider] = None, - request_hook: typing.Optional[AsyncRequestHook] = None, - response_hook: typing.Optional[AsyncResponseHook] = None, + tracer_provider: TracerProvider | None = None, + request_hook: AsyncRequestHook | None = None, + response_hook: AsyncResponseHook | None = None, ): _OpenTelemetrySemanticConventionStability._initialize() self._sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode( @@ -557,19 +566,19 @@ async def __aenter__(self) -> "AsyncOpenTelemetryTransport": async def __aexit__( self, - exc_type: typing.Optional[typing.Type[BaseException]] = None, - exc_value: typing.Optional[BaseException] = None, - traceback: typing.Optional[TracebackType] = None, + exc_type: typing.Type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: TracebackType | None = None, ) -> None: await self._transport.__aexit__(exc_type, exc_value, traceback) # pylint: disable=R0914 async def handle_async_request( - self, *args, **kwargs - ) -> typing.Union[ - typing.Tuple[int, "Headers", httpx.AsyncByteStream, dict], - httpx.Response, - ]: + self, *args: typing.Any, **kwargs: typing.Any + ) -> ( + tuple[int, httpx.Headers, httpx.AsyncByteStream, dict[str, typing.Any]] + | httpx.Response + ): """Add request info to span.""" if not is_http_instrumentation_enabled(): return await self._transport.handle_async_request(*args, **kwargs) @@ -653,7 +662,7 @@ class HTTPXClientInstrumentor(BaseInstrumentor): def instrumentation_dependencies(self) -> typing.Collection[str]: return _instruments - def _instrument(self, **kwargs): + def _instrument(self, **kwargs: typing.Any): """Instruments httpx Client and AsyncClient Args: @@ -716,20 +725,20 @@ def _instrument(self, **kwargs): ), ) - def _uninstrument(self, **kwargs): + def _uninstrument(self, **kwargs: typing.Any): unwrap(httpx.HTTPTransport, "handle_request") unwrap(httpx.AsyncHTTPTransport, "handle_async_request") @staticmethod def _handle_request_wrapper( # pylint: disable=too-many-locals - wrapped, - instance, - args, - kwargs, - tracer, - sem_conv_opt_in_mode, - request_hook, - response_hook, + wrapped: typing.Callable[..., typing.Any], + instance: httpx.HTTPTransport, + args: tuple[typing.Any, ...], + kwargs: dict[str, typing.Any], + tracer: Tracer, + sem_conv_opt_in_mode: _StabilityMode, + request_hook: RequestHook, + response_hook: ResponseHook, ): if not is_http_instrumentation_enabled(): return wrapped(*args, **kwargs) @@ -796,14 +805,14 @@ def _handle_request_wrapper( # pylint: disable=too-many-locals @staticmethod async def _handle_async_request_wrapper( # pylint: disable=too-many-locals - wrapped, - instance, - args, - kwargs, - tracer, - sem_conv_opt_in_mode, - async_request_hook, - async_response_hook, + wrapped: typing.Callable[..., typing.Awaitable[typing.Any]], + instance: httpx.AsyncHTTPTransport, + args: tuple[typing.Any, ...], + kwargs: dict[str, typing.Any], + tracer: Tracer, + sem_conv_opt_in_mode: _StabilityMode, + async_request_hook: AsyncRequestHook, + async_response_hook: AsyncResponseHook, ): if not is_http_instrumentation_enabled(): return await wrapped(*args, **kwargs) @@ -872,14 +881,10 @@ async def _handle_async_request_wrapper( # pylint: disable=too-many-locals @classmethod def instrument_client( cls, - client: typing.Union[httpx.Client, httpx.AsyncClient], - tracer_provider: TracerProvider = None, - request_hook: typing.Union[ - typing.Optional[RequestHook], typing.Optional[AsyncRequestHook] - ] = None, - response_hook: typing.Union[ - typing.Optional[ResponseHook], typing.Optional[AsyncResponseHook] - ] = None, + client: httpx.Client | httpx.AsyncClient, + tracer_provider: TracerProvider | None = None, + request_hook: RequestHook | AsyncRequestHook | None = None, + response_hook: ResponseHook | AsyncResponseHook | None = None, ) -> None: """Instrument httpx Client or AsyncClient @@ -977,9 +982,7 @@ def instrument_client( client._is_instrumented_by_opentelemetry = True @staticmethod - def uninstrument_client( - client: typing.Union[httpx.Client, httpx.AsyncClient], - ): + def uninstrument_client(client: httpx.Client | httpx.AsyncClient) -> None: """Disables instrumentation for the given client instance Args: diff --git a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/py.typed b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/py.typed new file mode 100644 index 0000000000..e69de29bb2 From 07c97eac380d2f86f09a95851fb6c38182537d05 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Wed, 15 Jan 2025 16:30:01 +0000 Subject: [PATCH 08/12] Add type hints to `psycopg` (#3067) * Add type hints to Psycopg * fix tests * fix * Add psycopg.Connection to nitpick * Add py.typed * add psycopg to nitpick again * add psycopg to nitpick again * move py.typed to the right folder --------- Co-authored-by: Riccardo Magliocchetti --- docs/nitpick-exceptions.ini | 2 + .../instrumentation/psycopg/__init__.py | 69 +++++++++++-------- .../instrumentation/psycopg/package.py | 4 +- .../instrumentation/psycopg/py.typed | 0 .../tests/test_psycopg_integration.py | 4 +- 5 files changed, 45 insertions(+), 34 deletions(-) create mode 100644 instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/py.typed diff --git a/docs/nitpick-exceptions.ini b/docs/nitpick-exceptions.ini index b1fcdd5342..bf120765c9 100644 --- a/docs/nitpick-exceptions.ini +++ b/docs/nitpick-exceptions.ini @@ -41,6 +41,8 @@ py-class= callable Consumer confluent_kafka.Message + psycopg.Connection + psycopg.AsyncConnection ObjectProxy any= diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py index 81390ed48f..38a6264c6d 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py @@ -137,27 +137,28 @@ --- """ +from __future__ import annotations + import logging -import typing -from typing import Collection +from typing import Any, Callable, Collection, TypeVar import psycopg # pylint: disable=import-self -from psycopg import ( - AsyncCursor as pg_async_cursor, # pylint: disable=import-self,no-name-in-module -) -from psycopg import ( - Cursor as pg_cursor, # pylint: disable=no-name-in-module,import-self -) from psycopg.sql import Composed # pylint: disable=no-name-in-module from opentelemetry.instrumentation import dbapi from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.psycopg.package import _instruments from opentelemetry.instrumentation.psycopg.version import __version__ +from opentelemetry.trace import TracerProvider _logger = logging.getLogger(__name__) _OTEL_CURSOR_FACTORY_KEY = "_otel_orig_cursor_factory" +ConnectionT = TypeVar( + "ConnectionT", psycopg.Connection, psycopg.AsyncConnection +) +CursorT = TypeVar("CursorT", psycopg.Cursor, psycopg.AsyncCursor) + class PsycopgInstrumentor(BaseInstrumentor): _CONNECTION_ATTRIBUTES = { @@ -172,7 +173,7 @@ class PsycopgInstrumentor(BaseInstrumentor): def instrumentation_dependencies(self) -> Collection[str]: return _instruments - def _instrument(self, **kwargs): + def _instrument(self, **kwargs: Any): """Integrate with PostgreSQL Psycopg library. Psycopg: http://initd.org/psycopg/ """ @@ -223,7 +224,7 @@ def _instrument(self, **kwargs): enable_attribute_commenter=enable_attribute_commenter, ) - def _uninstrument(self, **kwargs): + def _uninstrument(self, **kwargs: Any): """ "Disable Psycopg instrumentation""" dbapi.unwrap_connect(psycopg, "connect") # pylint: disable=no-member dbapi.unwrap_connect( @@ -237,7 +238,9 @@ def _uninstrument(self, **kwargs): # TODO(owais): check if core dbapi can do this for all dbapi implementations e.g, pymysql and mysql @staticmethod - def instrument_connection(connection, tracer_provider=None): + def instrument_connection( + connection: ConnectionT, tracer_provider: TracerProvider | None = None + ) -> ConnectionT: """Enable instrumentation in a psycopg connection. Args: @@ -269,7 +272,7 @@ def instrument_connection(connection, tracer_provider=None): # TODO(owais): check if core dbapi can do this for all dbapi implementations e.g, pymysql and mysql @staticmethod - def uninstrument_connection(connection): + def uninstrument_connection(connection: ConnectionT) -> ConnectionT: connection.cursor_factory = getattr( connection, _OTEL_CURSOR_FACTORY_KEY, None ) @@ -281,9 +284,9 @@ def uninstrument_connection(connection): class DatabaseApiIntegration(dbapi.DatabaseApiIntegration): def wrapped_connection( self, - connect_method: typing.Callable[..., typing.Any], - args: typing.Tuple[typing.Any, typing.Any], - kwargs: typing.Dict[typing.Any, typing.Any], + connect_method: Callable[..., Any], + args: tuple[Any, Any], + kwargs: dict[Any, Any], ): """Add object proxy to connection object.""" base_cursor_factory = kwargs.pop("cursor_factory", None) @@ -299,9 +302,9 @@ def wrapped_connection( class DatabaseApiAsyncIntegration(dbapi.DatabaseApiIntegration): async def wrapped_connection( self, - connect_method: typing.Callable[..., typing.Any], - args: typing.Tuple[typing.Any, typing.Any], - kwargs: typing.Dict[typing.Any, typing.Any], + connect_method: Callable[..., Any], + args: tuple[Any, Any], + kwargs: dict[Any, Any], ): """Add object proxy to connection object.""" base_cursor_factory = kwargs.pop("cursor_factory", None) @@ -317,7 +320,7 @@ async def wrapped_connection( class CursorTracer(dbapi.CursorTracer): - def get_operation_name(self, cursor, args): + def get_operation_name(self, cursor: CursorT, args: list[Any]) -> str: if not args: return "" @@ -332,7 +335,7 @@ def get_operation_name(self, cursor, args): return "" - def get_statement(self, cursor, args): + def get_statement(self, cursor: CursorT, args: list[Any]) -> str: if not args: return "" @@ -342,7 +345,11 @@ def get_statement(self, cursor, args): return statement -def _new_cursor_factory(db_api=None, base_factory=None, tracer_provider=None): +def _new_cursor_factory( + db_api: DatabaseApiIntegration | None = None, + base_factory: type[psycopg.Cursor] | None = None, + tracer_provider: TracerProvider | None = None, +): if not db_api: db_api = DatabaseApiIntegration( __name__, @@ -352,21 +359,21 @@ def _new_cursor_factory(db_api=None, base_factory=None, tracer_provider=None): tracer_provider=tracer_provider, ) - base_factory = base_factory or pg_cursor + base_factory = base_factory or psycopg.Cursor _cursor_tracer = CursorTracer(db_api) class TracedCursorFactory(base_factory): - def execute(self, *args, **kwargs): + def execute(self, *args: Any, **kwargs: Any): return _cursor_tracer.traced_execution( self, super().execute, *args, **kwargs ) - def executemany(self, *args, **kwargs): + def executemany(self, *args: Any, **kwargs: Any): return _cursor_tracer.traced_execution( self, super().executemany, *args, **kwargs ) - def callproc(self, *args, **kwargs): + def callproc(self, *args: Any, **kwargs: Any): return _cursor_tracer.traced_execution( self, super().callproc, *args, **kwargs ) @@ -375,7 +382,9 @@ def callproc(self, *args, **kwargs): def _new_cursor_async_factory( - db_api=None, base_factory=None, tracer_provider=None + db_api: DatabaseApiAsyncIntegration | None = None, + base_factory: type[psycopg.AsyncCursor] | None = None, + tracer_provider: TracerProvider | None = None, ): if not db_api: db_api = DatabaseApiAsyncIntegration( @@ -385,21 +394,21 @@ def _new_cursor_async_factory( version=__version__, tracer_provider=tracer_provider, ) - base_factory = base_factory or pg_async_cursor + base_factory = base_factory or psycopg.AsyncCursor _cursor_tracer = CursorTracer(db_api) class TracedCursorAsyncFactory(base_factory): - async def execute(self, *args, **kwargs): + async def execute(self, *args: Any, **kwargs: Any): return await _cursor_tracer.traced_execution( self, super().execute, *args, **kwargs ) - async def executemany(self, *args, **kwargs): + async def executemany(self, *args: Any, **kwargs: Any): return await _cursor_tracer.traced_execution( self, super().executemany, *args, **kwargs ) - async def callproc(self, *args, **kwargs): + async def callproc(self, *args: Any, **kwargs: Any): return await _cursor_tracer.traced_execution( self, super().callproc, *args, **kwargs ) diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/package.py b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/package.py index 635edfb4db..a3ee72d1ae 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/package.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/package.py @@ -11,6 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations - -_instruments = ("psycopg >= 3.1.0",) +_instruments: tuple[str, ...] = ("psycopg >= 3.1.0",) diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/py.typed b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/py.typed new file mode 100644 index 0000000000..e69de29bb2 diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/tests/test_psycopg_integration.py b/instrumentation/opentelemetry-instrumentation-psycopg/tests/test_psycopg_integration.py index 4ddaad9174..6c9bcf2d4b 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg/tests/test_psycopg_integration.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg/tests/test_psycopg_integration.py @@ -132,10 +132,10 @@ class PostgresqlIntegrationTestMixin: def setUp(self): super().setUp() self.cursor_mock = mock.patch( - "opentelemetry.instrumentation.psycopg.pg_cursor", MockCursor + "opentelemetry.instrumentation.psycopg.psycopg.Cursor", MockCursor ) self.cursor_async_mock = mock.patch( - "opentelemetry.instrumentation.psycopg.pg_async_cursor", + "opentelemetry.instrumentation.psycopg.psycopg.AsyncCursor", MockAsyncCursor, ) self.connection_mock = mock.patch("psycopg.connect", MockConnection) From a716949d1c28341b2fb9af75f43b541ddeac9335 Mon Sep 17 00:00:00 2001 From: Drew Robbins Date: Thu, 16 Jan 2025 07:24:35 +0900 Subject: [PATCH 09/12] Add metrics to the Python OpenAI instrumentation (#3180) --- .../CHANGELOG.md | 1 + .../README.rst | 45 ++++- .../instrumentation/openai_v2/__init__.py | 18 +- .../instrumentation/openai_v2/instruments.py | 11 + .../instrumentation/openai_v2/patch.py | 107 +++++++++- .../test_async_chat_completion_metrics.yaml | 133 ++++++++++++ .../test_chat_completion_metrics.yaml | 135 +++++++++++++ .../tests/conftest.py | 83 +++++++- .../tests/test_chat_completions.py | 49 ++++- .../tests/test_chat_metrics.py | 190 ++++++++++++++++++ 10 files changed, 763 insertions(+), 9 deletions(-) create mode 100644 instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/instruments.py create mode 100644 instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/cassettes/test_async_chat_completion_metrics.yaml create mode 100644 instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/cassettes/test_chat_completion_metrics.yaml create mode 100644 instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_metrics.py diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md index 4644ee3dc5..ed27904e63 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add example to `opentelemetry-instrumentation-openai-v2` ([#3006](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3006)) - Support for `AsyncOpenAI/AsyncCompletions` ([#2984](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2984)) +- Add metrics ([#3180](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3180)) ## Version 2.0b0 (2024-11-08) diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/README.rst b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/README.rst index d2cb0b5724..c402b30bc0 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/README.rst +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/README.rst @@ -7,7 +7,8 @@ OpenTelemetry OpenAI Instrumentation :target: https://pypi.org/project/opentelemetry-instrumentation-openai-v2/ This library allows tracing LLM requests and logging of messages made by the -`OpenAI Python API library `_. +`OpenAI Python API library `_. It also captures +the duration of the operations and the number of tokens used as metrics. Installation @@ -74,6 +75,48 @@ To uninstrument clients, call the uninstrument method: # Uninstrument all clients OpenAIInstrumentor().uninstrument() +Bucket Boundaries +----------------- + +This section describes the explicit bucket boundaries for metrics such as token usage and operation duration, and guides users to create Views to implement them according to the semantic conventions. + +The bucket boundaries are defined as follows: + +- For `gen_ai.client.token.usage`: [1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864] +- For `gen_ai.client.operation.duration`: [0.01, 0.02, 0.04, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12, 10.24, 20.48, 40.96, 81.92] + +To implement these bucket boundaries, you can create Views in your OpenTelemetry SDK setup. Here is an example: + +.. code-block:: python + + from opentelemetry.sdk.metrics import MeterProvider, View + from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader + from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter + from opentelemetry.sdk.metrics.aggregation import ExplicitBucketHistogramAggregation + + views = [ + View( + instrument_name="gen_ai.client.token.usage", + aggregation=ExplicitBucketHistogramAggregation([1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864]), + ), + View( + instrument_name="gen_ai.client.operation.duration", + aggregation=ExplicitBucketHistogramAggregation([0.01, 0.02, 0.04, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12, 10.24, 20.48, 40.96, 81.92]), + ), + ] + + metric_exporter = OTLPMetricExporter(endpoint="http://localhost:4317") + metric_reader = PeriodicExportingMetricReader(metric_exporter) + provider = MeterProvider( + metric_readers=[metric_reader], + views=views + ) + + from opentelemetry.sdk.metrics import set_meter_provider + set_meter_provider(provider) + +For more details, refer to the `OpenTelemetry GenAI Metrics documentation `_. + References ---------- * `OpenTelemetry OpenAI Instrumentation `_ diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/__init__.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/__init__.py index ee3bbfdb73..ab4b6f9d7b 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/__init__.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/__init__.py @@ -49,13 +49,18 @@ from opentelemetry.instrumentation.openai_v2.package import _instruments from opentelemetry.instrumentation.openai_v2.utils import is_content_enabled from opentelemetry.instrumentation.utils import unwrap +from opentelemetry.metrics import get_meter from opentelemetry.semconv.schemas import Schemas from opentelemetry.trace import get_tracer +from .instruments import Instruments from .patch import async_chat_completions_create, chat_completions_create class OpenAIInstrumentor(BaseInstrumentor): + def __init__(self): + self._meter = None + def instrumentation_dependencies(self) -> Collection[str]: return _instruments @@ -75,12 +80,21 @@ def _instrument(self, **kwargs): schema_url=Schemas.V1_28_0.value, event_logger_provider=event_logger_provider, ) + meter_provider = kwargs.get("meter_provider") + self._meter = get_meter( + __name__, + "", + meter_provider, + schema_url=Schemas.V1_28_0.value, + ) + + instruments = Instruments(self._meter) wrap_function_wrapper( module="openai.resources.chat.completions", name="Completions.create", wrapper=chat_completions_create( - tracer, event_logger, is_content_enabled() + tracer, event_logger, instruments, is_content_enabled() ), ) @@ -88,7 +102,7 @@ def _instrument(self, **kwargs): module="openai.resources.chat.completions", name="AsyncCompletions.create", wrapper=async_chat_completions_create( - tracer, event_logger, is_content_enabled() + tracer, event_logger, instruments, is_content_enabled() ), ) diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/instruments.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/instruments.py new file mode 100644 index 0000000000..d1e184ac84 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/instruments.py @@ -0,0 +1,11 @@ +from opentelemetry.semconv._incubating.metrics import gen_ai_metrics + + +class Instruments: + def __init__(self, meter): + self.operation_duration_histogram = ( + gen_ai_metrics.create_gen_ai_client_operation_duration(meter) + ) + self.token_usage_histogram = ( + gen_ai_metrics.create_gen_ai_client_token_usage(meter) + ) diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/patch.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/patch.py index cd284473ce..307b312fca 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/patch.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/patch.py @@ -13,6 +13,7 @@ # limitations under the License. +from timeit import default_timer from typing import Optional from openai import Stream @@ -21,8 +22,12 @@ from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, ) +from opentelemetry.semconv._incubating.attributes import ( + server_attributes as ServerAttributes, +) from opentelemetry.trace import Span, SpanKind, Tracer +from .instruments import Instruments from .utils import ( choice_to_event, get_llm_request_attributes, @@ -34,7 +39,10 @@ def chat_completions_create( - tracer: Tracer, event_logger: EventLogger, capture_content: bool + tracer: Tracer, + event_logger: EventLogger, + instruments: Instruments, + capture_content: bool, ): """Wrap the `create` method of the `ChatCompletion` class to trace it.""" @@ -54,6 +62,9 @@ def traced_method(wrapped, instance, args, kwargs): message_to_event(message, capture_content) ) + start = default_timer() + result = None + error_type = None try: result = wrapped(*args, **kwargs) if is_streaming(kwargs): @@ -69,14 +80,27 @@ def traced_method(wrapped, instance, args, kwargs): return result except Exception as error: + error_type = type(error).__qualname__ handle_span_exception(span, error) raise + finally: + duration = max((default_timer() - start), 0) + _record_metrics( + instruments, + duration, + result, + span_attributes, + error_type, + ) return traced_method def async_chat_completions_create( - tracer: Tracer, event_logger: EventLogger, capture_content: bool + tracer: Tracer, + event_logger: EventLogger, + instruments: Instruments, + capture_content: bool, ): """Wrap the `create` method of the `AsyncChatCompletion` class to trace it.""" @@ -96,6 +120,9 @@ async def traced_method(wrapped, instance, args, kwargs): message_to_event(message, capture_content) ) + start = default_timer() + result = None + error_type = None try: result = await wrapped(*args, **kwargs) if is_streaming(kwargs): @@ -111,12 +138,88 @@ async def traced_method(wrapped, instance, args, kwargs): return result except Exception as error: + error_type = type(error).__qualname__ handle_span_exception(span, error) raise + finally: + duration = max((default_timer() - start), 0) + _record_metrics( + instruments, + duration, + result, + span_attributes, + error_type, + ) return traced_method +def _record_metrics( + instruments: Instruments, + duration: float, + result, + span_attributes: dict, + error_type: Optional[str], +): + common_attributes = { + GenAIAttributes.GEN_AI_OPERATION_NAME: GenAIAttributes.GenAiOperationNameValues.CHAT.value, + GenAIAttributes.GEN_AI_SYSTEM: GenAIAttributes.GenAiSystemValues.OPENAI.value, + GenAIAttributes.GEN_AI_REQUEST_MODEL: span_attributes[ + GenAIAttributes.GEN_AI_REQUEST_MODEL + ], + } + + if error_type: + common_attributes["error.type"] = error_type + + if result and getattr(result, "model", None): + common_attributes[GenAIAttributes.GEN_AI_RESPONSE_MODEL] = result.model + + if result and getattr(result, "service_tier", None): + common_attributes[ + GenAIAttributes.GEN_AI_OPENAI_RESPONSE_SERVICE_TIER + ] = result.service_tier + + if result and getattr(result, "system_fingerprint", None): + common_attributes["gen_ai.openai.response.system_fingerprint"] = ( + result.system_fingerprint + ) + + if ServerAttributes.SERVER_ADDRESS in span_attributes: + common_attributes[ServerAttributes.SERVER_ADDRESS] = span_attributes[ + ServerAttributes.SERVER_ADDRESS + ] + + if ServerAttributes.SERVER_PORT in span_attributes: + common_attributes[ServerAttributes.SERVER_PORT] = span_attributes[ + ServerAttributes.SERVER_PORT + ] + + instruments.operation_duration_histogram.record( + duration, + attributes=common_attributes, + ) + + if result and getattr(result, "usage", None): + input_attributes = { + **common_attributes, + GenAIAttributes.GEN_AI_TOKEN_TYPE: GenAIAttributes.GenAiTokenTypeValues.INPUT.value, + } + instruments.token_usage_histogram.record( + result.usage.prompt_tokens, + attributes=input_attributes, + ) + + completion_attributes = { + **common_attributes, + GenAIAttributes.GEN_AI_TOKEN_TYPE: GenAIAttributes.GenAiTokenTypeValues.COMPLETION.value, + } + instruments.token_usage_histogram.record( + result.usage.completion_tokens, + attributes=completion_attributes, + ) + + def _set_response_attributes( span, result, event_logger: EventLogger, capture_content: bool ): diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/cassettes/test_async_chat_completion_metrics.yaml b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/cassettes/test_async_chat_completion_metrics.yaml new file mode 100644 index 0000000000..e771e93cbe --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/cassettes/test_async_chat_completion_metrics.yaml @@ -0,0 +1,133 @@ +interactions: +- request: + body: |- + { + "messages": [ + { + "role": "user", + "content": "Say this is a test" + } + ], + "model": "gpt-4o-mini", + "stream": false + } + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - Bearer test_openai_api_key + connection: + - keep-alive + content-length: + - '106' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - AsyncOpenAI/Python 1.26.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - async:asyncio + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.26.0 + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.12.5 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: |- + { + "id": "chatcmpl-ASv9R2E7Yhb2e7bj4Xl0qm9s3J42Y", + "object": "chat.completion", + "created": 1731456237, + "model": "gpt-4o-mini-2024-07-18", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "This is a test. How can I assist you further?", + "refusal": null + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "service_tier": "default", + "usage": { + "prompt_tokens": 12, + "completion_tokens": 12, + "total_tokens": 24, + "prompt_tokens_details": { + "cached_tokens": 0, + "audio_tokens": 0 + }, + "completion_tokens_details": { + "reasoning_tokens": 0, + "audio_tokens": 0, + "accepted_prediction_tokens": 0, + "rejected_prediction_tokens": 0 + } + }, + "system_fingerprint": "fp_0ba0d124f1" + } + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 8e1a80679a8311a6-MRS + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 13 Nov 2024 00:03:58 GMT + Server: + - cloudflare + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + content-length: + - '796' + openai-organization: test_openai_org_id + openai-processing-ms: + - '359' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999978' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + x-request-id: + - req_41ea134c1fc450d4ca4cf8d0c6a7c53a + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/cassettes/test_chat_completion_metrics.yaml b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/cassettes/test_chat_completion_metrics.yaml new file mode 100644 index 0000000000..1c6c11c858 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/cassettes/test_chat_completion_metrics.yaml @@ -0,0 +1,135 @@ +interactions: +- request: + body: |- + { + "messages": [ + { + "role": "user", + "content": "Say this is a test" + } + ], + "model": "gpt-4o-mini", + "stream": false + } + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - Bearer test_openai_api_key + connection: + - keep-alive + content-length: + - '106' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.54.3 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.54.3 + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.12.6 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: |- + { + "id": "chatcmpl-ASYMQRl3A3DXL9FWCK9tnGRcKIO7q", + "object": "chat.completion", + "created": 1731368630, + "model": "gpt-4o-mini-2024-07-18", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "This is a test.", + "refusal": null + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "service_tier": "default", + "usage": { + "prompt_tokens": 12, + "completion_tokens": 5, + "total_tokens": 17, + "prompt_tokens_details": { + "cached_tokens": 0, + "audio_tokens": 0 + }, + "completion_tokens_details": { + "reasoning_tokens": 0, + "audio_tokens": 0, + "accepted_prediction_tokens": 0, + "rejected_prediction_tokens": 0 + } + }, + "system_fingerprint": "fp_0ba0d124f1" + } + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 8e122593ff368bc8-SIN + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Mon, 11 Nov 2024 23:43:50 GMT + Server: + - cloudflare + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + content-length: + - '765' + openai-organization: test_openai_org_id + openai-processing-ms: + - '287' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '200000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '199977' + x-ratelimit-reset-requests: + - 8.64s + x-ratelimit-reset-tokens: + - 6ms + x-request-id: + - req_58cff97afd0e7c0bba910ccf0b044a6f + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/conftest.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/conftest.py index 18e6582dff..51521dbadd 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/conftest.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/conftest.py @@ -17,6 +17,17 @@ InMemoryLogExporter, SimpleLogRecordProcessor, ) +from opentelemetry.sdk.metrics import ( + Histogram, + MeterProvider, +) +from opentelemetry.sdk.metrics.export import ( + InMemoryMetricReader, +) +from opentelemetry.sdk.metrics.view import ( + ExplicitBucketHistogramAggregation, + View, +) from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import SimpleSpanProcessor from opentelemetry.sdk.trace.export.in_memory_span_exporter import ( @@ -36,6 +47,12 @@ def fixture_log_exporter(): yield exporter +@pytest.fixture(scope="function", name="metric_reader") +def fixture_metric_reader(): + exporter = InMemoryMetricReader() + yield exporter + + @pytest.fixture(scope="function", name="tracer_provider") def fixture_tracer_provider(span_exporter): provider = TracerProvider() @@ -52,6 +69,62 @@ def fixture_event_logger_provider(log_exporter): return event_logger_provider +@pytest.fixture(scope="function", name="meter_provider") +def fixture_meter_provider(metric_reader): + token_usage_histogram_view = View( + instrument_type=Histogram, + instrument_name="gen_ai.client.token.usage", + aggregation=ExplicitBucketHistogramAggregation( + boundaries=[ + 1, + 4, + 16, + 64, + 256, + 1024, + 4096, + 16384, + 65536, + 262144, + 1048576, + 4194304, + 16777216, + 67108864, + ] + ), + ) + + duration_histogram_view = View( + instrument_type=Histogram, + instrument_name="gen_ai.client.operation.duration", + aggregation=ExplicitBucketHistogramAggregation( + boundaries=[ + 0.01, + 0.02, + 0.04, + 0.08, + 0.16, + 0.32, + 0.64, + 1.28, + 2.56, + 5.12, + 10.24, + 20.48, + 40.96, + 81.92, + ] + ), + ) + + meter_provider = MeterProvider( + metric_readers=[metric_reader], + views=[token_usage_histogram_view, duration_histogram_view], + ) + + return meter_provider + + @pytest.fixture(autouse=True) def environment(): if not os.getenv("OPENAI_API_KEY"): @@ -83,7 +156,9 @@ def vcr_config(): @pytest.fixture(scope="function") -def instrument_no_content(tracer_provider, event_logger_provider): +def instrument_no_content( + tracer_provider, event_logger_provider, meter_provider +): os.environ.update( {OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: "False"} ) @@ -92,6 +167,7 @@ def instrument_no_content(tracer_provider, event_logger_provider): instrumentor.instrument( tracer_provider=tracer_provider, event_logger_provider=event_logger_provider, + meter_provider=meter_provider, ) yield instrumentor @@ -100,7 +176,9 @@ def instrument_no_content(tracer_provider, event_logger_provider): @pytest.fixture(scope="function") -def instrument_with_content(tracer_provider, event_logger_provider): +def instrument_with_content( + tracer_provider, event_logger_provider, meter_provider +): os.environ.update( {OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: "True"} ) @@ -108,6 +186,7 @@ def instrument_with_content(tracer_provider, event_logger_provider): instrumentor.instrument( tracer_provider=tracer_provider, event_logger_provider=event_logger_provider, + meter_provider=meter_provider, ) yield instrumentor diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_completions.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_completions.py index 4677b7cb95..9685903603 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_completions.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_completions.py @@ -32,6 +32,7 @@ from opentelemetry.semconv._incubating.attributes import ( server_attributes as ServerAttributes, ) +from opentelemetry.semconv._incubating.metrics import gen_ai_metrics @pytest.mark.vcr() @@ -94,7 +95,9 @@ def test_chat_completion_no_content( assert_message_in_logs(logs[1], "gen_ai.choice", choice_event, spans[0]) -def test_chat_completion_bad_endpoint(span_exporter, instrument_no_content): +def test_chat_completion_bad_endpoint( + span_exporter, metric_reader, instrument_no_content +): llm_model_value = "gpt-4o-mini" messages_value = [{"role": "user", "content": "Say this is a test"}] @@ -116,10 +119,31 @@ def test_chat_completion_bad_endpoint(span_exporter, instrument_no_content): "APIConnectionError" == spans[0].attributes[ErrorAttributes.ERROR_TYPE] ) + metrics = metric_reader.get_metrics_data().resource_metrics + assert len(metrics) == 1 + + metric_data = metrics[0].scope_metrics[0].metrics + duration_metric = next( + ( + m + for m in metric_data + if m.name == gen_ai_metrics.GEN_AI_CLIENT_OPERATION_DURATION + ), + None, + ) + assert duration_metric is not None + assert duration_metric.data.data_points[0].sum > 0 + assert ( + duration_metric.data.data_points[0].attributes[ + ErrorAttributes.ERROR_TYPE + ] + == "APIConnectionError" + ) + @pytest.mark.vcr() def test_chat_completion_404( - span_exporter, openai_client, instrument_no_content + span_exporter, openai_client, metric_reader, instrument_no_content ): llm_model_value = "this-model-does-not-exist" messages_value = [{"role": "user", "content": "Say this is a test"}] @@ -135,6 +159,27 @@ def test_chat_completion_404( assert_all_attributes(spans[0], llm_model_value) assert "NotFoundError" == spans[0].attributes[ErrorAttributes.ERROR_TYPE] + metrics = metric_reader.get_metrics_data().resource_metrics + assert len(metrics) == 1 + + metric_data = metrics[0].scope_metrics[0].metrics + duration_metric = next( + ( + m + for m in metric_data + if m.name == gen_ai_metrics.GEN_AI_CLIENT_OPERATION_DURATION + ), + None, + ) + assert duration_metric is not None + assert duration_metric.data.data_points[0].sum > 0 + assert ( + duration_metric.data.data_points[0].attributes[ + ErrorAttributes.ERROR_TYPE + ] + == "NotFoundError" + ) + @pytest.mark.vcr() def test_chat_completion_extra_params( diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_metrics.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_metrics.py new file mode 100644 index 0000000000..d0f7c5a596 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_metrics.py @@ -0,0 +1,190 @@ +import pytest + +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAIAttributes, +) +from opentelemetry.semconv._incubating.attributes import ( + server_attributes as ServerAttributes, +) +from opentelemetry.semconv._incubating.metrics import gen_ai_metrics + + +def assert_all_metric_attributes(data_point): + assert GenAIAttributes.GEN_AI_OPERATION_NAME in data_point.attributes + assert ( + data_point.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] + == GenAIAttributes.GenAiOperationNameValues.CHAT.value + ) + assert GenAIAttributes.GEN_AI_SYSTEM in data_point.attributes + assert ( + data_point.attributes[GenAIAttributes.GEN_AI_SYSTEM] + == GenAIAttributes.GenAiSystemValues.OPENAI.value + ) + assert GenAIAttributes.GEN_AI_REQUEST_MODEL in data_point.attributes + assert ( + data_point.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL] + == "gpt-4o-mini" + ) + assert GenAIAttributes.GEN_AI_RESPONSE_MODEL in data_point.attributes + assert ( + data_point.attributes[GenAIAttributes.GEN_AI_RESPONSE_MODEL] + == "gpt-4o-mini-2024-07-18" + ) + assert "gen_ai.openai.response.system_fingerprint" in data_point.attributes + assert ( + data_point.attributes["gen_ai.openai.response.system_fingerprint"] + == "fp_0ba0d124f1" + ) + assert ( + GenAIAttributes.GEN_AI_OPENAI_RESPONSE_SERVICE_TIER + in data_point.attributes + ) + assert ( + data_point.attributes[ + GenAIAttributes.GEN_AI_OPENAI_RESPONSE_SERVICE_TIER + ] + == "default" + ) + assert ( + data_point.attributes[ServerAttributes.SERVER_ADDRESS] + == "api.openai.com" + ) + + +@pytest.mark.vcr() +def test_chat_completion_metrics( + metric_reader, openai_client, instrument_with_content +): + llm_model_value = "gpt-4o-mini" + messages_value = [{"role": "user", "content": "Say this is a test"}] + + openai_client.chat.completions.create( + messages=messages_value, model=llm_model_value, stream=False + ) + + metrics = metric_reader.get_metrics_data().resource_metrics + assert len(metrics) == 1 + + metric_data = metrics[0].scope_metrics[0].metrics + assert len(metric_data) == 2 + + duration_metric = next( + ( + m + for m in metric_data + if m.name == gen_ai_metrics.GEN_AI_CLIENT_OPERATION_DURATION + ), + None, + ) + assert duration_metric is not None + assert duration_metric.data.data_points[0].sum > 0 + assert_all_metric_attributes(duration_metric.data.data_points[0]) + + token_usage_metric = next( + ( + m + for m in metric_data + if m.name == gen_ai_metrics.GEN_AI_CLIENT_TOKEN_USAGE + ), + None, + ) + assert token_usage_metric is not None + + input_token_usage = next( + ( + d + for d in token_usage_metric.data.data_points + if d.attributes[GenAIAttributes.GEN_AI_TOKEN_TYPE] + == GenAIAttributes.GenAiTokenTypeValues.INPUT.value + ), + None, + ) + assert input_token_usage is not None + assert input_token_usage.sum == 12 + # assert against buckets [1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864] + assert input_token_usage.bucket_counts[2] == 1 + assert_all_metric_attributes(input_token_usage) + + output_token_usage = next( + ( + d + for d in token_usage_metric.data.data_points + if d.attributes[GenAIAttributes.GEN_AI_TOKEN_TYPE] + == GenAIAttributes.GenAiTokenTypeValues.COMPLETION.value + ), + None, + ) + assert output_token_usage is not None + assert output_token_usage.sum == 5 + # assert against buckets [1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864] + assert output_token_usage.bucket_counts[2] == 1 + assert_all_metric_attributes(output_token_usage) + + +@pytest.mark.vcr() +@pytest.mark.asyncio() +async def test_async_chat_completion_metrics( + metric_reader, async_openai_client, instrument_with_content +): + llm_model_value = "gpt-4o-mini" + messages_value = [{"role": "user", "content": "Say this is a test"}] + + await async_openai_client.chat.completions.create( + messages=messages_value, model=llm_model_value, stream=False + ) + + metrics = metric_reader.get_metrics_data().resource_metrics + assert len(metrics) == 1 + + metric_data = metrics[0].scope_metrics[0].metrics + assert len(metric_data) == 2 + + duration_metric = next( + ( + m + for m in metric_data + if m.name == gen_ai_metrics.GEN_AI_CLIENT_OPERATION_DURATION + ), + None, + ) + assert duration_metric is not None + assert duration_metric.data.data_points[0].sum > 0 + assert_all_metric_attributes(duration_metric.data.data_points[0]) + + token_usage_metric = next( + ( + m + for m in metric_data + if m.name == gen_ai_metrics.GEN_AI_CLIENT_TOKEN_USAGE + ), + None, + ) + assert token_usage_metric is not None + + input_token_usage = next( + ( + d + for d in token_usage_metric.data.data_points + if d.attributes[GenAIAttributes.GEN_AI_TOKEN_TYPE] + == GenAIAttributes.GenAiTokenTypeValues.INPUT.value + ), + None, + ) + + assert input_token_usage is not None + assert input_token_usage.sum == 12 + assert_all_metric_attributes(input_token_usage) + + output_token_usage = next( + ( + d + for d in token_usage_metric.data.data_points + if d.attributes[GenAIAttributes.GEN_AI_TOKEN_TYPE] + == GenAIAttributes.GenAiTokenTypeValues.COMPLETION.value + ), + None, + ) + + assert output_token_usage is not None + assert output_token_usage.sum == 12 + assert_all_metric_attributes(output_token_usage) From 9d9353d4c6e9d1230a6364914eede3720f58772e Mon Sep 17 00:00:00 2001 From: Aaron Abbott Date: Thu, 16 Jan 2025 14:25:35 -0500 Subject: [PATCH 10/12] Run pyright on Vertex AI instrumentation (#3184) --- .../src/opentelemetry/instrumentation/vertexai/__init__.py | 6 +++--- .../src/opentelemetry/instrumentation/vertexai/py.typed | 0 pyproject.toml | 5 ++++- tox.ini | 1 + 4 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/py.typed diff --git a/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/__init__.py b/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/__init__.py index b2011513a9..9437184ff0 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/__init__.py +++ b/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/__init__.py @@ -39,7 +39,7 @@ --- """ -from typing import Collection +from typing import Any, Collection from opentelemetry._events import get_event_logger from opentelemetry.instrumentation.instrumentor import BaseInstrumentor @@ -52,7 +52,7 @@ class VertexAIInstrumentor(BaseInstrumentor): def instrumentation_dependencies(self) -> Collection[str]: return _instruments - def _instrument(self, **kwargs): + def _instrument(self, **kwargs: Any): """Enable VertexAI instrumentation.""" tracer_provider = kwargs.get("tracer_provider") _tracer = get_tracer( @@ -70,5 +70,5 @@ def _instrument(self, **kwargs): ) # TODO: implemented in later PR - def _uninstrument(self, **kwargs) -> None: + def _uninstrument(self, **kwargs: Any) -> None: """TODO: implemented in later PR""" diff --git a/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/py.typed b/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/py.typed new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pyproject.toml b/pyproject.toml index 6ba2e933c3..c023fc549f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,10 +48,13 @@ pythonVersion = "3.8" reportPrivateUsage = false # Ignore private attributes added by instrumentation packages. # Add progressively instrumentation packages here. include = [ - "instrumentation/opentelemetry-instrumentation-threading/**/*.py" + "instrumentation/opentelemetry-instrumentation-threading/**/*.py", + "instrumentation-genai/opentelemetry-instrumentation-vertexai/**/*.py", ] # We should also add type hints to the test suite - It helps on finding bugs. # We are excluding for now because it's easier, and more important to add to the instrumentation packages. exclude = [ "instrumentation/opentelemetry-instrumentation-threading/tests/**", + "instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/**/*.py", + "instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/**/*.py", ] diff --git a/tox.ini b/tox.ini index feeda77702..13dd9fafb6 100644 --- a/tox.ini +++ b/tox.ini @@ -994,5 +994,6 @@ deps = {[testenv]test_deps} {toxinidir}/opentelemetry-instrumentation {toxinidir}/util/opentelemetry-util-http + {toxinidir}/instrumentation-genai/opentelemetry-instrumentation-vertexai[instruments] commands = pyright From 9b217bb4ffe4b96aa0bdd3468579507461ffb183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Em=C3=ADdio=20Neto?= <9735060+emdneto@users.noreply.github.com> Date: Fri, 17 Jan 2025 13:33:52 -0300 Subject: [PATCH 11/12] introducing tox-uv for real (#3185) Signed-off-by: emdneto <9735060+emdneto@users.noreply.github.com> --- .github/workflows/core_contrib_test_0.yml | 180 +++---- .../core_contrib_test.yml.j2 | 2 +- .../src/generate_workflows_lib/lint.yml.j2 | 2 +- .../src/generate_workflows_lib/misc.yml.j2 | 2 +- .../src/generate_workflows_lib/test.yml.j2 | 2 +- .github/workflows/lint_0.yml | 124 ++--- .github/workflows/misc_0.yml | 16 +- .github/workflows/test_0.yml | 500 +++++++++--------- .github/workflows/test_1.yml | 500 +++++++++--------- .github/workflows/test_2.yml | 204 +++---- CONTRIBUTING.md | 10 +- tox.ini | 2 + 12 files changed, 776 insertions(+), 768 deletions(-) diff --git a/.github/workflows/core_contrib_test_0.yml b/.github/workflows/core_contrib_test_0.yml index 6c0616e0a6..7ab737c657 100644 --- a/.github/workflows/core_contrib_test_0.yml +++ b/.github/workflows/core_contrib_test_0.yml @@ -36,7 +36,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-openai-v2-0 -- -ra @@ -58,7 +58,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-openai-v2-1 -- -ra @@ -80,7 +80,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-vertexai-0 -- -ra @@ -102,7 +102,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-vertexai-1 -- -ra @@ -124,7 +124,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-resource-detector-container -- -ra @@ -146,7 +146,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-resource-detector-azure-0 -- -ra @@ -168,7 +168,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-resource-detector-azure-1 -- -ra @@ -190,7 +190,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-sdk-extension-aws-0 -- -ra @@ -212,7 +212,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-sdk-extension-aws-1 -- -ra @@ -234,7 +234,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-distro -- -ra @@ -256,7 +256,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-opentelemetry-instrumentation -- -ra @@ -278,7 +278,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aiohttp-client -- -ra @@ -300,7 +300,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aiohttp-server -- -ra @@ -322,7 +322,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aiopg -- -ra @@ -344,7 +344,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aws-lambda -- -ra @@ -366,7 +366,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-botocore -- -ra @@ -388,7 +388,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-boto3sqs -- -ra @@ -410,7 +410,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-django-0 -- -ra @@ -432,7 +432,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-django-1 -- -ra @@ -454,7 +454,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-django-2 -- -ra @@ -476,7 +476,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-dbapi -- -ra @@ -498,7 +498,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-boto -- -ra @@ -520,7 +520,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-click -- -ra @@ -542,7 +542,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-elasticsearch-0 -- -ra @@ -564,7 +564,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-elasticsearch-1 -- -ra @@ -586,7 +586,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-elasticsearch-2 -- -ra @@ -608,7 +608,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-falcon-0 -- -ra @@ -630,7 +630,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-falcon-1 -- -ra @@ -652,7 +652,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-falcon-2 -- -ra @@ -674,7 +674,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-falcon-3 -- -ra @@ -696,7 +696,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-fastapi -- -ra @@ -718,7 +718,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-flask-0 -- -ra @@ -740,7 +740,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-flask-1 -- -ra @@ -762,7 +762,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-flask-2 -- -ra @@ -784,7 +784,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-urllib -- -ra @@ -806,7 +806,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-urllib3-0 -- -ra @@ -828,7 +828,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-urllib3-1 -- -ra @@ -850,7 +850,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-requests -- -ra @@ -872,7 +872,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-starlette -- -ra @@ -894,7 +894,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-jinja2 -- -ra @@ -916,7 +916,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-logging -- -ra @@ -938,7 +938,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-exporter-richconsole -- -ra @@ -960,7 +960,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-exporter-prometheus-remote-write -- -ra @@ -982,7 +982,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-mysql-0 -- -ra @@ -1004,7 +1004,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-mysql-1 -- -ra @@ -1026,7 +1026,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-mysqlclient -- -ra @@ -1048,7 +1048,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-psycopg2 -- -ra @@ -1070,7 +1070,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-psycopg -- -ra @@ -1092,7 +1092,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymemcache-0 -- -ra @@ -1114,7 +1114,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymemcache-1 -- -ra @@ -1136,7 +1136,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymemcache-2 -- -ra @@ -1158,7 +1158,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymemcache-3 -- -ra @@ -1180,7 +1180,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymemcache-4 -- -ra @@ -1202,7 +1202,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymongo -- -ra @@ -1224,7 +1224,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymysql -- -ra @@ -1246,7 +1246,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pyramid -- -ra @@ -1268,7 +1268,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-asgi -- -ra @@ -1290,7 +1290,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-asyncpg -- -ra @@ -1312,7 +1312,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-sqlite3 -- -ra @@ -1334,7 +1334,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-wsgi -- -ra @@ -1356,7 +1356,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-grpc-0 -- -ra @@ -1378,7 +1378,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-grpc-1 -- -ra @@ -1400,7 +1400,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-sqlalchemy-1 -- -ra @@ -1422,7 +1422,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-sqlalchemy-2 -- -ra @@ -1444,7 +1444,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-redis -- -ra @@ -1466,7 +1466,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-remoulade -- -ra @@ -1488,7 +1488,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-celery -- -ra @@ -1510,7 +1510,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-system-metrics -- -ra @@ -1532,7 +1532,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-threading -- -ra @@ -1554,7 +1554,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-tornado -- -ra @@ -1576,7 +1576,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-tortoiseorm -- -ra @@ -1598,7 +1598,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-httpx-0 -- -ra @@ -1620,7 +1620,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-httpx-1 -- -ra @@ -1642,7 +1642,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-util-http -- -ra @@ -1664,7 +1664,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-propagator-aws-xray-0 -- -ra @@ -1686,7 +1686,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-propagator-aws-xray-1 -- -ra @@ -1708,7 +1708,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-propagator-ot-trace -- -ra @@ -1730,7 +1730,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-sio-pika-0 -- -ra @@ -1752,7 +1752,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-sio-pika-1 -- -ra @@ -1774,7 +1774,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aio-pika-0 -- -ra @@ -1796,7 +1796,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aio-pika-1 -- -ra @@ -1818,7 +1818,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aio-pika-2 -- -ra @@ -1840,7 +1840,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aio-pika-3 -- -ra @@ -1862,7 +1862,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aiokafka -- -ra @@ -1884,7 +1884,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-kafka-python -- -ra @@ -1906,7 +1906,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-kafka-pythonng -- -ra @@ -1928,7 +1928,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-confluent-kafka -- -ra @@ -1950,7 +1950,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-asyncio -- -ra @@ -1972,7 +1972,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-cassandra -- -ra @@ -1994,7 +1994,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-processor-baggage -- -ra diff --git a/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/core_contrib_test.yml.j2 b/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/core_contrib_test.yml.j2 index 5553caf8eb..f34b8e7941 100644 --- a/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/core_contrib_test.yml.j2 +++ b/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/core_contrib_test.yml.j2 @@ -37,7 +37,7 @@ jobs: architecture: "x64" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e {{ job_data.tox_env }} -- -ra diff --git a/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/lint.yml.j2 b/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/lint.yml.j2 index 225387e352..ef779bc5c9 100644 --- a/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/lint.yml.j2 +++ b/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/lint.yml.j2 @@ -30,7 +30,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e {{ job_data.tox_env }} diff --git a/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/misc.yml.j2 b/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/misc.yml.j2 index 9972507bb6..b6af56048f 100644 --- a/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/misc.yml.j2 +++ b/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/misc.yml.j2 @@ -57,7 +57,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e {{ job_data }} diff --git a/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/test.yml.j2 b/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/test.yml.j2 index e5168470d8..e5d15beb4d 100644 --- a/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/test.yml.j2 +++ b/.github/workflows/generate_workflows_lib/src/generate_workflows_lib/test.yml.j2 @@ -30,7 +30,7 @@ jobs: python-version: "{{ job_data.python_version }}" - name: Install tox - run: pip install tox + run: pip install tox-uv {%- if job_data.os == "windows-latest" %} - name: Configure git to support long filenames diff --git a/.github/workflows/lint_0.yml b/.github/workflows/lint_0.yml index e36a6a2ad2..34db823570 100644 --- a/.github/workflows/lint_0.yml +++ b/.github/workflows/lint_0.yml @@ -29,7 +29,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-openai-v2 @@ -47,7 +47,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-vertexai @@ -65,7 +65,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-resource-detector-container @@ -83,7 +83,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-resource-detector-azure @@ -101,7 +101,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-sdk-extension-aws @@ -119,7 +119,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-distro @@ -137,7 +137,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-opentelemetry-instrumentation @@ -155,7 +155,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-aiohttp-client @@ -173,7 +173,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-aiohttp-server @@ -191,7 +191,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-aiopg @@ -209,7 +209,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-aws-lambda @@ -227,7 +227,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-botocore @@ -245,7 +245,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-boto3sqs @@ -263,7 +263,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-django @@ -281,7 +281,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-dbapi @@ -299,7 +299,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-boto @@ -317,7 +317,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-click @@ -335,7 +335,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-elasticsearch @@ -353,7 +353,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-falcon @@ -371,7 +371,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-fastapi @@ -389,7 +389,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-flask @@ -407,7 +407,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-urllib @@ -425,7 +425,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-urllib3 @@ -443,7 +443,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-requests @@ -461,7 +461,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-starlette @@ -479,7 +479,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-jinja2 @@ -497,7 +497,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-logging @@ -515,7 +515,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-exporter-richconsole @@ -533,7 +533,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-exporter-prometheus-remote-write @@ -551,7 +551,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-mysql @@ -569,7 +569,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-mysqlclient @@ -587,7 +587,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-psycopg2 @@ -605,7 +605,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-psycopg @@ -623,7 +623,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-pymemcache @@ -641,7 +641,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-pymongo @@ -659,7 +659,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-pymysql @@ -677,7 +677,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-pyramid @@ -695,7 +695,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-asgi @@ -713,7 +713,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-asyncpg @@ -731,7 +731,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-sqlite3 @@ -749,7 +749,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-wsgi @@ -767,7 +767,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-grpc @@ -785,7 +785,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-sqlalchemy @@ -803,7 +803,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-redis @@ -821,7 +821,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-remoulade @@ -839,7 +839,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-celery @@ -857,7 +857,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-system-metrics @@ -875,7 +875,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-threading @@ -893,7 +893,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-tornado @@ -911,7 +911,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-tortoiseorm @@ -929,7 +929,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-httpx @@ -947,7 +947,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-util-http @@ -965,7 +965,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-propagator-aws-xray @@ -983,7 +983,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-propagator-ot-trace @@ -1001,7 +1001,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-sio-pika @@ -1019,7 +1019,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-aio-pika @@ -1037,7 +1037,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-aiokafka @@ -1055,7 +1055,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-kafka-python @@ -1073,7 +1073,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-confluent-kafka @@ -1091,7 +1091,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-asyncio @@ -1109,7 +1109,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-instrumentation-cassandra @@ -1127,7 +1127,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e lint-processor-baggage diff --git a/.github/workflows/misc_0.yml b/.github/workflows/misc_0.yml index 422669b86f..2e59715660 100644 --- a/.github/workflows/misc_0.yml +++ b/.github/workflows/misc_0.yml @@ -29,7 +29,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e spellcheck @@ -47,7 +47,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e docker-tests @@ -67,7 +67,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e docs @@ -85,7 +85,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e generate @@ -109,7 +109,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e generate-workflows @@ -130,7 +130,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e shellcheck @@ -148,7 +148,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e ruff @@ -166,7 +166,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e typecheck diff --git a/.github/workflows/test_0.yml b/.github/workflows/test_0.yml index e651777907..bbfb5a6865 100644 --- a/.github/workflows/test_0.yml +++ b/.github/workflows/test_0.yml @@ -29,7 +29,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-openai-v2-0 -- -ra @@ -47,7 +47,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-openai-v2-1 -- -ra @@ -65,7 +65,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-openai-v2-0 -- -ra @@ -83,7 +83,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-openai-v2-1 -- -ra @@ -101,7 +101,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-openai-v2-0 -- -ra @@ -119,7 +119,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-openai-v2-1 -- -ra @@ -137,7 +137,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-openai-v2-0 -- -ra @@ -155,7 +155,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-openai-v2-1 -- -ra @@ -173,7 +173,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-openai-v2-0 -- -ra @@ -191,7 +191,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-openai-v2-1 -- -ra @@ -209,7 +209,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-openai-v2-0 -- -ra @@ -227,7 +227,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-openai-v2-1 -- -ra @@ -245,7 +245,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-openai-v2-0 -- -ra @@ -263,7 +263,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-openai-v2-1 -- -ra @@ -281,7 +281,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-vertexai-0 -- -ra @@ -299,7 +299,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-vertexai-1 -- -ra @@ -317,7 +317,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-vertexai-0 -- -ra @@ -335,7 +335,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-vertexai-1 -- -ra @@ -353,7 +353,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-vertexai-0 -- -ra @@ -371,7 +371,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-vertexai-1 -- -ra @@ -389,7 +389,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-vertexai-0 -- -ra @@ -407,7 +407,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-vertexai-1 -- -ra @@ -425,7 +425,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-vertexai-0 -- -ra @@ -443,7 +443,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-vertexai-1 -- -ra @@ -461,7 +461,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-vertexai-0 -- -ra @@ -479,7 +479,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-vertexai-1 -- -ra @@ -497,7 +497,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-resource-detector-container -- -ra @@ -515,7 +515,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-resource-detector-container -- -ra @@ -533,7 +533,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-resource-detector-container -- -ra @@ -551,7 +551,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-resource-detector-container -- -ra @@ -569,7 +569,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-resource-detector-container -- -ra @@ -587,7 +587,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-resource-detector-container -- -ra @@ -605,7 +605,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-resource-detector-container -- -ra @@ -623,7 +623,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-resource-detector-azure-0 -- -ra @@ -641,7 +641,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-resource-detector-azure-1 -- -ra @@ -659,7 +659,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-resource-detector-azure-0 -- -ra @@ -677,7 +677,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-resource-detector-azure-1 -- -ra @@ -695,7 +695,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-resource-detector-azure-0 -- -ra @@ -713,7 +713,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-resource-detector-azure-1 -- -ra @@ -731,7 +731,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-resource-detector-azure-0 -- -ra @@ -749,7 +749,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-resource-detector-azure-1 -- -ra @@ -767,7 +767,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-resource-detector-azure-0 -- -ra @@ -785,7 +785,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-resource-detector-azure-1 -- -ra @@ -803,7 +803,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-resource-detector-azure-0 -- -ra @@ -821,7 +821,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-resource-detector-azure-1 -- -ra @@ -839,7 +839,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-resource-detector-azure-0 -- -ra @@ -857,7 +857,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-resource-detector-azure-1 -- -ra @@ -875,7 +875,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-sdk-extension-aws-0 -- -ra @@ -893,7 +893,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-sdk-extension-aws-1 -- -ra @@ -911,7 +911,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-sdk-extension-aws-0 -- -ra @@ -929,7 +929,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-sdk-extension-aws-1 -- -ra @@ -947,7 +947,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-sdk-extension-aws-0 -- -ra @@ -965,7 +965,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-sdk-extension-aws-1 -- -ra @@ -983,7 +983,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-sdk-extension-aws-0 -- -ra @@ -1001,7 +1001,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-sdk-extension-aws-1 -- -ra @@ -1019,7 +1019,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-sdk-extension-aws-0 -- -ra @@ -1037,7 +1037,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-sdk-extension-aws-1 -- -ra @@ -1055,7 +1055,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-sdk-extension-aws-0 -- -ra @@ -1073,7 +1073,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-sdk-extension-aws-1 -- -ra @@ -1091,7 +1091,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-sdk-extension-aws-0 -- -ra @@ -1109,7 +1109,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-sdk-extension-aws-1 -- -ra @@ -1127,7 +1127,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-distro -- -ra @@ -1145,7 +1145,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-distro -- -ra @@ -1163,7 +1163,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-distro -- -ra @@ -1181,7 +1181,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-distro -- -ra @@ -1199,7 +1199,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-distro -- -ra @@ -1217,7 +1217,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-distro -- -ra @@ -1235,7 +1235,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-distro -- -ra @@ -1253,7 +1253,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-opentelemetry-instrumentation -- -ra @@ -1271,7 +1271,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-opentelemetry-instrumentation -- -ra @@ -1289,7 +1289,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-opentelemetry-instrumentation -- -ra @@ -1307,7 +1307,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-opentelemetry-instrumentation -- -ra @@ -1325,7 +1325,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-opentelemetry-instrumentation -- -ra @@ -1343,7 +1343,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-opentelemetry-instrumentation -- -ra @@ -1361,7 +1361,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-opentelemetry-instrumentation -- -ra @@ -1379,7 +1379,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aiohttp-client -- -ra @@ -1397,7 +1397,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-aiohttp-client -- -ra @@ -1415,7 +1415,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-aiohttp-client -- -ra @@ -1433,7 +1433,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-aiohttp-client -- -ra @@ -1451,7 +1451,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-aiohttp-client -- -ra @@ -1469,7 +1469,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-aiohttp-client -- -ra @@ -1487,7 +1487,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-aiohttp-client -- -ra @@ -1505,7 +1505,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aiohttp-server -- -ra @@ -1523,7 +1523,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-aiohttp-server -- -ra @@ -1541,7 +1541,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-aiohttp-server -- -ra @@ -1559,7 +1559,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-aiohttp-server -- -ra @@ -1577,7 +1577,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-aiohttp-server -- -ra @@ -1595,7 +1595,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-aiohttp-server -- -ra @@ -1613,7 +1613,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-aiohttp-server -- -ra @@ -1631,7 +1631,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aiopg -- -ra @@ -1649,7 +1649,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-aiopg -- -ra @@ -1667,7 +1667,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-aiopg -- -ra @@ -1685,7 +1685,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-aiopg -- -ra @@ -1703,7 +1703,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-aiopg -- -ra @@ -1721,7 +1721,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-aiopg -- -ra @@ -1739,7 +1739,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aws-lambda -- -ra @@ -1757,7 +1757,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-aws-lambda -- -ra @@ -1775,7 +1775,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-aws-lambda -- -ra @@ -1793,7 +1793,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-aws-lambda -- -ra @@ -1811,7 +1811,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-aws-lambda -- -ra @@ -1829,7 +1829,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-aws-lambda -- -ra @@ -1847,7 +1847,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-aws-lambda -- -ra @@ -1865,7 +1865,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-botocore -- -ra @@ -1883,7 +1883,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-botocore -- -ra @@ -1901,7 +1901,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-botocore -- -ra @@ -1919,7 +1919,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-botocore -- -ra @@ -1937,7 +1937,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-botocore -- -ra @@ -1955,7 +1955,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-botocore -- -ra @@ -1973,7 +1973,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-boto3sqs -- -ra @@ -1991,7 +1991,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-boto3sqs -- -ra @@ -2009,7 +2009,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-boto3sqs -- -ra @@ -2027,7 +2027,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-boto3sqs -- -ra @@ -2045,7 +2045,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-boto3sqs -- -ra @@ -2063,7 +2063,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-boto3sqs -- -ra @@ -2081,7 +2081,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-boto3sqs -- -ra @@ -2099,7 +2099,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-django-0 -- -ra @@ -2117,7 +2117,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-django-1 -- -ra @@ -2135,7 +2135,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-django-2 -- -ra @@ -2153,7 +2153,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-django-0 -- -ra @@ -2171,7 +2171,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-django-1 -- -ra @@ -2189,7 +2189,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-django-2 -- -ra @@ -2207,7 +2207,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-django-1 -- -ra @@ -2225,7 +2225,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-django-3 -- -ra @@ -2243,7 +2243,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-django-1 -- -ra @@ -2261,7 +2261,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-django-3 -- -ra @@ -2279,7 +2279,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-django-1 -- -ra @@ -2297,7 +2297,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-django-3 -- -ra @@ -2315,7 +2315,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-django-3 -- -ra @@ -2333,7 +2333,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-django-0 -- -ra @@ -2351,7 +2351,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-django-1 -- -ra @@ -2369,7 +2369,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-dbapi -- -ra @@ -2387,7 +2387,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-dbapi -- -ra @@ -2405,7 +2405,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-dbapi -- -ra @@ -2423,7 +2423,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-dbapi -- -ra @@ -2441,7 +2441,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-dbapi -- -ra @@ -2459,7 +2459,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-dbapi -- -ra @@ -2477,7 +2477,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-dbapi -- -ra @@ -2495,7 +2495,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-boto -- -ra @@ -2513,7 +2513,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-boto -- -ra @@ -2531,7 +2531,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-boto -- -ra @@ -2549,7 +2549,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-boto -- -ra @@ -2567,7 +2567,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-click -- -ra @@ -2585,7 +2585,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-click -- -ra @@ -2603,7 +2603,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-click -- -ra @@ -2621,7 +2621,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-click -- -ra @@ -2639,7 +2639,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-click -- -ra @@ -2657,7 +2657,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-click -- -ra @@ -2675,7 +2675,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-click -- -ra @@ -2693,7 +2693,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-elasticsearch-0 -- -ra @@ -2711,7 +2711,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-elasticsearch-1 -- -ra @@ -2729,7 +2729,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-elasticsearch-2 -- -ra @@ -2747,7 +2747,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-elasticsearch-0 -- -ra @@ -2765,7 +2765,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-elasticsearch-1 -- -ra @@ -2783,7 +2783,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-elasticsearch-2 -- -ra @@ -2801,7 +2801,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-elasticsearch-0 -- -ra @@ -2819,7 +2819,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-elasticsearch-1 -- -ra @@ -2837,7 +2837,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-elasticsearch-2 -- -ra @@ -2855,7 +2855,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-elasticsearch-0 -- -ra @@ -2873,7 +2873,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-elasticsearch-1 -- -ra @@ -2891,7 +2891,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-elasticsearch-2 -- -ra @@ -2909,7 +2909,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-elasticsearch-0 -- -ra @@ -2927,7 +2927,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-elasticsearch-1 -- -ra @@ -2945,7 +2945,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-elasticsearch-2 -- -ra @@ -2963,7 +2963,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-elasticsearch-0 -- -ra @@ -2981,7 +2981,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-elasticsearch-1 -- -ra @@ -2999,7 +2999,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-elasticsearch-2 -- -ra @@ -3017,7 +3017,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-elasticsearch-0 -- -ra @@ -3035,7 +3035,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-elasticsearch-1 -- -ra @@ -3053,7 +3053,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-elasticsearch-2 -- -ra @@ -3071,7 +3071,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-falcon-0 -- -ra @@ -3089,7 +3089,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-falcon-1 -- -ra @@ -3107,7 +3107,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-falcon-2 -- -ra @@ -3125,7 +3125,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-falcon-3 -- -ra @@ -3143,7 +3143,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-falcon-0 -- -ra @@ -3161,7 +3161,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-falcon-1 -- -ra @@ -3179,7 +3179,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-falcon-2 -- -ra @@ -3197,7 +3197,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-falcon-3 -- -ra @@ -3215,7 +3215,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-falcon-1 -- -ra @@ -3233,7 +3233,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-falcon-2 -- -ra @@ -3251,7 +3251,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-falcon-3 -- -ra @@ -3269,7 +3269,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-falcon-4 -- -ra @@ -3287,7 +3287,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-falcon-1 -- -ra @@ -3305,7 +3305,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-falcon-2 -- -ra @@ -3323,7 +3323,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-falcon-3 -- -ra @@ -3341,7 +3341,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-falcon-4 -- -ra @@ -3359,7 +3359,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-falcon-1 -- -ra @@ -3377,7 +3377,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-falcon-2 -- -ra @@ -3395,7 +3395,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-falcon-3 -- -ra @@ -3413,7 +3413,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-falcon-4 -- -ra @@ -3431,7 +3431,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-falcon-4 -- -ra @@ -3449,7 +3449,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-falcon-0 -- -ra @@ -3467,7 +3467,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-falcon-1 -- -ra @@ -3485,7 +3485,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-falcon-2 -- -ra @@ -3503,7 +3503,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-falcon-3 -- -ra @@ -3521,7 +3521,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-falcon-4 -- -ra @@ -3539,7 +3539,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-fastapi -- -ra @@ -3557,7 +3557,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-fastapi -- -ra @@ -3575,7 +3575,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-fastapi -- -ra @@ -3593,7 +3593,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-fastapi -- -ra @@ -3611,7 +3611,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-fastapi -- -ra @@ -3629,7 +3629,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-fastapi -- -ra @@ -3647,7 +3647,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-fastapi -- -ra @@ -3665,7 +3665,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-flask-0 -- -ra @@ -3683,7 +3683,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-flask-1 -- -ra @@ -3701,7 +3701,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-flask-2 -- -ra @@ -3719,7 +3719,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-flask-0 -- -ra @@ -3737,7 +3737,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-flask-1 -- -ra @@ -3755,7 +3755,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-flask-2 -- -ra @@ -3773,7 +3773,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-flask-0 -- -ra @@ -3791,7 +3791,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-flask-1 -- -ra @@ -3809,7 +3809,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-flask-2 -- -ra @@ -3827,7 +3827,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-flask-0 -- -ra @@ -3845,7 +3845,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-flask-1 -- -ra @@ -3863,7 +3863,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-flask-2 -- -ra @@ -3881,7 +3881,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-flask-0 -- -ra @@ -3899,7 +3899,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-flask-1 -- -ra @@ -3917,7 +3917,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-flask-2 -- -ra @@ -3935,7 +3935,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-flask-0 -- -ra @@ -3953,7 +3953,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-flask-1 -- -ra @@ -3971,7 +3971,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-flask-2 -- -ra @@ -3989,7 +3989,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-flask-0 -- -ra @@ -4007,7 +4007,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-flask-1 -- -ra @@ -4025,7 +4025,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-urllib -- -ra @@ -4043,7 +4043,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-urllib -- -ra @@ -4061,7 +4061,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-urllib -- -ra @@ -4079,7 +4079,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-urllib -- -ra @@ -4097,7 +4097,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-urllib -- -ra @@ -4115,7 +4115,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-urllib -- -ra @@ -4133,7 +4133,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-urllib -- -ra @@ -4151,7 +4151,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-urllib3-0 -- -ra @@ -4169,7 +4169,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-urllib3-1 -- -ra @@ -4187,7 +4187,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-urllib3-0 -- -ra @@ -4205,7 +4205,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-urllib3-1 -- -ra @@ -4223,7 +4223,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-urllib3-0 -- -ra @@ -4241,7 +4241,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-urllib3-1 -- -ra @@ -4259,7 +4259,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-urllib3-0 -- -ra @@ -4277,7 +4277,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-urllib3-1 -- -ra @@ -4295,7 +4295,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-urllib3-0 -- -ra @@ -4313,7 +4313,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-urllib3-1 -- -ra @@ -4331,7 +4331,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-urllib3-0 -- -ra @@ -4349,7 +4349,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-urllib3-1 -- -ra @@ -4367,7 +4367,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-urllib3-0 -- -ra @@ -4385,7 +4385,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-urllib3-1 -- -ra @@ -4403,7 +4403,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-requests -- -ra @@ -4421,7 +4421,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-requests -- -ra @@ -4439,7 +4439,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-requests -- -ra @@ -4457,7 +4457,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-requests -- -ra @@ -4475,7 +4475,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-requests -- -ra @@ -4493,7 +4493,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-requests -- -ra @@ -4511,7 +4511,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-starlette -- -ra diff --git a/.github/workflows/test_1.yml b/.github/workflows/test_1.yml index b26bb48e33..7cd1b5ed61 100644 --- a/.github/workflows/test_1.yml +++ b/.github/workflows/test_1.yml @@ -29,7 +29,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-starlette -- -ra @@ -47,7 +47,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-starlette -- -ra @@ -65,7 +65,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-starlette -- -ra @@ -83,7 +83,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-starlette -- -ra @@ -101,7 +101,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-starlette -- -ra @@ -119,7 +119,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-starlette -- -ra @@ -137,7 +137,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-jinja2 -- -ra @@ -155,7 +155,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-jinja2 -- -ra @@ -173,7 +173,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-jinja2 -- -ra @@ -191,7 +191,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-jinja2 -- -ra @@ -209,7 +209,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-jinja2 -- -ra @@ -227,7 +227,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-jinja2 -- -ra @@ -245,7 +245,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-jinja2 -- -ra @@ -263,7 +263,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-logging -- -ra @@ -281,7 +281,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-logging -- -ra @@ -299,7 +299,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-logging -- -ra @@ -317,7 +317,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-logging -- -ra @@ -335,7 +335,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-logging -- -ra @@ -353,7 +353,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-logging -- -ra @@ -371,7 +371,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-logging -- -ra @@ -389,7 +389,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-exporter-richconsole -- -ra @@ -407,7 +407,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-exporter-richconsole -- -ra @@ -425,7 +425,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-exporter-richconsole -- -ra @@ -443,7 +443,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-exporter-richconsole -- -ra @@ -461,7 +461,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-exporter-richconsole -- -ra @@ -479,7 +479,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-exporter-richconsole -- -ra @@ -497,7 +497,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-exporter-richconsole -- -ra @@ -515,7 +515,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-exporter-prometheus-remote-write -- -ra @@ -533,7 +533,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-exporter-prometheus-remote-write -- -ra @@ -551,7 +551,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-exporter-prometheus-remote-write -- -ra @@ -569,7 +569,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-exporter-prometheus-remote-write -- -ra @@ -587,7 +587,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-exporter-prometheus-remote-write -- -ra @@ -605,7 +605,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-exporter-prometheus-remote-write -- -ra @@ -623,7 +623,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-exporter-prometheus-remote-write -- -ra @@ -641,7 +641,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-mysql-0 -- -ra @@ -659,7 +659,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-mysql-1 -- -ra @@ -677,7 +677,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-mysql-0 -- -ra @@ -695,7 +695,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-mysql-1 -- -ra @@ -713,7 +713,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-mysql-0 -- -ra @@ -731,7 +731,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-mysql-1 -- -ra @@ -749,7 +749,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-mysql-0 -- -ra @@ -767,7 +767,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-mysql-1 -- -ra @@ -785,7 +785,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-mysql-0 -- -ra @@ -803,7 +803,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-mysql-1 -- -ra @@ -821,7 +821,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-mysql-0 -- -ra @@ -839,7 +839,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-mysql-1 -- -ra @@ -857,7 +857,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-mysql-0 -- -ra @@ -875,7 +875,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-mysql-1 -- -ra @@ -893,7 +893,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-mysqlclient -- -ra @@ -911,7 +911,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-mysqlclient -- -ra @@ -929,7 +929,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-mysqlclient -- -ra @@ -947,7 +947,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-mysqlclient -- -ra @@ -965,7 +965,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-mysqlclient -- -ra @@ -983,7 +983,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-mysqlclient -- -ra @@ -1001,7 +1001,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-mysqlclient -- -ra @@ -1019,7 +1019,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-psycopg2 -- -ra @@ -1037,7 +1037,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-psycopg2 -- -ra @@ -1055,7 +1055,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-psycopg2 -- -ra @@ -1073,7 +1073,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-psycopg2 -- -ra @@ -1091,7 +1091,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-psycopg2 -- -ra @@ -1109,7 +1109,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-psycopg2 -- -ra @@ -1127,7 +1127,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-psycopg -- -ra @@ -1145,7 +1145,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-psycopg -- -ra @@ -1163,7 +1163,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-psycopg -- -ra @@ -1181,7 +1181,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-psycopg -- -ra @@ -1199,7 +1199,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-psycopg -- -ra @@ -1217,7 +1217,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-psycopg -- -ra @@ -1235,7 +1235,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-psycopg -- -ra @@ -1253,7 +1253,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymemcache-0 -- -ra @@ -1271,7 +1271,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymemcache-1 -- -ra @@ -1289,7 +1289,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymemcache-2 -- -ra @@ -1307,7 +1307,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymemcache-3 -- -ra @@ -1325,7 +1325,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymemcache-4 -- -ra @@ -1343,7 +1343,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-pymemcache-0 -- -ra @@ -1361,7 +1361,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-pymemcache-1 -- -ra @@ -1379,7 +1379,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-pymemcache-2 -- -ra @@ -1397,7 +1397,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-pymemcache-3 -- -ra @@ -1415,7 +1415,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-pymemcache-4 -- -ra @@ -1433,7 +1433,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-pymemcache-0 -- -ra @@ -1451,7 +1451,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-pymemcache-1 -- -ra @@ -1469,7 +1469,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-pymemcache-2 -- -ra @@ -1487,7 +1487,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-pymemcache-3 -- -ra @@ -1505,7 +1505,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-pymemcache-4 -- -ra @@ -1523,7 +1523,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-pymemcache-0 -- -ra @@ -1541,7 +1541,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-pymemcache-1 -- -ra @@ -1559,7 +1559,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-pymemcache-2 -- -ra @@ -1577,7 +1577,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-pymemcache-3 -- -ra @@ -1595,7 +1595,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-pymemcache-4 -- -ra @@ -1613,7 +1613,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-pymemcache-0 -- -ra @@ -1631,7 +1631,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-pymemcache-1 -- -ra @@ -1649,7 +1649,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-pymemcache-2 -- -ra @@ -1667,7 +1667,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-pymemcache-3 -- -ra @@ -1685,7 +1685,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-pymemcache-4 -- -ra @@ -1703,7 +1703,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-pymemcache-0 -- -ra @@ -1721,7 +1721,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-pymemcache-1 -- -ra @@ -1739,7 +1739,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-pymemcache-2 -- -ra @@ -1757,7 +1757,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-pymemcache-3 -- -ra @@ -1775,7 +1775,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-pymemcache-4 -- -ra @@ -1793,7 +1793,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-pymemcache-0 -- -ra @@ -1811,7 +1811,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-pymemcache-1 -- -ra @@ -1829,7 +1829,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-pymemcache-2 -- -ra @@ -1847,7 +1847,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-pymemcache-3 -- -ra @@ -1865,7 +1865,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-pymemcache-4 -- -ra @@ -1883,7 +1883,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymongo -- -ra @@ -1901,7 +1901,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-pymongo -- -ra @@ -1919,7 +1919,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-pymongo -- -ra @@ -1937,7 +1937,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-pymongo -- -ra @@ -1955,7 +1955,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-pymongo -- -ra @@ -1973,7 +1973,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-pymongo -- -ra @@ -1991,7 +1991,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-pymongo -- -ra @@ -2009,7 +2009,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pymysql -- -ra @@ -2027,7 +2027,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-pymysql -- -ra @@ -2045,7 +2045,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-pymysql -- -ra @@ -2063,7 +2063,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-pymysql -- -ra @@ -2081,7 +2081,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-pymysql -- -ra @@ -2099,7 +2099,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-pymysql -- -ra @@ -2117,7 +2117,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-pymysql -- -ra @@ -2135,7 +2135,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-pyramid -- -ra @@ -2153,7 +2153,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-pyramid -- -ra @@ -2171,7 +2171,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-pyramid -- -ra @@ -2189,7 +2189,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-pyramid -- -ra @@ -2207,7 +2207,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-pyramid -- -ra @@ -2225,7 +2225,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-pyramid -- -ra @@ -2243,7 +2243,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-asgi -- -ra @@ -2261,7 +2261,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-asgi -- -ra @@ -2279,7 +2279,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-asgi -- -ra @@ -2297,7 +2297,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-asgi -- -ra @@ -2315,7 +2315,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-asgi -- -ra @@ -2333,7 +2333,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-asgi -- -ra @@ -2351,7 +2351,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-asgi -- -ra @@ -2369,7 +2369,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-asyncpg -- -ra @@ -2387,7 +2387,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-asyncpg -- -ra @@ -2405,7 +2405,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-asyncpg -- -ra @@ -2423,7 +2423,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-asyncpg -- -ra @@ -2441,7 +2441,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-asyncpg -- -ra @@ -2459,7 +2459,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-asyncpg -- -ra @@ -2477,7 +2477,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-sqlite3 -- -ra @@ -2495,7 +2495,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-sqlite3 -- -ra @@ -2513,7 +2513,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-sqlite3 -- -ra @@ -2531,7 +2531,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-sqlite3 -- -ra @@ -2549,7 +2549,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-sqlite3 -- -ra @@ -2567,7 +2567,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-sqlite3 -- -ra @@ -2585,7 +2585,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-sqlite3 -- -ra @@ -2603,7 +2603,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-wsgi -- -ra @@ -2621,7 +2621,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-wsgi -- -ra @@ -2639,7 +2639,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-wsgi -- -ra @@ -2657,7 +2657,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-wsgi -- -ra @@ -2675,7 +2675,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-wsgi -- -ra @@ -2693,7 +2693,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-wsgi -- -ra @@ -2711,7 +2711,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-wsgi -- -ra @@ -2729,7 +2729,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-grpc-0 -- -ra @@ -2747,7 +2747,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-grpc-1 -- -ra @@ -2765,7 +2765,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-grpc-0 -- -ra @@ -2783,7 +2783,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-grpc-1 -- -ra @@ -2801,7 +2801,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-grpc-0 -- -ra @@ -2819,7 +2819,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-grpc-1 -- -ra @@ -2837,7 +2837,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-grpc-0 -- -ra @@ -2855,7 +2855,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-grpc-1 -- -ra @@ -2873,7 +2873,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-grpc-0 -- -ra @@ -2891,7 +2891,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-grpc-1 -- -ra @@ -2909,7 +2909,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-grpc-1 -- -ra @@ -2927,7 +2927,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-sqlalchemy-1 -- -ra @@ -2945,7 +2945,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-sqlalchemy-2 -- -ra @@ -2963,7 +2963,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-sqlalchemy-1 -- -ra @@ -2981,7 +2981,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-sqlalchemy-2 -- -ra @@ -2999,7 +2999,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-sqlalchemy-1 -- -ra @@ -3017,7 +3017,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-sqlalchemy-2 -- -ra @@ -3035,7 +3035,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-sqlalchemy-1 -- -ra @@ -3053,7 +3053,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-sqlalchemy-2 -- -ra @@ -3071,7 +3071,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-sqlalchemy-1 -- -ra @@ -3089,7 +3089,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-sqlalchemy-2 -- -ra @@ -3107,7 +3107,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-sqlalchemy-1 -- -ra @@ -3125,7 +3125,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-sqlalchemy-2 -- -ra @@ -3143,7 +3143,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-sqlalchemy-0 -- -ra @@ -3161,7 +3161,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-sqlalchemy-1 -- -ra @@ -3179,7 +3179,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-sqlalchemy-2 -- -ra @@ -3197,7 +3197,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-redis -- -ra @@ -3215,7 +3215,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-redis -- -ra @@ -3233,7 +3233,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-redis -- -ra @@ -3251,7 +3251,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-redis -- -ra @@ -3269,7 +3269,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-redis -- -ra @@ -3287,7 +3287,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-redis -- -ra @@ -3305,7 +3305,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-redis -- -ra @@ -3323,7 +3323,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-remoulade -- -ra @@ -3341,7 +3341,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-remoulade -- -ra @@ -3359,7 +3359,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-remoulade -- -ra @@ -3377,7 +3377,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-remoulade -- -ra @@ -3395,7 +3395,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-remoulade -- -ra @@ -3413,7 +3413,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-remoulade -- -ra @@ -3431,7 +3431,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-celery -- -ra @@ -3449,7 +3449,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-celery -- -ra @@ -3467,7 +3467,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-celery -- -ra @@ -3485,7 +3485,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-celery -- -ra @@ -3503,7 +3503,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-celery -- -ra @@ -3521,7 +3521,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-celery -- -ra @@ -3539,7 +3539,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-celery -- -ra @@ -3557,7 +3557,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-system-metrics -- -ra @@ -3575,7 +3575,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-system-metrics -- -ra @@ -3593,7 +3593,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-system-metrics -- -ra @@ -3611,7 +3611,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-system-metrics -- -ra @@ -3629,7 +3629,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-system-metrics -- -ra @@ -3647,7 +3647,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-system-metrics -- -ra @@ -3665,7 +3665,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-system-metrics -- -ra @@ -3683,7 +3683,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-threading -- -ra @@ -3701,7 +3701,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-threading -- -ra @@ -3719,7 +3719,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-threading -- -ra @@ -3737,7 +3737,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-threading -- -ra @@ -3755,7 +3755,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-threading -- -ra @@ -3773,7 +3773,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-threading -- -ra @@ -3791,7 +3791,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-threading -- -ra @@ -3809,7 +3809,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-tornado -- -ra @@ -3827,7 +3827,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-tornado -- -ra @@ -3845,7 +3845,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-tornado -- -ra @@ -3863,7 +3863,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-tornado -- -ra @@ -3881,7 +3881,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-tornado -- -ra @@ -3899,7 +3899,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-tornado -- -ra @@ -3917,7 +3917,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-tornado -- -ra @@ -3935,7 +3935,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-tortoiseorm -- -ra @@ -3953,7 +3953,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-tortoiseorm -- -ra @@ -3971,7 +3971,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-tortoiseorm -- -ra @@ -3989,7 +3989,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-tortoiseorm -- -ra @@ -4007,7 +4007,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-tortoiseorm -- -ra @@ -4025,7 +4025,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-tortoiseorm -- -ra @@ -4043,7 +4043,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-tortoiseorm -- -ra @@ -4061,7 +4061,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-httpx-0 -- -ra @@ -4079,7 +4079,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-httpx-1 -- -ra @@ -4097,7 +4097,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-httpx-0 -- -ra @@ -4115,7 +4115,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-httpx-1 -- -ra @@ -4133,7 +4133,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-httpx-0 -- -ra @@ -4151,7 +4151,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-httpx-1 -- -ra @@ -4169,7 +4169,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-httpx-0 -- -ra @@ -4187,7 +4187,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-httpx-1 -- -ra @@ -4205,7 +4205,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-httpx-0 -- -ra @@ -4223,7 +4223,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-httpx-1 -- -ra @@ -4241,7 +4241,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-httpx-1 -- -ra @@ -4259,7 +4259,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-httpx-0 -- -ra @@ -4277,7 +4277,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-httpx-1 -- -ra @@ -4295,7 +4295,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-util-http -- -ra @@ -4313,7 +4313,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-util-http -- -ra @@ -4331,7 +4331,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-util-http -- -ra @@ -4349,7 +4349,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-util-http -- -ra @@ -4367,7 +4367,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-util-http -- -ra @@ -4385,7 +4385,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-util-http -- -ra @@ -4403,7 +4403,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-util-http -- -ra @@ -4421,7 +4421,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-propagator-aws-xray-0 -- -ra @@ -4439,7 +4439,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-propagator-aws-xray-1 -- -ra @@ -4457,7 +4457,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-propagator-aws-xray-0 -- -ra @@ -4475,7 +4475,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-propagator-aws-xray-1 -- -ra @@ -4493,7 +4493,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-propagator-aws-xray-0 -- -ra @@ -4511,7 +4511,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-propagator-aws-xray-1 -- -ra diff --git a/.github/workflows/test_2.yml b/.github/workflows/test_2.yml index ceac5ac9ed..fd1dcb00e0 100644 --- a/.github/workflows/test_2.yml +++ b/.github/workflows/test_2.yml @@ -29,7 +29,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-propagator-aws-xray-0 -- -ra @@ -47,7 +47,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-propagator-aws-xray-1 -- -ra @@ -65,7 +65,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-propagator-aws-xray-0 -- -ra @@ -83,7 +83,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-propagator-aws-xray-1 -- -ra @@ -101,7 +101,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-propagator-aws-xray-0 -- -ra @@ -119,7 +119,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-propagator-aws-xray-1 -- -ra @@ -137,7 +137,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-propagator-aws-xray-0 -- -ra @@ -155,7 +155,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-propagator-aws-xray-1 -- -ra @@ -173,7 +173,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-propagator-ot-trace -- -ra @@ -191,7 +191,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-propagator-ot-trace -- -ra @@ -209,7 +209,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-propagator-ot-trace -- -ra @@ -227,7 +227,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-propagator-ot-trace -- -ra @@ -245,7 +245,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-propagator-ot-trace -- -ra @@ -263,7 +263,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-propagator-ot-trace -- -ra @@ -281,7 +281,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-propagator-ot-trace -- -ra @@ -299,7 +299,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-sio-pika-0 -- -ra @@ -317,7 +317,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-sio-pika-1 -- -ra @@ -335,7 +335,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-sio-pika-0 -- -ra @@ -353,7 +353,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-sio-pika-1 -- -ra @@ -371,7 +371,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-sio-pika-0 -- -ra @@ -389,7 +389,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-sio-pika-1 -- -ra @@ -407,7 +407,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-sio-pika-0 -- -ra @@ -425,7 +425,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-sio-pika-1 -- -ra @@ -443,7 +443,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-sio-pika-0 -- -ra @@ -461,7 +461,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-sio-pika-1 -- -ra @@ -479,7 +479,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-sio-pika-0 -- -ra @@ -497,7 +497,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-sio-pika-1 -- -ra @@ -515,7 +515,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-sio-pika-0 -- -ra @@ -533,7 +533,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-sio-pika-1 -- -ra @@ -551,7 +551,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aio-pika-0 -- -ra @@ -569,7 +569,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aio-pika-1 -- -ra @@ -587,7 +587,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aio-pika-2 -- -ra @@ -605,7 +605,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aio-pika-3 -- -ra @@ -623,7 +623,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-aio-pika-0 -- -ra @@ -641,7 +641,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-aio-pika-1 -- -ra @@ -659,7 +659,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-aio-pika-2 -- -ra @@ -677,7 +677,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-aio-pika-3 -- -ra @@ -695,7 +695,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-aio-pika-0 -- -ra @@ -713,7 +713,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-aio-pika-1 -- -ra @@ -731,7 +731,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-aio-pika-2 -- -ra @@ -749,7 +749,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-aio-pika-3 -- -ra @@ -767,7 +767,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-aio-pika-0 -- -ra @@ -785,7 +785,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-aio-pika-1 -- -ra @@ -803,7 +803,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-aio-pika-2 -- -ra @@ -821,7 +821,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-aio-pika-3 -- -ra @@ -839,7 +839,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-aio-pika-0 -- -ra @@ -857,7 +857,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-aio-pika-1 -- -ra @@ -875,7 +875,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-aio-pika-2 -- -ra @@ -893,7 +893,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-aio-pika-3 -- -ra @@ -911,7 +911,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-aio-pika-0 -- -ra @@ -929,7 +929,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-aio-pika-1 -- -ra @@ -947,7 +947,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-aio-pika-2 -- -ra @@ -965,7 +965,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-aio-pika-3 -- -ra @@ -983,7 +983,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-aio-pika-0 -- -ra @@ -1001,7 +1001,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-aio-pika-1 -- -ra @@ -1019,7 +1019,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-aio-pika-2 -- -ra @@ -1037,7 +1037,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-aio-pika-3 -- -ra @@ -1055,7 +1055,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-aiokafka -- -ra @@ -1073,7 +1073,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-aiokafka -- -ra @@ -1091,7 +1091,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-aiokafka -- -ra @@ -1109,7 +1109,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-aiokafka -- -ra @@ -1127,7 +1127,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-aiokafka -- -ra @@ -1145,7 +1145,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-aiokafka -- -ra @@ -1163,7 +1163,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-aiokafka -- -ra @@ -1181,7 +1181,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-kafka-python -- -ra @@ -1199,7 +1199,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-kafka-python -- -ra @@ -1217,7 +1217,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-kafka-python -- -ra @@ -1235,7 +1235,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-kafka-python -- -ra @@ -1253,7 +1253,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-kafka-pythonng -- -ra @@ -1271,7 +1271,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-kafka-pythonng -- -ra @@ -1289,7 +1289,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-kafka-pythonng -- -ra @@ -1307,7 +1307,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-kafka-pythonng -- -ra @@ -1325,7 +1325,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-kafka-pythonng -- -ra @@ -1343,7 +1343,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-kafka-pythonng -- -ra @@ -1361,7 +1361,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-kafka-python -- -ra @@ -1379,7 +1379,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-kafka-pythonng -- -ra @@ -1397,7 +1397,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-confluent-kafka -- -ra @@ -1415,7 +1415,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-confluent-kafka -- -ra @@ -1433,7 +1433,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-confluent-kafka -- -ra @@ -1451,7 +1451,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-confluent-kafka -- -ra @@ -1469,7 +1469,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-confluent-kafka -- -ra @@ -1487,7 +1487,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-confluent-kafka -- -ra @@ -1505,7 +1505,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-asyncio -- -ra @@ -1523,7 +1523,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-asyncio -- -ra @@ -1541,7 +1541,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-asyncio -- -ra @@ -1559,7 +1559,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-asyncio -- -ra @@ -1577,7 +1577,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-asyncio -- -ra @@ -1595,7 +1595,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-asyncio -- -ra @@ -1613,7 +1613,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-instrumentation-cassandra -- -ra @@ -1631,7 +1631,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-instrumentation-cassandra -- -ra @@ -1649,7 +1649,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-instrumentation-cassandra -- -ra @@ -1667,7 +1667,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-instrumentation-cassandra -- -ra @@ -1685,7 +1685,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-instrumentation-cassandra -- -ra @@ -1703,7 +1703,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-instrumentation-cassandra -- -ra @@ -1721,7 +1721,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-instrumentation-cassandra -- -ra @@ -1739,7 +1739,7 @@ jobs: python-version: "3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py38-test-processor-baggage -- -ra @@ -1757,7 +1757,7 @@ jobs: python-version: "3.9" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py39-test-processor-baggage -- -ra @@ -1775,7 +1775,7 @@ jobs: python-version: "3.10" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py310-test-processor-baggage -- -ra @@ -1793,7 +1793,7 @@ jobs: python-version: "3.11" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py311-test-processor-baggage -- -ra @@ -1811,7 +1811,7 @@ jobs: python-version: "3.12" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py312-test-processor-baggage -- -ra @@ -1829,7 +1829,7 @@ jobs: python-version: "3.13" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e py313-test-processor-baggage -- -ra @@ -1847,7 +1847,7 @@ jobs: python-version: "pypy-3.8" - name: Install tox - run: pip install tox + run: pip install tox-uv - name: Run tests run: tox -e pypy3-test-processor-baggage -- -ra diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8119304875..448950bccc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,6 +59,12 @@ To install `tox`, run: pip install tox ``` +You can also run tox with `uv` support. By default [tox.ini](./tox.ini) will automatically create a provisioned tox environment with `tox-uv`, but you can install it at host level: + +```sh +pip install tox-uv +``` + You can run `tox` with the following arguments: * `tox` to run all existing tox commands, including unit tests for all packages @@ -89,7 +95,7 @@ for more detail on available tox commands. ### Troubleshooting -Some packages may require additional system-wide dependencies to be installed. For example, you may need to install `libpq-dev` to run the postgresql client libraries instrumentation tests or `libsnappy-dev` to run the prometheus exporter tests. If you encounter a build error, please check the installation instructions for the package you are trying to run tests for. +Some packages may require additional system-wide dependencies to be installed. For example, you may need to install `libpq-dev` to run the postgresql client libraries instrumentation tests or `libsnappy-dev` to run the prometheus exporter tests. If you encounter a build error, please check the installation instructions for the package you are trying to run tests for. For `docs` building, you may need to install `mysql-client` and other required dependencies as necessary. Ensure the Python version used in your local setup matches the version used in the [CI](./.github/workflows/) to maintain compatibility when building the documentation. @@ -139,7 +145,7 @@ git remote add fork https://github.com/YOUR_GITHUB_USERNAME/opentelemetry-python make sure you have all supported versions of Python installed, install `tox` only for the first time: ```sh -pip install tox +pip install tox tox-uv ``` Run tests in the root of the repository (this will run all tox environments and may take some time): diff --git a/tox.ini b/tox.ini index 13dd9fafb6..d198c0a836 100644 --- a/tox.ini +++ b/tox.ini @@ -1,4 +1,6 @@ [tox] +requires = + tox-uv>=1 isolated_build = True skipsdist = True skip_missing_interpreters = True From 86a7f6bab3d394f5e9ea5c458b657373583fde21 Mon Sep 17 00:00:00 2001 From: OpenTelemetry Bot <107717825+opentelemetrybot@users.noreply.github.com> Date: Fri, 17 Jan 2025 22:12:12 -0600 Subject: [PATCH 12/12] Update opentelemetry-instrumentation-openai-v2 version to v2.2b0 (#3194) --- .../opentelemetry-instrumentation-openai-v2/CHANGELOG.md | 2 ++ .../src/opentelemetry/instrumentation/openai_v2/version.py | 2 +- .../src/opentelemetry/instrumentation/bootstrap_gen.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md index ed27904e63..0d5ed666ed 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## Version 2.1b0 (2025-01-17) + - Coerce openai response_format to semconv format ([#3073](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3073)) - Add example to `opentelemetry-instrumentation-openai-v2` diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/version.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/version.py index 5b77207d9d..a6098e22cc 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/version.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "2.1b0.dev" +__version__ = "2.2b0.dev" diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py index a55f0ccd8e..071abe2ad7 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py @@ -18,7 +18,7 @@ libraries = [ { "library": "openai >= 1.26.0", - "instrumentation": "opentelemetry-instrumentation-openai-v2==2.1b0.dev", + "instrumentation": "opentelemetry-instrumentation-openai-v2==2.2b0.dev", }, { "library": "google-cloud-aiplatform >= 1.64",