Observability¶
Structured logging, event constants, correlation tracking, and log sinks.
Logger¶
observability
¶
Observability module for structured logging and correlation tracking.
Provides:
- Structured logging via structlog with stdlib bridge
- Log configuration with console and file sinks
- Sensitive field sanitization
- Correlation ID tracking via context variables
.. note::
Call :func:`configure_logging` once at application startup to
initialise the logging pipeline. Use :func:`get_logger` in all
modules to obtain a bound structured logger.
get_logger
¶
Get a structured logger bound to the given name.
Thin wrapper over :func:structlog.get_logger that ensures
consistent logger creation across the codebase.
Usage::
from synthorg.observability import get_logger
logger = get_logger(__name__)
logger.info("something happened", key="value")
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Logger name, typically |
required |
**initial_bindings
|
Any
|
Key-value pairs bound to every log entry. |
{}
|
Returns:
| Type | Description |
|---|---|
BoundLogger
|
A bound structlog logger. |
Source code in src/synthorg/observability/_logger.py
Config¶
config
¶
Observability configuration models.
Frozen Pydantic models for log sinks, rotation, and top-level logging configuration. All models are immutable and validated on construction.
.. note::
``DEFAULT_SINKS`` provides the standard eleven-sink layout described
in the design spec (console + ten file sinks).
RotationConfig
pydantic-model
¶
Bases: BaseModel
Log file rotation configuration.
Attributes:
| Name | Type | Description |
|---|---|---|
strategy |
RotationStrategy
|
Rotation mechanism to use. |
max_bytes |
int
|
Maximum file size in bytes before rotation.
Only used when |
backup_count |
int
|
Number of rotated backup files to keep. |
compress_rotated |
bool
|
Whether to gzip-compress rotated backup files. Only supported with builtin rotation. |
Config:
frozen:Trueallow_inf_nan:False
Fields:
-
strategy(RotationStrategy) -
max_bytes(int) -
backup_count(int) -
compress_rotated(bool)
Validators:
-
_reject_compress_with_external
SinkConfig
pydantic-model
¶
Bases: BaseModel
Configuration for a single log output destination.
Attributes:
| Name | Type | Description |
|---|---|---|
sink_type |
SinkType
|
Where to send log output. |
level |
LogLevel
|
Minimum log level for this sink. |
file_path |
str | None
|
Relative path for FILE sinks (within |
rotation |
RotationConfig | None
|
Rotation settings for FILE sinks. |
json_format |
bool
|
Whether to format output as JSON. |
syslog_host |
str | None
|
Hostname for SYSLOG sinks. |
syslog_port |
int
|
Port for SYSLOG sinks. |
syslog_facility |
SyslogFacility
|
Syslog facility code. |
syslog_protocol |
SyslogProtocol
|
Transport protocol (TCP or UDP). |
http_url |
str | None
|
Endpoint URL for HTTP sinks. |
http_headers |
tuple[tuple[str, str], ...]
|
Extra HTTP headers as |
http_batch_size |
int
|
Records per HTTP POST batch. |
http_flush_interval_seconds |
float
|
Seconds between automatic flushes. |
http_timeout_seconds |
float
|
HTTP request timeout. |
http_max_retries |
int
|
Retry count on HTTP failure. |
Config:
frozen:Trueallow_inf_nan:False
Fields:
-
sink_type(SinkType) -
level(LogLevel) -
file_path(str | None) -
rotation(RotationConfig | None) -
json_format(bool) -
syslog_host(str | None) -
syslog_port(int) -
syslog_facility(SyslogFacility) -
syslog_protocol(SyslogProtocol) -
http_url(str | None) -
http_headers(tuple[tuple[str, str], ...]) -
http_batch_size(int) -
http_flush_interval_seconds(float) -
http_timeout_seconds(float) -
http_max_retries(int)
Validators:
-
_validate_sink_type_fields
http_flush_interval_seconds
pydantic-field
¶
Seconds between automatic flushes
LogConfig
pydantic-model
¶
Bases: BaseModel
Top-level logging configuration.
Attributes:
| Name | Type | Description |
|---|---|---|
root_level |
LogLevel
|
Root logger level (handlers filter individually). |
logger_levels |
tuple[tuple[NotBlankStr, LogLevel], ...]
|
Per-logger level overrides as |
sinks |
tuple[SinkConfig, ...]
|
Tuple of sink configurations. |
enable_correlation |
bool
|
Whether to enable correlation ID tracking. |
log_dir |
NotBlankStr
|
Directory for log files. |
Config:
frozen:Trueallow_inf_nan:False
Fields:
-
root_level(LogLevel) -
logger_levels(tuple[tuple[NotBlankStr, LogLevel], ...]) -
sinks(tuple[SinkConfig, ...]) -
enable_correlation(bool) -
log_dir(NotBlankStr)
Validators:
-
_validate_at_least_one_sink -
_validate_no_duplicate_logger_names -
_validate_no_duplicate_file_paths -
_validate_no_duplicate_syslog_endpoints -
_validate_no_duplicate_http_urls -
_validate_log_dir_safe
enable_correlation
pydantic-field
¶
Whether to enable correlation ID tracking
Correlation¶
correlation
¶
Correlation ID management for structured logging.
Uses structlog's contextvars integration for async-safe context propagation across agent actions, tasks, and API requests.
.. note::
All binding functions are safe to call from both sync and async
code because Python's :mod:`contextvars` is natively async-aware.
generate_correlation_id
¶
Generate a new correlation ID.
Returns:
| Type | Description |
|---|---|
str
|
A UUID4 string suitable for use as a correlation identifier. |
bind_correlation_id
¶
Bind correlation IDs to the current context.
Only non-None values are bound. Existing bindings for
unspecified keys are left unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request_id
|
str | None
|
Request correlation identifier. |
None
|
task_id
|
str | None
|
Task correlation identifier. |
None
|
agent_id
|
str | None
|
Agent correlation identifier. |
None
|
Source code in src/synthorg/observability/correlation.py
unbind_correlation_id
¶
Remove specific correlation IDs from the current context.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request_id
|
bool
|
Whether to unbind the |
False
|
task_id
|
bool
|
Whether to unbind the |
False
|
agent_id
|
bool
|
Whether to unbind the |
False
|
Source code in src/synthorg/observability/correlation.py
clear_correlation_ids
¶
Remove all correlation IDs from the current context.
Unbinds request_id, task_id, and agent_id. Other
context variables are preserved.
Source code in src/synthorg/observability/correlation.py
correlation_scope
¶
Scoped correlation binding that restores prior values on exit.
Uses structlog's bound_contextvars to save and restore any
pre-existing correlation IDs, making this safe for nested
execution contexts (e.g. hierarchical agent delegation).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request_id
|
str | None
|
Request correlation identifier to bind. |
None
|
task_id
|
str | None
|
Task correlation identifier to bind. |
None
|
agent_id
|
str | None
|
Agent correlation identifier to bind. |
None
|
Source code in src/synthorg/observability/correlation.py
with_correlation
¶
Decorator that binds correlation IDs for a function's duration.
Correlation IDs are bound before the function executes and unbound
after it returns or raises. Only non-None IDs are managed.
Note
This decorator is for synchronous functions only. Applying
it to an async def function raises :exc:TypeError. For
async functions, use :func:with_correlation_async instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request_id
|
str | None
|
Request correlation identifier to bind. |
None
|
task_id
|
str | None
|
Task correlation identifier to bind. |
None
|
agent_id
|
str | None
|
Agent correlation identifier to bind. |
None
|
Returns:
| Type | Description |
|---|---|
Callable[[Callable[_P, _T]], Callable[_P, _T]]
|
A decorator that manages correlation ID lifecycle. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the decorated function is a coroutine function. |
Source code in src/synthorg/observability/correlation.py
with_correlation_async
¶
Decorator that binds correlation IDs for an async function's duration.
Correlation IDs are bound before the coroutine executes and unbound
after it returns or raises. Only non-None IDs are managed.
Note
This decorator is for async functions only. Applying it to
a synchronous function raises :exc:TypeError. For sync
functions use :func:with_correlation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request_id
|
str | None
|
Request correlation identifier to bind. |
None
|
task_id
|
str | None
|
Task correlation identifier to bind. |
None
|
agent_id
|
str | None
|
Agent correlation identifier to bind. |
None
|
Returns:
| Type | Description |
|---|---|
Callable[[Callable[_P, Coroutine[object, object, _T]]], Callable[_P, Coroutine[object, object, _T]]]
|
A decorator that manages correlation ID lifecycle for async |
Callable[[Callable[_P, Coroutine[object, object, _T]]], Callable[_P, Coroutine[object, object, _T]]]
|
functions. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the decorated function is not a coroutine function. |
Source code in src/synthorg/observability/correlation.py
Setup¶
setup
¶
Logging system setup and configuration.
Provides the idempotent :func:configure_logging entry point that
wires structlog processors, stdlib handlers, and per-logger levels.
configure_logging
¶
Configure the structured logging system.
Sets up structlog processor chains, stdlib handlers, and per-logger levels. This function is idempotent -- calling it multiple times replaces the previous configuration without duplicating handlers.
Respects the SYNTHORG_LOG_LEVEL env var to override the console
sink level (useful for Docker deployments).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
LogConfig | None
|
Logging configuration. When |
None
|
routing_overrides
|
Mapping[str, tuple[str, ...]] | None
|
Optional extra logger-name routing entries
(e.g. from custom sinks) merged with the default
|
None
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If a critical sink fails to initialise. |
Source code in src/synthorg/observability/setup.py
Processors¶
processors
¶
Custom structlog processors for the observability pipeline.
sanitize_sensitive_fields
¶
Redact values of keys matching sensitive patterns.
Returns a new dict rather than mutating the original event dict, following the project's immutability convention. Redaction is applied recursively to nested dicts, lists, and tuples.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logger
|
Any
|
The wrapped logger object (unused, required by structlog). |
required |
method_name
|
str
|
The name of the log method called (unused). |
required |
event_dict
|
MutableMapping[str, Any]
|
The event dictionary to process. |
required |
Returns:
| Type | Description |
|---|---|
Mapping[str, Any]
|
A new event dict with sensitive values replaced by |
Mapping[str, Any]
|
|
Source code in src/synthorg/observability/processors.py
Sinks¶
sinks
¶
Log handler factory for building stdlib handlers from sink config.
Translates :class:~synthorg.observability.config.SinkConfig instances
into fully configured :class:logging.Handler objects with the
appropriate structlog :class:~structlog.stdlib.ProcessorFormatter.
build_handler
¶
Build a stdlib logging handler from a sink configuration.
For CONSOLE sinks a :class:logging.StreamHandler writing to
stderr is created. For FILE sinks see
:func:_build_file_handler. For SYSLOG and HTTP sinks,
dedicated handler builders are used.
Note: SYSLOG and HTTP sinks are built and returned by dedicated handler modules; they do not participate in logger-name routing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sink
|
SinkConfig
|
The sink configuration describing the handler to build. |
required |
log_dir
|
Path
|
Base directory for log files. |
required |
foreign_pre_chain
|
list[Any]
|
Processor chain for stdlib-originated logs. |
required |
routing
|
Mapping[str, tuple[str, ...]] | None
|
Optional routing table to use instead of the
module-level |
None
|
Returns:
| Type | Description |
|---|---|
Handler
|
A configured :class: |
Source code in src/synthorg/observability/sinks.py
Sink Config Builder¶
sink_config_builder
¶
Build a LogConfig from DEFAULT_SINKS + runtime overrides + custom sinks.
Pure-function module that merges static defaults with runtime settings
to produce a validated :class:LogConfig suitable for
:func:configure_logging.
The two JSON inputs come from SettingsService settings:
sink_overrides: JSON object keyed by sink identifier (__console__for the console sink, file path for file sinks). Each value is an object with optional fields:enabled,level,json_format,rotation.custom_sinks: JSON array of objects, each describing a new sink (file, syslog, or http). File sinks requirefile_path; syslog sinks requiresyslog_host; HTTP sinks requirehttp_url. All types accept optionallevel.
SinkBuildResult
dataclass
¶
Result of building a LogConfig from settings.
Attributes:
| Name | Type | Description |
|---|---|---|
config |
LogConfig
|
The fully validated logging configuration. |
routing_overrides |
MappingProxyType[str, tuple[str, ...]]
|
Custom sink routing entries keyed by file_path, mapping to logger name prefix tuples. |
build_log_config_from_settings
¶
build_log_config_from_settings(
*,
root_level,
enable_correlation,
sink_overrides_json,
custom_sinks_json,
log_dir="logs",
)
Merge DEFAULT_SINKS with runtime overrides and custom sinks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
root_level
|
LogLevel
|
Root logger level. |
required |
enable_correlation
|
bool
|
Whether to enable correlation ID tracking. |
required |
sink_overrides_json
|
str
|
JSON object of per-sink overrides. |
required |
custom_sinks_json
|
str
|
JSON array of custom sink definitions. |
required |
log_dir
|
str
|
Directory for log files. |
'logs'
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
SinkBuildResult
|
class: |
SinkBuildResult
|
class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
On invalid JSON, validation failures, or attempts to disable the console sink. |
Source code in src/synthorg/observability/sink_config_builder.py
Enums¶
enums
¶
Observability-specific enumerations.
LogLevel
¶
Bases: StrEnum
Standard log severity levels.
Values match Python's stdlib logging level names for seamless
integration between structlog and the logging module.
RotationStrategy
¶
Bases: StrEnum
Log file rotation strategies.
Attributes:
| Name | Type | Description |
|---|---|---|
BUILTIN |
Size-based rotation via |
|
EXTERNAL |
Watched rotation via |
SinkType
¶
Bases: StrEnum
Log output destination types.
Attributes:
| Name | Type | Description |
|---|---|---|
CONSOLE |
Write to stderr via |
|
FILE |
Write to a log file with optional rotation. |
|
SYSLOG |
Ship structured JSON to a syslog endpoint. |
|
HTTP |
POST JSON log batches to an HTTP endpoint. |
SyslogFacility
¶
Bases: StrEnum
Syslog facility codes.
Maps to logging.handlers.SysLogHandler.LOG_* constants.
SyslogProtocol
¶
Bases: StrEnum
Syslog transport protocol.
Attributes:
| Name | Type | Description |
|---|---|---|
TCP |
Reliable delivery via |
|
UDP |
Lightweight delivery via |
Events¶
events
¶
Per-domain event name constants for observability.
All event names follow a dotted domain.subject[.qualifier] convention and are
used as the first positional argument to structured log calls::
from synthorg.observability.events.config import CONFIG_LOADED
logger.info(CONFIG_LOADED, config_path=path)
Import constants from their domain module directly (e.g.
events.provider, events.budget, events.tool).