Skip to main content

dynalog for Python

PyPI Python License

dynalog is a structured logging library for Python. It provides colored console logs, named events, contextual fields, JSON and logfmt output, filtering, redaction, enrichment, custom highlights, and test-friendly clocks through one default dynalog instance.

[D7MFXJ01RE3W4 info] Server started port=3000 service=api

Console records use compact, sortable LSB32 timestamps. File and memory records retain the original nanosecond timestamp and contain no ANSI color sequences.

Features

  • Pythonic: Module-level logging functions and configurable Dynalog instances.
  • Structured: Immutable events with named JSON-compatible payloads.
  • Contextual: Shared fields with per-call overrides.
  • Readable: Level colors, semantic indicators, and custom highlights.
  • Flexible: Plain text, JSON, and compact logfmt output.
  • Composable: Console, file, memory, fan-out, and custom destinations.
  • Controlled: Minimum-level filtering, recursive redaction, and enrichment.
  • Precise: Nanosecond event timestamps and 13-character LSB32 display IDs.
  • Testable: Injectable clocks and in-memory capture.

Installation

pip install dynalog

Dynalog requires Python 3.10 or newer.

Quick Start

import dynalog
from dynalog import Level

dynalog.setup(
    level=Level.INFO,
    context={"service": "api"},
)

dynalog.info("Server started", context={"port": 3000})
dynalog.event("user.login", {"id": 42, "username": "Alice"})

The default destination is Console. Call setup once during application startup to select a minimum level, output format, shared context, destinations, or custom clock.

Logging Levels

dynalog.trace("Resolving configuration")
dynalog.debug("Cache connected")
dynalog.info("Server started")
dynalog.warn("Queue depth is elevated", context={"depth": 82})
dynalog.error("Request failed", context={"status": 503})
dynalog.fatal("Worker stopped")

Set a minimum level to discard lower-priority records:

from dynalog import Level

dynalog.setup(level=Level.WARN)

Use allows before computing expensive diagnostic fields:

if dynalog.allows(Level.DEBUG):
    dynalog.debug("Cache snapshot", context=collect_cache_details())

Structured Events

Use named events for records intended for search, analytics, metrics, alerts, or automated processing.

dynalog.event(
    "payment.completed",
    {
        "order": "ORD-1042",
        "amount": 129.95,
        "currency": "USD",
    },
)

Messages and structured events use the same timestamp, filtering, context, formatting, and destination configuration.

Events and Sources

Construct an event directly when a caller needs explicit timestamps, context, or source information:

from dynalog import Event, Level, Source

event = Event.message(
    "Server started",
    timestamp=1_767_225_600_123_456_789,
    level=Level.INFO,
    context={"port": 3000},
    source=Source("app.py", 12, "app"),
)

dynalog.write(event)

Event values are immutable. Transforming an event returns a replacement instead of changing the original value.

Context

Shared context is merged into every new log record. Per-call context overrides matching shared values without changing later events.

dynalog.setup(
    context={"service": "checkout", "region": "west"},
)

dynalog.info(
    "Order accepted",
    context={"request": "req-42", "region": "central"},
)

Context values can be strings, integers, floats, booleans, or nested mappings.

Output Formats

Format Use case
Output.PLAIN Human-readable terminal output
Output.JSON Files, collectors, and structured ingestion
Output.COMPACT Dense single-line logfmt output
from dynalog import Output

dynalog.setup(output=Output.JSON)

Format an event without writing it to a destination:

from dynalog import Event, Level

event = Event.message(
    "Cache connected",
    level=Level.INFO,
    context={"host": "cache.internal"},
)

plain = dynalog.text(event, "plain")
json = dynalog.text(event, "json")
compact = dynalog.text(event, "compact")

format returns bytes; text returns a decoded string.

Destinations

Send the same record to multiple destinations by listing them in sinks. Every destination is attempted, and failures are reported together after dispatch.

import dynalog
from dynalog import Console, File, Memory, Output

memory = Memory()

dynalog.setup(
    output=Output.JSON,
    sinks=[Console(), File("app.jsonl"), memory],
)

dynalog.info("Ready", context={"port": 3000})

assert len(memory.events) == 1
assert len(memory.records) == 1

Memory.clear() removes captured events and records.

Custom Destinations

A custom destination implements write(record, event):

from dynalog import Event

class Queue:
    def __init__(self) -> None:
        self.records: list[tuple[bytes, Event]] = []

    def write(self, record: bytes, event: Event) -> None:
        self.records.append((bytes(record), event))

dynalog.setup(sinks=[Queue()])

Redaction and Enrichment

