aeat.core.logging module

Logging configuration entry point.

Provides get_logger() as the consistent logger factory to avoid scattered bare logging instances, with configure_logging() installing the project defaults. The installed log-record factory reads aeat.core.observability.current_run_context() state indirectly through contextvars, so every record automatically picks up the active run_id / step_id while a run context is bound.

This module attaches the log-record secret scrubber. Every handler attached through configure_logging() receives a SecretScrubbingFilter so sensitive fields are redacted before formatting. Shape-based NIF, URL, and bearer-token matching is delegated to redact_for_log(); this module keeps only logging-specific key-paired placeholders such as cookies, passphrases, and certificate serial suffixes. Per-run JSONL handlers are attached with attach_run_sink() so the same filter protects observability output.

Logging is a diagnostic channel, not the CLI result contract. Operator-facing success payloads and typed Notice values are rendered through the JSON/text output stack; this module only prepares redacted log records and plaintext diagnostic log files rooted by settings.

class SecretScrubbingFilter(name='')[source]

Bases: Filter

Redact sensitive fields from log records before formatting.

The filter mutates each logging.LogRecord in place so handlers, stderr diagnostics, and JSONL run sinks see the same scrubbed record. It is deliberately narrower than CLI output redaction: structured command results still route through aeat.core.output_rendering or aeat.core.json_contract, while this filter protects logging-only message text, %-format args, exception text, and extra fields.

filter(record)[source]

Scrub sensitive values from record in-place and return True to allow it.

Parameters:

record (LogRecord) – The log record whose msg, args, exc_info, exc_text, and extra fields are scrubbed before formatting.

Return type:

bool

Returns:

Always True — every record is allowed through after scrubbing.

default_log_file_path()[source]

Return the file path for non-interactive project logs.

The diagnostic log is rooted under aeat_log_dir, which the Settings validator derives from <aeat_local_storage_root>/logs when no explicit AEAT_LOG_DIR override is supplied — so the log stays isolated per workspace rather than mixing every session’s records into a single system-wide file.

Return type:

Path

configure_logging()[source]

Configure the project-wide diagnostic logging defaults.

Installs settings-derived stderr/file handlers, the run-context record factory, and SecretScrubbingFilter on the root logger plus every configured handler. The file handler writes redacted diagnostic plaintext under default_log_file_path(); this module does not encrypt logs or persist them through secure-object repositories.

When the diagnostic log directory cannot be created (an inaccessible AEAT_LOCAL_STORAGE_ROOT / AEAT_LOG_DIR), logging degrades to stderr-only and records an instructive diagnostic naming the likely remedy — it never crashes CLI startup with a raw traceback.

The function is idempotent so early imports can safely call get_logger() without duplicating handlers.

Return type:

None

set_log_level(level, *, file_level=10)[source]

Apply level to the root logger and every attached handler.

The root logger itself is always set to logging.DEBUG so no record is discarded before reaching a handler; each handler then applies its own level gate. FileHandler instances receive file_level (default DEBUG) to keep the diagnostic log comprehensive. All other handlers (typically the stderr stream handler) receive level.

configure_logging() is called first so the dictConfig contract is in place before any level mutation.

Parameters:
  • level (int) – The effective level for non-file handlers (e.g. logging.INFO for verbose mode).

  • file_level (int) – The level applied to logging.FileHandler instances (default logging.DEBUG).

Return type:

None

attach_run_sink(sink)[source]

Install SecretScrubbingFilter on sink then attach it to root.

Ensures every record flowing through the JSONL run sink is scrubbed before it reaches the serialiser, even when the root-logger filter has already scrubbed the shared record in-place. The filter is idempotent: a second call with the same sink is a no-op because the guard checks root_logger.handlers for an existing instance.

Parameters:

sink (Handler) – The logging.Handler (typically aeat.core.observability._sink.JsonlRunSink) to attach to the root logger.

Return type:

None

The sink is a diagnostic observability target. It receives redacted log records, not CLI result payloads or secure-storage records.

detach_run_sink(sink)[source]

Remove sink from the root logger and perform symmetric teardown.

Reverses every side-effect of attach_run_sink(): the handler is removed from the root logger, the SecretScrubbingFilter instances that attach_run_sink() installed on the sink are removed, and the sink is flushed so in-flight records reach their destination before the handle is released.

The caller is responsible for closing the sink after detach; this function deliberately does not call close() so a caller can flush output and inspect state before teardown.

Parameters:

sink (Handler) – The logging.Handler previously attached by attach_run_sink().

Return type:

None

get_logger(name)[source]

Return a configured logger for the given module name.

Preferred over direct logging.getLogger() in production modules because it ensures the project defaults are installed and attaches SecretScrubbingFilter directly to the returned logger. Startup modules that must use stdlib logging before settings load rely on later propagation through the configured root logger instead.

Parameters:

name (str) – The name of the module, typically __name__.

Return type:

Logger

Returns:

A configured logging.Logger instance.