Repository: elastic/elastic-otel-python

Issue:
Easier authentication configuration
**Is your feature request related to a problem? Please describe.**

Url-quoting the authentication header is annoying 

**Describe the solution you'd like**

We can expose two different Elastic specific configuration variable to send just the Bearer token or the plain API Key so that we don't need to ask the users to quote the content of the authorization header.

**Describe alternatives you've considered**

None

**Additional context**



Discussion:

Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 673b9bb..898b02f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -46,10 +46,11 @@ jobs:
       py39: 3.9
       py310: "3.10"
       py311: "3.11"
+      py312: "3.12"
     strategy:
       fail-fast: false
       matrix:
-        python-version: [py38, py39, py310, py311]
+        python-version: [py38, py39, py310, py311, py312]
     steps:
     - uses: actions/checkout@v4
     - name: Set up Python ${{ env[matrix.python-version] }}
diff --git a/README.md b/README.md
index 8d56115..64d41e2 100644
--- a/README.md
+++ b/README.md
@@ -25,11 +25,10 @@ e.g. into your container image build process.
 At runtime you have to make some environment variables available to provide the needed configuration.
 A *service name* is required to have your app easily recognizable from the other. Then you need to provide
 the *authorization* headers for authentication with Elastic cloud and the project endpoint where to send your data.
-For details about the authentication format see the chapter below.
 
 ```bash
 OTEL_RESOURCE_ATTRIBUTES=service.name=<app-name>
-OTEL_EXPORTER_OTLP_HEADERS="Authorization=<url encoded apikey header value>"
+OTEL_EXPORTER_OTLP_HEADERS="Authorization=<authorization header value>"
 OTEL_EXPORTER_OTLP_ENDPOINT=<your elastic cloud url>
 ```
 
