Skip to content

Commit 9e58cbe

Browse files
authored
Merge branch 'main' into feat/datapoint-flags
2 parents 53e3340 + f879913 commit 9e58cbe

51 files changed

Lines changed: 884 additions & 120 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212

1313
## Unreleased
1414

15+
- `opentelemetry-sdk`: fix multi-processor `force_flush` skipping remaining processors when one returns `None`
16+
([#5179](https://github.com/open-telemetry/opentelemetry-python/pull/5179))
1517
- Apply fixes for `UP` ruff rule
1618
([#5133](https://github.com/open-telemetry/opentelemetry-python/pull/5133))
1719
- Switch to SPDX license headers and add CI enforcement
@@ -46,12 +48,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4648
([#5135](https://github.com/open-telemetry/opentelemetry-python/pull/5135))
4749
- ci: wait for tracecontext server readiness instead of a fixed sleep in `scripts/tracecontext-integration-test.sh`
4850
([#5149](https://github.com/open-telemetry/opentelemetry-python/pull/5149))
51+
- `opentelemetry-api`: update `EnvironmentGetter` and `EnvironmentSetter` to use normalized environment variable names
52+
([#5119](https://github.com/open-telemetry/opentelemetry-python/pull/5119))
4953
- `opentelemetry-sdk`: only load entrypoints for resource detectors if they are configured via `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS`
5054
([#5145](https://github.com/open-telemetry/opentelemetry-python/pull/5145))
5155
- `opentelemetry-exporter-otlp-json-common`: add 'opentelemetry-exporter-otlp-json-common' package for OTLP JSON exporters
5256
([#4996](https://github.com/open-telemetry/opentelemetry-python/pull/4996))
5357
- `opentelemetry-exporter-otlp-proto-grpc`: make retryable gRPC error codes configurable for gRPC exporters
5458
([#4917](https://github.com/open-telemetry/opentelemetry-python/pull/4917))
59+
- `opentelemetry-sdk`: add sampler plugin loading to declarative file configuration via the `opentelemetry_sampler` entry point group, matching the spec's PluginComponentProvider mechanism
60+
([#5095](https://github.com/open-telemetry/opentelemetry-python/pull/5095))
61+
- Add `registry` keyword argument to `PrometheusMetricReader` to allow passing a custom Prometheus registry
62+
([#5055](https://github.com/open-telemetry/opentelemetry-python/pull/5055))
63+
- Add ability to selectively enable exporting of SDK internal metrics with the `OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED` environment variable.
64+
([#5151](https://github.com/open-telemetry/opentelemetry-python/pull/5151))
65+
- `opentelemetry-api`, `opentelemetry-sdk`: add support for 'random-trace-id' flags in W3C traceparent header trace flags. Implementations of `IdGenerator` that do randomly generate the 56 least significant bits, should also implement a `is_trace_id_random` methods that returns `True`.
66+
([#4854](https://github.com/open-telemetry/opentelemetry-python/pull/4854))
5567
- [BREAKING] `opentelemetry-sdk`, `opentelemetry-exporter-otlp-proto-common`: Add support for metric data-point flags
5668
([#4916](https://github.com/open-telemetry/opentelemetry-python/pull/4916))
5769

CONTRIBUTING.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,14 @@ git commit
234234
git push fork feature
235235
```
236236

237-
Open a pull request against the main `opentelemetry-python` repo.
237+
Open a pull request (PR) against the main `opentelemetry-python` repo.
238+
239+
A descriptive PR title will help the community better triage and review your changes. Make sure to prefix with the name(s) of the package/subdirectory/domain that your PR updates. Following any of these examples will help:
240+
241+
* "opentelemetry-sdk: make test_force_flush_late_by_timeout less flaky on pypy/windows"
242+
* "opentelemetry-exporter-otlp-proto-http: enable typechecking"
243+
* "docs: replace TODO placeholders with API and SDK overview descriptions"
244+
* "feat(config): Add TracerProvider support for declarative config"
238245

239246
Pull requests are also tested for their compatibility with packages distributed
240247
by OpenTelemetry in the [OpenTelemetry Python Contrib Repository](https://github.com/open-telemetry/opentelemetry-python.git).

codegen/opentelemetry-codegen-json/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "opentelemetry-codegen-json"
7-
dynamic = ["version"]
7+
version = "0.0.0" # Not published to PyPI
88
description = "Protobuf plugin to generate JSON serializers and deserializers for OpenTelemetry protobuf messages"
99
readme = "README.rst"
1010
license = "Apache-2.0"

codegen/opentelemetry-codegen-json/src/opentelemetry/codegen/json/generator.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
is_int64_type,
2424
to_json_field_name,
2525
)
26-
from opentelemetry.codegen.json.version import __version__ as GENERATOR_VERSION
2726
from opentelemetry.codegen.json.writer import CodeWriter
2827

2928
_logger = logging.getLogger(__name__)
@@ -1046,9 +1045,7 @@ def generate_code(
10461045
Returns:
10471046
Dictionary mapping output file paths to generated code
10481047
"""
1049-
generator = OtlpJsonGenerator(
1050-
request, package_transform, version=GENERATOR_VERSION
1051-
)
1048+
generator = OtlpJsonGenerator(request, package_transform, version="0.0.0")
10521049
return generator.generate_all()
10531050

10541051

codegen/opentelemetry-codegen-json/src/opentelemetry/codegen/json/plugin.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from google.protobuf.compiler import plugin_pb2 as plugin
1212

1313
from opentelemetry.codegen.json.generator import generate_plugin_response
14-
from opentelemetry.codegen.json.version import __version__
1514

1615
_logger = logging.getLogger(__name__)
1716

@@ -24,7 +23,7 @@ def code_generation() -> Iterator[
2423
Context manager for handling the code generation process.
2524
"""
2625
if len(sys.argv) > 1 and sys.argv[1] in ("-V", "--version"):
27-
print("opentelemetry-codegen-json " + __version__)
26+
print("opentelemetry-codegen-json 0.0.0")
2827
sys.exit(0)
2928

3029
data = sys.stdin.buffer.read()

codegen/opentelemetry-codegen-json/src/opentelemetry/codegen/json/version/__init__.py

Lines changed: 0 additions & 4 deletions
This file was deleted.

dev-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ requests==2.32.3
1414
ruamel.yaml==0.17.21
1515
asgiref==3.7.2
1616
psutil==7.2.2
17-
GitPython==3.1.47
17+
GitPython==3.1.50
1818
pre-commit==3.7.0
1919
ruff==0.14.1

exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_exporter_metrics.py

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
from collections import Counter
77
from collections.abc import Iterator
8-
from contextlib import contextmanager
8+
from contextlib import AbstractContextManager, contextmanager
99
from dataclasses import dataclass
1010
from time import perf_counter
11-
from typing import TYPE_CHECKING
11+
from typing import TYPE_CHECKING, Protocol
1212

1313
from opentelemetry.metrics import MeterProvider, get_meter_provider
1414
from opentelemetry.semconv._incubating.attributes.otel_attributes import (
@@ -46,6 +46,18 @@ class ExportResult:
4646
error_attrs: Attributes = None
4747

4848

49+
class ExporterMetricsT(Protocol):
50+
def export_operation(
51+
self, num_items: int
52+
) -> AbstractContextManager[ExportResult]: ...
53+
54+
55+
class NoOpExporterMetrics:
56+
@contextmanager
57+
def export_operation(self, num_items: int) -> Iterator[ExportResult]:
58+
yield ExportResult()
59+
60+
4961
class ExporterMetrics:
5062
def __init__(
5163
self,
@@ -75,14 +87,14 @@ def __init__(
7587
elif endpoint.scheme == "http":
7688
port = 80
7789

78-
component_type = (
79-
component_type or OtelComponentTypeValues("unknown_otlp_exporter")
80-
).value
81-
count = _component_counter[component_type]
82-
_component_counter[component_type] = count + 1
90+
component_type_value = (
91+
component_type.value if component_type else "unknown_otlp_exporter"
92+
)
93+
count = _component_counter[component_type_value]
94+
_component_counter[component_type_value] = count + 1
8395
self._standard_attrs: dict[str, AttributeValue] = {
84-
OTEL_COMPONENT_TYPE: component_type,
85-
OTEL_COMPONENT_NAME: f"{component_type}/{count}",
96+
OTEL_COMPONENT_TYPE: component_type_value,
97+
OTEL_COMPONENT_NAME: f"{component_type_value}/{count}",
8698
}
8799
if endpoint.hostname:
88100
self._standard_attrs[SERVER_ADDRESS] = endpoint.hostname
@@ -121,3 +133,21 @@ def export_operation(self, num_items: int) -> Iterator[ExportResult]:
121133
else exported_attrs
122134
)
123135
self._duration.record(end_time - start_time, duration_attrs)
136+
137+
138+
def create_exporter_metrics(
139+
component_type: OtelComponentTypeValues | None,
140+
signal: Literal["traces", "metrics", "logs"],
141+
endpoint: UrlParseResult,
142+
meter_provider: MeterProvider | None,
143+
enabled: bool,
144+
) -> ExporterMetricsT:
145+
if not enabled:
146+
return NoOpExporterMetrics()
147+
148+
return ExporterMetrics(
149+
component_type,
150+
signal,
151+
endpoint,
152+
meter_provider,
153+
)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Copyright The OpenTelemetry Authors
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
import unittest
5+
from unittest.mock import Mock, patch
6+
from urllib.parse import urlparse
7+
8+
from opentelemetry.exporter.otlp.proto.common._exporter_metrics import (
9+
ExporterMetrics,
10+
NoOpExporterMetrics,
11+
create_exporter_metrics,
12+
)
13+
from opentelemetry.semconv._incubating.attributes.otel_attributes import (
14+
OtelComponentTypeValues,
15+
)
16+
17+
18+
class TestExporterMetrics(unittest.TestCase):
19+
def test_factory_returns_noop_when_disabled(self):
20+
meter_provider = Mock()
21+
22+
with patch(
23+
"opentelemetry.exporter.otlp.proto.common."
24+
"_exporter_metrics.get_meter_provider"
25+
) as get_meter_provider:
26+
metrics = create_exporter_metrics(
27+
OtelComponentTypeValues.OTLP_HTTP_SPAN_EXPORTER,
28+
"traces",
29+
urlparse("http://localhost:4318/v1/traces"),
30+
meter_provider,
31+
False,
32+
)
33+
34+
self.assertIsInstance(metrics, NoOpExporterMetrics)
35+
meter_provider.get_meter.assert_not_called()
36+
get_meter_provider.assert_not_called()
37+
38+
def test_factory_returns_exporter_metrics_when_enabled(self):
39+
meter_provider = Mock()
40+
meter_provider.get_meter.return_value = Mock()
41+
42+
metrics = create_exporter_metrics(
43+
OtelComponentTypeValues.OTLP_HTTP_SPAN_EXPORTER,
44+
"traces",
45+
urlparse("http://localhost:4318/v1/traces"),
46+
meter_provider,
47+
True,
48+
)
49+
50+
self.assertIsInstance(metrics, ExporterMetrics)
51+
meter_provider.get_meter.assert_called_once_with("opentelemetry-sdk")
52+
53+
def test_noop_export_operation_yields_result(self):
54+
metrics = NoOpExporterMetrics()
55+
56+
with metrics.export_operation(1) as result:
57+
result.error = RuntimeError("error")
58+
59+
self.assertIsInstance(result.error, RuntimeError)

exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
ssl_channel_credentials,
4747
)
4848
from opentelemetry.exporter.otlp.proto.common._exporter_metrics import (
49-
ExporterMetrics,
49+
create_exporter_metrics,
5050
)
5151
from opentelemetry.exporter.otlp.proto.common._internal import (
5252
_get_resource_data,
@@ -93,6 +93,7 @@
9393
OTEL_EXPORTER_OTLP_HEADERS,
9494
OTEL_EXPORTER_OTLP_INSECURE,
9595
OTEL_EXPORTER_OTLP_TIMEOUT,
96+
OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED,
9697
)
9798
from opentelemetry.sdk.metrics.export import MetricExportResult, MetricsData
9899
from opentelemetry.sdk.resources import Resource as SDKResource
@@ -395,11 +396,15 @@ def __init__(
395396
self._component_type = component_type
396397
self._signal: Literal["traces", "metrics", "logs"] = signal
397398
self._parsed_url = parsed_url
398-
self._metrics = ExporterMetrics(
399+
self._metrics = create_exporter_metrics(
399400
self._component_type,
400401
signal,
401402
parsed_url,
402403
meter_provider,
404+
os.environ.get(OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED, "")
405+
.strip()
406+
.lower()
407+
== "true",
403408
)
404409

405410
self._initialize_channel_and_stub()
@@ -557,9 +562,13 @@ def _exporting(self) -> str:
557562
pass
558563

559564
def _set_meter_provider(self, meter_provider: MeterProvider) -> None:
560-
self._metrics = ExporterMetrics(
565+
self._metrics = create_exporter_metrics(
561566
self._component_type,
562567
self._signal,
563568
self._parsed_url,
564569
meter_provider,
570+
os.environ.get(OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED, "")
571+
.strip()
572+
.lower()
573+
== "true",
565574
)

0 commit comments

Comments
 (0)