Uniform JSON logging for University Medicine Essen applications. Designed for microservices running in Docker/Kubernetes with ELK stack integration.
- 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
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]"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}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"}Emails and phone numbers are automatically redacted:
log.info("Contact: john.doe@hospital.com, Phone: +49 201 723-0")
# Output: "Contact: [email], Phone: [phone]"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"
When OpenTelemetry is configured, trace and span IDs are automatically added to every log:
{"message":"Processing","trace_id":"0af7651916cd43dd8448eb211c80319c","span_id":"b7ad6b7169203331"}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
)Attach logs as events on the current trace span:
import logging
from umelogging.otel.handler import OTelSpanEventHandler
logging.getLogger().addHandler(OTelSpanEventHandler())| 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 |
| 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 |
Configure the root logger with JSON formatting and PII filtering.
Set context variables that are included in all subsequent logs.
Set or generate a request ID. Returns the ID.
Get current context as a dictionary.
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/ -vMIT License — Copyright © University Medicine Essen