@@ -46,20 +45,6 @@ For a web service running with gunicorn it may looks like:
 opentelemetry-instrument gunicorn main:app
 ```
 
-## Authentication
-
-Authentication is done passing an URL encoded API Key as `Authorization` header, given the Api Key available
-from your project dashboard you can encode it this way:
-
-```python
-from urllib.parse import quote
-quote("ApiKey <your api key>")
-```
-
-In the end it will look something like the following:
-
-"ApiKey%20RM2sVN55Su49RgCYNI7SvYoeyWCyt3sbdFirjvmtin6IavUfZrBXCInwao%3D%3D"
-
 ## Configuration
 
 The distribution supports all the configuration variables from OpenTelemetry Python project version 1.25.0.
@@ -71,7 +56,7 @@ This distribution sets the following defaults:
 - `OTEL_TRACES_EXPORTER`: `otlp`
 - `OTEL_METRICS_EXPORTER`: `otlp`
 - `OTEL_EXPORTER_OTLP_PROTOCOL`: `grpc`
-- `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS`: `process_runtime,otel,telemetry_distro`
+- `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS`: `process_runtime,os,otel,telemetry_distro`
 
 ### Distribution specific configuration variables
 
diff --git a/dev-requirements.txt b/dev-requirements.txt
index ad55ec6..459bd45 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -17,6 +17,7 @@ deprecated==1.2.14
     #   opentelemetry-api
     #   opentelemetry-exporter-otlp-proto-grpc
     #   opentelemetry-exporter-otlp-proto-http
+    #   opentelemetry-semantic-conventions
 exceptiongroup==1.2.2
     # via pytest
 googleapis-common-protos==1.63.2
@@ -35,7 +36,7 @@ iniconfig==2.0.0
     # via pytest
 leb128==1.0.8
     # via elastic-opentelemetry (pyproject.toml)
-opentelemetry-api==1.25.0
+opentelemetry-api==1.27.0
     # via
     #   elastic-opentelemetry (pyproject.toml)
     #   opentelemetry-exporter-otlp-proto-grpc
@@ -45,34 +46,34 @@ opentelemetry-api==1.25.0
     #   opentelemetry-sdk
     #   opentelemetry-semantic-conventions
     #   oteltest
-opentelemetry-exporter-otlp==1.25.0
+opentelemetry-exporter-otlp==1.27.0
     # via elastic-opentelemetry (pyproject.toml)
-opentelemetry-exporter-otlp-proto-common==1.25.0
+opentelemetry-exporter-otlp-proto-common==1.27.0
     # via
     #   opentelemetry-exporter-otlp-proto-grpc
     #   opentelemetry-exporter-otlp-proto-http
-opentelemetry-exporter-otlp-proto-grpc==1.25.0
+opentelemetry-exporter-otlp-proto-grpc==1.27.0
     # via opentelemetry-exporter-otlp
-opentelemetry-exporter-otlp-proto-http==1.25.0
+opentelemetry-exporter-otlp-proto-http==1.27.0
     # via opentelemetry-exporter-otlp
-opentelemetry-instrumentation==0.46b0
+opentelemetry-instrumentation==0.48b0
     # via
     #   elastic-opentelemetry (pyproject.toml)
     #   opentelemetry-instrumentation-system-metrics
-opentelemetry-instrumentation-system-metrics==0.46b0
+opentelemetry-instrumentation-system-metrics==0.48b0
     # via elastic-opentelemetry (pyproject.toml)
-opentelemetry-proto==1.25.0
+opentelemetry-proto==1.27.0
     # via
     #   opentelemetry-exporter-otlp-proto-common
     #   opentelemetry-exporter-otlp-proto-grpc
     #   opentelemetry-exporter-otlp-proto-http
     #   oteltest
-opentelemetry-sdk==1.25.0
+opentelemetry-sdk==1.27.0
     # via
     #   elastic-opentelemetry (pyproject.toml)
     #   opentelemetry-exporter-otlp-proto-grpc
     #   opentelemetry-exporter-otlp-proto-http
-opentelemetry-semantic-conventions==0.46b0
+opentelemetry-semantic-conventions==0.48b0
     # via
     #   elastic-opentelemetry (pyproject.toml)
     #   opentelemetry-sdk
diff --git a/pyproject.toml b/pyproject.toml
index 55bdd0e..3b25117 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -22,16 +22,17 @@ classifiers = [
   "Programming Language :: Python :: 3.9",
   "Programming Language :: Python :: 3.10",
   "Programming Language :: Python :: 3.11",
+  "Programming Language :: Python :: 3.12",
   "Typing :: Typed",
 ]
 
 dependencies = [
-    "opentelemetry-api == 1.25.0",
-    "opentelemetry-exporter-otlp == 1.25.0",
-    "opentelemetry-instrumentation == 0.46b0",
-    "opentelemetry-instrumentation-system-metrics == 0.46b0",
-    "opentelemetry-semantic-conventions == 0.46b0",
-    "opentelemetry-sdk == 1.25.0",
+    "opentelemetry-api == 1.27.0",
+    "opentelemetry-exporter-otlp == 1.27.0",
+    "opentelemetry-instrumentation == 0.48b0",
+    "opentelemetry-instrumentation-system-metrics == 0.48b0",
+    "opentelemetry-semantic-conventions == 0.48b0",
+    "opentelemetry-sdk == 1.27.0",
 ]
 
 [project.optional-dependencies]
diff --git a/src/elasticotel/distro/__init__.py b/src/elasticotel/distro/__init__.py
index eb6a37e..d3796ae 100644
--- a/src/elasticotel/distro/__init__.py
+++ b/src/elasticotel/distro/__init__.py
@@ -57,4 +57,4 @@ class ElasticOpenTelemetryDistro(BaseDistro):
         os.environ.setdefault(OTEL_TRACES_EXPORTER, "otlp")
         os.environ.setdefault(OTEL_METRICS_EXPORTER, "otlp")
         os.environ.setdefault(OTEL_EXPORTER_OTLP_PROTOCOL, "grpc")
-        os.environ.setdefault(OTEL_EXPERIMENTAL_RESOURCE_DETECTORS, "process_runtime,otel,telemetry_distro")
+        os.environ.setdefault(OTEL_EXPERIMENTAL_RESOURCE_DETECTORS, "process_runtime,os,otel,telemetry_distro")


Test patch:
diff --git a/tests/distro/test_distro.py b/tests/distro/test_distro.py
index 3c99a7b..40f9b85 100644
--- a/tests/distro/test_distro.py
+++ b/tests/distro/test_distro.py
@@ -37,7 +37,9 @@ class TestDistribution(TestCase):
         self.assertEqual("otlp", os.environ.get(OTEL_TRACES_EXPORTER))
         self.assertEqual("otlp", os.environ.get(OTEL_METRICS_EXPORTER))
         self.assertEqual("grpc", os.environ.get(OTEL_EXPORTER_OTLP_PROTOCOL))
-        self.assertEqual("process_runtime,otel,telemetry_distro", os.environ.get(OTEL_EXPERIMENTAL_RESOURCE_DETECTORS))
+        self.assertEqual(
+            "process_runtime,os,otel,telemetry_distro", os.environ.get(OTEL_EXPERIMENTAL_RESOURCE_DETECTORS)
+        )
 
     @mock.patch.dict("os.environ", {}, clear=True)
     def test_load_instrumentor_call_with_default_kwargs_for_SystemMetricsInstrumentor(self):
diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py
index 72aa2d5..62dd1be 100644
--- a/tests/integration/test_integration.py
+++ b/tests/integration/test_integration.py
@@ -44,6 +44,8 @@ class IntegrationTestCase(ElasticIntegrationTestCase):
         self.assertTrue(resource["process.runtime.description"])
         self.assertTrue(resource["process.runtime.name"])
         self.assertTrue(resource["process.runtime.version"])
+        self.assertTrue(resource["os.type"])
+        self.assertTrue(resource["os.version"])
 
     def test_traces_sets_resource_attributes_from_env(self):
         env = {"OTEL_RESOURCE_ATTRIBUTES": "service.name=my-service"}
@@ -112,5 +114,6 @@ class IntegrationTestCase(ElasticIntegrationTestCase):
                 "process.runtime.cpython.thread_count",
                 "process.runtime.cpython.cpu.utilization",
                 "process.runtime.cpython.context_switches",
+                "process.open_file_descriptor.count",
             ],
         )