Lifecycle¶
LogSpark enforces a strict lifecycle for the logger:
This is the most important thing to understand about LogSpark. Everything else follows from it.
Why a lifecycle?¶
Stdlib logging has no lifecycle. You can call addHandler() at any point, reconfigure at any point, and nothing stops you. In a real application this means configuration state becomes unpredictable. A module imported late can silently change how the root logger behaves.
LogSpark treats logging as infrastructure. Infrastructure is configured once at startup, then used. It does not reconfigure at runtime.
configure()¶
configure() is the single entry point for setting up the logger. Call it once, early, before threads or workers start.
import logging
from logspark import logger
from logspark.Types.Options import TracebackOptions, PathResolutionSetting
logger.configure(
level=logging.INFO,
traceback_policy=TracebackOptions.COMPACT,
path_resolution=PathResolutionSetting.RELATIVE,
multiline=True,
)
What configure() does:
- Validates the level
- Creates the appropriate handler if none is provided
- Attaches configured filters
- Freezes the logger (unless
no_freeze=True)
After configure() returns, the logger is frozen. No further calls to addHandler(), addFilter(), eject_handlers(), or configure() will succeed. They raise FrozenClassException.
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
level |
str \| int |
logging.INFO |
Minimum log level |
handler |
logging.Handler |
None |
Custom handler. If omitted, LogSpark creates a SparkTerminalHandler. |
traceback_policy |
TracebackOptions |
COMPACT |
How exceptions are rendered |
path_resolution |
PathResolutionSetting |
RELATIVE |
How file paths appear in log lines |
multiline |
bool |
True |
Whether log output can span multiple lines |
no_freeze |
bool |
False |
Skip automatic freeze after configure. Advanced use only. |
Freeze¶
Once frozen, the logger is immutable for the lifetime of the process:
- Handler list is locked
- Filter list is locked
configure()cannot be called againaddHandler(),addFilter(), andeject_handlers()raiseFrozenClassExceptionimmediately
By default, configure() freezes automatically. Deferring with no_freeze=True and calling logger.freeze() manually is only needed in unusual initialization sequences:
Checking state¶
Before configure() is called¶
Logging before configure() does not silently discard records. LogSpark:
- Emits a
SparkLoggerUnconfiguredUsageWarningonce per process - Falls back to a minimal
SparkPreConfigHandlerwith a simple stdout format
Logging never disappears, but lifecycle violations are always surfaced.
kill() -- resetting the singleton¶
kill() forcefully resets the logger singleton. It exists for test isolation only.
Do not use kill() in application code. It bypasses all lifecycle guarantees.
TempLogLevel -- scoped level overrides¶
If you need debug output from a specific path without reconfiguring, use TempLogLevel. It bypasses freeze only for the effective level. Handlers and filters are untouched.