Skip to content

Logger API ​

The Logger class is the primary interface for all logging operations. Import it from logly:

python
from logly import logger

Log Methods ​

log(level, message, *args, **kwargs) ​

Log a message at the specified level.

python
logger.log("INFO", "Message at INFO level")
logger.log("CUSTOM", "Message at custom level")

Parameters:

  • level (str | int): Level name (e.g., "INFO") or numeric priority (e.g., 20)
  • message (object): Format string or message (supports str.format() placeholders)
  • *args: Positional format arguments
  • **kwargs: Keyword format arguments

Returns: dict[str, object] | None - record dict if opt(record=True), else None


trace(message, *args, **kwargs) ​

Log at TRACE level (numeric 5).

python
logger.trace("Fine-grained trace: {var}", var=value)

debug(message, *args, **kwargs) ​

Log at DEBUG level (numeric 10).

python
logger.debug("Debug info: {data}", data=payload)

info(message, *args, **kwargs) ​

Log at INFO level (numeric 20).

python
logger.info("Application started on port {port}", port=8000)

notice(message, *args, **kwargs) ​

Log at NOTICE level (numeric 25).

python
logger.notice("Configuration reloaded")

success(message, *args, **kwargs) ​

Log at SUCCESS level (numeric 30).

python
logger.success("Deployment completed!")

warning(message, *args, **kwargs) ​

Log at WARNING level (numeric 40).

python
logger.warning("Disk usage above {pct}%", pct=90)

error(message, *args, **kwargs) ​

Log at ERROR level (numeric 50).

python
logger.error("Database connection failed")

fail(message, *args, **kwargs) ​

Log at FAIL level (numeric 55).

python
logger.fail("Task failed: {reason}", reason="timeout")

critical(message, *args, **kwargs) ​

Log at CRITICAL level (numeric 60).

python
logger.critical("System memory exhausted")

fatal(message, *args, **kwargs) ​

Log at FATAL level (numeric 70).

python
logger.fatal("Unrecoverable error - shutting down")

audit(message, *args, **kwargs) ​

Log at AUDIT level (must be registered first).

python
logger.level("AUDIT", no=35, color="<green>")
logger.audit("User performed action")

Configuration Methods ​

add(sink, **kwargs) ​

Add a new sink to the logger. Returns an integer sink ID.

python
sink_id = logger.add("app.log", level="INFO", rotation="daily")

Parameters:

ParameterTypeDefaultDescription
sinkstr | Path | Callable | objectFile path, text/binary stream, callable, or sink object
levelstr | int"DEBUG"Minimum log level for this sink (names or priorities)
formatstr | Callable | Nonebuilt-in defaultCustom format string or formatter callable
rotationstr | int | Callable | object | NoneNoneRotation policy ("daily", "10 MB", byte count, callable, or policy object); file sinks only
retentionstr | int | object | NoneNoneRetention policy ("30 days", 7); file sinks only
compressionstr | object | NoneNoneCompression codec ("gzip", "zip"); file sinks only
enqueueboolFalseUse queue-based async worker (drained at shutdown)
colorizebool | NoneNoneEnable ANSI color output (None auto-detects)
backtraceboolTrueAccepted for compatibility; use per-message opt(backtrace=...)
diagnoseboolFalseAccepted for compatibility; use per-message opt(diagnose=...)
filterstr | Callable | Mapping | NoneNonePrefix string, filter callable, or extra-field mapping
serializeboolFalseOutput as JSON
pretty_jsonbool | PrettyJsonConfig | NoneNoneTrue or JSON formatting options
patchCallable | NoneNonePatch function for all records
encodingstr"utf-8"File encoding (non-default opens in Python; no rotation)
delayboolFalseDelay file opening until first write; file sinks only
watchboolFalseReopen the log file if deleted or replaced externally; file sinks only
contextNoneNoneReserved; must be None (spawn children with their own Logger)
catchboolTrueCatch sink errors silently
modestr"a"File mode: "a" (append) or "w" (overwrite)
bufferingint1File buffering level (non-default needs a plain file sink)
loopAbstractEventLoop | NoneNoneEvent loop for async sinks
openerCallable | NoneNoneCustom file opener (plain file sinks only)

