Skip to content

[Task]32767979: Support AI Foundry by Handling GEN_AI_SYSTEM Attributes #41705

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
span.attributes,
)
elif gen_ai_attributes.GEN_AI_SYSTEM in span.attributes: # GenAI
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These mappings take precedence over other mappings (ex. HTTP) even if their attributes are also present on the span.

This check needs to be moved up before the HTTP check.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just curious, why it was added after other mappings originally?

Copy link
Member Author

@Karlie-777 Karlie-777 Jun 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

read the spec again, I assume it should mean gen_ai attribute value should override all other values (please correct me if I am wrong)
if we put gen_ai logic before http mapping, for example:

if attributes[gen_ai]
... // gen_ai mapping

if HTTP_REQUEST_METHOD in attributes // http mappings
... // other mappings

then the gen_ai value will be reset by other attribute values.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so put gen_ai mapping after all other mappings, then gen_ai value will take precedence over other values

data.type = span.attributes[gen_ai_attributes.GEN_AI_SYSTEM]
data.type = "GenAI | {}".format(span.attributes[gen_ai_attributes.GEN_AI_SYSTEM])
else:
data.type = "N/A"
elif span.kind is SpanKind.PRODUCER: # Messaging
Expand All @@ -428,6 +428,8 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
data.type = "InProc"
if _AZURE_SDK_NAMESPACE_NAME in span.attributes:
data.type += " | {}".format(span.attributes[_AZURE_SDK_NAMESPACE_NAME])
elif gen_ai_attributes.GEN_AI_SYSTEM in span.attributes: # GenAI
data.type = "GenAI | {}".format(span.attributes[gen_ai_attributes.GEN_AI_SYSTEM])
# Apply truncation
# See https://github.com/MohanGsk/ApplicationInsights-Home/tree/master/EndpointSpecs/Schemas/Bond
if data.name:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
user_agent_attributes,
)
from opentelemetry.semconv.trace import DbSystemValues, SpanAttributes
from opentelemetry.semconv._incubating.attributes import gen_ai_attributes
from opentelemetry.util.types import Attributes


Expand Down Expand Up @@ -202,6 +203,11 @@ def _get_target_and_path_for_http_dependency(
target = parsed_url.hostname
elif parsed_url.netloc:
target = parsed_url.netloc
elif gen_ai_attributes.GEN_AI_SYSTEM in attributes:
# If no fields are available to set target using standard rules, set Dependency Target to gen_ai.system if present
gen_ai_system = attributes.get(gen_ai_attributes.GEN_AI_SYSTEM)
if gen_ai_system:
target = gen_ai_system
if not target:
# Get target from peer.* attributes that are NOT peer.service
target = _get_target_for_dependency_from_peer(attributes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -762,8 +762,32 @@ def test_span_to_envelope_client_gen_ai(self):
self.assertEqual(envelope.data.base_data.result_code, "0")

self.assertEqual(envelope.data.base_type, "RemoteDependencyData")
self.assertEqual(envelope.data.base_data.type, "az.ai.inference")
self.assertEqual(envelope.data.base_data.type, "GenAI | az.ai.inference")
self.assertEqual(len(envelope.data.base_data.properties), 1)

def test_span_to_envelope_client_internal_genai_type(self):
exporter = self._exporter
start_time = 1575494316027613500
end_time = start_time + 1001000000

span = trace._Span(
name="genai-test",
context=SpanContext(
trace_id=36873507687745823477771305566750195431,
span_id=12030755672171557337,
is_remote=False,
),
attributes={
"gen_ai.system": "az.ai.inference",
},
kind=SpanKind.INTERNAL,
)
span.start(start_time=start_time)
span.end(end_time=end_time)
span._status = Status(status_code=StatusCode.UNSET)
envelope = exporter._span_to_envelope(span)

self.assertEqual(envelope.data.base_data.type, "GenAI | az.ai.inference")

def test_span_to_envelope_client_azure(self):
exporter = self._exporter
Expand Down
Loading