bat.telemetry.attributes
OpenTelemetry attribute names and values set on the ADK's own spans.
GEN_AI_OPERATION_NAME
GEN_AI_OPERATION_NAME = "gen_ai.operation.name"
The operation a span performs, e.g. OP_INVOKE_AGENT.
GEN_AI_AGENT_NAME
GEN_AI_AGENT_NAME = "gen_ai.agent.name"
The name of the agent the span belongs to.
GEN_AI_CONVERSATION_ID
GEN_AI_CONVERSATION_ID = "gen_ai.conversation.id"
The conversation (A2A context) id.
OP_INVOKE_AGENT
OP_INVOKE_AGENT = "invoke_agent"
GEN_AI_OPERATION_NAME value of a span invoking an agent.
BAT_TASK_ID
BAT_TASK_ID = "bat.a2a.task_id"
The A2A task id: with the conversation id, it selects one turn's spans.
BAT_A2A_TASK_STATE
BAT_A2A_TASK_STATE = "bat.a2a.task_state"
Final A2A TaskState of a call to another agent, on CallAgentNode's span.
SESSION_ID
SESSION_ID = "session.id"
Groups a conversation's traces into one Phoenix session (the context id).
OPENINFERENCE_PROJECT_NAME
OPENINFERENCE_PROJECT_NAME = "openinference.project.name"
Resource attribute selecting the Phoenix project. Agents that share a distributed trace must share a project, or the trace fragments.
INPUT_VALUE
INPUT_VALUE = "input.value"
Span input, shown by Phoenix as a span's Input.
OUTPUT_VALUE
OUTPUT_VALUE = "output.value"
Span output, shown by Phoenix as a span's Output.
bat.telemetry.setup
setup_telemetry
def setup_telemetry(config: Optional[TelemetryConfig] = None) -> bool
Install the global tracer provider, exporters and LangChain instrumentation. Idempotent.
Returns:
bool-Falsewhen telemetry is disabled or thetelemetryextra is missing (logged; the agent keeps running without it).
shutdown_telemetry
def shutdown_telemetry() -> None
Flush buffered spans and close the exporters. Idempotent; registered
with atexit by :func:setup_telemetry.
mark_span_error
def mark_span_error(span: Any, description: str) -> None
Set span's status to ERROR, saying why.
Trace readers (the eval engine, Phoenix) key off the status, not the recorded exception. A no-op without the telemetry extra.
get_tracer
def get_tracer(name: str) -> Any
Return a tracer for name; a no-op one without the telemetry extra.
OTel's tracer is a proxy that starts recording once
:func:setup_telemetry installs the provider, so a module-level
tracer = get_tracer(__name__) captured at import time still works.
inject_context
def inject_context(carrier: Dict[str, str],
span: Optional[Any] = None) -> Dict[str, str]
Inject the current trace context, or span's, into carrier.
Pass span from async generators that yield across tasks, where
attaching it to the ambient context would break the contextvars
detach.
extract_context
def extract_context(carrier: Dict[str, str]) -> Optional[Any]
Extract a trace context from carrier; None when unavailable.
is_enabled
def is_enabled() -> bool
Whether telemetry has been successfully initialized.
bat.telemetry.privacy
Telemetry privacy levels: one ordered dial instead of several booleans.
Each level is a superset of the one below it, so the setting reads as "how much of the agent's internals may leave the process" rather than as a set of independent switches that can be combined into states nobody designed.
Being ordered is also what makes the privacy floor simple: an agent sets a
minimum level in its own source and the effective level is max(floor, configured) -- see :func:resolve_privacy. With booleans this was an OR
per flag; with a ladder it is one comparison that cannot express a
contradiction.
Levels
none (0)
No redaction. Spans carry prompts, completions, tool definitions and
node names in full. The default.
content (1)
Redact what the agent says and knows: prompts, messages, completions,
invocation parameters, and every tool's description, parameter schema and
call arguments. Tool names and node names still export, so traces stay
fully navigable and the eval engine's tool-call metrics keep working.
names (2)
Also redact span names, so LangGraph node names stop leaking. Span kinds
(LLM/CHAIN/TOOL) replace them, so the trace keeps its shape.
The eval engine is still unaffected.
full (3)
Also redact tool names. Only token counts, span kinds, hierarchy and
timing survive. NOTE: the eval engine reconstructs per-episode tool calls
from span attributes and keys its metrics off the tool name, so at this
level those metrics go empty. Use it when the tool inventory itself is
considered proprietary.
TelemetryPrivacyLevel
TelemetryPrivacyLevel = Literal["none", "content", "names", "full"]
TelemetryPrivacyLevel is a type alias for the names of the
TelemetryPrivacy levels, as written in config.yaml.
TelemetryPrivacy Objects
class TelemetryPrivacy(IntEnum)
How much of the agent's internals may leave the process.
Ordered and cumulative: each level redacts everything the level below it does. See the module docstring for what each one covers.
hides_content
@property
def hides_content() -> bool
Prompts, completions and tool descriptions/schemas/arguments.
hides_span_names
@property
def hides_span_names() -> bool
Span (LangGraph node) names.
hides_tool_names
@property
def hides_tool_names() -> bool
Tool names (costs the eval engine its tool-call metrics).
parse_privacy
def parse_privacy(value: object) -> TelemetryPrivacy
Coerce a config.yaml value into a :class:TelemetryPrivacy.
Accepts the level name (case-insensitive) or its ordinal; None means
"not configured" and maps to :attr:TelemetryPrivacy.NONE.
Raises:
ValueError- For anything else. A typo'd level must fail loudly, not fall back tononeand export in the clear.
resolve_privacy
def resolve_privacy(configured: object,
floor: object = TelemetryPrivacy.NONE) -> TelemetryPrivacy
Combine what config.yaml asked for with the agent's own floor,
choosing the more private of the two.
Arguments:
configuredobject - The levelconfig.yamlasked for, as a level name, an ordinal, or a :class:TelemetryPrivacy.floorobject - The minimum the agent allows. Defaults to :attr:TelemetryPrivacy.NONE, which leavesconfiguredto decide alone.
Raises:
ValueError- Ifconfiguredis not a known level.
bat.telemetry.config
ExporterSpec Objects
@dataclass
class ExporterSpec()
One span destination.
Attributes:
kindstr -"file","otlp"or"console".file_pathOptional[str] - JSONL file, forfile.traces_endpointOptional[str] - OTLP/HTTP traces URL, forotlp.
TelemetryConfig Objects
@dataclass
class TelemetryConfig()
Resolved telemetry settings.
Attributes:
enabledbool - Master switch.service_namestr - Theservice.nameresource attribute.project_nameOptional[str] - Phoenix project (theopeninference.project.nameresource attribute);Noneleaves Phoenix'sdefaultproject.privacyTelemetryPrivacy - See :mod:bat.telemetry.privacy.exportersList[ExporterSpec] - Every span goes to all of them.
from_settings
@classmethod
def from_settings(
cls,
*,
enabled: bool = False,
service_name: Optional[str] = None,
project_name: Optional[str] = None,
privacy: object = None,
outputs: Optional[List[Dict[str, Any]]] = None,
default_service_name: Optional[str] = None) -> "TelemetryConfig"
Build a :class:TelemetryConfig from the config.yaml
telemetry section.
service_name falls back to default_service_name (the agent
card name), then DEFAULT_SERVICE_NAME. Each outputs entry is
a dict with type (local/remote/console) and
file_path or endpoint; unknown types are skipped.