Returns: int - sink ID for use with remove() / reinstall()

Built-in Sink Objects:

SinkDescription
HttpJsonSinkHTTP JSON log shipping
BatchHttpJsonSinkBatched HTTP JSON log shipping
TcpSinkTCP socket logging
UdpSinkUDP socket logging
SyslogSinkSystem syslog logging

Example with BatchHttpJsonSink:

python
from logly import BatchHttpJsonSink, logger

sink = BatchHttpJsonSink(
    url="https://logs.example.com/ingest",
    batch_size=100,
    flush_interval=5.0,
)
logger.add(sink, level="INFO")

remove(handler_id=None) ​

Remove a sink by its ID, or all sinks when omitted.

python
logger.remove(sink_id)
logger.remove()  # remove all sinks

configure(**kwargs) ​

Configure the logger with a complete configuration dict.

python
logger.configure(
    handlers=[
        {"sink": "stdout", "level": "INFO"},
        {"sink": "app.log", "level": "DEBUG"},
    ],
    extra={"app_name": "myapp"},
)

Parameters:

  • handlers (list[dict[str, Any]]): List of sink configuration dicts
  • extra (dict[str, Any]): Default extra fields for all records
  • levels (list[dict[str, Any]]): Custom level definitions
  • patcher (Callable): Global patcher function
  • activation (list[tuple[str, bool]]): Level activation pairs

level(name, no=None, color=None, icon=None) ​

Get or create a custom log level.

python
# Get existing level
level_obj = logger.level("INFO")
print(level_obj.name)  # "INFO"
print(level_obj.no)  # 20
print(level_obj.color)  # None
print(level_obj.icon)  # None

# Create custom level
logger.level("AUDIT", no=35, color="<green><bold>", icon="🔒")

Parameters:

  • name (str): Level name
  • no (int | None): Numeric value
  • color (str | None): ANSI color markup
  • icon (str | None): Level icon

Returns: Level - level object with .name, .no, .color, .icon attributes


reinstall(handler_id=None) ​

Remove and re-add sinks with their original configuration. Useful to reset file handlers after external rotation.

python
logger.reinstall()
logger.reinstall(sink_id)  # reinstall one sink

enable(name) ​

Enable log emission for a logger name previously passed to disable.

python
logger.enable("myapp")

disable(name) ​

Disable log emission for a logger name. Matching log() calls (including structured logging) are silently discarded.

python
logger.disable("myapp")

complete() ​

Wait for all pending log messages to be processed (async workers).

python
logger.complete()

flush() ​

Flush all sinks, ensuring buffered records are written. Equivalent to complete(); safe to call multiple times.

python
logger.flush()

root_dir(path) ​

Set the root directory for relative file paths.

python
logger.root_dir("/var/log/myapp")

Optimization Methods ​

opt(**kwargs) ​

Configure logging behavior for subsequent calls.

python
# Record mode - return the record dict
record = logger.opt(record=True).info("Hello")

# Lazy evaluation - defer string formatting
logger.opt(lazy=True).info("Expensive: {data}", data=compute())

# Raw mode - skip format processing
logger.opt(raw=True).info("Raw message: {time}")

# Exception mode - include exception info
logger.opt(exception=True).info("Failed")

# Colors mode - enable ANSI color in message
logger.opt(colors=True).info("<green>Success!</green>")

# Depth mode - capture caller info from N frames up
logger.opt(depth=2).info("Called from caller")

# Backtrace - include backtrace on exception
logger.opt(backtrace=True).info("Error context")

# Diagnose - include variable values on exception
logger.opt(exception=True, diagnose=True).error("Debug context")

# Capture - disable caller file/line/function capture for speed
logger.opt(capture=False).info("Hot path")

Parameters:

ParameterTypeDefaultDescription
exceptionBaseException | bool | NoneNoneException instance or True to capture the active one
recordboolFalseReturn record dict
lazyboolFalseDefer string formatting
colorsboolFalseEnable ANSI color codes in output
rawboolFalseSkip format string interpolation
depthint0Additional stack frames to skip for caller info
captureboolTrueCapture caller file/line/function info
backtraceboolTrueInclude backtrace in exception output
diagnoseboolFalseInclude diagnostic info in exceptions
ansiboolFalseTreat message as ANSI-formatted (implies colors)

