From 59ac40fe1c49a89cdb0319e2f2af044c234f0e96 Mon Sep 17 00:00:00 2001
From: Alex Boten <aboten@lightstep.com>
Date: Wed, 5 Oct 2022 09:52:46 -0700
Subject: [PATCH 1/3] `exporter-otlp-proto-http`: add user agent string

Adding user agent string to OTLP HTTP exporter. As part of the change, I refactored the content-type header as well.

Part of #2958
---
 .../src/opentelemetry/exporter/otlp/proto/http/__init__.py | 7 +++++++
 .../exporter/otlp/proto/http/_log_exporter/__init__.py     | 6 ++----
 .../otlp/proto/http/_log_exporter/encoder/__init__.py      | 2 --
 .../exporter/otlp/proto/http/trace_exporter/__init__.py    | 6 ++----
 .../otlp/proto/http/trace_exporter/encoder/__init__.py     | 2 --
 .../tests/test_proto_log_exporter.py                       | 7 ++-----
 .../tests/test_proto_span_exporter.py                      | 2 ++
 .../tests/test_protobuf_encoder.py                         | 5 -----
 8 files changed, 15 insertions(+), 22 deletions(-)

diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/__init__.py
index 08b07258351..efdb1d1d1ff 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/__init__.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/__init__.py
@@ -71,6 +71,13 @@
 """
 import enum
 
+from .version import __version__
+
+
+_OTLP_HTTP_HEADERS = {
+    "Content-Type": "application/x-protobuf",
+    "User-Agent": "OTel OTLP Exporter Python/" + __version__
+}
 
 class Compression(enum.Enum):
     NoCompression = "none"
diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py
index 041f1ab3c07..217dba384cf 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py
@@ -35,7 +35,7 @@
     LogExportResult,
     LogData,
 )
-from opentelemetry.exporter.otlp.proto.http import Compression
+from opentelemetry.exporter.otlp.proto.http import _OTLP_HTTP_HEADERS, Compression
 from opentelemetry.exporter.otlp.proto.http._log_exporter.encoder import (
     _ProtobufEncoder,
 )
@@ -78,9 +78,7 @@ def __init__(
         self._compression = compression or _compression_from_env()
         self._session = session or requests.Session()
         self._session.headers.update(self._headers)
-        self._session.headers.update(
-            {"Content-Type": _ProtobufEncoder._CONTENT_TYPE}
-        )
+        self._session.headers.update(_OTLP_HTTP_HEADERS)
         if self._compression is not Compression.NoCompression:
             self._session.headers.update(
                 {"Content-Encoding": self._compression.value}
diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/encoder/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/encoder/__init__.py
index bf8784aacf8..c8f2dd84564 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/encoder/__init__.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/encoder/__init__.py
@@ -36,8 +36,6 @@
 
 
 class _ProtobufEncoder:
-    _CONTENT_TYPE = "application/x-protobuf"
-
     @classmethod
     def serialize(cls, batch: Sequence[LogData]) -> str:
         return cls.encode(batch).SerializeToString()
diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py
index 3c95a325b8d..c1a33d5eba7 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py
@@ -36,7 +36,7 @@
     OTEL_EXPORTER_OTLP_TIMEOUT,
 )
 from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
-from opentelemetry.exporter.otlp.proto.http import Compression
+from opentelemetry.exporter.otlp.proto.http import _OTLP_HTTP_HEADERS, Compression
 from opentelemetry.exporter.otlp.proto.http.trace_exporter.encoder import (
     _ProtobufEncoder,
 )
@@ -89,9 +89,7 @@ def __init__(
         self._compression = compression or _compression_from_env()
         self._session = session or requests.Session()
         self._session.headers.update(self._headers)
-        self._session.headers.update(
-            {"Content-Type": _ProtobufEncoder._CONTENT_TYPE}
-        )
+        self._session.headers.update(_OTLP_HTTP_HEADERS)
         if self._compression is not Compression.NoCompression:
             self._session.headers.update(
                 {"Content-Encoding": self._compression.value}
diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/encoder/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/encoder/__init__.py
index fc0d9608ef2..c1c9fe88643 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/encoder/__init__.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/encoder/__init__.py
@@ -60,8 +60,6 @@
 
 
 class _ProtobufEncoder:
-    _CONTENT_TYPE = "application/x-protobuf"
-
     @classmethod
     def serialize(cls, sdk_spans: Sequence[SDKSpan]) -> str:
         return cls.encode(sdk_spans).SerializeToString()
diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py
index d5e34b7463d..12e9ed2fcfb 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py
@@ -84,6 +84,8 @@ def test_constructor_default(self):
         self.assertIs(exporter._compression, DEFAULT_COMPRESSION)
         self.assertEqual(exporter._headers, {})
         self.assertIsInstance(exporter._session, requests.Session)
+        self.assertIn("User-Agent", exporter._session.headers)
+        self.assertEqual(exporter._session.headers.get("Content-Type"), "application/x-protobuf")
 
     @patch.dict(
         "os.environ",
@@ -154,11 +156,6 @@ def test_serialize(self):
             expected_encoding.SerializeToString(),
         )
 
-    def test_content_type(self):
-        self.assertEqual(
-            _ProtobufEncoder._CONTENT_TYPE, "application/x-protobuf"
-        )
-
     @staticmethod
     def _get_sdk_log_data() -> List[LogData]:
         log1 = LogData(
diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py
index 4eb0db6160c..bcbb06dec30 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py
@@ -58,6 +58,8 @@ def test_constructor_default(self):
         self.assertIs(exporter._compression, DEFAULT_COMPRESSION)
         self.assertEqual(exporter._headers, {})
         self.assertIsInstance(exporter._session, requests.Session)
+        self.assertIn("User-Agent", exporter._session.headers)
+        self.assertEqual(exporter._session.headers.get("Content-Type"), "application/x-protobuf")
 
     @patch.dict(
         "os.environ",
diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_protobuf_encoder.py b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_protobuf_encoder.py
index b3718623c18..7145ddbfa97 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_protobuf_encoder.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_protobuf_encoder.py
@@ -69,11 +69,6 @@ def test_serialize(self):
             expected_encoding.SerializeToString(),
         )
 
-    def test_content_type(self):
-        self.assertEqual(
-            _ProtobufEncoder._CONTENT_TYPE, "application/x-protobuf"
-        )
-
     @staticmethod
     def get_exhaustive_otel_span_list() -> List[SDKSpan]:
         trace_id = 0x3E0C63257DE34C926F9EFCD03927272E

From fe670606c3c9b725e9d72a689be2505f54a035d0 Mon Sep 17 00:00:00 2001
From: Alex Boten <aboten@lightstep.com>
Date: Wed, 5 Oct 2022 10:49:16 -0700
Subject: [PATCH 2/3] update changelog

---
 CHANGELOG.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ea4f873b37d..89fe8c9cf77 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 - Update explicit histogram bucket boundaries
   ([#2947](https://github.com/open-telemetry/opentelemetry-python/pull/2947))
+- `exporter-otlp-proto-http`: add user agent string
+  ([#2959](https://github.com/open-telemetry/opentelemetry-python/pull/2959))
 
 ## [1.13.0-0.34b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.13.0) - 2022-09-26
 

From d65bf5f52710bdc3ceef5b8d9cbed48ec026206e Mon Sep 17 00:00:00 2001
From: Alex Boten <aboten@lightstep.com>
Date: Wed, 5 Oct 2022 11:07:09 -0700
Subject: [PATCH 3/3] fix linting, fix link

---
 CHANGELOG.md                                                 | 2 +-
 .../src/opentelemetry/exporter/otlp/proto/http/__init__.py   | 3 ++-
 .../exporter/otlp/proto/http/_log_exporter/__init__.py       | 5 ++++-
 .../exporter/otlp/proto/http/trace_exporter/__init__.py      | 5 ++++-
 .../tests/test_proto_log_exporter.py                         | 5 ++++-
 .../tests/test_proto_span_exporter.py                        | 5 ++++-
 6 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 89fe8c9cf77..879ec025985 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
-## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.13.0-0.34b0...HEAD)
+## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.13.0...HEAD)
 
 - Update explicit histogram bucket boundaries
   ([#2947](https://github.com/open-telemetry/opentelemetry-python/pull/2947))
diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/__init__.py
index efdb1d1d1ff..a14f0e2992d 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/__init__.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/__init__.py
@@ -76,9 +76,10 @@
 
 _OTLP_HTTP_HEADERS = {
     "Content-Type": "application/x-protobuf",
-    "User-Agent": "OTel OTLP Exporter Python/" + __version__
+    "User-Agent": "OTel OTLP Exporter Python/" + __version__,
 }
 
+
 class Compression(enum.Enum):
     NoCompression = "none"
     Deflate = "deflate"
diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py
index 217dba384cf..a74f849f406 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py
@@ -35,7 +35,10 @@
     LogExportResult,
     LogData,
 )
-from opentelemetry.exporter.otlp.proto.http import _OTLP_HTTP_HEADERS, Compression
+from opentelemetry.exporter.otlp.proto.http import (
+    _OTLP_HTTP_HEADERS,
+    Compression,
+)
 from opentelemetry.exporter.otlp.proto.http._log_exporter.encoder import (
     _ProtobufEncoder,
 )
diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py
index c1a33d5eba7..a65bc44320f 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py
@@ -36,7 +36,10 @@
     OTEL_EXPORTER_OTLP_TIMEOUT,
 )
 from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
-from opentelemetry.exporter.otlp.proto.http import _OTLP_HTTP_HEADERS, Compression
+from opentelemetry.exporter.otlp.proto.http import (
+    _OTLP_HTTP_HEADERS,
+    Compression,
+)
 from opentelemetry.exporter.otlp.proto.http.trace_exporter.encoder import (
     _ProtobufEncoder,
 )
diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py
index 12e9ed2fcfb..2063820b5d2 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py
@@ -85,7 +85,10 @@ def test_constructor_default(self):
         self.assertEqual(exporter._headers, {})
         self.assertIsInstance(exporter._session, requests.Session)
         self.assertIn("User-Agent", exporter._session.headers)
-        self.assertEqual(exporter._session.headers.get("Content-Type"), "application/x-protobuf")
+        self.assertEqual(
+            exporter._session.headers.get("Content-Type"),
+            "application/x-protobuf",
+        )
 
     @patch.dict(
         "os.environ",
diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py
index bcbb06dec30..73e54e86c0b 100644
--- a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py
@@ -59,7 +59,10 @@ def test_constructor_default(self):
         self.assertEqual(exporter._headers, {})
         self.assertIsInstance(exporter._session, requests.Session)
         self.assertIn("User-Agent", exporter._session.headers)
-        self.assertEqual(exporter._session.headers.get("Content-Type"), "application/x-protobuf")
+        self.assertEqual(
+            exporter._session.headers.get("Content-Type"),
+            "application/x-protobuf",
+        )
 
     @patch.dict(
         "os.environ",