diff --git a/CHANGELOG.md b/CHANGELOG.md index 339cdb62460..95a73fb7031 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#2997](https://github.com/open-telemetry/opentelemetry-python/pull/2997)) - Fix a bug with exporter retries for with newer versions of the backoff library ([#2980](https://github.com/open-telemetry/opentelemetry-python/pull/2980)) +- [exporter-otlp-proto-grpc] add user agent string + ([#3009](https://github.com/open-telemetry/opentelemetry-python/pull/3009)) ## Version 1.13.0/0.34b0 (2022-09-26) diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/__init__.py index 0a33b6325ad..c00882db726 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/__init__.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/__init__.py @@ -69,3 +69,7 @@ API --- """ +from .version import __version__ + +otel_string = "OTel OTLP Exporter Python/" + __version__ +_OTLP_GRPC_HEADERS = [("user-agent", otel_string)] diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py index aef66b79dec..f9c57d8e67b 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py @@ -54,6 +54,9 @@ from opentelemetry.sdk.resources import Resource as SDKResource from opentelemetry.util.re import parse_headers from opentelemetry.sdk.metrics.export import MetricsData +from opentelemetry.exporter.otlp.proto.grpc import ( + _OTLP_GRPC_HEADERS, +) logger = getLogger(__name__) SDKDataT = TypeVar("SDKDataT") @@ -251,6 +254,10 @@ def __init__( self._headers = tuple(temp_headers.items()) elif isinstance(self._headers, dict): self._headers = tuple(self._headers.items()) + if self._headers is None: + self._headers = tuple(_OTLP_GRPC_HEADERS) + else: + self._headers = self._headers + tuple(_OTLP_GRPC_HEADERS) self._timeout = timeout or int( environ.get(OTEL_EXPORTER_OTLP_TIMEOUT, 10) diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py index 07616090837..ed4eb5f0322 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py @@ -24,6 +24,8 @@ from opentelemetry.exporter.otlp.proto.grpc._log_exporter import ( OTLPLogExporter, ) +from opentelemetry.exporter.otlp.proto.grpc.version import __version__ + from opentelemetry.exporter.otlp.proto.grpc.exporter import _translate_value from opentelemetry.proto.collector.logs.v1.logs_service_pb2 import ( ExportLogsServiceRequest, @@ -48,6 +50,9 @@ from opentelemetry.sdk._logs.severity import ( SeverityNumber as SDKSeverityNumber, ) +from opentelemetry.sdk.environment_variables import ( + OTEL_EXPORTER_OTLP_METRICS_HEADERS, +) from opentelemetry.sdk.resources import Resource as SDKResource from opentelemetry.sdk.util.instrumentation import InstrumentationScope from opentelemetry.trace import TraceFlags @@ -173,11 +178,8 @@ def test_exporting(self): "opentelemetry.exporter.otlp.proto.grpc._log_exporter.OTLPLogExporter._stub" ) # pylint: disable=unused-argument - def test_no_credentials_error( - self, mock_ssl_channel, mock_secure, mock_stub - ): - OTLPLogExporter(insecure=False) - self.assertTrue(mock_ssl_channel.called) + def test_header_agent(self): + self.exporter # pylint: disable=no-self-use @patch("opentelemetry.exporter.otlp.proto.grpc.exporter.insecure_channel") @@ -251,6 +253,19 @@ def test_otlp_exporter_endpoint(self, mock_secure, mock_insecure): ) mock_method.reset_mock() + @patch.dict( + "os.environ", + {OTEL_EXPORTER_OTLP_TRACES_HEADERS: " key1=value1,KEY2 = VALUE=2 "}, + ) + + @patch( + "opentelemetry.exporter.otlp.proto.grpc.exporter" + ) + def test_otlp_headers_from_env(self): + self.assertEqual( + self.exporter._headers, (("key1", "value1"),("key2", "VALUE=2"), ("user-agent", "OTel OTLP Exporter Python/" + __version__)) + ) + @patch("opentelemetry.exporter.otlp.proto.grpc.exporter._expo") @patch("opentelemetry.exporter.otlp.proto.grpc.exporter.sleep") def test_unavailable(self, mock_sleep, mock_expo): diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_metrics_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_metrics_exporter.py index 4f0349257d8..bca8725c7ea 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_metrics_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_metrics_exporter.py @@ -78,6 +78,9 @@ ) from opentelemetry.test.metrictestutil import _generate_gauge, _generate_sum +from opentelemetry.exporter.otlp.proto.grpc.version import __version__ + + THIS_DIR = dirname(__file__) @@ -413,14 +416,14 @@ def test_otlp_headers_from_env(self, mock_ssl_channel, mock_secure): exporter = OTLPMetricExporter() # pylint: disable=protected-access self.assertEqual( - exporter._headers, (("key1", "value1"), ("key2", "VALUE=2")) + exporter._headers, (("key1", "value1"), ("key2", "VALUE=2"),("user-agent", "OTel OTLP Exporter Python/" + __version__)) ) exporter = OTLPMetricExporter( headers=(("key3", "value3"), ("key4", "value4")) ) # pylint: disable=protected-access self.assertEqual( - exporter._headers, (("key3", "value3"), ("key4", "value4")) + exporter._headers, (("key3", "value3"), ("key4", "value4"),("user-agent", "OTel OTLP Exporter Python/" + __version__)) ) @patch.dict( diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_trace_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_trace_exporter.py index cfb286edee0..9272fe11d40 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_trace_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_trace_exporter.py @@ -69,6 +69,8 @@ from opentelemetry.test.spantestutil import ( get_span_with_dropped_attributes_events_links, ) +from opentelemetry.exporter.otlp.proto.grpc.version import __version__ + THIS_DIR = os.path.dirname(__file__) @@ -275,21 +277,21 @@ def test_otlp_headers_from_env(self, mock_ssl_channel, mock_secure): exporter = OTLPSpanExporter() # pylint: disable=protected-access self.assertEqual( - exporter._headers, (("key1", "value1"), ("key2", "VALUE=2")) + exporter._headers, (("key1", "value1"),("key2", "VALUE=2"), ("user-agent", "OTel OTLP Exporter Python/" + __version__)) ) exporter = OTLPSpanExporter( headers=(("key3", "value3"), ("key4", "value4")) ) # pylint: disable=protected-access self.assertEqual( - exporter._headers, (("key3", "value3"), ("key4", "value4")) + exporter._headers, (("key3", "value3"), ("key4", "value4"), ("user-agent", "OTel OTLP Exporter Python/" + __version__)) ) exporter = OTLPSpanExporter( headers={"key5": "value5", "key6": "value6"} ) # pylint: disable=protected-access self.assertEqual( - exporter._headers, (("key5", "value5"), ("key6", "value6")) + exporter._headers, (("key5", "value5"), ("key6", "value6"), ("user-agent", "OTel OTLP Exporter Python/" + __version__)) ) @patch.dict( @@ -434,7 +436,8 @@ def test_otlp_exporter_otlp_compression_precendence( def test_otlp_headers(self, mock_ssl_channel, mock_secure): exporter = OTLPSpanExporter() # pylint: disable=protected-access - self.assertIsNone(exporter._headers, None) + #This ensures that there is no other header than standard user-agent. + self.assertEqual(exporter._headers, (("user-agent", "OTel OTLP Exporter Python/" + __version__),)) @patch("opentelemetry.exporter.otlp.proto.grpc.exporter.backoff") @patch("opentelemetry.exporter.otlp.proto.grpc.exporter.sleep")