Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/sap_cloud_sdk/core/telemetry/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from sap_cloud_sdk.core.telemetry.genai_operation import GenAIOperation
from sap_cloud_sdk.core.telemetry.metrics_decorator import record_metrics
from sap_cloud_sdk.core.telemetry.auto_instrument import auto_instrument
from sap_cloud_sdk.core.telemetry.config import register_sdk_resource_attributes
from sap_cloud_sdk.core.telemetry.tracer import (
context_overlay,
get_current_span,
Expand Down Expand Up @@ -67,6 +68,7 @@
"set_tenant_id",
"get_tenant_id",
"auto_instrument",
"register_sdk_resource_attributes",
"context_overlay",
"get_current_span",
"add_span_attribute",
Expand Down
30 changes: 30 additions & 0 deletions src/sap_cloud_sdk/core/telemetry/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,34 @@
SDK_NAME,
)

# Registry of extra resource attributes contributed by companion SDKs.
# Populated via register_sdk_resource_attributes() at import time of those SDKs.
_extra_sdk_attributes: dict = {}


def register_sdk_resource_attributes(attributes: dict) -> None:
"""Register additional OTel resource attributes to be included in every provider.

Companion SDKs call this once at import time so their version appears on every
span and metric without any change to agent startup code. Read the version from
``importlib.metadata`` rather than hardcoding it::

from importlib.metadata import version, PackageNotFoundError
from sap_cloud_sdk.core.telemetry.config import register_sdk_resource_attributes

try:
sdk_version = version("my-sdk-package")
except PackageNotFoundError:
sdk_version = "unknown"

register_sdk_resource_attributes({
"sap.my_sdk.version": sdk_version,
"sap.my_sdk.language": "python",
})
"""
_extra_sdk_attributes.update(attributes)


# Default attribute values
DEFAULT_UNKNOWN = "unknown"

Expand Down Expand Up @@ -172,6 +200,8 @@ def create_resource_attributes_from_env() -> dict:
if service_display_name is not None:
attributes[ATTR_SAP_SERVICE_DISPLAY_NAME] = service_display_name

attributes.update(_extra_sdk_attributes)

return attributes


Expand Down
39 changes: 39 additions & 0 deletions tests/core/unit/telemetry/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
create_resource_attributes_from_env,
get_config,
set_config,
register_sdk_resource_attributes,
_extra_sdk_attributes,
)
from sap_cloud_sdk.core.telemetry.constants import (
ATTR_MLFLOW_EXPERIMENT_ID,
Expand Down Expand Up @@ -299,3 +301,40 @@ def test_service_display_name_independent_of_other_attributes(self):

assert attrs[ATTR_SAP_SERVICE_DISPLAY_NAME] == "My Service"
assert attrs[ATTR_SAP_ORD_ID] == "my-ord-id"


class TestRegisterSdkResourceAttributes:
"""Tests for the companion-SDK resource attribute registry."""

def setup_method(self):
_extra_sdk_attributes.clear()

def teardown_method(self):
_extra_sdk_attributes.clear()

def test_registered_attributes_appear_in_resource(self):
register_sdk_resource_attributes({"sap.internal_sdk.version": "1.0.0"})
attrs = create_resource_attributes_from_env()
assert attrs["sap.internal_sdk.version"] == "1.0.0"

def test_multiple_registrations_are_merged(self):
register_sdk_resource_attributes({"sap.foo.version": "1.0"})
register_sdk_resource_attributes({"sap.bar.version": "2.0"})
attrs = create_resource_attributes_from_env()
assert attrs["sap.foo.version"] == "1.0"
assert attrs["sap.bar.version"] == "2.0"

def test_registered_attributes_do_not_override_cloud_sdk_keys(self):
from sap_cloud_sdk.core.telemetry.constants import ATTR_SAP_SDK_VERSION
original = create_resource_attributes_from_env()[ATTR_SAP_SDK_VERSION]
register_sdk_resource_attributes({ATTR_SAP_SDK_VERSION: "999"})
attrs = create_resource_attributes_from_env()
assert attrs[ATTR_SAP_SDK_VERSION] == "999"
_extra_sdk_attributes.clear()
assert create_resource_attributes_from_env()[ATTR_SAP_SDK_VERSION] == original

def test_empty_registry_does_not_affect_output(self):
attrs_without = create_resource_attributes_from_env()
register_sdk_resource_attributes({})
attrs_with = create_resource_attributes_from_env()
assert attrs_without == attrs_with
Loading