A loguru sink that sends structured logs to Seq using CLEF format
Project description
loguru-seq
A loguru sink that sends structured logs to Seq using the CLEF format over HTTP with background batching.
Features
- Non-blocking background thread with configurable batch interval and size
- Structured fields via loguru's
bind()forwarded as CLEF properties - Exception traces forwarded as the CLEF
@xfield - Optional API key authentication
- Graceful shutdown that flushes remaining events on process exit
Installation
pip install loguru-seq
Or with uv:
uv add loguru-seq
Quick start
from loguru import logger
from loguru_seq import SeqSink
sink = SeqSink(url="http://localhost:5341")
logger.add(sink)
logger.info("Application started")
logger.warning("Low disk space")
With an API key
sink = SeqSink(
url="http://seq.example.com",
api_key="your-api-key",
)
logger.add(sink)
Structured properties with bind()
Extra fields passed to logger.bind() are forwarded as top-level CLEF properties and become searchable in Seq.
logger.bind(user_id=42, order_id="ORD-999").info("Order placed")
logger.bind(component="auth").warning("Token about to expire")
Structured properties via message arguments
Named keyword arguments passed directly to the log call are also forwarded as CLEF properties, and additionally rendered into the message text:
logger.info("User {name} logged in from {ip}", name="alice", ip="192.168.1.1")
# @mt → "User alice logged in from 192.168.1.1"
# name → "alice" (searchable property in Seq)
# ip → "192.168.1.1" (searchable property in Seq)
The difference from bind() is that the values are also baked into @mt, so they appear twice: in the message text and as discrete properties. With bind() the message text stays as a clean template and the values only live in their respective properties.
Positional arguments (e.g. logger.info("value is {}", 42)) are used for rendering only and do not become CLEF properties.
Use bind() for context that applies to multiple log calls (e.g. a request ID). Use inline kwargs when the value is specific to a single message and you want it visible in the message text as well.
Exception capture
try:
result = 1 / 0
except ZeroDivisionError:
logger.exception("Unexpected error in calculation")
The full traceback is sent in the CLEF @x field and displayed in Seq's exception viewer.
Configuration reference
SeqSink(
url, # Base URL of the Seq server, e.g. "http://localhost:5341"
api_key=None, # Seq API key (Settings → API Keys in the Seq UI)
batch_interval_seconds=5.0, # Seconds between automatic flushes
batch_size=100, # Flush early when this many events are buffered
timeout_seconds=10.0, # HTTP request timeout, in seconds
max_queue_size=10_000, # Drop events (with a stderr warning) when queue exceeds this
)
| Parameter | Default | Description |
|---|---|---|
url |
— | Base URL of the Seq instance |
api_key |
None |
API key for authenticated Seq instances |
batch_interval_seconds |
5.0 |
Maximum seconds to wait before flushing |
batch_size |
100 |
Flush immediately when this many events are queued |
timeout_seconds |
10.0 |
HTTP timeout, in seconds, for each flush request |
max_queue_size |
10_000 |
Hard cap on the in-memory event queue |
Manual flush
Call sink.flush() to send all buffered events immediately, for example before a scheduled job ends.
sink = SeqSink(url="http://localhost:5341", batch_interval_seconds=60)
logger.add(sink)
logger.info("Job started")
# ... work ...
logger.info("Job finished")
sink.flush()
Log level mapping
| loguru | CLEF / Seq |
|---|---|
TRACE |
Verbose |
DEBUG |
Debug |
INFO |
Information |
SUCCESS |
Information |
WARNING |
Warning |
ERROR |
Error |
CRITICAL |
Fatal |
Contributing
Contributions are welcome. Please open an issue before submitting large changes so we can discuss approach first.
Prerequisites
- Python 3.9 or later
- uv — used for environment and dependency management
Setting up the development environment
# Clone the repository
git clone https://github.com/gabrielgt/loguru-seq.git
cd loguru-seq
# Create the virtual environment and install all dependencies (including dev extras)
uv sync
uv sync reads pyproject.toml and uv.lock, creates a .venv directory, and installs the package in editable mode along with the dev dependency group (pytest, pytest-mock, ruff, pyright).
Alternatively, open the repository in the provided dev container (VS Code's "Reopen in Container", or GitHub Codespaces) for a preconfigured Python 3.11 environment with uv and the recommended VS Code extensions already installed.
Project structure
src/loguru_seq/
__init__.py # Public API — exports SeqSink
sink.py # SeqSink: buffering, batching, background thread
sender.py # SeqSender: httpx client, sends CLEF to Seq's /api/events/raw
clef.py # loguru record → CLEF dict, list of dicts → NDJSON string
tests/
unit/ # Fast, no network required
integration/ # Require a running Seq instance
Running unit tests
Unit tests use mocks and require no external services.
uv run pytest tests/unit
Running integration tests
Integration tests send real HTTP requests to a Seq instance.
- Start a local Seq instance (Docker is the easiest way):
docker run --name seq -d --restart unless-stopped \
-e ACCEPT_EULA=Y \
-e SEQ_PASSWORD=<initial-password> \
-p 5341:80 \
datalust/seq:latest
- Copy the example environment file and fill in your values:
cp example.env .env
# Edit .env — set SEQ_URL and optionally SEQ_API_KEY
The defaults in .env point to http://host.docker.internal:5341, which resolves correctly from inside another Docker container (for example a dev container). If you are running tests directly on your host machine, change SEQ_URL to http://localhost:5341.
- Run the integration tests:
uv run pytest tests/integration
Running all tests
uv run pytest
Code style
This project uses ruff for linting/formatting and pyright for type checking. All public functions and methods should be fully type-annotated.
Run everything CI checks (lint, format, type check, unit tests, integration tests) with one command:
./scripts/check.sh
Integration tests skip automatically with a clear message if no Seq instance is reachable — see Running integration tests to set one up locally.
Or run the checks individually:
uv run ruff check . # Lint
uv run ruff format --check . # Format (check only; use `ruff format .` to apply)
uv run pyright # Type check (checks src/ only)
uv run pytest tests/unit # Unit tests
uv run pytest tests/integration # Integration tests (skipped if Seq isn't reachable)
Submitting changes
- Fork the repository and create a branch from
main. - Make your changes with tests.
- Run
./scripts/check.shand verify it passes (this mirrors CI'stestjob; theintegrationjob runs the sametests/integrationsuite against a real Seq service container in CI). - Open a pull request with a clear description of what and why.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file loguru_seq-0.1.0.tar.gz.
File metadata
- Download URL: loguru_seq-0.1.0.tar.gz
- Upload date:
- Size: 11.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0da8ca6e239c2e6dec44dc21a14775f9b7d425e9c6d8a3e03651e9008fc02d2
|
|
| MD5 |
d0d7458dc121aac0707b7fdf84167e8e
|
|
| BLAKE2b-256 |
359673c4392b7c6d00f55642961151e020e9ae8ef74e38dd4259fd1494650a03
|
File details
Details for the file loguru_seq-0.1.0-py3-none-any.whl.
File metadata
- Download URL: loguru_seq-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
144cbb6d56b3ec9afbcbd3324ce336e2de11aabcc03ee095efee05a4d0ab29c5
|
|
| MD5 |
5f235c9b33b8d3ed3b2e2c4b60125b40
|
|
| BLAKE2b-256 |
0aff5cf58cfd91ebe51773132759e7e07dc2f78717db4e2d2cc4c377f90f3ed1
|