Framework-agnostic metrics and structured log collection with hexagonal architecture
Project description
observabilipy
Framework-agnostic metrics and structured log collection with hexagonal architecture.
Develop observability features decoupled from your infrastructure. Use embedded storage (SQLite, in-memory) during development, then optionally expose endpoints for scraping by Prometheus, Grafana Alloy, or other observability platforms when you're ready.
Features
- Prometheus-style metrics -
/metricsendpoint in text format - Structured logs -
/logsendpoint in NDJSON (Grafana Alloy compatible) - Framework adapters - FastAPI, Django, ASGI, WSGI
- Storage backends - In-memory, SQLite (with WAL), Ring buffer
- Retention policies - Automatic cleanup with EmbeddedRuntime
Installation
git clone https://github.com/PhilHem/observabilipy.git
cd observabilipy
uv sync
For framework support:
uv sync --extra fastapi
uv sync --extra django
Quick Start
from fastapi import FastAPI
from observabilipy import InMemoryLogStorage, InMemoryMetricsStorage
from observabilipy.adapters.frameworks.fastapi import create_observability_router
app = FastAPI()
log_storage = InMemoryLogStorage()
metrics_storage = InMemoryMetricsStorage()
app.include_router(create_observability_router(log_storage, metrics_storage))
Run with uvicorn and visit:
/logs- NDJSON logs (with optional?since=<timestamp>&level=<level>)/metrics- NDJSON metrics (with optional?since=<timestamp>)/metrics/prometheus- Prometheus text format (latest value per metric)
Recording Metrics and Logs
Use the helper functions for a cleaner API:
from observabilipy import info, error, counter, gauge
# Log entries with level-specific helpers
await log_storage.write(info("User logged in", user_id=123, ip="192.168.1.1"))
await log_storage.write(error("Payment failed", order_id=456, reason="timeout"))
# Metrics with semantic helpers
await metrics_storage.write(counter("http_requests_total", method="GET", path="/api/users"))
await metrics_storage.write(gauge("active_connections", value=42))
Context Managers
from observabilipy import timer, timed_log
# Auto-record timing to histogram
async with timer(metrics_storage, "request_duration_seconds", method="GET"):
await handle_request()
# Log entry and exit with elapsed time
async with timed_log(log_storage, "Processing order", order_id=123):
await process_order()
Exception Logging
from observabilipy import log_exception
try:
risky_operation()
except Exception:
await log_storage.write(log_exception("Operation failed", operation="risky"))
Raw Model Access
For full control, use the models directly:
import time
from observabilipy import LogEntry, MetricSample
await log_storage.write(
LogEntry(
timestamp=time.time(),
level="INFO",
message="User logged in",
attributes={"user_id": 123},
)
)
await metrics_storage.write(
MetricSample(
name="http_requests_total",
timestamp=time.time(),
value=1.0,
labels={"method": "GET"},
)
)
Storage Backends
| Backend | Use Case |
|---|---|
InMemoryLogStorage / InMemoryMetricsStorage |
Development and testing |
SQLiteLogStorage / SQLiteMetricsStorage |
Persistent storage with WAL mode for concurrent access |
RingBufferLogStorage / RingBufferMetricsStorage |
Fixed-size buffer for memory-constrained environments |
All backends implement the same port interfaces and are interchangeable.
Examples
See the examples/ directory:
| Example | Description |
|---|---|
| minimal_example.py | Dummy metrics and logs generator for testing |
| cgroups_example.py | Container CPU and memory metrics from cgroups v2 |
| fastapi_example.py | Basic FastAPI setup with in-memory storage |
| django_example.py | Django integration |
| asgi_example.py | Generic ASGI middleware |
| sqlite_example.py | Persistent storage with SQLite |
| ring_buffer_example.py | Fixed-size storage for constrained environments |
| embedded_runtime_example.py | Background retention cleanup |
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 observabilipy-1.1.0.tar.gz.
File metadata
- Download URL: observabilipy-1.1.0.tar.gz
- Upload date:
- Size: 119.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 |
1b866170d15d127758bf04ddf6193b343c8c2d8b3f6925bad4672b87913444fd
|
|
| MD5 |
c777d9565c9dfb311dc4f76d5d3abb72
|
|
| BLAKE2b-256 |
8bbf84a28ec4dd6194e4cd634caefc0d1b42f407fa11700225297394655d6511
|
Provenance
The following attestation bundles were made for observabilipy-1.1.0.tar.gz:
Publisher:
release.yml on PhilHem/observabilipy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
observabilipy-1.1.0.tar.gz -
Subject digest:
1b866170d15d127758bf04ddf6193b343c8c2d8b3f6925bad4672b87913444fd - Sigstore transparency entry: 763382535
- Sigstore integration time:
-
Permalink:
PhilHem/observabilipy@b5bf7ead42e01fe0efbf4285f463e8f2a13eb655 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/PhilHem
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b5bf7ead42e01fe0efbf4285f463e8f2a13eb655 -
Trigger Event:
push
-
Statement type:
File details
Details for the file observabilipy-1.1.0-py3-none-any.whl.
File metadata
- Download URL: observabilipy-1.1.0-py3-none-any.whl
- Upload date:
- Size: 35.9 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 |
32507c956114f771baa7ef56b969f63fc5bc08e33805eb5b1c285eb0add51fad
|
|
| MD5 |
4e7f52aa702f1468136695d618e71e5f
|
|
| BLAKE2b-256 |
520b32c94b64287105ccfea8b7ea0fdd2f6a49914a01bd0decf5cc7cd877eacf
|
Provenance
The following attestation bundles were made for observabilipy-1.1.0-py3-none-any.whl:
Publisher:
release.yml on PhilHem/observabilipy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
observabilipy-1.1.0-py3-none-any.whl -
Subject digest:
32507c956114f771baa7ef56b969f63fc5bc08e33805eb5b1c285eb0add51fad - Sigstore transparency entry: 763382536
- Sigstore integration time:
-
Permalink:
PhilHem/observabilipy@b5bf7ead42e01fe0efbf4285f463e8f2a13eb655 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/PhilHem
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b5bf7ead42e01fe0efbf4285f463e8f2a13eb655 -
Trigger Event:
push
-
Statement type: