Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
5f81dca
Enable A365 tracing in agentserver-core when hosted
singankit May 4, 2026
0392a27
Add agent_id, blueprint_id, and tenant_id resolution to tracing enric…
singankit May 4, 2026
8db62c6
Enable a365_enable_observability_exporter in A365 tracing config
singankit May 4, 2026
d8bb33e
Add a365_observability_scope_override to A365 tracing config
singankit May 5, 2026
a0c1637
Fix streaming context: capture full context (span + baggage) for iter…
singankit May 5, 2026
046cc7b
Fix baggage propagation: extract only W3C baggage from request headers
singankit May 6, 2026
aee8584
Fix W3C baggage propagation in invocations and add tests for both pac…
singankit May 6, 2026
167bd4a
Fix test: remove assertion for server-added baggage at span start time
singankit May 6, 2026
ce9ae4f
Fix test: use correct span name 'invoke_agent' instead of 'create_res…
singankit May 6, 2026
dab1c87
Fix invocations test: remove assertion for server-added baggage at sp…
singankit May 6, 2026
078502d
Add bkey/bval to local cspell ignore lists
singankit May 6, 2026
3cda909
Remove unused imports detach_context and set_current_span
singankit May 6, 2026
d9d5982
Add enable_sensitive_data param to configure_observability
singankit May 7, 2026
36b9d38
Fix test assertions to include enable_sensitive_data param
singankit May 7, 2026
0a1e5ec
Add microsoft.foundry.agent.type attribute scoped to invoke_agent spans
singankit May 8, 2026
0c0eea7
Remove invoke_agent SERVER span, keep W3C context propagation
singankit May 13, 2026
b9c187c
Add proper span parenting test for responses package
singankit May 13, 2026
7410482
Bump azure-ai-agentserver-core min dependency to >=2.0.0b4
singankit May 14, 2026
21e8641
Make request_context backward-compatible with core 2.0.0b3
singankit May 14, 2026
69b2660
Add e2e span parenting test with real caller span
singankit May 14, 2026
baf6478
Stamp invocation_id on spans via FoundryEnrichmentSpanProcessor and a…
singankit May 14, 2026
dff280f
Fix CI test failures: prevent OTel distro from contaminating global s…
singankit May 14, 2026
5857a8b
fix: use inject(headers) in traceparent test for CI reliability
singankit May 14, 2026
400d271
refactor: use OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT for …
singankit May 14, 2026
871e203
fix: use inject(headers) in invocations traceparent tests for CI reli…
singankit May 15, 2026
4290e21
Fix test_incoming_baggage_stamped_on_handler_spans for CI
singankit May 15, 2026
8047e3f
Merge origin/main into feature/enable-a365-tracing
singankit May 15, 2026
61e3a0e
Fix pylint errors: line-too-long and unused imports
singankit May 15, 2026
7ff6248
Simplify request_context() and add debug logging
singankit May 15, 2026
58806dc
Fix debug log: use get_current_span() instead of non-existent get_spa…
singankit May 15, 2026
6faa575
debug: log raw trace headers and full post-attach span context
singankit May 15, 2026
dd97f34
debug: create SERVER span in request_context for downstream instrumen…
singankit May 15, 2026
c19a4a7
debug: test span without explicit parent context
singankit May 15, 2026
422eb1d
debug: re-enable context=ctx on blah span to parent under remote trace
singankit May 15, 2026
dcbb745
feat: add Starlette OTel instrumentation for automatic HTTP SERVER spans
singankit May 15, 2026
9b7ee76
refactor: replace request_context with BaggageMiddleware + Starlette …
singankit May 16, 2026
7939515
Suppress noisy ASGI receive/send internal spans
singankit May 16, 2026
9db26d2
Test: remove BaggageMiddleware to isolate NonRecordingSpan crash
singankit May 16, 2026
55698eb
Replace Starlette instrumentor with TraceContextMiddleware
singankit May 16, 2026
c76059f
Fix TraceContextMiddleware: use opentelemetry.propagate.extract
singankit May 16, 2026
51b7c7b
Remove unused opentelemetry-instrumentation-starlette dependency
singankit May 16, 2026
7d73600
Fix pylint: trailing newline and unused contextlib import
singankit May 16, 2026
4d6e1e9
Fix E2E tracing test: skip distro mock when running with -m tracing_e2e
singankit May 17, 2026
c7dae15
Fix core E2E tests: remove request_context() calls
singankit May 17, 2026
7d116bf
Fix E2E test: use get_span_context() instead of .context
singankit May 17, 2026
c40da1b
Add E2E test: framework spans emitted without incoming trace context
singankit May 17, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,14 @@ def __init__(

# Observability (logging + tracing) --------------------------------
_conn_str = applicationinsights_connection_string or self.config.appinsights_connection_string
_env_val = os.environ.get("OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT", "true")
_sensitive_data = _env_val.lower() not in ("false", "0")
if configure_observability is not None:
try:
configure_observability(
connection_string=_conn_str,
log_level=log_level,
enable_sensitive_data=_sensitive_data,
)
except ValueError:
raise # invalid log_level etc. — user should fix their config
Expand Down Expand Up @@ -284,6 +287,13 @@ async def _lifespan(_app: Starlette) -> AsyncGenerator[None, None]: # noqa: RUF
**kwargs,
)

