Uniform JSON logging for University Medicine Essen (UME)
Project description
ume-logging
Uniform JSON logging for University Medicine Essen applications. Designed for microservices running in Docker/Kubernetes with ELK stack integration.
Features
- Structured JSON output — Machine-readable logs for ELK/Loki/CloudWatch
- Context injection — Automatically include app, env, service, request ID in every log
- Request tracing — Track requests across services with
X-Request-IDpropagation - PII scrubbing — Automatically redact emails and phone numbers from logs
- OpenTelemetry integration — Trace/span IDs in logs + log→span event bridge
- FastAPI middleware — Request/response logging with latency tracking
- User privacy — Hash user identifiers with configurable salt
Installation
pip install ume-logging
# With FastAPI support
pip install "ume-logging[fastapi]"
# With OpenTelemetry support
pip install "ume-logging[otel]"
# Everything
pip install "ume-logging[fastapi,otel]"
Quick Start
import logging
from umelogging import log_configure
log_configure("INFO", app="patient-api", env="prod", service="fhir-import")
log = logging.getLogger(__name__)
log.info("Processing patient records", extra={"count": 42})
Output:
{"time":"2025-01-15T10:30:00","level":"INFO","logger":"__main__","message":"Processing patient records","org":"UME","app":"patient-api","env":"prod","service":"fhir-import","count":42}
Context Management
Track requests and users across your application:
from umelogging import set_context, with_request_id
# Set request ID (or auto-generate with with_request_id())
with_request_id("req-abc-123")
# Track user (automatically hashed for privacy)
set_context(user_id="patient@example.com", component="auth")
# Add custom context
set_context(extra={"tenant": "hospital-a", "study_id": "ST001"})
All subsequent logs will include this context:
{"message":"User authenticated","request_id":"req-abc-123","user":{"hash":"a1b2c3..."},"component":"auth","tenant":"hospital-a"}
PII Scrubbing
Emails and phone numbers are automatically redacted:
log.info("Contact: john.doe@hospital.com, Phone: +49 201 723-0")
# Output: "Contact: [email], Phone: [phone]"
FastAPI Integration
from fastapi import FastAPI
from umelogging import log_configure, UMERequestLoggerMiddleware
log_configure("INFO", app="my-api", env="prod")
app = FastAPI()
app.add_middleware(UMERequestLoggerMiddleware)
@app.get("/patients/{id}")
async def get_patient(id: str):
return {"id": id}
Every request logs:
{"message":"request.start","method":"GET","path":"/patients/123","request_id":"550e8400-..."}
{"message":"request.end","status":200,"duration_ms":45,"request_id":"550e8400-..."}
The middleware:
- Extracts
X-Request-IDfrom headers (or generates UUID) - Returns
X-Request-IDin response headers - Measures request latency
- Sets
componentcontext to"http"
OpenTelemetry Integration
Add Trace IDs to Logs
When OpenTelemetry is configured, trace and span IDs are automatically added to every log:
{"message":"Processing","trace_id":"0af7651916cd43dd8448eb211c80319c","span_id":"b7ad6b7169203331"}
Setup Tracing
from umelogging.otel.handler import setup_otel_tracing
setup_otel_tracing(
service_name="patient-api",
otlp_endpoint="http://otel-collector:4318",
sampling_ratio=0.1, # Sample 10% of traces
)
Mirror Logs to Span Events
Attach logs as events on the current trace span:
import logging
from umelogging.otel.handler import OTelSpanEventHandler
logging.getLogger().addHandler(OTelSpanEventHandler())
Environment Variables
Core Configuration
| Variable | Description | Default |
|---|---|---|
UME_LOG_LEVEL |
Logging level | INFO |
UME_APP |
Application name | |
UME_ENV |
Environment (prod/dev/test) | prod |
UME_SERVICE |
Service name | |
UME_COMPONENT |
Component/module name | |
UME_USER_HASH_SALT |
Salt for user ID hashing | ume |
OpenTelemetry Configuration
| Variable | Description | Default |
|---|---|---|
OTEL_SERVICE_NAME |
Service name for traces | ume-service |
OTEL_EXPORTER_OTLP_ENDPOINT |
Collector endpoint | http://localhost:4318 |
OTEL_EXPORTER_OTLP_HEADERS |
Headers (key=val,k2=v2) |
|
OTEL_TRACES_SAMPLER_ARG |
Sampling ratio (0.0-1.0) | 1.0 |
API Reference
log_configure(level, *, app, env, service, component, stream, static_fields, propagate_existing)
Configure the root logger with JSON formatting and PII filtering.
set_context(*, app, env, service, component, request_id, user_id, extra)
Set context variables that are included in all subsequent logs.
with_request_id(request_id=None) -> str
Set or generate a request ID. Returns the ID.
get_context() -> dict
Get current context as a dictionary.
Development
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
License
MIT License — Copyright © University Medicine Essen
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 ume_logging-0.0.17.tar.gz.
File metadata
- Download URL: ume_logging-0.0.17.tar.gz
- Upload date:
- Size: 20.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a627c0b2756a4d1c6c2c8f1244a95b0f16ebaab4cfb149f498d6e90ac2e98097
|
|
| MD5 |
714c7355b02a45cf077b044e9f44893f
|
|
| BLAKE2b-256 |
49b189d08f7df63e6d3bd73febd5e72a499f510e397af8431cb10ff4f7ce02c6
|
Provenance
The following attestation bundles were made for ume_logging-0.0.17.tar.gz:
Publisher:
python-publish.yml on UMEssen/ume-logging
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ume_logging-0.0.17.tar.gz -
Subject digest:
a627c0b2756a4d1c6c2c8f1244a95b0f16ebaab4cfb149f498d6e90ac2e98097 - Sigstore transparency entry: 1181093768
- Sigstore integration time:
-
Permalink:
UMEssen/ume-logging@6c66bb28d57769d683affa66bf15d498255d90dc -
Branch / Tag:
refs/tags/0.0.17 - Owner: https://github.com/UMEssen
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@6c66bb28d57769d683affa66bf15d498255d90dc -
Trigger Event:
release
-
Statement type:
File details
Details for the file ume_logging-0.0.17-py3-none-any.whl.
File metadata
- Download URL: ume_logging-0.0.17-py3-none-any.whl
- Upload date:
- Size: 10.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f575b24bd4dc6f3711b9ea53fb28a916a85f8d741858520270c3c102553dbdbc
|
|
| MD5 |
7b59ac47fd789a61a9d63a27b297adeb
|
|
| BLAKE2b-256 |
db55cb341f43ce61f605360ca31ae36f456472152745f71589e6b4bdd3f85d3e
|
Provenance
The following attestation bundles were made for ume_logging-0.0.17-py3-none-any.whl:
Publisher:
python-publish.yml on UMEssen/ume-logging
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ume_logging-0.0.17-py3-none-any.whl -
Subject digest:
f575b24bd4dc6f3711b9ea53fb28a916a85f8d741858520270c3c102553dbdbc - Sigstore transparency entry: 1181093776
- Sigstore integration time:
-
Permalink:
UMEssen/ume-logging@6c66bb28d57769d683affa66bf15d498255d90dc -
Branch / Tag:
refs/tags/0.0.17 - Owner: https://github.com/UMEssen
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@6c66bb28d57769d683affa66bf15d498255d90dc -
Trigger Event:
release
-
Statement type: