Agent
Core reference

Agent Logger

The AgentLogger is the specialized structured logging engine for the jazzmine agent system. It is designed to provide high-fidelity observability into the internal life of an agent. Unlike standard prose-based logging, the AgentLogger emits Semantic Events—standardized, JSON-serializable records that allow dashboards, alert systems, and developers to track the agent's reasoning, tool execution, and resource consumption with mathematical precision.

Agent: agent_logger

1. Behavior and Context

In the jazzmine architecture, the logger is the "Observability Hub." It is deeply integrated with the Agent.chat() loop through a unique Correlation Design:

  • Context-Aware Logging: It utilizes structlog and Python's contextvars. By calling turn_context() at the start of a message turn, the logger binds fields like trace_id, conversation_id, and turn_number to the current execution thread.
  • Automatic Inheritance: Every log call made anywhere in the agent's call stack—including internal components like the ToolOrchestrator, ScriptExecutor, or MessageEnhancer—automatically inherits these correlation fields. No parameters need to be passed down the stack.
  • Graceful Fallback: It features a "Zero-Dependency" fallback. If the optional jazzmine-logging package is missing, the logger automatically switches to standard library logging while preserving the structured field metadata.
  • Async-Native: It supports asynchronous sink workers (e.g., sending logs to Datadog or Loki) that run in the background to minimize the impact on the agent's response latency.

2. Purpose

  • Correlation & Tracing: Providing a single thread of logs that link one specific user message to dozens of internal events (LLM calls, sandbox executions, memory hits).
  • Performance Monitoring: Recording latencies for every sub-step (recall, generation, execution) to identify bottlenecks.
  • Cost & Token Auditing: Aggregating token usage per turn for accurate billing and quota management.
  • Lifecycle Tracking: Monitoring when skills (Flows) are started, completed, or cancelled.
  • Incident Response: Capturing structured error events (agent_error) with specific "Stage" labels for fast diagnosis.

3. High-Level API

The AgentLogger is usually initialized via the factory and used within the Agent core.

Example: Manual Initialization and Context Binding

python
from jazzmine.core.agent.agent_logger import AgentLogger

# 1. Initialize from a standard config dict
logger = AgentLogger.from_config({
    "name": "Aria",
    "level": "INFO",
    "json": True,
    "sinks": [{"type": "console"}]
})

# 2. Bind context for a turn
with logger.turn_context(
    trace_id="msg_uuid_123",
    conversation_id="conv_abc",
    user_id="user_99",
    agent_id="bot_v1",
    turn_number=5
):
    # This call automatically carries all IDs above in its JSON payload
    logger.flow_selected(flow_name="refund", flow_type="action")

5. Detailed Functionality

Event (Constant Class)

Defines the stable string identifiers for events. Dashboards should hard-code these strings for filtering:

  • TURN_START, TURN_END
  • FLOW_SELECTED, FLOW_EVENT
  • TASK_DISPATCHED, TOOL_RESULT
  • SCRIPT_GENERATED, SCRIPT_EXECUTED
  • LLM_CALL, MEMORY_RECALL, AGENT_ERROR

Factory Methods

noop() [Class Method]

Returns a functional logger that emits only to standard structlog. Used as the fallback to ensure the agent never crashes due to a missing logging configuration.

from_config(config, agent_name="agent") [Class Method]

The primary way to build a production logger. It attempts to load BaseLogger from jazzmine-logging. If the package isn't installed, it logs a warning and returns a standard structlog instance.


Correlation Management

turn_context(trace_id, conversation_id, user_id, agent_id, turn_number)

Functionality: An asynchronous-safe context manager that binds correlation IDs to the current execution task.

  • Mechanism: Uses structlog.contextvars.bind_contextvars.
  • Cleanup: Automatically unbinds the variables when the context exits, ensuring that the next task in the event loop doesn't "leak" the previous turn's context.

Semantic Log Methods

Each of these methods emits a structured event. Fields are kept Flat (no nested objects) to allow for easy filtering and faceting in tools like Kibana or Datadog.

turn_start(content_len, has_tools, has_memory)

Emitted the millisecond chat() is called.

  • Fields: Input message length and a snapshot of the agent's configured capabilities.

llm_call(purpose, model, prompt_tokens, completion_tokens, latency_ms, success, ...)

Records a single round-trip to an LLM provider.

  • purpose: Distinguishes between agent_loop, slot_extraction, script_gen, etc.

script_generated(sandbox, attempt, ...)

Emitted inside the ToolOrchestrator after the LLM produces Python code.

  • ast_ok: Boolean field indicating if the script passed the security/validation check.

script_executed(sandbox, attempt, success, duration_ms, ...)

Emitted after the Docker container runs the script.

  • result_keys: Captures the top-level keys of the JSON result (without values) to verify data shape without logging sensitive data.

tool_result(sandbox, success, total_attempts, total_ms, ...)

The "Outer Summary" of a task delegation. Useful for high-level success-rate tracking.

turn_end(total_latency_ms, total_prompt_tokens, total_completion_tokens, ...)

The final event of the turn. This is the most important record for monitoring.

  • Fields: Aggregate token costs, lists of invoked flows/tools, error counts, and response length.

6. Error Handling

  • Import Safety: The module uses a try...except ImportError block when referencing jazzmine.logging. This ensures that jazzmine remains lightweight and doesn't force a large logging dependency on the user.
  • Emission Safety: The internal _emit method wraps all sink calls in a try...except. If a remote sink (like Datadog) is unreachable, the logger logs a debug message to stderr but allows the agent turn to continue.
  • Type Safety: turn_context binds standard strings and integers. If complex objects are passed, the underlying structlog processor handles stringification to prevent serialization errors.

7. Remarks

  • Flat Field Philosophy: Every method avoids nested dictionaries. This is intentional; modern log aggregators perform significantly faster and provide better visualization when querying flat fields (e.g., total_tokens vs usage.total).
  • Correlation ID: The framework uses the Message ID as the trace_id. This creates a perfect link between the record in the MessageStore and every log line in your external logging stack.
  • Lifecycle: AgentLogger should be started (await logger.start()) at application boot to initialize background workers and shut down (await logger.shutdown()) to ensure no logs are lost in the buffer.