bind(**kwargs) ​

Create a new logger with persistent context fields.

python
user_logger = logger.bind(user_id="12345", request_id="abc")
user_logger.info("Action performed")
# Output includes: user_id=12345 request_id=abc

Returns: Self - new logger with bound context


patch(patcher) ​

Create a new logger with a record patcher function.

python
patched = logger.patch(lambda record: record.update({"env": "production"}))
patched.info("Running in production")

Parameters:

  • patcher (Callable[[dict], None]): Function that modifies the record dict

Returns: Self - new logger with patcher applied


contextualize(**kwargs) ​

Context manager for scoped context fields.

python
with logger.contextualize(request_id="abc-123"):
    logger.info("Scoped to request")
    # request_id is automatically included

Exception Methods ​

catch(exception=Exception, level="ERROR", reraise=False, onerror=None, exclude=None, default=None, message=None) ​

Context manager (sync and async) for automatic exception logging. Also works as a decorator for sync, async, generator, and async-generator functions.

python
# Basic usage
with logger.catch():
    risky_operation()

# Exclude specific exceptions
with logger.catch(exclude=(ValueError, KeyError)):
    optional_operation()

# Custom error handling
with logger.catch(onerror=lambda e: send_alert(str(e))):
    critical_operation()

# Return default on exception
result = logger.catch(default=None)(risky_function)()

# Re-raise after logging
with logger.catch(reraise=True):
    dangerous_operation()

Parameters:

ParameterTypeDefaultDescription
exceptiontype | tupleExceptionException types to catch
levelstr"ERROR"Log level for caught exceptions
reraiseboolFalseRe-raise after logging
onerrorCallable | NoneNoneCallback on exception
excludetype | tuple | NoneNoneException types to exclude (re-raise)
defaultAnyNoneDefault return value on exception (decorator mode)
messagestr | NoneNoneCustom message logged with the exception

Lifecycle Methods ​

start(*args, **kwargs) ​

Compatibility hook for application startup code. Accepts arbitrary arguments and performs no work; queued sinks start their workers when registered.

python
logger.start()

stop() ​

Flush sinks and stop logger-managed background workers. Equivalent to complete().

python
logger.stop()

warn(message, *args, **kwargs) ​

Alias for warning.

exception(message, *args, exc_info=True, **kwargs) ​

Log at ERROR level, attaching the currently active exception when present.

Parse Method ​

parse(path, pattern=None, *, cast=None, chunk=65536, encoding="utf-8") ​

Parse log files using regex patterns. This is a static method returning a generator — iterate it or wrap with list().

python
# Parse all log lines
entries = list(logger.parse("app.log"))

# Custom pattern
entries = list(
    logger.parse(
        "app.log",
        pattern=r"(?P<time>\d{4}-\d{2}-\d{2}) (?P<level>\w+) (?P<message>.+)",
    )
)

# With type casting (values are callables, e.g. int)
entries = list(
    logger.parse(
        "app.log",
        pattern=r"(?P<time>\S+) (?P<level>\w+) (?P<message>.+)",
        cast={"level": int},
    )
)

Parameters:

ParameterTypeDefaultDescription
pathstr | PathLog file path (missing files yield nothing)
patternstr | Pattern | NoneNoneRegex pattern with named groups
castdict[str, Callable] | NoneNonePer-group casting functions (bad values keep the raw string)
chunkint65536Read block size in bytes
encodingstr"utf-8"File encoding

Returns: Generator[dict, None, None] - parsed log entries, one dict per matched line

Properties ​

levels ​

List of registered level names in severity order.

python
for level_name in logger.levels:
    print(level_name)

Builtin Levels ​

LevelNumericColor
TRACE5Gray
DEBUG10Blue
INFO20Green
NOTICE25Cyan
SUCCESS30Green (bold)
WARNING40Yellow
ERROR50Red
FAIL55Red (bold)
CRITICAL60Red (bold, bg)
FATAL70Red (bold, bg)

Released under the MIT License.