Skip to main content

stonedog-logs

Structured logging for Python with optional OpenTelemetry (OTLP) export to providers like Seq.

stonedog-logs is a thin, dependency-free wrapper over the standard library logging module. It gives you:

  • Structured fields — pass key=value pairs to any log call, rendered as readable key=value text or as JSON.
  • Context bindinglog.bind(device="pi-01") returns a child logger that stamps every record with that context.
  • One-call setupconfigure() installs handlers/formatters and reads sensible defaults from environment variables.
  • Opt-in cloud export — set STONEDOG_LOGS_OTLP_ENDPOINT to ship logs to any OTLP/HTTP collector (Seq, Grafana, an OpenTelemetry Collector, …). With no endpoint set, it logs to the console and has zero heavy dependencies — ideal for offline/embedded use such as the Raspberry Pi card sorter.

Install

pip install stonedog-logs            # console logging, no extra deps
pip install "stonedog-logs[otlp]"    # + OpenTelemetry OTLP export

Usage

from stonedog_logs import configure, get_logger

configure(service_name="card-sorter")        # call once at startup
log = get_logger(__name__)

log.info("sorted card", card="Black Lotus", bin=3)
# 2026-06-24T19:40:00+00:00 INFO     [card-sorter] __main__: sorted card card="Black Lotus" bin=3

job = log.bind(job_id="abc123")               # bound context
job.warning("reject bin full", bin=9)

try:
    risky()
except Exception:
    log.exception("operation failed", op="sort")   # includes traceback

JSON output (great for log shippers):

configure(service_name="card-sorter", json_output=True)
# {"timestamp": "...", "level": "INFO", "service": "card-sorter", "logger": "...", "message": "sorted card", "card": "Black Lotus", "bin": 3}

Configuration

Every configure() argument falls back to an environment variable, so you can deploy without touching code:

Argument Environment variable Default
service_name STONEDOG_LOGS_SERVICE_NAME app
level STONEDOG_LOGS_LEVEL INFO
json_output STONEDOG_LOGS_JSON false
otlp_endpoint STONEDOG_LOGS_OTLP_ENDPOINT (unset → console only)
otlp_headers STONEDOG_LOGS_OTLP_HEADERS (unset)

Each variable also accepts its pre-rename ROZ_LOGS_* spelling, which is read only when the STONEDOG_LOGS_* one is unset. Deployed card sorters were configured with the old names, and dropping them would not fail loudly — it would silently revert those devices to defaults. Prefer the new names in anything written from here on.

STONEDOG_LOGS_JSON accepts any of 1, true, yes, on (case-insensitive) to switch from the human-readable TextFormatter to the line-delimited JsonFormatter; anything else keeps text output.

Configuring when you might not be the only one

configure() installs handlers, so it belongs in an application entry point and never in a library — a library that configures logging hijacks it for everything that imports the library.

Sometimes an application cannot be sure it is alone: an app running as a sidecar inside somebody else's process, a CLI that may be imported, a worker under a host that set up its own logging. Calling configure() there installs a second handler and every line appears twice.

from stonedog_logs import configure, logging_is_configured

# no-op if ANYTHING has already installed a handler, including one we did not
configure(service_name="my-service", only_if_unconfigured=True)

logging_is_configured()          # ask directly

This is a different question from calling configure() twice, which has always been safe: that removes handlers this library installed, so configuration never stacks up on itself. The flag is about not overriding somebody else.

Both configure() and logging_is_configured() accept a logger object as well as a name, so a caller that already holds one does not need to know its name.

OTLP export (shipping to Seq and other collectors)

The core library has zero runtime dependencies and only ever writes to the console. Cloud/collector export is opt-in through the otlp extra, which pulls in the OpenTelemetry SDK and the OTLP/HTTP log exporter:

pip install "stonedog-logs[otlp]"

Once installed, setting an OTLP endpoint makes configure() attach a second handler (in addition to the console) that batches log records and exports them over OTLP/HTTP:

export STONEDOG_LOGS_OTLP_ENDPOINT="http://localhost:5341/ingest/otlp/v1/logs"
export STONEDOG_LOGS_OTLP_HEADERS="X-Seq-ApiKey=<your-api-key>"

Under the hood build_otlp_handler() wires up an OpenTelemetry LoggerProvider (tagged with service.name = your service_name), a BatchLogRecordProcessor, and an OTLPLogExporter pointed at your endpoint, then returns a stdlib logging.Handler bridging the two. Records flow:

log.info(...) → stdlib logging → OTLP LoggingHandler → BatchLogRecordProcessor
             → OTLPLogExporter (HTTP) → Seq / OTel Collector / Grafana / …

For Seq the endpoint is http://<host>:5341/ingest/otlp/v1/logs and the API key travels in a header (X-Seq-ApiKey). Any OTLP/HTTP logs endpoint works the same way.

Graceful degradation: if you request an endpoint but the otlp extra is not installed, stonedog-logs logs a warning and keeps console logging working rather than crashing — so the same code runs on a constrained device (console only) and a server (console + OTLP) with no changes.

Development

pip install pytest pytest-cov
pytest                        # runs unit tests with a 90% coverage gate

# to exercise the OTLP code paths, install the extra into your test env:
pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http

Renamed from roz-logs

This library was published as roz-logs through 0.1.0. It is the same library under the StoneDogCode name: the distribution is now stonedog-logs and the import is stonedog_logs.

from roz_logs import configure, get_logger        # before
from stonedog_logs import configure, get_logger   # now

The old roz-logs distribution stays on PyPI so existing installs keep working, but it receives no further releases.

License

MIT

Download files

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

Source Distribution

stonedog_logs-0.3.0.tar.gz (14.5 kB view details)

Uploaded Source

Built Distribution

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

stonedog_logs-0.3.0-py3-none-any.whl (16.5 kB view details)

Uploaded Python 3

File details

Details for the file stonedog_logs-0.3.0.tar.gz.

File metadata

  • Download URL: stonedog_logs-0.3.0.tar.gz
  • Upload date:
  • Size: 14.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for stonedog_logs-0.3.0.tar.gz
Algorithm Hash digest
SHA256 f6030aebb32aa6a508fff082a5582ffcc6892ee84096f6c561dece90e537feb9
MD5 3f1f843c1714befcee79aae5b2ac80b7
BLAKE2b-256 718a9f28a1336d003293036d7a14294eae08bf86b7c629dc48775f363bda78c4

See more details on using hashes here.

File details

Details for the file stonedog_logs-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: stonedog_logs-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 16.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for stonedog_logs-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 af071fb407dbdb459d560f0ce209d889c2cb3ddcf57ae2bb593256b00d568067
MD5 f1b86ae56731b5e2354b1b24cb50afc6
BLAKE2b-256 78ff8e8741eda0fffda620e2dbc9c5fe940a5e574b2cac777b63ffe5d99fbb76

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.2.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page