Skip to content

Commit e3a5c9d

Browse files
authored
[Core OTel] Add schema version support to OTel plugin (#40161)
This is to support cases where a user might be using the plugin span and wants to set attributes defined in a later version of the OTel schema. This allows passing in a specific version and setting the corresponding schema URL on the tracer instrumentation scope. Signed-off-by: Paul Van Eck <[email protected]>
1 parent bc06de7 commit e3a5c9d

File tree

5 files changed

+49
-11
lines changed

5 files changed

+49
-11
lines changed

sdk/core/azure-core-tracing-opentelemetry/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Features Added
66

77
- If a span exits with an exception, the exception name is now recorded in the `error.type` attribute. ([#34619](https://github.com/Azure/azure-sdk-for-python/pull/34619))
8+
- Added support for passing a schema version to fetch available attribute mappings and set the schema URL on the tracer's instrumentation scope. ([#40161](https://github.com/Azure/azure-sdk-for-python/pull/40161))
89

910
### Breaking Changes
1011

sdk/core/azure-core-tracing-opentelemetry/azure/core/tracing/ext/opentelemetry_span/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
from azure.core.tracing import SpanKind, HttpSpanMixin, Link as CoreLink # type: ignore[attr-defined] # pylint: disable=no-name-in-module
2929

30-
from ._schema import OpenTelemetrySchema
30+
from ._schema import OpenTelemetrySchema, OpenTelemetrySchemaVersion as _OpenTelemetrySchemaVersion
3131
from ._version import VERSION
3232

3333
AttributeValue = Union[
@@ -113,6 +113,8 @@ class OpenTelemetrySpan(HttpSpanMixin, object):
113113
:paramtype links: list[~azure.core.tracing.Link]
114114
:keyword context: Context headers of parent span that should be used when creating a new span.
115115
:paramtype context: Dict[str, str]
116+
:keyword schema_version: The OpenTelemetry schema version to use for the span.
117+
:paramtype schema_version: str
116118
"""
117119

118120
def __init__(
@@ -125,9 +127,7 @@ def __init__(
125127
**kwargs: Any,
126128
) -> None:
127129
self._current_ctxt_manager: Optional[_SuppressionContextManager] = None
128-
129-
# TODO: Once we have additional supported versions, we should add a way to specify the version.
130-
self._schema_version = OpenTelemetrySchema.get_latest_version()
130+
self._schema_version = kwargs.pop("schema_version", _OpenTelemetrySchemaVersion.V1_23_1)
131131
self._attribute_mappings = OpenTelemetrySchema.get_attribute_mappings(self._schema_version)
132132

133133
if span:

sdk/core/azure-core-tracing-opentelemetry/azure/core/tracing/ext/opentelemetry_span/_schema.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def get_latest_version(cls) -> OpenTelemetrySchemaVersion:
5353

5454
@classmethod
5555
def get_attribute_mappings(cls, version: OpenTelemetrySchemaVersion) -> Dict[str, str]:
56-
return cls._ATTRIBUTE_MAPPINGS[version]
56+
return cls._ATTRIBUTE_MAPPINGS.get(version, {})
5757

5858
@classmethod
5959
def get_schema_url(cls, version: OpenTelemetrySchemaVersion) -> str:

sdk/core/azure-core-tracing-opentelemetry/tests/test_schema.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
from opentelemetry.trace import SpanKind as OpenTelemetrySpanKind
88

99
from azure.core.tracing.ext.opentelemetry_span import OpenTelemetrySpan
10-
from azure.core.tracing.ext.opentelemetry_span._schema import OpenTelemetrySchema
10+
from azure.core.tracing.ext.opentelemetry_span._schema import OpenTelemetrySchema, OpenTelemetrySchemaVersion
1111

1212

1313
class TestOpenTelemetrySchema:
1414
def test_latest_schema_attributes_renamed(self, tracing_helper):
1515
with tracing_helper.tracer.start_as_current_span("Root", kind=OpenTelemetrySpanKind.CLIENT) as parent:
1616
wrapped_class = OpenTelemetrySpan(span=parent)
17-
schema_version = OpenTelemetrySchema.get_latest_version()
17+
schema_version = wrapped_class._schema_version
1818
attribute_mappings = OpenTelemetrySchema.get_attribute_mappings(schema_version)
1919
attribute_values = {}
2020
for key, value in attribute_mappings.items():
@@ -42,6 +42,18 @@ def test_latest_schema_attributes_not_renamed(self, tracing_helper):
4242

4343
def test_schema_url_in_instrumentation_scope(self):
4444
with OpenTelemetrySpan(name="span") as span:
45-
schema_version = OpenTelemetrySchema.get_latest_version()
46-
schema_url = OpenTelemetrySchema.get_schema_url(schema_version)
45+
schema_url = OpenTelemetrySchema.get_schema_url(span._schema_version)
4746
assert span.span_instance.instrumentation_scope.schema_url == schema_url
47+
48+
def test_schema_version_argument(self, tracing_helper):
49+
with OpenTelemetrySpan(name="span", schema_version="1.0.0") as span:
50+
assert span._schema_version == "1.0.0"
51+
assert span._attribute_mappings == {}
52+
assert span.span_instance.instrumentation_scope.schema_url == "https://opentelemetry.io/schemas/1.0.0"
53+
54+
def test_schema_version_formats(self, tracing_helper):
55+
assert OpenTelemetrySchema.get_attribute_mappings(OpenTelemetrySchemaVersion.V1_19_0)
56+
assert OpenTelemetrySchema.get_attribute_mappings(OpenTelemetrySchemaVersion.V1_23_1)
57+
assert OpenTelemetrySchema.get_attribute_mappings("1.19.0")
58+
assert OpenTelemetrySchema.get_attribute_mappings("1.23.1")
59+
assert not OpenTelemetrySchema.get_attribute_mappings("1.0.0")

sdk/core/azure-core-tracing-opentelemetry/tests/test_tracing_implementations.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,34 @@ def test_add_attribute(self, tracing_helper):
452452
assert wrapped_class.span_instance.attributes["test"] == "test2"
453453
assert parent.attributes["test"] == "test2"
454454

455-
def test_set_http_attributes(self, tracing_helper):
455+
def test_set_http_attributes_v1_19_0(self, tracing_helper):
456456
with tracing_helper.tracer.start_as_current_span("Root", kind=OpenTelemetrySpanKind.CLIENT) as parent:
457-
wrapped_class = OpenTelemetrySpan(span=parent)
457+
wrapped_class = OpenTelemetrySpan(span=parent, schema_version="1.19.0")
458+
request = mock.Mock()
459+
setattr(request, "method", "GET")
460+
setattr(request, "url", "https://foo.bar/path")
461+
response = mock.Mock()
462+
setattr(request, "headers", {})
463+
setattr(response, "status_code", 200)
464+
wrapped_class.set_http_attributes(request)
465+
assert wrapped_class.span_instance.kind == OpenTelemetrySpanKind.CLIENT
466+
assert wrapped_class.span_instance.attributes.get("http.method") == request.method
467+
assert wrapped_class.span_instance.attributes.get("component") == "http"
468+
assert wrapped_class.span_instance.attributes.get("http.url") == request.url
469+
assert wrapped_class.span_instance.attributes.get("http.status_code") == 504
470+
assert wrapped_class.span_instance.attributes.get("user_agent.original") is None
471+
472+
request.headers["User-Agent"] = "some user agent"
473+
request.url = "http://foo.bar:8080/path"
474+
wrapped_class.set_http_attributes(request, response)
475+
assert wrapped_class.span_instance.attributes.get("http.status_code") == response.status_code
476+
assert wrapped_class.span_instance.attributes.get("user_agent.original") == request.headers.get(
477+
"User-Agent"
478+
)
479+
480+
def test_set_http_attributes_v1_23_1(self, tracing_helper):
481+
with tracing_helper.tracer.start_as_current_span("Root", kind=OpenTelemetrySpanKind.CLIENT) as parent:
482+
wrapped_class = OpenTelemetrySpan(span=parent, schema_version="1.23.1")
458483
request = mock.Mock()
459484
setattr(request, "method", "GET")
460485
setattr(request, "url", "https://foo.bar/path")

0 commit comments

Comments
 (0)