Skip to main content

otelstarter (Python)

Business-aware domain events for OpenTelemetry. Part of otelstarter.

from otelstarter import observability

observability.event(
    "payment.completed",
    domain="payments",
    operation="payment",
    outcome="success",
    entity_type="payment",
    entity_id=payment.id,
)

Each call emits one OpenTelemetry log-based event: a log record whose event name is payment.completed, linked to the current trace. OpenTelemetry adds the trace and span IDs, service name and environment itself.

Install

pip install otelstarter

otelstarter init adds it for you, pinned to the version it was tested with.

It depends only on opentelemetry-api. Run your app with OpenTelemetry configured (for example via otelstarter run -- <your command>), or event() quietly does nothing.

Rules it enforces

  • Business meaning, not payloads. Only the named fields above exist, with values that are short strings or ints. Anything else is left out with a warning.
  • <domain>.<action> names, in lowercase, such as order.created or payment.authorization.failed. A name that breaks the rule is still recorded, and a warning is logged once.
  • Never breaks your app. event() never raises. Internal errors are logged once as a warning.
  • One signal per event. No duplicate span event or log line, and no automatic metric, so entity_id never becomes a metric label.

Structured logs, redaction and query sanitising (0.3.0)

With the settings otelstarter init writes to otel.env, an app started by otelstarter run (or opentelemetry-instrument) gets three things, with no code changes:

  • Console logs become one JSON object per line, using the fields in docs/TELEMETRY_CONVENTIONS.md, shared with the Node.js SDK:
    log.info("order placed", extra={"orderId": "ord_1", "password": "hunter2"})
    # {"severity": "INFO", "timestamp": "…", "service.name": "shop", "environment": "local",
    #  "trace_id": "…", "span_id": "…", "orderId": "ord_1", "password": "[REDACTED]", "message": "order placed"}
    
    Set OTELSTARTER_JSON_LOGS=false to keep your own format.
  • Secrets are redacted in logs and in spans: passwords, tokens, API keys, Authorization and cookies.
  • SQL values become ?: WHERE email = 'ann@shop.rw' → WHERE email = ?.

This works because otel.env selects the SDK's exporters:

OTEL_TRACES_EXPORTER=otelstarter
OTEL_LOGS_EXPORTER=otelstarter

They make a cleaned copy of each span and log record, then send it with the standard OTLP HTTP exporter. Python freezes a finished span, so copying is the only safe way to change what gets exported.

FastAPI note. Recent FastAPI versions (0.142 in testing) log "FastAPI automatic telemetry configuration failed" with these settings. It is harmless: it means FastAPI did not add a second exporter. With otlp, it would, and every span would be sent twice. To silence the message: FastAPI(telemetry={"auto_configure": False}).

Seeing events while you develop

Set OTELSTARTER_CONSOLE_EVENTS=true and each event also prints one line to stderr. otelstarter run -- <command> sets this for you.

[otelstarter] event order.created domain=orders outcome=success entity_id=ord_1 trace_id=e566aa670b7683784763c4860c4f6e71

This line is only printed, never exported, so the event is still sent once.

Problems such as a badly named event are logged as warnings on the otelstarter logger. They appear in your terminal next to your own logs, pointing at the line that called event(), and in your backend:

WARNING [otelstarter] [main.py:14] [trace_id=...] - Event name 'ordercreated' does not follow <domain>.<action> ...

To turn them off: logging.getLogger("otelstarter").setLevel(logging.ERROR).

Finding events in Grafana

With otelstarter run, open Grafana → Explore → Loki:

{service_name="shop"} |= "payment."                       # all payment events
{service_name="shop"} | event_domain="payments"           # by domain
{service_name="shop"} | event_outcome="failure"           # failures only
{service_name="shop"} | scope_name="otelstarter" | detected_level="warn"   # event problems

Each event carries trace_id, so you can jump from it to the request's trace in Tempo. Loki does not store OpenTelemetry's event-name field, which is why the event name is also the log body.

See docs/DOMAIN_EVENTS.md for the event model.

Development

cd sdk/python
python -m venv .venv && . .venv/bin/activate
pip install -e '.[dev]'
pytest
ruff check . && ruff format --check .
mypy

Metadata

Release files for otelstarter 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for otelstarter 0.3.0
File Size Uploaded
otelstarter-0.3.0.tar.gz 18.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for otelstarter 0.3.0
File Interpreter ABI Platform
otelstarter-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 35.5 kB

Release files / otelstarter-0.3.0.tar.gz

Download URL otelstarter-0.3.0.tar.gz
Size 18.5 kB
Tags Source
SHA-256 checksum
How to use checksums
2f3d971cda269b04d881d9e70709ed9456852d10870f61bb5db72d703ca7e843
BLAKE2b-256 checksum
How to use checksums
3d512d8a2706f1fba71811de09e899b708f6e473c906c9ac78ca7444a6b46623
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release files / otelstarter-0.3.0-py3-none-any.whl

Download URL otelstarter-0.3.0-py3-none-any.whl
Size 17.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fa8ebb0d0640776327c9d747234b9a5bf697022024b92bc2424b3bbd1b783e80
BLAKE2b-256 checksum
How to use checksums
bedbee33f959728fe7f8bbd7747efbfb2c30ecf6899e53d628610fddd14d805f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release 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