prepare semconv utilities to support database stability opt-in (#3111)

This commit is contained in:
Emídio Neto
2024-12-17 14:58:04 -03:00
committed by GitHub
parent d155540038
commit cc62d1f05e
17 changed files with 423 additions and 134 deletions

View File

@ -11,11 +11,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased ## Unreleased
### Added
- Add support to database stability opt-in in `_semconv` utilities and add tests
([#3111](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3111))
### Fixed ### Fixed
- `opentelemetry-instrumentation-httpx` Fix `RequestInfo`/`ResponseInfo` type hints - `opentelemetry-instrumentation-httpx` Fix `RequestInfo`/`ResponseInfo` type hints
([#3105](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3105)) ([#3105](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3105))
## Version 1.29.0/0.50b0 (2024-12-11) ## Version 1.29.0/0.50b0 (2024-12-11)
### Added ### Added

View File

@ -92,13 +92,13 @@ from opentelemetry import context as context_api
from opentelemetry import trace from opentelemetry import trace
from opentelemetry.instrumentation._semconv import ( from opentelemetry.instrumentation._semconv import (
_get_schema_url, _get_schema_url,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType, _OpenTelemetryStabilitySignalType,
_report_new, _report_new,
_set_http_method, _set_http_method,
_set_http_url, _set_http_url,
_set_status, _set_status,
_StabilityMode,
) )
from opentelemetry.instrumentation.aiohttp_client.package import _instruments from opentelemetry.instrumentation.aiohttp_client.package import _instruments
from opentelemetry.instrumentation.aiohttp_client.version import __version__ from opentelemetry.instrumentation.aiohttp_client.version import __version__
@ -142,7 +142,7 @@ def _set_http_status_code_attribute(
span, span,
status_code, status_code,
metric_attributes=None, metric_attributes=None,
sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode=_StabilityMode.DEFAULT,
): ):
status_code_str = str(status_code) status_code_str = str(status_code)
try: try:
@ -169,7 +169,7 @@ def create_trace_config(
request_hook: _RequestHookT = None, request_hook: _RequestHookT = None,
response_hook: _ResponseHookT = None, response_hook: _ResponseHookT = None,
tracer_provider: TracerProvider = None, tracer_provider: TracerProvider = None,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
) -> aiohttp.TraceConfig: ) -> aiohttp.TraceConfig:
"""Create an aiohttp-compatible trace configuration. """Create an aiohttp-compatible trace configuration.
@ -326,7 +326,7 @@ def _instrument(
trace_configs: typing.Optional[ trace_configs: typing.Optional[
typing.Sequence[aiohttp.TraceConfig] typing.Sequence[aiohttp.TraceConfig]
] = None, ] = None,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
): ):
"""Enables tracing of all ClientSessions """Enables tracing of all ClientSessions

View File

@ -29,8 +29,8 @@ from opentelemetry import trace as trace_api
from opentelemetry.instrumentation import aiohttp_client from opentelemetry.instrumentation import aiohttp_client
from opentelemetry.instrumentation._semconv import ( from opentelemetry.instrumentation._semconv import (
OTEL_SEMCONV_STABILITY_OPT_IN, OTEL_SEMCONV_STABILITY_OPT_IN,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_StabilityMode,
) )
from opentelemetry.instrumentation.aiohttp_client import ( from opentelemetry.instrumentation.aiohttp_client import (
AioHttpClientInstrumentor, AioHttpClientInstrumentor,
@ -150,7 +150,7 @@ class TestAioHttpIntegration(TestBase):
path = "test-path?query=param#foobar" path = "test-path?query=param#foobar"
host, port = self._http_request( host, port = self._http_request(
trace_config=aiohttp_client.create_trace_config( trace_config=aiohttp_client.create_trace_config(
sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP sem_conv_opt_in_mode=_StabilityMode.HTTP
), ),
url=f"/{path}", url=f"/{path}",
status_code=status_code, status_code=status_code,
@ -173,7 +173,7 @@ class TestAioHttpIntegration(TestBase):
path = "test-path?query=param#foobar" path = "test-path?query=param#foobar"
host, port = self._http_request( host, port = self._http_request(
trace_config=aiohttp_client.create_trace_config( trace_config=aiohttp_client.create_trace_config(
sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP_DUP sem_conv_opt_in_mode=_StabilityMode.HTTP_DUP
), ),
url=f"/{path}", url=f"/{path}",
status_code=status_code, status_code=status_code,
@ -213,7 +213,7 @@ class TestAioHttpIntegration(TestBase):
with self.subTest(status_code=200): with self.subTest(status_code=200):
self._http_request( self._http_request(
trace_config=aiohttp_client.create_trace_config( trace_config=aiohttp_client.create_trace_config(
sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP sem_conv_opt_in_mode=_StabilityMode.HTTP
), ),
url="/test-path?query=param#foobar", url="/test-path?query=param#foobar",
status_code=200, status_code=200,
@ -230,7 +230,7 @@ class TestAioHttpIntegration(TestBase):
with self.subTest(status_code=200): with self.subTest(status_code=200):
self._http_request( self._http_request(
trace_config=aiohttp_client.create_trace_config( trace_config=aiohttp_client.create_trace_config(
sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP_DUP sem_conv_opt_in_mode=_StabilityMode.HTTP_DUP
), ),
url="/test-path?query=param#foobar", url="/test-path?query=param#foobar",
status_code=200, status_code=200,
@ -398,7 +398,7 @@ class TestAioHttpIntegration(TestBase):
host, port = self._http_request( host, port = self._http_request(
trace_config=aiohttp_client.create_trace_config( trace_config=aiohttp_client.create_trace_config(
sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP sem_conv_opt_in_mode=_StabilityMode.HTTP
), ),
url="/test", url="/test",
request_handler=request_handler, request_handler=request_handler,
@ -426,7 +426,7 @@ class TestAioHttpIntegration(TestBase):
host, port = self._http_request( host, port = self._http_request(
trace_config=aiohttp_client.create_trace_config( trace_config=aiohttp_client.create_trace_config(
sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP_DUP sem_conv_opt_in_mode=_StabilityMode.HTTP_DUP
), ),
url="/test", url="/test",
request_handler=request_handler, request_handler=request_handler,
@ -546,7 +546,7 @@ class TestAioHttpIntegration(TestBase):
def test_nonstandard_http_method_new_semconv(self): def test_nonstandard_http_method_new_semconv(self):
trace_configs = [ trace_configs = [
aiohttp_client.create_trace_config( aiohttp_client.create_trace_config(
sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP sem_conv_opt_in_mode=_StabilityMode.HTTP
) )
] ]
app = HttpServerMock("nonstandard_method") app = HttpServerMock("nonstandard_method")

View File

@ -205,7 +205,6 @@ from opentelemetry.instrumentation._semconv import (
_filter_semconv_active_request_count_attr, _filter_semconv_active_request_count_attr,
_filter_semconv_duration_attrs, _filter_semconv_duration_attrs,
_get_schema_url, _get_schema_url,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType, _OpenTelemetryStabilitySignalType,
_report_new, _report_new,
@ -225,6 +224,7 @@ from opentelemetry.instrumentation._semconv import (
_set_http_url, _set_http_url,
_set_http_user_agent, _set_http_user_agent,
_set_status, _set_status,
_StabilityMode,
) )
from opentelemetry.instrumentation.asgi.types import ( from opentelemetry.instrumentation.asgi.types import (
ClientRequestHook, ClientRequestHook,
@ -324,7 +324,7 @@ asgi_setter = ASGISetter()
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
def collect_request_attributes( def collect_request_attributes(
scope, sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT scope, sem_conv_opt_in_mode=_StabilityMode.DEFAULT
): ):
"""Collects HTTP request attributes from the ASGI scope and returns a """Collects HTTP request attributes from the ASGI scope and returns a
dictionary to be used as span creation attributes.""" dictionary to be used as span creation attributes."""
@ -356,7 +356,7 @@ def collect_request_attributes(
_set_http_url( _set_http_url(
result, result,
remove_url_credentials(http_url), remove_url_credentials(http_url),
_HTTPStabilityMode.DEFAULT, _StabilityMode.DEFAULT,
) )
http_method = scope.get("method", "") http_method = scope.get("method", "")
if http_method: if http_method:
@ -439,7 +439,7 @@ def set_status_code(
span, span,
status_code, status_code,
metric_attributes=None, metric_attributes=None,
sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode=_StabilityMode.DEFAULT,
): ):
"""Adds HTTP response attributes to span using the status_code argument.""" """Adds HTTP response attributes to span using the status_code argument."""
status_code_str = str(status_code) status_code_str = str(status_code)
@ -755,12 +755,12 @@ class OpenTelemetryMiddleware:
) )
duration_s = default_timer() - start duration_s = default_timer() - start
duration_attrs_old = _parse_duration_attrs( duration_attrs_old = _parse_duration_attrs(
attributes, _HTTPStabilityMode.DEFAULT attributes, _StabilityMode.DEFAULT
) )
if target: if target:
duration_attrs_old[SpanAttributes.HTTP_TARGET] = target duration_attrs_old[SpanAttributes.HTTP_TARGET] = target
duration_attrs_new = _parse_duration_attrs( duration_attrs_new = _parse_duration_attrs(
attributes, _HTTPStabilityMode.HTTP attributes, _StabilityMode.HTTP
) )
if self.duration_histogram_old: if self.duration_histogram_old:
self.duration_histogram_old.record( self.duration_histogram_old.record(
@ -960,7 +960,7 @@ class OpenTelemetryMiddleware:
def _parse_duration_attrs( def _parse_duration_attrs(
req_attrs, sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT req_attrs, sem_conv_opt_in_mode=_StabilityMode.DEFAULT
): ):
return _filter_semconv_duration_attrs( return _filter_semconv_duration_attrs(
req_attrs, req_attrs,
@ -971,7 +971,7 @@ def _parse_duration_attrs(
def _parse_active_request_count_attrs( def _parse_active_request_count_attrs(
req_attrs, sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT req_attrs, sem_conv_opt_in_mode=_StabilityMode.DEFAULT
): ):
return _filter_semconv_active_request_count_attr( return _filter_semconv_active_request_count_attr(
req_attrs, req_attrs,

View File

@ -24,12 +24,12 @@ import opentelemetry.instrumentation.asgi as otel_asgi
from opentelemetry import trace as trace_api from opentelemetry import trace as trace_api
from opentelemetry.instrumentation._semconv import ( from opentelemetry.instrumentation._semconv import (
OTEL_SEMCONV_STABILITY_OPT_IN, OTEL_SEMCONV_STABILITY_OPT_IN,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_server_active_requests_count_attrs_new, _server_active_requests_count_attrs_new,
_server_active_requests_count_attrs_old, _server_active_requests_count_attrs_old,
_server_duration_attrs_new, _server_duration_attrs_new,
_server_duration_attrs_old, _server_duration_attrs_old,
_StabilityMode,
) )
from opentelemetry.instrumentation.propagators import ( from opentelemetry.instrumentation.propagators import (
TraceResponsePropagator, TraceResponsePropagator,
@ -1652,7 +1652,7 @@ class TestAsgiAttributes(unittest.TestCase):
attrs = otel_asgi.collect_request_attributes( attrs = otel_asgi.collect_request_attributes(
self.scope, self.scope,
_HTTPStabilityMode.HTTP, _StabilityMode.HTTP,
) )
self.assertDictEqual( self.assertDictEqual(
@ -1677,7 +1677,7 @@ class TestAsgiAttributes(unittest.TestCase):
attrs = otel_asgi.collect_request_attributes( attrs = otel_asgi.collect_request_attributes(
self.scope, self.scope,
_HTTPStabilityMode.HTTP_DUP, _StabilityMode.HTTP_DUP,
) )
self.assertDictEqual( self.assertDictEqual(
@ -1715,7 +1715,7 @@ class TestAsgiAttributes(unittest.TestCase):
self.scope["query_string"] = b"foo=bar" self.scope["query_string"] = b"foo=bar"
attrs = otel_asgi.collect_request_attributes( attrs = otel_asgi.collect_request_attributes(
self.scope, self.scope,
_HTTPStabilityMode.HTTP, _StabilityMode.HTTP,
) )
self.assertEqual(attrs[URL_SCHEME], "http") self.assertEqual(attrs[URL_SCHEME], "http")
self.assertEqual(attrs[CLIENT_ADDRESS], "127.0.0.1") self.assertEqual(attrs[CLIENT_ADDRESS], "127.0.0.1")
@ -1726,7 +1726,7 @@ class TestAsgiAttributes(unittest.TestCase):
self.scope["query_string"] = b"foo=bar" self.scope["query_string"] = b"foo=bar"
attrs = otel_asgi.collect_request_attributes( attrs = otel_asgi.collect_request_attributes(
self.scope, self.scope,
_HTTPStabilityMode.HTTP_DUP, _StabilityMode.HTTP_DUP,
) )
self.assertEqual( self.assertEqual(
attrs[SpanAttributes.HTTP_URL], "http://127.0.0.1/?foo=bar" attrs[SpanAttributes.HTTP_URL], "http://127.0.0.1/?foo=bar"
@ -1762,7 +1762,7 @@ class TestAsgiAttributes(unittest.TestCase):
self.span, self.span,
404, 404,
None, None,
_HTTPStabilityMode.HTTP, _StabilityMode.HTTP,
) )
expected = (mock.call(HTTP_RESPONSE_STATUS_CODE, 404),) expected = (mock.call(HTTP_RESPONSE_STATUS_CODE, 404),)
self.assertEqual(self.span.set_attribute.call_count, 1) self.assertEqual(self.span.set_attribute.call_count, 1)
@ -1774,7 +1774,7 @@ class TestAsgiAttributes(unittest.TestCase):
self.span, self.span,
404, 404,
None, None,
_HTTPStabilityMode.HTTP_DUP, _StabilityMode.HTTP_DUP,
) )
expected = (mock.call(SpanAttributes.HTTP_STATUS_CODE, 404),) expected = (mock.call(SpanAttributes.HTTP_STATUS_CODE, 404),)
expected2 = (mock.call(HTTP_RESPONSE_STATUS_CODE, 404),) expected2 = (mock.call(HTTP_RESPONSE_STATUS_CODE, 404),)

View File

@ -25,13 +25,13 @@ from opentelemetry.context import detach
from opentelemetry.instrumentation._semconv import ( from opentelemetry.instrumentation._semconv import (
_filter_semconv_active_request_count_attr, _filter_semconv_active_request_count_attr,
_filter_semconv_duration_attrs, _filter_semconv_duration_attrs,
_HTTPStabilityMode,
_report_new, _report_new,
_report_old, _report_old,
_server_active_requests_count_attrs_new, _server_active_requests_count_attrs_new,
_server_active_requests_count_attrs_old, _server_active_requests_count_attrs_old,
_server_duration_attrs_new, _server_duration_attrs_new,
_server_duration_attrs_old, _server_duration_attrs_old,
_StabilityMode,
) )
from opentelemetry.instrumentation.propagators import ( from opentelemetry.instrumentation.propagators import (
get_global_response_propagator, get_global_response_propagator,
@ -158,7 +158,7 @@ class _DjangoMiddleware(MiddlewareMixin):
_duration_histogram_old = None _duration_histogram_old = None
_duration_histogram_new = None _duration_histogram_new = None
_active_request_counter = None _active_request_counter = None
_sem_conv_opt_in_mode = _HTTPStabilityMode.DEFAULT _sem_conv_opt_in_mode = _StabilityMode.DEFAULT
_otel_request_hook: Callable[[Span, HttpRequest], None] = None _otel_request_hook: Callable[[Span, HttpRequest], None] = None
_otel_response_hook: Callable[[Span, HttpRequest, HttpResponse], None] = ( _otel_response_hook: Callable[[Span, HttpRequest, HttpResponse], None] = (
@ -430,7 +430,7 @@ class _DjangoMiddleware(MiddlewareMixin):
duration_s = default_timer() - request_start_time duration_s = default_timer() - request_start_time
if self._duration_histogram_old: if self._duration_histogram_old:
duration_attrs_old = _parse_duration_attrs( duration_attrs_old = _parse_duration_attrs(
duration_attrs, _HTTPStabilityMode.DEFAULT duration_attrs, _StabilityMode.DEFAULT
) )
# http.target to be included in old semantic conventions # http.target to be included in old semantic conventions
target = duration_attrs.get(SpanAttributes.HTTP_TARGET) target = duration_attrs.get(SpanAttributes.HTTP_TARGET)
@ -441,7 +441,7 @@ class _DjangoMiddleware(MiddlewareMixin):
) )
if self._duration_histogram_new: if self._duration_histogram_new:
duration_attrs_new = _parse_duration_attrs( duration_attrs_new = _parse_duration_attrs(
duration_attrs, _HTTPStabilityMode.HTTP duration_attrs, _StabilityMode.HTTP
) )
self._duration_histogram_new.record( self._duration_histogram_new.record(
max(duration_s, 0), duration_attrs_new max(duration_s, 0), duration_attrs_new
@ -455,7 +455,7 @@ class _DjangoMiddleware(MiddlewareMixin):
def _parse_duration_attrs( def _parse_duration_attrs(
req_attrs, sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT req_attrs, sem_conv_opt_in_mode=_StabilityMode.DEFAULT
): ):
return _filter_semconv_duration_attrs( return _filter_semconv_duration_attrs(
req_attrs, req_attrs,
@ -466,7 +466,7 @@ def _parse_duration_attrs(
def _parse_active_request_count_attrs( def _parse_active_request_count_attrs(
req_attrs, sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT req_attrs, sem_conv_opt_in_mode=_StabilityMode.DEFAULT
): ):
return _filter_semconv_active_request_count_attr( return _filter_semconv_active_request_count_attr(
req_attrs, req_attrs,

View File

@ -186,9 +186,9 @@ from starlette.routing import Match
from opentelemetry.instrumentation._semconv import ( from opentelemetry.instrumentation._semconv import (
_get_schema_url, _get_schema_url,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType, _OpenTelemetryStabilitySignalType,
_StabilityMode,
) )
from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware
from opentelemetry.instrumentation.asgi.types import ( from opentelemetry.instrumentation.asgi.types import (
@ -362,7 +362,7 @@ class _InstrumentedFastAPI(fastapi.FastAPI):
_client_request_hook: ClientRequestHook = None _client_request_hook: ClientRequestHook = None
_client_response_hook: ClientResponseHook = None _client_response_hook: ClientResponseHook = None
_instrumented_fastapi_apps = set() _instrumented_fastapi_apps = set()
_sem_conv_opt_in_mode = _HTTPStabilityMode.DEFAULT _sem_conv_opt_in_mode = _StabilityMode.DEFAULT
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)

View File

@ -252,11 +252,11 @@ import opentelemetry.instrumentation.wsgi as otel_wsgi
from opentelemetry import context, trace from opentelemetry import context, trace
from opentelemetry.instrumentation._semconv import ( from opentelemetry.instrumentation._semconv import (
_get_schema_url, _get_schema_url,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType, _OpenTelemetryStabilitySignalType,
_report_new, _report_new,
_report_old, _report_old,
_StabilityMode,
) )
from opentelemetry.instrumentation.flask.package import _instruments from opentelemetry.instrumentation.flask.package import _instruments
from opentelemetry.instrumentation.flask.version import __version__ from opentelemetry.instrumentation.flask.version import __version__
@ -321,7 +321,7 @@ def _rewrapped_app(
duration_histogram_old=None, duration_histogram_old=None,
response_hook=None, response_hook=None,
excluded_urls=None, excluded_urls=None,
sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode=_StabilityMode.DEFAULT,
duration_histogram_new=None, duration_histogram_new=None,
): ):
def _wrapped_app(wrapped_app_environ, start_response): def _wrapped_app(wrapped_app_environ, start_response):
@ -392,7 +392,7 @@ def _rewrapped_app(
duration_s = default_timer() - start duration_s = default_timer() - start
if duration_histogram_old: if duration_histogram_old:
duration_attrs_old = otel_wsgi._parse_duration_attrs( duration_attrs_old = otel_wsgi._parse_duration_attrs(
attributes, _HTTPStabilityMode.DEFAULT attributes, _StabilityMode.DEFAULT
) )
if request_route: if request_route:
@ -406,7 +406,7 @@ def _rewrapped_app(
) )
if duration_histogram_new: if duration_histogram_new:
duration_attrs_new = otel_wsgi._parse_duration_attrs( duration_attrs_new = otel_wsgi._parse_duration_attrs(
attributes, _HTTPStabilityMode.HTTP attributes, _StabilityMode.HTTP
) )
if request_route: if request_route:
@ -427,7 +427,7 @@ def _wrapped_before_request(
excluded_urls=None, excluded_urls=None,
enable_commenter=True, enable_commenter=True,
commenter_options=None, commenter_options=None,
sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode=_StabilityMode.DEFAULT,
): ):
def _before_request(): def _before_request():
if excluded_urls and excluded_urls.url_disabled(flask.request.url): if excluded_urls and excluded_urls.url_disabled(flask.request.url):
@ -548,7 +548,7 @@ class _InstrumentedFlask(flask.Flask):
_enable_commenter = True _enable_commenter = True
_commenter_options = None _commenter_options = None
_meter_provider = None _meter_provider = None
_sem_conv_opt_in_mode = _HTTPStabilityMode.DEFAULT _sem_conv_opt_in_mode = _StabilityMode.DEFAULT
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)

View File

@ -205,7 +205,6 @@ from wrapt import wrap_function_wrapper
from opentelemetry.instrumentation._semconv import ( from opentelemetry.instrumentation._semconv import (
_get_schema_url, _get_schema_url,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType, _OpenTelemetryStabilitySignalType,
_report_new, _report_new,
@ -215,6 +214,7 @@ from opentelemetry.instrumentation._semconv import (
_set_http_peer_port_client, _set_http_peer_port_client,
_set_http_status_code, _set_http_status_code,
_set_http_url, _set_http_url,
_StabilityMode,
) )
from opentelemetry.instrumentation.httpx.package import _instruments from opentelemetry.instrumentation.httpx.package import _instruments
from opentelemetry.instrumentation.httpx.version import __version__ from opentelemetry.instrumentation.httpx.version import __version__
@ -334,7 +334,7 @@ def _apply_request_client_attributes_to_span(
span_attributes: dict, span_attributes: dict,
url: typing.Union[str, URL, httpx.URL], url: typing.Union[str, URL, httpx.URL],
method_original: str, method_original: str,
semconv: _HTTPStabilityMode, semconv: _StabilityMode,
): ):
url = httpx.URL(url) url = httpx.URL(url)
# http semconv transition: http.method -> http.request.method # http semconv transition: http.method -> http.request.method
@ -363,7 +363,7 @@ def _apply_response_client_attributes_to_span(
span: Span, span: Span,
status_code: int, status_code: int,
http_version: str, http_version: str,
semconv: _HTTPStabilityMode, semconv: _StabilityMode,
): ):
# http semconv transition: http.status_code -> http.response.status_code # http semconv transition: http.status_code -> http.response.status_code
# TODO: use _set_status when it's stable for http clients # TODO: use _set_status when it's stable for http clients

View File

@ -87,7 +87,6 @@ from opentelemetry.instrumentation._semconv import (
_client_duration_attrs_old, _client_duration_attrs_old,
_filter_semconv_duration_attrs, _filter_semconv_duration_attrs,
_get_schema_url, _get_schema_url,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType, _OpenTelemetryStabilitySignalType,
_report_new, _report_new,
@ -100,6 +99,7 @@ from opentelemetry.instrumentation._semconv import (
_set_http_scheme, _set_http_scheme,
_set_http_status_code, _set_http_status_code,
_set_http_url, _set_http_url,
_StabilityMode,
) )
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.requests.package import _instruments from opentelemetry.instrumentation.requests.package import _instruments
@ -147,7 +147,7 @@ def _instrument(
request_hook: _RequestHookT = None, request_hook: _RequestHookT = None,
response_hook: _ResponseHookT = None, response_hook: _ResponseHookT = None,
excluded_urls: ExcludeList = None, excluded_urls: ExcludeList = None,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
): ):
"""Enables tracing of all requests calls that go through """Enables tracing of all requests calls that go through
:code:`requests.session.Session.request` (this includes :code:`requests.session.Session.request` (this includes
@ -312,7 +312,7 @@ def _instrument(
metric_labels, metric_labels,
_client_duration_attrs_old, _client_duration_attrs_old,
_client_duration_attrs_new, _client_duration_attrs_new,
_HTTPStabilityMode.DEFAULT, _StabilityMode.DEFAULT,
) )
duration_histogram_old.record( duration_histogram_old.record(
max(round(elapsed_time * 1000), 0), max(round(elapsed_time * 1000), 0),
@ -323,7 +323,7 @@ def _instrument(
metric_labels, metric_labels,
_client_duration_attrs_old, _client_duration_attrs_old,
_client_duration_attrs_new, _client_duration_attrs_new,
_HTTPStabilityMode.HTTP, _StabilityMode.HTTP,
) )
duration_histogram_new.record( duration_histogram_new.record(
elapsed_time, attributes=duration_attrs_new elapsed_time, attributes=duration_attrs_new

View File

@ -90,7 +90,6 @@ from opentelemetry.instrumentation._semconv import (
_client_duration_attrs_old, _client_duration_attrs_old,
_filter_semconv_duration_attrs, _filter_semconv_duration_attrs,
_get_schema_url, _get_schema_url,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType, _OpenTelemetryStabilitySignalType,
_report_new, _report_new,
@ -99,6 +98,7 @@ from opentelemetry.instrumentation._semconv import (
_set_http_network_protocol_version, _set_http_network_protocol_version,
_set_http_url, _set_http_url,
_set_status, _set_status,
_StabilityMode,
) )
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.urllib.package import _instruments from opentelemetry.instrumentation.urllib.package import _instruments
@ -209,7 +209,7 @@ def _instrument(
request_hook: _RequestHookT = None, request_hook: _RequestHookT = None,
response_hook: _ResponseHookT = None, response_hook: _ResponseHookT = None,
excluded_urls: ExcludeList = None, excluded_urls: ExcludeList = None,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
): ):
"""Enables tracing of all requests calls that go through """Enables tracing of all requests calls that go through
:code:`urllib.Client._make_request`""" :code:`urllib.Client._make_request`"""
@ -305,13 +305,13 @@ def _instrument(
labels, labels,
_client_duration_attrs_old, _client_duration_attrs_old,
_client_duration_attrs_new, _client_duration_attrs_new,
sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode=_StabilityMode.DEFAULT,
) )
duration_attrs_new = _filter_semconv_duration_attrs( duration_attrs_new = _filter_semconv_duration_attrs(
labels, labels,
_client_duration_attrs_old, _client_duration_attrs_old,
_client_duration_attrs_new, _client_duration_attrs_new,
sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP, sem_conv_opt_in_mode=_StabilityMode.HTTP,
) )
duration_attrs_old[SpanAttributes.HTTP_URL] = url duration_attrs_old[SpanAttributes.HTTP_URL] = url
@ -372,7 +372,7 @@ def _set_status_code_attribute(
span: Span, span: Span,
status_code: int, status_code: int,
metric_attributes: dict = None, metric_attributes: dict = None,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
) -> None: ) -> None:
status_code_str = str(status_code) status_code_str = str(status_code)
try: try:
@ -394,7 +394,7 @@ def _set_status_code_attribute(
def _create_client_histograms( def _create_client_histograms(
meter, sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT meter, sem_conv_opt_in_mode=_StabilityMode.DEFAULT
) -> Dict[str, Histogram]: ) -> Dict[str, Histogram]:
histograms = {} histograms = {}
if _report_old(sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode):
@ -442,7 +442,7 @@ def _record_histograms(
request_size: int, request_size: int,
response_size: int, response_size: int,
duration_s: float, duration_s: float,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
): ):
if _report_old(sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode):
duration = max(round(duration_s * 1000), 0) duration = max(round(duration_s * 1000), 0)

View File

@ -98,7 +98,6 @@ from opentelemetry.instrumentation._semconv import (
_client_duration_attrs_old, _client_duration_attrs_old,
_filter_semconv_duration_attrs, _filter_semconv_duration_attrs,
_get_schema_url, _get_schema_url,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType, _OpenTelemetryStabilitySignalType,
_report_new, _report_new,
@ -111,6 +110,7 @@ from opentelemetry.instrumentation._semconv import (
_set_http_scheme, _set_http_scheme,
_set_http_url, _set_http_url,
_set_status, _set_status,
_StabilityMode,
) )
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.urllib3.package import _instruments from opentelemetry.instrumentation.urllib3.package import _instruments
@ -309,7 +309,7 @@ def _instrument(
response_hook: _ResponseHookT = None, response_hook: _ResponseHookT = None,
url_filter: _UrlFilterT = None, url_filter: _UrlFilterT = None,
excluded_urls: ExcludeList = None, excluded_urls: ExcludeList = None,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
): ):
def instrumented_urlopen(wrapped, instance, args, kwargs): def instrumented_urlopen(wrapped, instance, args, kwargs):
if not is_http_instrumentation_enabled(): if not is_http_instrumentation_enabled():
@ -461,7 +461,7 @@ def _set_status_code_attribute(
span: Span, span: Span,
status_code: int, status_code: int,
metric_attributes: dict = None, metric_attributes: dict = None,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
) -> None: ) -> None:
status_code_str = str(status_code) status_code_str = str(status_code)
try: try:
@ -487,7 +487,7 @@ def _set_metric_attributes(
instance: urllib3.connectionpool.HTTPConnectionPool, instance: urllib3.connectionpool.HTTPConnectionPool,
response: urllib3.response.HTTPResponse, response: urllib3.response.HTTPResponse,
method: str, method: str,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
) -> None: ) -> None:
_set_http_host_client( _set_http_host_client(
metric_attributes, instance.host, sem_conv_opt_in_mode metric_attributes, instance.host, sem_conv_opt_in_mode
@ -516,7 +516,7 @@ def _set_metric_attributes(
def _filter_attributes_semconv( def _filter_attributes_semconv(
metric_attributes, metric_attributes,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
): ):
duration_attrs_old = None duration_attrs_old = None
duration_attrs_new = None duration_attrs_new = None
@ -525,14 +525,14 @@ def _filter_attributes_semconv(
metric_attributes, metric_attributes,
_client_duration_attrs_old, _client_duration_attrs_old,
_client_duration_attrs_new, _client_duration_attrs_new,
_HTTPStabilityMode.DEFAULT, _StabilityMode.DEFAULT,
) )
if _report_new(sem_conv_opt_in_mode): if _report_new(sem_conv_opt_in_mode):
duration_attrs_new = _filter_semconv_duration_attrs( duration_attrs_new = _filter_semconv_duration_attrs(
metric_attributes, metric_attributes,
_client_duration_attrs_old, _client_duration_attrs_old,
_client_duration_attrs_new, _client_duration_attrs_new,
_HTTPStabilityMode.HTTP, _StabilityMode.HTTP,
) )
return (duration_attrs_old, duration_attrs_new) return (duration_attrs_old, duration_attrs_new)
@ -549,7 +549,7 @@ def _record_metrics(
duration_s: float, duration_s: float,
request_size: typing.Optional[int], request_size: typing.Optional[int],
response_size: int, response_size: int,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
): ):
attrs_old, attrs_new = _filter_attributes_semconv( attrs_old, attrs_new = _filter_attributes_semconv(
metric_attributes, sem_conv_opt_in_mode metric_attributes, sem_conv_opt_in_mode

View File

@ -24,8 +24,8 @@ import urllib3.exceptions
from opentelemetry import trace from opentelemetry import trace
from opentelemetry.instrumentation._semconv import ( from opentelemetry.instrumentation._semconv import (
OTEL_SEMCONV_STABILITY_OPT_IN, OTEL_SEMCONV_STABILITY_OPT_IN,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_StabilityMode,
) )
from opentelemetry.instrumentation.urllib3 import ( from opentelemetry.instrumentation.urllib3 import (
RequestInfo, RequestInfo,
@ -106,7 +106,7 @@ class TestURLLib3Instrumentor(TestBase):
self, self,
response: urllib3.response.HTTPResponse, response: urllib3.response.HTTPResponse,
url: str, url: str,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
): ):
self.assertEqual(b"Hello!", response.data) self.assertEqual(b"Hello!", response.data)
@ -129,9 +129,9 @@ class TestURLLib3Instrumentor(TestBase):
} }
attributes = { attributes = {
_HTTPStabilityMode.DEFAULT: expected_attr_old, _StabilityMode.DEFAULT: expected_attr_old,
_HTTPStabilityMode.HTTP: expected_attr_new, _StabilityMode.HTTP: expected_attr_new,
_HTTPStabilityMode.HTTP_DUP: { _StabilityMode.HTTP_DUP: {
**expected_attr_new, **expected_attr_new,
**expected_attr_old, **expected_attr_old,
}, },
@ -143,7 +143,7 @@ class TestURLLib3Instrumentor(TestBase):
def assert_exception_span( def assert_exception_span(
self, self,
url: str, url: str,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
): ):
span = self.assert_span() span = self.assert_span()
@ -159,9 +159,9 @@ class TestURLLib3Instrumentor(TestBase):
} }
attributes = { attributes = {
_HTTPStabilityMode.DEFAULT: expected_attr_old, _StabilityMode.DEFAULT: expected_attr_old,
_HTTPStabilityMode.HTTP: expected_attr_new, _StabilityMode.HTTP: expected_attr_new,
_HTTPStabilityMode.HTTP_DUP: { _StabilityMode.HTTP_DUP: {
**expected_attr_new, **expected_attr_new,
**expected_attr_old, **expected_attr_old,
}, },
@ -192,7 +192,7 @@ class TestURLLib3Instrumentor(TestBase):
self.assert_success_span( self.assert_success_span(
response, response,
self.HTTP_URL, self.HTTP_URL,
sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode=_StabilityMode.DEFAULT,
) )
def test_basic_http_success_new_semconv(self): def test_basic_http_success_new_semconv(self):
@ -200,7 +200,7 @@ class TestURLLib3Instrumentor(TestBase):
self.assert_success_span( self.assert_success_span(
response, response,
self.HTTP_URL, self.HTTP_URL,
sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP, sem_conv_opt_in_mode=_StabilityMode.HTTP,
) )
def test_basic_http_success_both_semconv(self): def test_basic_http_success_both_semconv(self):
@ -208,7 +208,7 @@ class TestURLLib3Instrumentor(TestBase):
self.assert_success_span( self.assert_success_span(
response, response,
self.HTTP_URL, self.HTTP_URL,
sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP_DUP, sem_conv_opt_in_mode=_StabilityMode.HTTP_DUP,
) )
def test_basic_http_success_using_connection_pool(self): def test_basic_http_success_using_connection_pool(self):
@ -471,7 +471,7 @@ class TestURLLib3Instrumentor(TestBase):
) )
self.assert_exception_span( self.assert_exception_span(
self.HTTP_URL, sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP self.HTTP_URL, sem_conv_opt_in_mode=_StabilityMode.HTTP
) )
@mock.patch( @mock.patch(
@ -485,7 +485,7 @@ class TestURLLib3Instrumentor(TestBase):
) )
self.assert_exception_span( self.assert_exception_span(
self.HTTP_URL, sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP_DUP self.HTTP_URL, sem_conv_opt_in_mode=_StabilityMode.HTTP_DUP
) )
@mock.patch( @mock.patch(

View File

@ -217,7 +217,6 @@ from opentelemetry.instrumentation._semconv import (
_filter_semconv_active_request_count_attr, _filter_semconv_active_request_count_attr,
_filter_semconv_duration_attrs, _filter_semconv_duration_attrs,
_get_schema_url, _get_schema_url,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType, _OpenTelemetryStabilitySignalType,
_report_new, _report_new,
@ -237,6 +236,7 @@ from opentelemetry.instrumentation._semconv import (
_set_http_target, _set_http_target,
_set_http_user_agent, _set_http_user_agent,
_set_status, _set_status,
_StabilityMode,
) )
from opentelemetry.instrumentation.utils import _start_internal_or_server_span from opentelemetry.instrumentation.utils import _start_internal_or_server_span
from opentelemetry.instrumentation.wsgi.version import __version__ from opentelemetry.instrumentation.wsgi.version import __version__
@ -308,7 +308,7 @@ def setifnotnone(dic, key, value):
def collect_request_attributes( def collect_request_attributes(
environ, environ,
sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode=_StabilityMode.DEFAULT,
): ):
"""Collects HTTP request attributes from the PEP3333-conforming """Collects HTTP request attributes from the PEP3333-conforming
WSGI environ and returns a dictionary to be used as span creation attributes. WSGI environ and returns a dictionary to be used as span creation attributes.
@ -449,7 +449,7 @@ def _parse_status_code(resp_status):
def _parse_active_request_count_attrs( def _parse_active_request_count_attrs(
req_attrs, sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT req_attrs, sem_conv_opt_in_mode=_StabilityMode.DEFAULT
): ):
return _filter_semconv_active_request_count_attr( return _filter_semconv_active_request_count_attr(
req_attrs, req_attrs,
@ -460,7 +460,7 @@ def _parse_active_request_count_attrs(
def _parse_duration_attrs( def _parse_duration_attrs(
req_attrs, sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT req_attrs, sem_conv_opt_in_mode=_StabilityMode.DEFAULT
): ):
return _filter_semconv_duration_attrs( return _filter_semconv_duration_attrs(
req_attrs, req_attrs,
@ -475,7 +475,7 @@ def add_response_attributes(
start_response_status, start_response_status,
response_headers, response_headers,
duration_attrs=None, duration_attrs=None,
sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode=_StabilityMode.DEFAULT,
): # pylint: disable=unused-argument ): # pylint: disable=unused-argument
"""Adds HTTP response attributes to span using the arguments """Adds HTTP response attributes to span using the arguments
passed to a PEP3333-conforming start_response callable. passed to a PEP3333-conforming start_response callable.
@ -685,14 +685,14 @@ class OpenTelemetryMiddleware:
duration_s = default_timer() - start duration_s = default_timer() - start
if self.duration_histogram_old: if self.duration_histogram_old:
duration_attrs_old = _parse_duration_attrs( duration_attrs_old = _parse_duration_attrs(
req_attrs, _HTTPStabilityMode.DEFAULT req_attrs, _StabilityMode.DEFAULT
) )
self.duration_histogram_old.record( self.duration_histogram_old.record(
max(round(duration_s * 1000), 0), duration_attrs_old max(round(duration_s * 1000), 0), duration_attrs_old
) )
if self.duration_histogram_new: if self.duration_histogram_new:
duration_attrs_new = _parse_duration_attrs( duration_attrs_new = _parse_duration_attrs(
req_attrs, _HTTPStabilityMode.HTTP req_attrs, _StabilityMode.HTTP
) )
self.duration_histogram_new.record( self.duration_histogram_new.record(
max(duration_s, 0), duration_attrs_new max(duration_s, 0), duration_attrs_new

View File

@ -24,12 +24,12 @@ import opentelemetry.instrumentation.wsgi as otel_wsgi
from opentelemetry import trace as trace_api from opentelemetry import trace as trace_api
from opentelemetry.instrumentation._semconv import ( from opentelemetry.instrumentation._semconv import (
OTEL_SEMCONV_STABILITY_OPT_IN, OTEL_SEMCONV_STABILITY_OPT_IN,
_HTTPStabilityMode,
_OpenTelemetrySemanticConventionStability, _OpenTelemetrySemanticConventionStability,
_server_active_requests_count_attrs_new, _server_active_requests_count_attrs_new,
_server_active_requests_count_attrs_old, _server_active_requests_count_attrs_old,
_server_duration_attrs_new, _server_duration_attrs_new,
_server_duration_attrs_old, _server_duration_attrs_old,
_StabilityMode,
) )
from opentelemetry.sdk.metrics.export import ( from opentelemetry.sdk.metrics.export import (
HistogramDataPoint, HistogramDataPoint,
@ -527,7 +527,7 @@ class TestWsgiAttributes(unittest.TestCase):
attrs = otel_wsgi.collect_request_attributes( attrs = otel_wsgi.collect_request_attributes(
self.environ, self.environ,
_HTTPStabilityMode.HTTP, _StabilityMode.HTTP,
) )
self.assertDictEqual( self.assertDictEqual(
attrs, attrs,
@ -742,7 +742,7 @@ class TestWsgiAttributes(unittest.TestCase):
self.assertGreaterEqual( self.assertGreaterEqual(
otel_wsgi.collect_request_attributes( otel_wsgi.collect_request_attributes(
self.environ, self.environ,
_HTTPStabilityMode.HTTP, _StabilityMode.HTTP,
).items(), ).items(),
expected_new.items(), expected_new.items(),
) )
@ -758,7 +758,7 @@ class TestWsgiAttributes(unittest.TestCase):
self.assertGreaterEqual( self.assertGreaterEqual(
otel_wsgi.collect_request_attributes( otel_wsgi.collect_request_attributes(
self.environ, self.environ,
_HTTPStabilityMode.HTTP, _StabilityMode.HTTP,
).items(), ).items(),
expected_new.items(), expected_new.items(),
) )
@ -769,7 +769,7 @@ class TestWsgiAttributes(unittest.TestCase):
self.span, self.span,
"404 Not Found", "404 Not Found",
{}, {},
sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP, sem_conv_opt_in_mode=_StabilityMode.HTTP,
) )
expected = (mock.call(SpanAttributes.HTTP_STATUS_CODE, 404),) expected = (mock.call(SpanAttributes.HTTP_STATUS_CODE, 404),)
expected_new = ( expected_new = (

View File

@ -109,23 +109,23 @@ OTEL_SEMCONV_STABILITY_OPT_IN = "OTEL_SEMCONV_STABILITY_OPT_IN"
class _OpenTelemetryStabilitySignalType: class _OpenTelemetryStabilitySignalType:
HTTP = "http" HTTP = "http"
DATABASE = "database"
class _HTTPStabilityMode(Enum): class _StabilityMode(Enum):
# http - emit the new, stable HTTP and networking conventions ONLY
HTTP = "http"
# http/dup - emit both the old and the stable HTTP and networking conventions
HTTP_DUP = "http/dup"
# default - continue emitting old experimental HTTP and networking conventions
DEFAULT = "default" DEFAULT = "default"
HTTP = "http"
HTTP_DUP = "http/dup"
DATABASE = "database"
DATABASE_DUP = "database/dup"
def _report_new(mode): def _report_new(mode: _StabilityMode):
return mode.name != _HTTPStabilityMode.DEFAULT.name return mode != _StabilityMode.DEFAULT
def _report_old(mode): def _report_old(mode: _StabilityMode):
return mode.name != _HTTPStabilityMode.HTTP.name return mode not in (_StabilityMode.HTTP, _StabilityMode.DATABASE)
class _OpenTelemetrySemanticConventionStability: class _OpenTelemetrySemanticConventionStability:
@ -135,35 +135,61 @@ class _OpenTelemetrySemanticConventionStability:
@classmethod @classmethod
def _initialize(cls): def _initialize(cls):
with _OpenTelemetrySemanticConventionStability._lock: with cls._lock:
if not _OpenTelemetrySemanticConventionStability._initialized: if cls._initialized:
return
# Users can pass in comma delimited string for opt-in options # Users can pass in comma delimited string for opt-in options
# Only values for http stability are supported for now # Only values for http and database stability are supported for now
opt_in = os.environ.get(OTEL_SEMCONV_STABILITY_OPT_IN, "") opt_in = os.environ.get(OTEL_SEMCONV_STABILITY_OPT_IN)
opt_in_list = []
if opt_in: if not opt_in:
# early return in case of default
cls._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING = {
_OpenTelemetryStabilitySignalType.HTTP: _StabilityMode.DEFAULT,
_OpenTelemetryStabilitySignalType.DATABASE: _StabilityMode.DEFAULT,
}
cls._initialized = True
return
opt_in_list = [s.strip() for s in opt_in.split(",")] opt_in_list = [s.strip() for s in opt_in.split(",")]
http_opt_in = _HTTPStabilityMode.DEFAULT
if opt_in_list: cls._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING[
# Process http opt-in
# http/dup takes priority over http
if _HTTPStabilityMode.HTTP_DUP.value in opt_in_list:
http_opt_in = _HTTPStabilityMode.HTTP_DUP
elif _HTTPStabilityMode.HTTP.value in opt_in_list:
http_opt_in = _HTTPStabilityMode.HTTP
_OpenTelemetrySemanticConventionStability._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING[
_OpenTelemetryStabilitySignalType.HTTP _OpenTelemetryStabilitySignalType.HTTP
] = http_opt_in ] = cls._filter_mode(
_OpenTelemetrySemanticConventionStability._initialized = True opt_in_list, _StabilityMode.HTTP, _StabilityMode.HTTP_DUP
)
cls._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING[
_OpenTelemetryStabilitySignalType.DATABASE
] = cls._filter_mode(
opt_in_list,
_StabilityMode.DATABASE,
_StabilityMode.DATABASE_DUP,
)
cls._initialized = True
@staticmethod
def _filter_mode(opt_in_list, stable_mode, dup_mode):
# Process semconv stability opt-in
# http/dup,database/dup has higher precedence over http,database
if dup_mode.value in opt_in_list:
return dup_mode
return (
stable_mode
if stable_mode.value in opt_in_list
else _StabilityMode.DEFAULT
)
@classmethod @classmethod
# Get OpenTelemetry opt-in mode based off of signal type (http, messaging, etc.)
def _get_opentelemetry_stability_opt_in_mode( def _get_opentelemetry_stability_opt_in_mode(
cls, cls, signal_type: _OpenTelemetryStabilitySignalType
signal_type: _OpenTelemetryStabilitySignalType, ) -> _StabilityMode:
) -> _HTTPStabilityMode: # Get OpenTelemetry opt-in mode based off of signal type (http, messaging, etc.)
return _OpenTelemetrySemanticConventionStability._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING.get( return cls._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING.get(
signal_type, _HTTPStabilityMode.DEFAULT signal_type, _StabilityMode.DEFAULT
) )
@ -171,14 +197,12 @@ def _filter_semconv_duration_attrs(
attrs, attrs,
old_attrs, old_attrs,
new_attrs, new_attrs,
sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode=_StabilityMode.DEFAULT,
): ):
filtered_attrs = {} filtered_attrs = {}
# duration is two different metrics depending on sem_conv_opt_in_mode, so no DUP attributes # duration is two different metrics depending on sem_conv_opt_in_mode, so no DUP attributes
allowed_attributes = ( allowed_attributes = (
new_attrs new_attrs if sem_conv_opt_in_mode == _StabilityMode.HTTP else old_attrs
if sem_conv_opt_in_mode == _HTTPStabilityMode.HTTP
else old_attrs
) )
for key, val in attrs.items(): for key, val in attrs.items():
if key in allowed_attributes: if key in allowed_attributes:
@ -190,7 +214,7 @@ def _filter_semconv_active_request_count_attr(
attrs, attrs,
old_attrs, old_attrs,
new_attrs, new_attrs,
sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode=_StabilityMode.DEFAULT,
): ):
filtered_attrs = {} filtered_attrs = {}
if _report_old(sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode):
@ -367,9 +391,10 @@ def _set_status(
status_code: int, status_code: int,
status_code_str: str, status_code_str: str,
server_span: bool = True, server_span: bool = True,
sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
): ):
if status_code < 0: if status_code < 0:
if _report_new(sem_conv_opt_in_mode):
metrics_attributes[ERROR_TYPE] = status_code_str metrics_attributes[ERROR_TYPE] = status_code_str
if span.is_recording(): if span.is_recording():
if _report_new(sem_conv_opt_in_mode): if _report_new(sem_conv_opt_in_mode):
@ -404,7 +429,7 @@ def _set_status(
# Get schema version based off of opt-in mode # Get schema version based off of opt-in mode
def _get_schema_url(mode: _HTTPStabilityMode) -> str: def _get_schema_url(mode: _StabilityMode) -> str:
if mode is _HTTPStabilityMode.DEFAULT: if mode is _StabilityMode.DEFAULT:
return "https://opentelemetry.io/schemas/1.11.0" return "https://opentelemetry.io/schemas/1.11.0"
return SpanAttributes.SCHEMA_URL return SpanAttributes.SCHEMA_URL

View File

@ -0,0 +1,258 @@
# Copyright The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
import os
from unittest import TestCase
from unittest.mock import Mock, patch
from opentelemetry.instrumentation._semconv import (
OTEL_SEMCONV_STABILITY_OPT_IN,
_OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType,
_set_status,
_StabilityMode,
)
from opentelemetry.trace.status import StatusCode
def stability_mode(mode):
def decorator(test_case):
@patch.dict(os.environ, {OTEL_SEMCONV_STABILITY_OPT_IN: mode})
def wrapper(*args, **kwargs):
_OpenTelemetrySemanticConventionStability._initialized = False
_OpenTelemetrySemanticConventionStability._initialize()
return test_case(*args, **kwargs)
return wrapper
return decorator
class TestOpenTelemetrySemConvStability(TestCase):
@stability_mode("")
def test_default_mode(self):
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.HTTP
),
_StabilityMode.DEFAULT,
)
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.DATABASE
),
_StabilityMode.DEFAULT,
)
@stability_mode("http")
def test_http_stable_mode(self):
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.HTTP
),
_StabilityMode.HTTP,
)
@stability_mode("http/dup")
def test_http_dup_mode(self):
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.HTTP
),
_StabilityMode.HTTP_DUP,
)
@stability_mode("database")
def test_database_stable_mode(self):
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.DATABASE
),
_StabilityMode.DATABASE,
)
@stability_mode("database/dup")
def test_database_dup_mode(self):
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.DATABASE
),
_StabilityMode.DATABASE_DUP,
)
@stability_mode("database,http")
def test_multiple_stability_database_http_modes(self):
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.DATABASE
),
_StabilityMode.DATABASE,
)
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.HTTP
),
_StabilityMode.HTTP,
)
@stability_mode("database,http/dup")
def test_multiple_stability_database_http_dup_modes(self):
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.DATABASE
),
_StabilityMode.DATABASE,
)
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.HTTP
),
_StabilityMode.HTTP_DUP,
)
@stability_mode("database/dup,http")
def test_multiple_stability_database_dup_http_stable_modes(self):
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.DATABASE
),
_StabilityMode.DATABASE_DUP,
)
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.HTTP
),
_StabilityMode.HTTP,
)
@stability_mode("database,database/dup,http,http/dup")
def test_stability_mode_dup_precedence(self):
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.DATABASE
),
_StabilityMode.DATABASE_DUP,
)
self.assertEqual(
_OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.HTTP
),
_StabilityMode.HTTP_DUP,
)
class TestOpenTelemetrySemConvStabilityHTTP(TestCase):
def test_set_status_for_non_http_code_with_recording_span(self):
span = Mock()
span.is_recording.return_value = True
metric_attributes = {}
_set_status(
span,
metric_attributes,
-1,
"Exception",
sem_conv_opt_in_mode=_StabilityMode.DEFAULT,
)
self.assertIsNone(metric_attributes.get("error.type"))
span.set_attribute.assert_not_called()
status_call = span.set_status.call_args[0][0]
self.assertEqual(status_call.status_code, StatusCode.ERROR)
self.assertEqual(
status_call.description, "Non-integer HTTP status: " + "Exception"
)
def test_status_code_http_default(self):
span = Mock()
metrics_attributes = {}
_set_status(
span=span,
metrics_attributes=metrics_attributes,
status_code=404,
status_code_str="404",
server_span=True,
sem_conv_opt_in_mode=_StabilityMode.DEFAULT,
)
# Verify only old conventions are emitted
span.set_attribute.assert_called_with("http.status_code", 404)
self.assertIn("http.status_code", metrics_attributes)
self.assertNotIn("http.response_status_code", metrics_attributes)
def test_status_code_http_stable(self):
span = Mock()
metrics_attributes = {}
_set_status(
span=span,
metrics_attributes=metrics_attributes,
status_code=200,
status_code_str="200",
server_span=True,
sem_conv_opt_in_mode=_StabilityMode.HTTP,
)
# Verify only new conventions are emitted
span.set_attribute.assert_called_with("http.response.status_code", 200)
self.assertIn("http.response.status_code", metrics_attributes)
self.assertNotIn("http.status_code", metrics_attributes)
def test_status_code_http_dup(self):
span = Mock()
metrics_attributes = {}
_set_status(
span=span,
metrics_attributes=metrics_attributes,
status_code=500,
status_code_str="500",
server_span=True,
sem_conv_opt_in_mode=_StabilityMode.HTTP_DUP,
)
# Verify both old and new conventions are emitted
span.set_attribute.assert_any_call("http.status_code", 500)
span.set_attribute.assert_any_call("http.response.status_code", 500)
self.assertIn("http.status_code", metrics_attributes)
self.assertIn("http.response.status_code", metrics_attributes)
def test_error_status_code_new_mode(self):
span = Mock()
metrics_attributes = {}
_set_status(
span=span,
metrics_attributes=metrics_attributes,
status_code=500,
status_code_str="500",
server_span=True,
sem_conv_opt_in_mode=_StabilityMode.HTTP,
)
# Verify error type is set for new conventions
span.set_attribute.assert_any_call("error.type", "500")
self.assertIn("error.type", metrics_attributes)
self.assertEqual(metrics_attributes["error.type"], "500")
def test_non_recording_span(self):
span = Mock()
span.is_recording.return_value = False
metrics_attributes = {}
_set_status(
span=span,
metrics_attributes=metrics_attributes,
status_code=200,
status_code_str="200",
server_span=True,
sem_conv_opt_in_mode=_StabilityMode.HTTP_DUP,
)
# Verify no span attributes are set if not recording
span.set_attribute.assert_not_called()
span.set_status.assert_not_called()
# Verify status code set for metrics independent of tracing decision
self.assertIn("http.status_code", metrics_attributes)
self.assertIn("http.response.status_code", metrics_attributes)