Redaction returns a replacement event and leaves the original unchanged. Matching keys are masked recursively.

from dynalog import Event, Level

event = Event.message(
    "Authentication failed",
    timestamp=1_767_225_600_123_456_789,
    level=Level.ERROR,
    context={
        "user": "alice",
        "token": "secret",
        "credentials": {"password": "secret"},
    },
)

safe = dynalog.redact(event, ["password", "token"])
enriched = dynalog.enrich(safe, "api-01")
dynalog.write(enriched)

The default redaction keys are password and token. When no process ID is provided, enrich uses the current Python process.

Console Highlights

Built-in rules emphasize failures, warnings, HTTP status classes, booleans, identifiers, timing values, paths, hosts, and ports. Add literal or compiled regular expression rules for application-specific indicators.

import re
import dynalog
from dynalog import Console, Tone

console = (
    Console(color=True)
    .highlight(re.compile(r"\bAUTH-\d+\b"), Tone.MAGENTA)
    .highlight("payment declined", Tone.RED)
)

dynalog.setup(sinks=[console])
dynalog.error("Payment AUTH-42 failed", context={"status": 503})

Available tones are RED, YELLOW, GREEN, CYAN, MAGENTA, BLUE, WHITE, and GRAY. The first custom rule wins when matches overlap.

Color is selected automatically for a compatible terminal and disabled when NO_COLOR is present. Pass True or False to Console to override automatic detection.

Testable Time

Provide a clock function that returns nanoseconds as an integer:

import dynalog
from dynalog import Memory

memory = Memory()
now = 1_000_000_000

def clock() -> int:
    return now

dynalog.setup(sinks=[memory], clock=clock)
dynalog.info("first")
now += 1_000_000_000
dynalog.info("second")

delta = memory.events[1].timestamp - memory.events[0].timestamp
assert delta == 1_000_000_000

The default clock is time.time_ns.

Public API

Export Purpose
dynalog Module-level default logger functions
Dynalog Independent logger instance
Event Immutable message or structured event
Source File, line, and module information
Level Six ordered logging levels
Output Plain, JSON, or compact formatting
Tone Named console highlight color
Console Colored terminal destination
File Append-only file destination
Memory In-memory events and records
Sink Custom destination protocol

Module-level functions include setup, format, text, allows, redact, enrich, write, event, trace, debug, info, warn, error, fatal, and version.

Requirements

  • Python 3.10 or newer.
  • A wheel compatible with the target Python version and platform, or a Rust toolchain for source builds.
  • A supported terminal for automatic ANSI colors.

Publishing

Upload verified distributions to PyPI:

python -m build
python -m twine check dist/*
python -m twine upload dist/*

PyPI authentication can use an API token through TWINE_USERNAME=__token__ and TWINE_PASSWORD.

The distribution includes the Python API, native extension, runtime artifact, documentation, and both license texts.

Limitations and Compatibility

  • High-level log methods omit source fields unless source metadata is supplied explicitly.
  • File output is append-only and does not currently rotate.
  • Destination writes are synchronous; custom destinations should remain fast.
  • Nanosecond timestamps do not guarantee uniqueness when events share an instant.
  • LSB32 display IDs require every producer and consumer to use the same epoch.
  • Building from source requires a supported Rust toolchain and native compiler.

License

Dynalog is dual-licensed under either of the following, at your option:

SPDX: LGPL-3.0-only OR GPL-3.0-only

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dynalog-0.1.1.tar.gz (229.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dynalog-0.1.1-cp310-abi3-win_amd64.whl (6.2 MB view details)

Uploaded CPython 3.10+Windows x86-64

File details

Details for the file dynalog-0.1.1.tar.gz.

File metadata

  • Download URL: dynalog-0.1.1.tar.gz
  • Upload date:
  • Size: 229.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for dynalog-0.1.1.tar.gz
Algorithm Hash digest
SHA256 327e4f59ce9c7edcf3b75e8d940596dd44de8a681910ca1738e3baae6216d7a7
MD5 d7e206e167180f10def4bb8a56a9badb
BLAKE2b-256 68b047031c4906a1a356ae675120d2adcfce6594d259a01f95018dbfbd57ad29

See more details on using hashes here.

File details

Details for the file dynalog-0.1.1-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: dynalog-0.1.1-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 6.2 MB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for dynalog-0.1.1-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 4c18afd86d82b5d1c3bac47f7503b8c76d86ec4c43c6e88ea7211d26532f5baf
MD5 51209f14e83ecaaf64eafa5598810163
BLAKE2b-256 374799eeb968ba7bb8ba83bf11098c2e36582630e73b5a3f1991847671cd7a27

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page