# Extract W3C trace context (traceparent/tracestate) and baggage
# from incoming HTTP requests so that any spans created downstream
# (e.g. by MAF / agent-framework) are children of the caller's trace.
# We do NOT create a SERVER span ourselves — we only propagate context.
from azure.ai.agentserver.core._tracing import TraceContextMiddleware # pylint: disable=import-outside-toplevel
self.add_middleware(TraceContextMiddleware)

# ------------------------------------------------------------------
# Server version (x-platform-server header)
# ------------------------------------------------------------------
Expand Down Expand Up @@ -326,56 +336,6 @@ def _build_server_version(self) -> str:
# Tracing (for protocol subclasses)
# ------------------------------------------------------------------

#: Default instrumentation scope for tracing spans.
#: Protocol subclasses should override this per the spec.
_INSTRUMENTATION_SCOPE = "Azure.AI.AgentServer"

@contextlib.contextmanager
def request_span(
self,
headers: Any,
request_id: str,
operation: str,
*,
operation_name: Optional[str] = None,
session_id: str = "",
end_on_exit: bool = True,
) -> Any:
"""Create a request-scoped span with this host's identity attributes.

Delegates to :func:`_tracing.request_span` with pre-populated
agent identity from environment variables.

:param headers: HTTP request headers.
:type headers: any
:param request_id: The request/invocation ID.
:type request_id: str
:param operation: Span operation (e.g. ``"invoke_agent"``).
:type operation: str
:keyword operation_name: Optional ``gen_ai.operation.name`` value.
:paramtype operation_name: str or None
:keyword session_id: Session ID.
:paramtype session_id: str
:keyword end_on_exit: Whether to end the span when the context exits.
:paramtype end_on_exit: bool
:return: Context manager yielding the OTel span.
:rtype: any
"""
with _tracing.request_span(
headers,
request_id,
operation,
agent_id=self.config.agent_id,
agent_name=self.config.agent_name,
agent_version=self.config.agent_version,
project_id=self.config.project_id,
operation_name=operation_name,
session_id=session_id,
end_on_exit=end_on_exit,
instrumentation_scope=self._INSTRUMENTATION_SCOPE,
) as span:
yield span

# ------------------------------------------------------------------
# Shutdown handler (server-level lifecycle)
# ------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@

_ENV_FOUNDRY_AGENT_NAME = "FOUNDRY_AGENT_NAME"
_ENV_FOUNDRY_AGENT_VERSION = "FOUNDRY_AGENT_VERSION"
_ENV_FOUNDRY_AGENT_INSTANCE_CLIENT_ID = "FOUNDRY_AGENT_INSTANCE_CLIENT_ID"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

_ENV_FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID = "FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID"
_ENV_FOUNDRY_AGENT_TENANT_ID = "FOUNDRY_AGENT_TENANT_ID"
_ENV_FOUNDRY_HOSTING_ENVIRONMENT = "FOUNDRY_HOSTING_ENVIRONMENT"
_ENV_FOUNDRY_PROJECT_ENDPOINT = "FOUNDRY_PROJECT_ENDPOINT"
_ENV_FOUNDRY_PROJECT_ARM_ID = "FOUNDRY_PROJECT_ARM_ID"
Expand Down Expand Up @@ -283,6 +286,46 @@ def resolve_agent_version() -> str:
return os.environ.get(_ENV_FOUNDRY_AGENT_VERSION, "")


def resolve_agent_id() -> str:
"""Resolve the agent ID.

Resolution order:
1. ``FOUNDRY_AGENT_INSTANCE_CLIENT_ID`` environment variable.
2. ``<agent_name>:<agent_version>`` if both are set.
3. ``<agent_name>`` if only name is set.
4. Empty string if nothing is available.

:return: The resolved agent ID, or an empty string if not determinable.
:rtype: str
"""
agent_id = os.environ.get(_ENV_FOUNDRY_AGENT_INSTANCE_CLIENT_ID, "")
if agent_id:
return agent_id
agent_name = os.environ.get(_ENV_FOUNDRY_AGENT_NAME, "")
agent_version = os.environ.get(_ENV_FOUNDRY_AGENT_VERSION, "")
if agent_name and agent_version:
return f"{agent_name}:{agent_version}"
return agent_name


def resolve_agent_blueprint_id() -> str:
"""Resolve the agent blueprint client ID from the ``FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID`` environment variable.

:return: The agent blueprint client ID, or an empty string if not set.
:rtype: str
"""
return os.environ.get(_ENV_FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID, "")


def resolve_agent_tenant_id() -> str:
"""Resolve the agent tenant ID from the ``FOUNDRY_AGENT_TENANT_ID`` environment variable.

:return: The agent tenant ID, or an empty string if not set.
:rtype: str
"""
return os.environ.get(_ENV_FOUNDRY_AGENT_TENANT_ID, "")


def resolve_project_id() -> str:
"""Resolve the Foundry project ARM resource ID from the ``FOUNDRY_PROJECT_ARM_ID`` environment variable.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class Constants:
# Tracing
APPLICATIONINSIGHTS_CONNECTION_STRING = "APPLICATIONINSIGHTS_CONNECTION_STRING"
OTEL_EXPORTER_OTLP_ENDPOINT = "OTEL_EXPORTER_OTLP_ENDPOINT"
FOUNDRY_AGENT365_TRACING_ENABLED = "FOUNDRY_AGENT365_TRACING_ENABLED"
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT = "OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"

# SSE keep-alive
SSE_KEEPALIVE_INTERVAL = "SSE_KEEPALIVE_INTERVAL"
Expand Down
Loading
Loading