Improvement: Clean Up and Standardize Application Logs
Problem
The current logging output is difficult to read and understand.
A lot of information is printed without a consistent structure, which makes it hard to:
- Follow the execution flow.
- Understand which log belongs to which request/run/conversation.
- Identify errors quickly.
- Search and filter logs.
- Debug issues in production.
- Distinguish useful information from noisy implementation details.
Currently, logs often feel like everything is simply being dumped into the output rather than intentionally logged.
We should introduce a clear and consistent logging format across Extra.
Goal
Logs should be:
- Structured.
- Consistent.
- Easy to scan.
- Easy to search.
- Useful for debugging.
- Correlated across the same execution flow.
- Free from unnecessary dumps/noise.
A developer should be able to look at the logs and immediately understand:
What happened?
For which request/conversation/run?
Which component produced the log?
What was the result?
If something failed, where and why?
Standard Log Format
All logs should follow the same general structure.
For example:
2026-08-20 20:15:32.421 INFO [orchestrator] run_started conversation_id=abc123 run_id=run456 agent_id=invoices_agent
2026-08-20 20:15:32.811 INFO [tool_registry] tool_started tool=get_invoice run_id=run456
2026-08-20 20:15:33.104 INFO [tool_registry] tool_completed tool=get_invoice run_id=run456 duration_ms=293
2026-08-20 20:15:33.220 ERROR [orchestrator] run_failed run_id=run456 error_type=TimeoutError message="Tool execution timed out"
The exact implementation can follow the logging framework already used by Extra, but the format should be consistent everywhere.
Correlation Context
Where applicable, logs should include common identifiers so the complete execution can be traced.
For example:
conversation_id
run_id
request_id
agent_id
tool_name
Not every field is required on every log, but relevant context should be included consistently.
For example:
request
↓
conversation_id=123
↓
run_id=456
↓
agent
↓
tool
Searching for:
should provide a clear view of the complete execution flow.
Log Levels
Log levels should also be used consistently.
INFO
Important lifecycle events:
run_started
run_completed
tool_started
tool_completed
conversation_created
agent_selected
DEBUG
Detailed implementation information useful during development:
resolved configuration
internal state changes
tool arguments metadata
routing decisions
Detailed/debug information should not pollute normal production logs.
WARN
Unexpected but recoverable situations:
fallback used
optional configuration missing
retry triggered
deprecated configuration detected
ERROR
Failures that require attention:
tool execution failure
LLM request failure
validation failure
unexpected exception
Avoid Raw Object Dumps
We should avoid logs like:
INFO request received: {very large object with nested objects, headers, messages, state, config, ...}
or:
DEBUG agent state = {...huge state...}
Instead, log only the fields that are useful for understanding the event.
For example, instead of:
INFO request={...500 lines...}
prefer:
INFO request_received request_id=req123 conversation_id=conv456 message_count=12
Large payloads should only be logged intentionally at DEBUG level when they are actually needed.
Sensitive Information
The logging cleanup should also ensure we do not accidentally dump sensitive information.
Avoid logging raw:
- Authorization headers.
- Tokens.
- Cookies.
- Secrets.
- Credentials.
If a value is required for debugging, it should be sanitized or masked.
For example:
instead of printing the actual token.
Exceptions
Exception logging should also be standardized.
We should avoid both extremes:
with no useful information,
and dumping unnecessary stack traces repeatedly across several layers.
A failure should ideally be logged once at the appropriate boundary with enough context:
ERROR [tool_executor] tool_failed
tool=get_invoice
run_id=run456
error_type=TimeoutError
message="Request timed out"
A stack trace should still be available where appropriate, especially for unexpected exceptions, but should not be duplicated by every layer that catches and rethrows the same error.
Lifecycle Logging
Important flows should have recognizable start/completion events.
For example:
run_started
↓
agent_started
↓
tool_started
↓
tool_completed
↓
agent_completed
↓
run_completed
This will make logs much easier to follow compared with arbitrary messages emitted throughout the code.
Where useful, completion logs should also contain execution duration:
INFO run_completed run_id=run456 duration_ms=1843
Development vs Production
The logging infrastructure should support different verbosity levels.
For example:
Development
→ More DEBUG information
→ Easier local debugging
Production
→ INFO/WARN/ERROR
→ Clean, structured logs
→ No unnecessary payload dumps
We should not rely on large print() statements or ad-hoc debug logging.
Scope
Review the main execution paths and normalize the existing logs, especially around:
- Request handling.
- Conversation lifecycle.
- Run lifecycle.
- Agent execution.
- LLM calls.
- Tool discovery.
- Tool execution.
- MCP execution.
- Validation.
- Approvals.
- Errors and cancellation.
The goal is not simply to change the visual formatter, but to clean up what we log and how we log it.
Acceptance Criteria
- A consistent logging format is used across Extra.
- Important logs contain relevant correlation IDs such as
conversation_id, run_id, and request_id.
- Log levels are used consistently.
- Main lifecycle events have clear start/completion logs.
- Execution duration is included for important operations where useful.
- Large objects and internal state are not dumped into normal logs.
- Detailed implementation logs are moved to
DEBUG where appropriate.
- Sensitive values such as tokens and authorization headers are never printed in plain text.
- Exceptions contain enough context to understand what failed.
- The same exception is not unnecessarily logged multiple times by different layers.
- Existing noisy/ad-hoc logging is cleaned up.
- Production logs are easy to scan and filter.
- Tests are added where applicable for log sanitization and formatting behavior.
Improvement: Clean Up and Standardize Application Logs
Problem
The current logging output is difficult to read and understand.
A lot of information is printed without a consistent structure, which makes it hard to:
Currently, logs often feel like everything is simply being dumped into the output rather than intentionally logged.
We should introduce a clear and consistent logging format across Extra.
Goal
Logs should be:
A developer should be able to look at the logs and immediately understand:
Standard Log Format
All logs should follow the same general structure.
For example:
The exact implementation can follow the logging framework already used by Extra, but the format should be consistent everywhere.
Correlation Context
Where applicable, logs should include common identifiers so the complete execution can be traced.
For example:
Not every field is required on every log, but relevant context should be included consistently.
For example:
Searching for:
should provide a clear view of the complete execution flow.
Log Levels
Log levels should also be used consistently.
INFOImportant lifecycle events:
DEBUGDetailed implementation information useful during development:
Detailed/debug information should not pollute normal production logs.
WARNUnexpected but recoverable situations:
ERRORFailures that require attention:
Avoid Raw Object Dumps
We should avoid logs like:
or:
Instead, log only the fields that are useful for understanding the event.
For example, instead of:
prefer:
Large payloads should only be logged intentionally at
DEBUGlevel when they are actually needed.Sensitive Information
The logging cleanup should also ensure we do not accidentally dump sensitive information.
Avoid logging raw:
If a value is required for debugging, it should be sanitized or masked.
For example:
instead of printing the actual token.
Exceptions
Exception logging should also be standardized.
We should avoid both extremes:
with no useful information,
and dumping unnecessary stack traces repeatedly across several layers.
A failure should ideally be logged once at the appropriate boundary with enough context:
A stack trace should still be available where appropriate, especially for unexpected exceptions, but should not be duplicated by every layer that catches and rethrows the same error.
Lifecycle Logging
Important flows should have recognizable start/completion events.
For example:
This will make logs much easier to follow compared with arbitrary messages emitted throughout the code.
Where useful, completion logs should also contain execution duration:
Development vs Production
The logging infrastructure should support different verbosity levels.
For example:
We should not rely on large
print()statements or ad-hoc debug logging.Scope
Review the main execution paths and normalize the existing logs, especially around:
The goal is not simply to change the visual formatter, but to clean up what we log and how we log it.
Acceptance Criteria
conversation_id,run_id, andrequest_id.DEBUGwhere appropriate.