Coverage for src / agent / observability.py: 88%
32 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-11 14:30 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-11 14:30 +0000
1# Copyright 2025-2026 Microsoft Corporation
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
15"""Observability helpers for Agent Base.
17This module provides helper utilities for OpenTelemetry integration.
18The main observability setup is handled by agent_framework.observability.setup_observability().
20For full observability setup, see:
21- agent_framework.observability.setup_observability()
22- Examples: examples/observability_example.py
23- Documentation: docs/decisions/0014-observability-integration.md
24"""
26import contextvars
27import logging
28import socket
29from typing import Any
30from urllib.parse import urlparse
32logger = logging.getLogger(__name__)
34# Context var to hold the current agent span for cross-task propagation
35_current_agent_span: contextvars.ContextVar[Any] = contextvars.ContextVar(
36 "_current_agent_span", default=None
37)
40def set_current_agent_span(span: Any) -> None:
41 """Record the current agent span in a context variable.
43 This helps preserve parent-child relationships for tool spans when
44 asynchronous task boundaries might lose the active span context.
46 Args:
47 span: The agent-level span to set as current
48 """
49 try:
50 _current_agent_span.set(span)
51 except Exception:
52 # Best-effort: ignore issues with context vars in constrained envs
53 pass
56def get_current_agent_span() -> Any:
57 """Retrieve the current agent span from the context variable.
59 Returns:
60 The agent span if set, otherwise None.
61 """
62 try:
63 return _current_agent_span.get()
64 except Exception:
65 return None
68def check_telemetry_endpoint(endpoint: str | None = None, timeout: float = 0.02) -> bool:
69 """Check if telemetry endpoint is reachable.
71 Uses a fast socket connection test with minimal timeout to avoid startup delays.
72 This enables auto-detection of telemetry availability without user configuration.
74 Args:
75 endpoint: OTLP endpoint URL (default: http://localhost:4317)
76 timeout: Connection timeout in seconds (default: 0.02 = 20ms)
78 Returns:
79 True if endpoint is reachable, False otherwise
81 Example:
82 >>> if check_telemetry_endpoint():
83 ... setup_observability()
85 Performance:
86 - When available: ~1-2ms
87 - When unavailable: ~20-30ms (timeout period)
88 """
89 if not endpoint:
90 endpoint = "http://localhost:4317"
92 try:
93 # Parse endpoint URL to extract host and port
94 parsed = urlparse(endpoint)
95 host = parsed.hostname or "localhost"
96 port = parsed.port or 4317
98 # Fast socket connection check
99 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
100 sock.settimeout(timeout)
101 result = sock.connect_ex((host, port))
102 sock.close()
104 return result == 0
105 except Exception as e:
106 logger.debug(f"Telemetry endpoint check failed: {e}")
107 return False