fastapi-observer 1.4.1__tar.gz → 1.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastapi_observer-1.6.0/PKG-INFO +215 -0
- fastapi_observer-1.6.0/README.md +139 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/pyproject.toml +3 -5
- fastapi_observer-1.6.0/src/fastapi_observer.egg-info/PKG-INFO +215 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapi_observer.egg-info/requires.txt +1 -6
- fastapi_observer-1.6.0/src/fastapiobserver/_version.py +1 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/fastapi.py +7 -0
- fastapi_observer-1.6.0/src/fastapiobserver/logging/filters.py +61 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/logging/formatter.py +18 -5
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/logging/queueing.py +11 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/middleware/metrics.py +6 -2
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/middleware/request_logging.py +31 -19
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/otel/tracing.py +0 -14
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/plugins.py +3 -1
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/security/normalize.py +4 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/security/proxies.py +15 -10
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/security/redaction.py +37 -20
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_fastapi_install.py +12 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_logging_schema_contract.py +60 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_otel_log_correlation.py +7 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_trust_boundary.py +22 -1
- fastapi_observer-1.4.1/PKG-INFO +0 -251
- fastapi_observer-1.4.1/README.md +0 -173
- fastapi_observer-1.4.1/src/fastapi_observer.egg-info/PKG-INFO +0 -251
- fastapi_observer-1.4.1/src/fastapiobserver/_version.py +0 -1
- fastapi_observer-1.4.1/src/fastapiobserver/logging/filters.py +0 -53
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/LICENSE +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/setup.cfg +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapi_observer.egg-info/SOURCES.txt +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapi_observer.egg-info/dependency_links.txt +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapi_observer.egg-info/top_level.txt +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/__init__.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/audit/__init__.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/audit/formatter.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/audit/providers.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/audit/verify.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/config.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/control_plane.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/db_tracing.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/integrations/__init__.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/integrations/strawberry.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/logging/__init__.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/logging/circuit_breaker.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/logging/setup.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/logging/state.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/loguru.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/__init__.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/builder.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/contracts.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/endpoint.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/noop.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/pathing.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/prometheus/__init__.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/prometheus/backend.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/prometheus/client.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/prometheus/collector.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/prometheus/exemplars.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/prometheus/multiprocess.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/metrics/registry.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/middleware/__init__.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/middleware/body_capture.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/middleware/context.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/middleware/events.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/middleware/headers.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/middleware/ip.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/middleware/span_errors.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/otel/__init__.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/otel/exclusions.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/otel/lifecycle.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/otel/logs.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/otel/metrics.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/otel/resource.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/otel/settings.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/otel/types.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/profiles.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/propagation.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/py.typed +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/request_context.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/security/__init__.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/security/policy.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/sinks/__init__.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/sinks/builtin.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/sinks/discovery.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/sinks/factory.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/sinks/logtail/__init__.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/sinks/logtail/dlq.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/sinks/logtail/handler.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/sinks/logtail/sink.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/sinks/protocol.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/sinks/registry.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/sinks/stats.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapiobserver/utils.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_audit_chain.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_body_media_allowlist.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_config_settings.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_db_tracing.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_dx_parity.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_excluded_url_precedence.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_fork_queue_listener.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_graphql_integrations.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_lifespan_teardown.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_log_queue_controls.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_logtail_dlq.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_loguru_bridge.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_metrics_contracts.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_metrics_optional_dependency.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_middleware.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_negotiate_content_type.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_otel_integration.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_otel_lifecycle.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_otel_logs_from_env.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_otel_logs_pipeline.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_otel_metrics_from_env.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_otlp_export_integration.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_plugin_isolation.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_profiles.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_propagation.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_redaction_presets.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_route_template_cardinality.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_runtime_control_auth.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_security_audit_fixes.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_security_redaction.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_sink_circuit_breaker.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_sinks.py +0 -0
- {fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/tests/test_utils_refactors.py +0 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fastapi-observer
|
|
3
|
+
Version: 1.6.0
|
|
4
|
+
Summary: Zero-glue FastAPI observability with security presets and runtime controls
|
|
5
|
+
Author-email: Vitaee <opensource@vitaee.dev>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Vitaee/FastapiObserver
|
|
8
|
+
Project-URL: Documentation, https://vitaee.github.io/FastapiObserver/
|
|
9
|
+
Project-URL: Repository, https://github.com/Vitaee/FastapiObserver.git
|
|
10
|
+
Project-URL: Issues, https://github.com/Vitaee/FastapiObserver/issues
|
|
11
|
+
Project-URL: Funding, https://buymeacoffee.com/FYbPCSu
|
|
12
|
+
Keywords: fastapi,observability,logging,metrics,opentelemetry
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
22
|
+
Classifier: Framework :: FastAPI
|
|
23
|
+
Classifier: Topic :: System :: Logging
|
|
24
|
+
Classifier: Topic :: System :: Monitoring
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: fastapi>=0.133.0
|
|
30
|
+
Requires-Dist: pydantic-settings>=2.10.1
|
|
31
|
+
Requires-Dist: starlette>=1.3.1
|
|
32
|
+
Provides-Extra: fast-json
|
|
33
|
+
Requires-Dist: orjson>=3.11.7; extra == "fast-json"
|
|
34
|
+
Provides-Extra: prometheus
|
|
35
|
+
Requires-Dist: prometheus-client>=0.24.1; extra == "prometheus"
|
|
36
|
+
Provides-Extra: loguru
|
|
37
|
+
Requires-Dist: loguru>=0.7.2; extra == "loguru"
|
|
38
|
+
Provides-Extra: otel
|
|
39
|
+
Requires-Dist: opentelemetry-api>=1.45.1; extra == "otel"
|
|
40
|
+
Requires-Dist: opentelemetry-sdk>=1.45.1; extra == "otel"
|
|
41
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.45.1; extra == "otel"
|
|
42
|
+
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.66b1; extra == "otel"
|
|
43
|
+
Requires-Dist: opentelemetry-instrumentation-logging>=0.66b1; extra == "otel"
|
|
44
|
+
Provides-Extra: otel-httpx
|
|
45
|
+
Requires-Dist: opentelemetry-instrumentation-httpx>=0.66b1; extra == "otel-httpx"
|
|
46
|
+
Provides-Extra: otel-requests
|
|
47
|
+
Requires-Dist: opentelemetry-instrumentation-requests>=0.66b1; extra == "otel-requests"
|
|
48
|
+
Provides-Extra: audit
|
|
49
|
+
Requires-Dist: cryptography>=50.0.0; extra == "audit"
|
|
50
|
+
Provides-Extra: otel-sqlalchemy
|
|
51
|
+
Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.66b1; extra == "otel-sqlalchemy"
|
|
52
|
+
Provides-Extra: all
|
|
53
|
+
Requires-Dist: orjson>=3.11.7; extra == "all"
|
|
54
|
+
Requires-Dist: prometheus-client>=0.24.1; extra == "all"
|
|
55
|
+
Requires-Dist: loguru>=0.7.2; extra == "all"
|
|
56
|
+
Requires-Dist: opentelemetry-api>=1.45.1; extra == "all"
|
|
57
|
+
Requires-Dist: opentelemetry-sdk>=1.45.1; extra == "all"
|
|
58
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.45.1; extra == "all"
|
|
59
|
+
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.66b1; extra == "all"
|
|
60
|
+
Requires-Dist: opentelemetry-instrumentation-logging>=0.66b1; extra == "all"
|
|
61
|
+
Requires-Dist: opentelemetry-instrumentation-httpx>=0.66b1; extra == "all"
|
|
62
|
+
Requires-Dist: opentelemetry-instrumentation-requests>=0.66b1; extra == "all"
|
|
63
|
+
Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.66b1; extra == "all"
|
|
64
|
+
Requires-Dist: cryptography>=50.0.0; extra == "all"
|
|
65
|
+
Provides-Extra: dev
|
|
66
|
+
Requires-Dist: httpx2>=2.16.0; extra == "dev"
|
|
67
|
+
Requires-Dist: loguru>=0.7.3; extra == "dev"
|
|
68
|
+
Requires-Dist: mypy>=2.4.1; extra == "dev"
|
|
69
|
+
Requires-Dist: pip-audit>=2.10.1; extra == "dev"
|
|
70
|
+
Requires-Dist: pytest>=9.2.0; extra == "dev"
|
|
71
|
+
Requires-Dist: pytest-randomly>=5.0.0; extra == "dev"
|
|
72
|
+
Requires-Dist: ruff>=0.17.3; extra == "dev"
|
|
73
|
+
Requires-Dist: cyclonedx-bom>=7.6.0; extra == "dev"
|
|
74
|
+
Requires-Dist: uvicorn>=0.54.0; extra == "dev"
|
|
75
|
+
Dynamic: license-file
|
|
76
|
+
|
|
77
|
+
# fastapi-observer
|
|
78
|
+
|
|
79
|
+
[](https://github.com/Vitaee/FastapiObserver/actions/workflows/ci.yml)
|
|
80
|
+
[](https://pypi.org/project/fastapi-observer/)
|
|
81
|
+
[](https://pypi.org/project/fastapi-observer/)
|
|
82
|
+
[](https://github.com/Vitaee/FastapiObserver/blob/main/LICENSE)
|
|
83
|
+
|
|
84
|
+
**One-call observability for FastAPI.** JSON logs with request IDs, Prometheus metrics and OpenTelemetry traces, with sensitive data redacted by default. No vendor backend: send it to whatever you already run.
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from fastapi import FastAPI
|
|
88
|
+
from fastapiobserver import install_observability
|
|
89
|
+
|
|
90
|
+
app = FastAPI()
|
|
91
|
+
install_observability(app)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Every request now writes one JSON line, with the same `trace_id` as its trace when tracing is on:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"timestamp": "2026-10-31T09:10:20.345831+00:00",
|
|
99
|
+
"level": "INFO",
|
|
100
|
+
"logger": "fastapiobserver.middleware",
|
|
101
|
+
"message": "request.completed",
|
|
102
|
+
"app_name": "orders-api",
|
|
103
|
+
"service": "orders",
|
|
104
|
+
"environment": "production",
|
|
105
|
+
"version": "2.3.1",
|
|
106
|
+
"request_id": "d496f541-5e5e-4f14-9174-e9bd697faa62",
|
|
107
|
+
"trace_id": "11d5b6f088bfdba501927e55463be4cd",
|
|
108
|
+
"span_id": "50a12c2d9937eacb",
|
|
109
|
+
"event": {
|
|
110
|
+
"method": "GET",
|
|
111
|
+
"path": "/orders/42",
|
|
112
|
+
"status_code": 200,
|
|
113
|
+
"duration_ms": 1.314,
|
|
114
|
+
"client_ip": "203.0.113.7",
|
|
115
|
+
"error_type": "ok"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Documentation:** [vitaee.github.io/FastapiObserver](https://vitaee.github.io/FastapiObserver/)
|
|
121
|
+
|
|
122
|
+
## Install
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pip install fastapi-observer # JSON logs, request IDs, redaction
|
|
126
|
+
pip install "fastapi-observer[prometheus]" # + Prometheus /metrics
|
|
127
|
+
pip install "fastapi-observer[otel]" # + OpenTelemetry traces and OTLP logs
|
|
128
|
+
pip install "fastapi-observer[all]" # everything
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Requires Python 3.11 or newer.
|
|
132
|
+
|
|
133
|
+
## Configure with environment variables
|
|
134
|
+
|
|
135
|
+
`install_observability(app)` reads its settings from the environment. These are the ones most apps set:
|
|
136
|
+
|
|
137
|
+
| Variable | Example | What it does |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| `APP_NAME`, `SERVICE_NAME`, `ENVIRONMENT`, `APP_VERSION` | `orders-api`, `orders`, `production`, `2.3.1` | Added to every log line |
|
|
140
|
+
| `METRICS_ENABLED` | `true` | Serves Prometheus metrics at `/metrics` (needs `[prometheus]`) |
|
|
141
|
+
| `OTEL_ENABLED`, `OTEL_EXPORTER_OTLP_ENDPOINT` | `true`, `http://collector:4317` | Sends traces over OTLP and adds `trace_id` to logs (needs `[otel]`) |
|
|
142
|
+
| `OBS_REDACTION_PRESET` | `strict`, `pci`, `gdpr` | Chooses which fields and headers are masked |
|
|
143
|
+
| `OBS_PROFILE` | `development`, `production` | Sensible defaults: `production` sets `INFO` logs, a larger log queue and the `strict` preset |
|
|
144
|
+
|
|
145
|
+
Explicit variables and Python arguments always win over profile defaults. Every setting is listed in the [configuration guide](https://vitaee.github.io/FastapiObserver/configuration/).
|
|
146
|
+
|
|
147
|
+
## What you get
|
|
148
|
+
|
|
149
|
+
- **One JSON line per request** with method, path, status, duration and client IP, and your service's name, environment and version on every line, including your own `logging` calls.
|
|
150
|
+
- **Request IDs** taken from `X-Request-ID` when the caller is a trusted proxy, generated otherwise, and returned in the response.
|
|
151
|
+
- **Redaction on by default.** Passwords, tokens, API keys, `Authorization` and cookies are masked before anything is written. Presets cover stricter needs (`strict`, `pci`, `gdpr`).
|
|
152
|
+
- **Prometheus metrics** labelled by route template (`/orders/{order_id}`), so URLs with IDs don't explode cardinality.
|
|
153
|
+
- **OpenTelemetry traces** with `trace_id` and `span_id` in every log line, and optional log export over OTLP.
|
|
154
|
+
- **Non-blocking log writes.** Lines are written from a background thread, so a slow stdout never stalls the event loop.
|
|
155
|
+
|
|
156
|
+
Optional extras: runtime log-level control, a tamper-evident audit log, SQLAlchemy, `httpx` and `requests` tracing, Strawberry GraphQL and a Loguru bridge. See the [documentation](https://vitaee.github.io/FastapiObserver/).
|
|
157
|
+
|
|
158
|
+

|
|
159
|
+
|
|
160
|
+
*The Grafana dashboard from [`examples/full_stack`](https://github.com/Vitaee/FastapiObserver/tree/main/examples/full_stack), a Docker Compose stack you can run locally.*
|
|
161
|
+
|
|
162
|
+
## How it compares
|
|
163
|
+
|
|
164
|
+
| | fastapi-observer | structlog or loguru | OpenTelemetry auto-instrumentation | Logfire |
|
|
165
|
+
|---|---|---|---|---|
|
|
166
|
+
| JSON log line per request | Built in | You write the middleware | No | A span per request |
|
|
167
|
+
| Request ID on every log line | Built in | You wire it up | No | Trace IDs |
|
|
168
|
+
| Redaction by default | Yes, with presets | You write a processor | No | Yes |
|
|
169
|
+
| Prometheus `/metrics` | Built in | No | Through an exporter | No |
|
|
170
|
+
| Traces | OpenTelemetry | No | Yes | Yes |
|
|
171
|
+
| Where data goes | stdout, Prometheus and any OTLP backend | stdout or files | Any OTLP backend | Logfire's platform |
|
|
172
|
+
|
|
173
|
+
**When not to use it:**
|
|
174
|
+
|
|
175
|
+
- You only want logs and need the lowest possible overhead: structlog alone does less work per line.
|
|
176
|
+
- You already send everything to Logfire, Datadog or Sentry: their own FastAPI integrations fit better.
|
|
177
|
+
- Your app isn't built on FastAPI or Starlette.
|
|
178
|
+
|
|
179
|
+
What it costs: with default settings, about 43 µs of CPU per request on an Apple M1. See the [benchmarks](https://vitaee.github.io/FastapiObserver/benchmarks/), including a comparison with wiring the same stack by hand.
|
|
180
|
+
|
|
181
|
+
## Works with
|
|
182
|
+
|
|
183
|
+
- **Servers:** uvicorn, gunicorn with `UvicornWorker`, and Granian. Uvicorn's duplicate access line is dropped automatically. To get the servers' own startup lines as JSON too, see [running with gunicorn and Granian](https://vitaee.github.io/FastapiObserver/servers/).
|
|
184
|
+
- **Backends:** Prometheus, Grafana (Loki, Tempo), Jaeger and anything that accepts OTLP. See [backends](https://vitaee.github.io/FastapiObserver/backends/).
|
|
185
|
+
- **Error tracking:** runs alongside Sentry. See the [Sentry notes](https://vitaee.github.io/FastapiObserver/sentry/).
|
|
186
|
+
|
|
187
|
+
## Why you can trust it
|
|
188
|
+
|
|
189
|
+
- Tested in CI on Python 3.11 to 3.15, fully typed, and used in production by its maintainer.
|
|
190
|
+
- Releases are published with PyPI Trusted Publishing and signed attestations. CI runs `pip-audit` and generates an SBOM.
|
|
191
|
+
- Security fixes are called out in the [changelog](https://github.com/Vitaee/FastapiObserver/blob/main/CHANGELOG.md). To report a vulnerability, see [SECURITY.md](https://github.com/Vitaee/FastapiObserver/blob/main/SECURITY.md).
|
|
192
|
+
- Benchmarks are reproducible from [`examples/benchmarks`](https://github.com/Vitaee/FastapiObserver/tree/main/examples/benchmarks).
|
|
193
|
+
|
|
194
|
+
## Compatibility
|
|
195
|
+
|
|
196
|
+
| Component | Supported |
|
|
197
|
+
|---|---|
|
|
198
|
+
| Python | `>=3.11` (CI: `3.11` to `3.15`) |
|
|
199
|
+
| FastAPI | `>=0.133.0` |
|
|
200
|
+
| Starlette | `>=1.3.1` |
|
|
201
|
+
| Prometheus extra | `prometheus-client>=0.24.1` |
|
|
202
|
+
| OpenTelemetry extra | `opentelemetry-api/sdk/exporter>=1.45.1` |
|
|
203
|
+
|
|
204
|
+
## Documentation
|
|
205
|
+
|
|
206
|
+
- [Configuration](https://vitaee.github.io/FastapiObserver/configuration/) and [structured logging](https://vitaee.github.io/FastapiObserver/logging/)
|
|
207
|
+
- [Security and redaction presets](https://vitaee.github.io/FastapiObserver/security/)
|
|
208
|
+
- [OpenTelemetry](https://vitaee.github.io/FastapiObserver/opentelemetry/)
|
|
209
|
+
- [Production deployment](https://vitaee.github.io/FastapiObserver/deployment/) and [Kubernetes](https://vitaee.github.io/FastapiObserver/kubernetes/)
|
|
210
|
+
- [Benchmarks](https://vitaee.github.io/FastapiObserver/benchmarks/) and [performance tuning](https://vitaee.github.io/FastapiObserver/tuning/)
|
|
211
|
+
- [Contributing](https://vitaee.github.io/FastapiObserver/contributing/)
|
|
212
|
+
|
|
213
|
+
## Support the project
|
|
214
|
+
|
|
215
|
+
If this library saves you time, you can [buy me a coffee](https://buymeacoffee.com/FYbPCSu).
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# fastapi-observer
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Vitaee/FastapiObserver/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/fastapi-observer/)
|
|
5
|
+
[](https://pypi.org/project/fastapi-observer/)
|
|
6
|
+
[](https://github.com/Vitaee/FastapiObserver/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
**One-call observability for FastAPI.** JSON logs with request IDs, Prometheus metrics and OpenTelemetry traces, with sensitive data redacted by default. No vendor backend: send it to whatever you already run.
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
from fastapi import FastAPI
|
|
12
|
+
from fastapiobserver import install_observability
|
|
13
|
+
|
|
14
|
+
app = FastAPI()
|
|
15
|
+
install_observability(app)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Every request now writes one JSON line, with the same `trace_id` as its trace when tracing is on:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"timestamp": "2026-10-31T09:10:20.345831+00:00",
|
|
23
|
+
"level": "INFO",
|
|
24
|
+
"logger": "fastapiobserver.middleware",
|
|
25
|
+
"message": "request.completed",
|
|
26
|
+
"app_name": "orders-api",
|
|
27
|
+
"service": "orders",
|
|
28
|
+
"environment": "production",
|
|
29
|
+
"version": "2.3.1",
|
|
30
|
+
"request_id": "d496f541-5e5e-4f14-9174-e9bd697faa62",
|
|
31
|
+
"trace_id": "11d5b6f088bfdba501927e55463be4cd",
|
|
32
|
+
"span_id": "50a12c2d9937eacb",
|
|
33
|
+
"event": {
|
|
34
|
+
"method": "GET",
|
|
35
|
+
"path": "/orders/42",
|
|
36
|
+
"status_code": 200,
|
|
37
|
+
"duration_ms": 1.314,
|
|
38
|
+
"client_ip": "203.0.113.7",
|
|
39
|
+
"error_type": "ok"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Documentation:** [vitaee.github.io/FastapiObserver](https://vitaee.github.io/FastapiObserver/)
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install fastapi-observer # JSON logs, request IDs, redaction
|
|
50
|
+
pip install "fastapi-observer[prometheus]" # + Prometheus /metrics
|
|
51
|
+
pip install "fastapi-observer[otel]" # + OpenTelemetry traces and OTLP logs
|
|
52
|
+
pip install "fastapi-observer[all]" # everything
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Requires Python 3.11 or newer.
|
|
56
|
+
|
|
57
|
+
## Configure with environment variables
|
|
58
|
+
|
|
59
|
+
`install_observability(app)` reads its settings from the environment. These are the ones most apps set:
|
|
60
|
+
|
|
61
|
+
| Variable | Example | What it does |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `APP_NAME`, `SERVICE_NAME`, `ENVIRONMENT`, `APP_VERSION` | `orders-api`, `orders`, `production`, `2.3.1` | Added to every log line |
|
|
64
|
+
| `METRICS_ENABLED` | `true` | Serves Prometheus metrics at `/metrics` (needs `[prometheus]`) |
|
|
65
|
+
| `OTEL_ENABLED`, `OTEL_EXPORTER_OTLP_ENDPOINT` | `true`, `http://collector:4317` | Sends traces over OTLP and adds `trace_id` to logs (needs `[otel]`) |
|
|
66
|
+
| `OBS_REDACTION_PRESET` | `strict`, `pci`, `gdpr` | Chooses which fields and headers are masked |
|
|
67
|
+
| `OBS_PROFILE` | `development`, `production` | Sensible defaults: `production` sets `INFO` logs, a larger log queue and the `strict` preset |
|
|
68
|
+
|
|
69
|
+
Explicit variables and Python arguments always win over profile defaults. Every setting is listed in the [configuration guide](https://vitaee.github.io/FastapiObserver/configuration/).
|
|
70
|
+
|
|
71
|
+
## What you get
|
|
72
|
+
|
|
73
|
+
- **One JSON line per request** with method, path, status, duration and client IP, and your service's name, environment and version on every line, including your own `logging` calls.
|
|
74
|
+
- **Request IDs** taken from `X-Request-ID` when the caller is a trusted proxy, generated otherwise, and returned in the response.
|
|
75
|
+
- **Redaction on by default.** Passwords, tokens, API keys, `Authorization` and cookies are masked before anything is written. Presets cover stricter needs (`strict`, `pci`, `gdpr`).
|
|
76
|
+
- **Prometheus metrics** labelled by route template (`/orders/{order_id}`), so URLs with IDs don't explode cardinality.
|
|
77
|
+
- **OpenTelemetry traces** with `trace_id` and `span_id` in every log line, and optional log export over OTLP.
|
|
78
|
+
- **Non-blocking log writes.** Lines are written from a background thread, so a slow stdout never stalls the event loop.
|
|
79
|
+
|
|
80
|
+
Optional extras: runtime log-level control, a tamper-evident audit log, SQLAlchemy, `httpx` and `requests` tracing, Strawberry GraphQL and a Loguru bridge. See the [documentation](https://vitaee.github.io/FastapiObserver/).
|
|
81
|
+
|
|
82
|
+

|
|
83
|
+
|
|
84
|
+
*The Grafana dashboard from [`examples/full_stack`](https://github.com/Vitaee/FastapiObserver/tree/main/examples/full_stack), a Docker Compose stack you can run locally.*
|
|
85
|
+
|
|
86
|
+
## How it compares
|
|
87
|
+
|
|
88
|
+
| | fastapi-observer | structlog or loguru | OpenTelemetry auto-instrumentation | Logfire |
|
|
89
|
+
|---|---|---|---|---|
|
|
90
|
+
| JSON log line per request | Built in | You write the middleware | No | A span per request |
|
|
91
|
+
| Request ID on every log line | Built in | You wire it up | No | Trace IDs |
|
|
92
|
+
| Redaction by default | Yes, with presets | You write a processor | No | Yes |
|
|
93
|
+
| Prometheus `/metrics` | Built in | No | Through an exporter | No |
|
|
94
|
+
| Traces | OpenTelemetry | No | Yes | Yes |
|
|
95
|
+
| Where data goes | stdout, Prometheus and any OTLP backend | stdout or files | Any OTLP backend | Logfire's platform |
|
|
96
|
+
|
|
97
|
+
**When not to use it:**
|
|
98
|
+
|
|
99
|
+
- You only want logs and need the lowest possible overhead: structlog alone does less work per line.
|
|
100
|
+
- You already send everything to Logfire, Datadog or Sentry: their own FastAPI integrations fit better.
|
|
101
|
+
- Your app isn't built on FastAPI or Starlette.
|
|
102
|
+
|
|
103
|
+
What it costs: with default settings, about 43 µs of CPU per request on an Apple M1. See the [benchmarks](https://vitaee.github.io/FastapiObserver/benchmarks/), including a comparison with wiring the same stack by hand.
|
|
104
|
+
|
|
105
|
+
## Works with
|
|
106
|
+
|
|
107
|
+
- **Servers:** uvicorn, gunicorn with `UvicornWorker`, and Granian. Uvicorn's duplicate access line is dropped automatically. To get the servers' own startup lines as JSON too, see [running with gunicorn and Granian](https://vitaee.github.io/FastapiObserver/servers/).
|
|
108
|
+
- **Backends:** Prometheus, Grafana (Loki, Tempo), Jaeger and anything that accepts OTLP. See [backends](https://vitaee.github.io/FastapiObserver/backends/).
|
|
109
|
+
- **Error tracking:** runs alongside Sentry. See the [Sentry notes](https://vitaee.github.io/FastapiObserver/sentry/).
|
|
110
|
+
|
|
111
|
+
## Why you can trust it
|
|
112
|
+
|
|
113
|
+
- Tested in CI on Python 3.11 to 3.15, fully typed, and used in production by its maintainer.
|
|
114
|
+
- Releases are published with PyPI Trusted Publishing and signed attestations. CI runs `pip-audit` and generates an SBOM.
|
|
115
|
+
- Security fixes are called out in the [changelog](https://github.com/Vitaee/FastapiObserver/blob/main/CHANGELOG.md). To report a vulnerability, see [SECURITY.md](https://github.com/Vitaee/FastapiObserver/blob/main/SECURITY.md).
|
|
116
|
+
- Benchmarks are reproducible from [`examples/benchmarks`](https://github.com/Vitaee/FastapiObserver/tree/main/examples/benchmarks).
|
|
117
|
+
|
|
118
|
+
## Compatibility
|
|
119
|
+
|
|
120
|
+
| Component | Supported |
|
|
121
|
+
|---|---|
|
|
122
|
+
| Python | `>=3.11` (CI: `3.11` to `3.15`) |
|
|
123
|
+
| FastAPI | `>=0.133.0` |
|
|
124
|
+
| Starlette | `>=1.3.1` |
|
|
125
|
+
| Prometheus extra | `prometheus-client>=0.24.1` |
|
|
126
|
+
| OpenTelemetry extra | `opentelemetry-api/sdk/exporter>=1.45.1` |
|
|
127
|
+
|
|
128
|
+
## Documentation
|
|
129
|
+
|
|
130
|
+
- [Configuration](https://vitaee.github.io/FastapiObserver/configuration/) and [structured logging](https://vitaee.github.io/FastapiObserver/logging/)
|
|
131
|
+
- [Security and redaction presets](https://vitaee.github.io/FastapiObserver/security/)
|
|
132
|
+
- [OpenTelemetry](https://vitaee.github.io/FastapiObserver/opentelemetry/)
|
|
133
|
+
- [Production deployment](https://vitaee.github.io/FastapiObserver/deployment/) and [Kubernetes](https://vitaee.github.io/FastapiObserver/kubernetes/)
|
|
134
|
+
- [Benchmarks](https://vitaee.github.io/FastapiObserver/benchmarks/) and [performance tuning](https://vitaee.github.io/FastapiObserver/tuning/)
|
|
135
|
+
- [Contributing](https://vitaee.github.io/FastapiObserver/contributing/)
|
|
136
|
+
|
|
137
|
+
## Support the project
|
|
138
|
+
|
|
139
|
+
If this library saves you time, you can [buy me a coffee](https://buymeacoffee.com/FYbPCSu).
|
|
@@ -7,7 +7,7 @@ name = "fastapi-observer"
|
|
|
7
7
|
dynamic = ["version"]
|
|
8
8
|
description = "Zero-glue FastAPI observability with security presets and runtime controls"
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
11
|
authors = [
|
|
12
12
|
{ name = "Vitaee", email = "opensource@vitaee.dev" },
|
|
13
13
|
]
|
|
@@ -16,7 +16,6 @@ classifiers = [
|
|
|
16
16
|
"Intended Audience :: Developers",
|
|
17
17
|
"Operating System :: OS Independent",
|
|
18
18
|
"Programming Language :: Python :: 3",
|
|
19
|
-
"Programming Language :: Python :: 3.10",
|
|
20
19
|
"Programming Language :: Python :: 3.11",
|
|
21
20
|
"Programming Language :: Python :: 3.12",
|
|
22
21
|
"Programming Language :: Python :: 3.13",
|
|
@@ -87,8 +86,7 @@ all = [
|
|
|
87
86
|
"cryptography>=50.0.0",
|
|
88
87
|
]
|
|
89
88
|
dev = [
|
|
90
|
-
"
|
|
91
|
-
"httpx2>=2.16.0; python_version >= '3.11'",
|
|
89
|
+
"httpx2>=2.16.0",
|
|
92
90
|
"loguru>=0.7.3",
|
|
93
91
|
"mypy>=2.4.1",
|
|
94
92
|
"pip-audit>=2.10.1",
|
|
@@ -109,7 +107,7 @@ version = { attr = "fastapiobserver._version.__version__" }
|
|
|
109
107
|
where = ["src"]
|
|
110
108
|
|
|
111
109
|
[tool.ruff]
|
|
112
|
-
target-version = "
|
|
110
|
+
target-version = "py311"
|
|
113
111
|
line-length = 100
|
|
114
112
|
src = ["src", "tests"]
|
|
115
113
|
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fastapi-observer
|
|
3
|
+
Version: 1.6.0
|
|
4
|
+
Summary: Zero-glue FastAPI observability with security presets and runtime controls
|
|
5
|
+
Author-email: Vitaee <opensource@vitaee.dev>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Vitaee/FastapiObserver
|
|
8
|
+
Project-URL: Documentation, https://vitaee.github.io/FastapiObserver/
|
|
9
|
+
Project-URL: Repository, https://github.com/Vitaee/FastapiObserver.git
|
|
10
|
+
Project-URL: Issues, https://github.com/Vitaee/FastapiObserver/issues
|
|
11
|
+
Project-URL: Funding, https://buymeacoffee.com/FYbPCSu
|
|
12
|
+
Keywords: fastapi,observability,logging,metrics,opentelemetry
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
22
|
+
Classifier: Framework :: FastAPI
|
|
23
|
+
Classifier: Topic :: System :: Logging
|
|
24
|
+
Classifier: Topic :: System :: Monitoring
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: fastapi>=0.133.0
|
|
30
|
+
Requires-Dist: pydantic-settings>=2.10.1
|
|
31
|
+
Requires-Dist: starlette>=1.3.1
|
|
32
|
+
Provides-Extra: fast-json
|
|
33
|
+
Requires-Dist: orjson>=3.11.7; extra == "fast-json"
|
|
34
|
+
Provides-Extra: prometheus
|
|
35
|
+
Requires-Dist: prometheus-client>=0.24.1; extra == "prometheus"
|
|
36
|
+
Provides-Extra: loguru
|
|
37
|
+
Requires-Dist: loguru>=0.7.2; extra == "loguru"
|
|
38
|
+
Provides-Extra: otel
|
|
39
|
+
Requires-Dist: opentelemetry-api>=1.45.1; extra == "otel"
|
|
40
|
+
Requires-Dist: opentelemetry-sdk>=1.45.1; extra == "otel"
|
|
41
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.45.1; extra == "otel"
|
|
42
|
+
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.66b1; extra == "otel"
|
|
43
|
+
Requires-Dist: opentelemetry-instrumentation-logging>=0.66b1; extra == "otel"
|
|
44
|
+
Provides-Extra: otel-httpx
|
|
45
|
+
Requires-Dist: opentelemetry-instrumentation-httpx>=0.66b1; extra == "otel-httpx"
|
|
46
|
+
Provides-Extra: otel-requests
|
|
47
|
+
Requires-Dist: opentelemetry-instrumentation-requests>=0.66b1; extra == "otel-requests"
|
|
48
|
+
Provides-Extra: audit
|
|
49
|
+
Requires-Dist: cryptography>=50.0.0; extra == "audit"
|
|
50
|
+
Provides-Extra: otel-sqlalchemy
|
|
51
|
+
Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.66b1; extra == "otel-sqlalchemy"
|
|
52
|
+
Provides-Extra: all
|
|
53
|
+
Requires-Dist: orjson>=3.11.7; extra == "all"
|
|
54
|
+
Requires-Dist: prometheus-client>=0.24.1; extra == "all"
|
|
55
|
+
Requires-Dist: loguru>=0.7.2; extra == "all"
|
|
56
|
+
Requires-Dist: opentelemetry-api>=1.45.1; extra == "all"
|
|
57
|
+
Requires-Dist: opentelemetry-sdk>=1.45.1; extra == "all"
|
|
58
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.45.1; extra == "all"
|
|
59
|
+
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.66b1; extra == "all"
|
|
60
|
+
Requires-Dist: opentelemetry-instrumentation-logging>=0.66b1; extra == "all"
|
|
61
|
+
Requires-Dist: opentelemetry-instrumentation-httpx>=0.66b1; extra == "all"
|
|
62
|
+
Requires-Dist: opentelemetry-instrumentation-requests>=0.66b1; extra == "all"
|
|
63
|
+
Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.66b1; extra == "all"
|
|
64
|
+
Requires-Dist: cryptography>=50.0.0; extra == "all"
|
|
65
|
+
Provides-Extra: dev
|
|
66
|
+
Requires-Dist: httpx2>=2.16.0; extra == "dev"
|
|
67
|
+
Requires-Dist: loguru>=0.7.3; extra == "dev"
|
|
68
|
+
Requires-Dist: mypy>=2.4.1; extra == "dev"
|
|
69
|
+
Requires-Dist: pip-audit>=2.10.1; extra == "dev"
|
|
70
|
+
Requires-Dist: pytest>=9.2.0; extra == "dev"
|
|
71
|
+
Requires-Dist: pytest-randomly>=5.0.0; extra == "dev"
|
|
72
|
+
Requires-Dist: ruff>=0.17.3; extra == "dev"
|
|
73
|
+
Requires-Dist: cyclonedx-bom>=7.6.0; extra == "dev"
|
|
74
|
+
Requires-Dist: uvicorn>=0.54.0; extra == "dev"
|
|
75
|
+
Dynamic: license-file
|
|
76
|
+
|
|
77
|
+
# fastapi-observer
|
|
78
|
+
|
|
79
|
+
[](https://github.com/Vitaee/FastapiObserver/actions/workflows/ci.yml)
|
|
80
|
+
[](https://pypi.org/project/fastapi-observer/)
|
|
81
|
+
[](https://pypi.org/project/fastapi-observer/)
|
|
82
|
+
[](https://github.com/Vitaee/FastapiObserver/blob/main/LICENSE)
|
|
83
|
+
|
|
84
|
+
**One-call observability for FastAPI.** JSON logs with request IDs, Prometheus metrics and OpenTelemetry traces, with sensitive data redacted by default. No vendor backend: send it to whatever you already run.
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from fastapi import FastAPI
|
|
88
|
+
from fastapiobserver import install_observability
|
|
89
|
+
|
|
90
|
+
app = FastAPI()
|
|
91
|
+
install_observability(app)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Every request now writes one JSON line, with the same `trace_id` as its trace when tracing is on:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"timestamp": "2026-10-31T09:10:20.345831+00:00",
|
|
99
|
+
"level": "INFO",
|
|
100
|
+
"logger": "fastapiobserver.middleware",
|
|
101
|
+
"message": "request.completed",
|
|
102
|
+
"app_name": "orders-api",
|
|
103
|
+
"service": "orders",
|
|
104
|
+
"environment": "production",
|
|
105
|
+
"version": "2.3.1",
|
|
106
|
+
"request_id": "d496f541-5e5e-4f14-9174-e9bd697faa62",
|
|
107
|
+
"trace_id": "11d5b6f088bfdba501927e55463be4cd",
|
|
108
|
+
"span_id": "50a12c2d9937eacb",
|
|
109
|
+
"event": {
|
|
110
|
+
"method": "GET",
|
|
111
|
+
"path": "/orders/42",
|
|
112
|
+
"status_code": 200,
|
|
113
|
+
"duration_ms": 1.314,
|
|
114
|
+
"client_ip": "203.0.113.7",
|
|
115
|
+
"error_type": "ok"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Documentation:** [vitaee.github.io/FastapiObserver](https://vitaee.github.io/FastapiObserver/)
|
|
121
|
+
|
|
122
|
+
## Install
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pip install fastapi-observer # JSON logs, request IDs, redaction
|
|
126
|
+
pip install "fastapi-observer[prometheus]" # + Prometheus /metrics
|
|
127
|
+
pip install "fastapi-observer[otel]" # + OpenTelemetry traces and OTLP logs
|
|
128
|
+
pip install "fastapi-observer[all]" # everything
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Requires Python 3.11 or newer.
|
|
132
|
+
|
|
133
|
+
## Configure with environment variables
|
|
134
|
+
|
|
135
|
+
`install_observability(app)` reads its settings from the environment. These are the ones most apps set:
|
|
136
|
+
|
|
137
|
+
| Variable | Example | What it does |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| `APP_NAME`, `SERVICE_NAME`, `ENVIRONMENT`, `APP_VERSION` | `orders-api`, `orders`, `production`, `2.3.1` | Added to every log line |
|
|
140
|
+
| `METRICS_ENABLED` | `true` | Serves Prometheus metrics at `/metrics` (needs `[prometheus]`) |
|
|
141
|
+
| `OTEL_ENABLED`, `OTEL_EXPORTER_OTLP_ENDPOINT` | `true`, `http://collector:4317` | Sends traces over OTLP and adds `trace_id` to logs (needs `[otel]`) |
|
|
142
|
+
| `OBS_REDACTION_PRESET` | `strict`, `pci`, `gdpr` | Chooses which fields and headers are masked |
|
|
143
|
+
| `OBS_PROFILE` | `development`, `production` | Sensible defaults: `production` sets `INFO` logs, a larger log queue and the `strict` preset |
|
|
144
|
+
|
|
145
|
+
Explicit variables and Python arguments always win over profile defaults. Every setting is listed in the [configuration guide](https://vitaee.github.io/FastapiObserver/configuration/).
|
|
146
|
+
|
|
147
|
+
## What you get
|
|
148
|
+
|
|
149
|
+
- **One JSON line per request** with method, path, status, duration and client IP, and your service's name, environment and version on every line, including your own `logging` calls.
|
|
150
|
+
- **Request IDs** taken from `X-Request-ID` when the caller is a trusted proxy, generated otherwise, and returned in the response.
|
|
151
|
+
- **Redaction on by default.** Passwords, tokens, API keys, `Authorization` and cookies are masked before anything is written. Presets cover stricter needs (`strict`, `pci`, `gdpr`).
|
|
152
|
+
- **Prometheus metrics** labelled by route template (`/orders/{order_id}`), so URLs with IDs don't explode cardinality.
|
|
153
|
+
- **OpenTelemetry traces** with `trace_id` and `span_id` in every log line, and optional log export over OTLP.
|
|
154
|
+
- **Non-blocking log writes.** Lines are written from a background thread, so a slow stdout never stalls the event loop.
|
|
155
|
+
|
|
156
|
+
Optional extras: runtime log-level control, a tamper-evident audit log, SQLAlchemy, `httpx` and `requests` tracing, Strawberry GraphQL and a Loguru bridge. See the [documentation](https://vitaee.github.io/FastapiObserver/).
|
|
157
|
+
|
|
158
|
+

|
|
159
|
+
|
|
160
|
+
*The Grafana dashboard from [`examples/full_stack`](https://github.com/Vitaee/FastapiObserver/tree/main/examples/full_stack), a Docker Compose stack you can run locally.*
|
|
161
|
+
|
|
162
|
+
## How it compares
|
|
163
|
+
|
|
164
|
+
| | fastapi-observer | structlog or loguru | OpenTelemetry auto-instrumentation | Logfire |
|
|
165
|
+
|---|---|---|---|---|
|
|
166
|
+
| JSON log line per request | Built in | You write the middleware | No | A span per request |
|
|
167
|
+
| Request ID on every log line | Built in | You wire it up | No | Trace IDs |
|
|
168
|
+
| Redaction by default | Yes, with presets | You write a processor | No | Yes |
|
|
169
|
+
| Prometheus `/metrics` | Built in | No | Through an exporter | No |
|
|
170
|
+
| Traces | OpenTelemetry | No | Yes | Yes |
|
|
171
|
+
| Where data goes | stdout, Prometheus and any OTLP backend | stdout or files | Any OTLP backend | Logfire's platform |
|
|
172
|
+
|
|
173
|
+
**When not to use it:**
|
|
174
|
+
|
|
175
|
+
- You only want logs and need the lowest possible overhead: structlog alone does less work per line.
|
|
176
|
+
- You already send everything to Logfire, Datadog or Sentry: their own FastAPI integrations fit better.
|
|
177
|
+
- Your app isn't built on FastAPI or Starlette.
|
|
178
|
+
|
|
179
|
+
What it costs: with default settings, about 43 µs of CPU per request on an Apple M1. See the [benchmarks](https://vitaee.github.io/FastapiObserver/benchmarks/), including a comparison with wiring the same stack by hand.
|
|
180
|
+
|
|
181
|
+
## Works with
|
|
182
|
+
|
|
183
|
+
- **Servers:** uvicorn, gunicorn with `UvicornWorker`, and Granian. Uvicorn's duplicate access line is dropped automatically. To get the servers' own startup lines as JSON too, see [running with gunicorn and Granian](https://vitaee.github.io/FastapiObserver/servers/).
|
|
184
|
+
- **Backends:** Prometheus, Grafana (Loki, Tempo), Jaeger and anything that accepts OTLP. See [backends](https://vitaee.github.io/FastapiObserver/backends/).
|
|
185
|
+
- **Error tracking:** runs alongside Sentry. See the [Sentry notes](https://vitaee.github.io/FastapiObserver/sentry/).
|
|
186
|
+
|
|
187
|
+
## Why you can trust it
|
|
188
|
+
|
|
189
|
+
- Tested in CI on Python 3.11 to 3.15, fully typed, and used in production by its maintainer.
|
|
190
|
+
- Releases are published with PyPI Trusted Publishing and signed attestations. CI runs `pip-audit` and generates an SBOM.
|
|
191
|
+
- Security fixes are called out in the [changelog](https://github.com/Vitaee/FastapiObserver/blob/main/CHANGELOG.md). To report a vulnerability, see [SECURITY.md](https://github.com/Vitaee/FastapiObserver/blob/main/SECURITY.md).
|
|
192
|
+
- Benchmarks are reproducible from [`examples/benchmarks`](https://github.com/Vitaee/FastapiObserver/tree/main/examples/benchmarks).
|
|
193
|
+
|
|
194
|
+
## Compatibility
|
|
195
|
+
|
|
196
|
+
| Component | Supported |
|
|
197
|
+
|---|---|
|
|
198
|
+
| Python | `>=3.11` (CI: `3.11` to `3.15`) |
|
|
199
|
+
| FastAPI | `>=0.133.0` |
|
|
200
|
+
| Starlette | `>=1.3.1` |
|
|
201
|
+
| Prometheus extra | `prometheus-client>=0.24.1` |
|
|
202
|
+
| OpenTelemetry extra | `opentelemetry-api/sdk/exporter>=1.45.1` |
|
|
203
|
+
|
|
204
|
+
## Documentation
|
|
205
|
+
|
|
206
|
+
- [Configuration](https://vitaee.github.io/FastapiObserver/configuration/) and [structured logging](https://vitaee.github.io/FastapiObserver/logging/)
|
|
207
|
+
- [Security and redaction presets](https://vitaee.github.io/FastapiObserver/security/)
|
|
208
|
+
- [OpenTelemetry](https://vitaee.github.io/FastapiObserver/opentelemetry/)
|
|
209
|
+
- [Production deployment](https://vitaee.github.io/FastapiObserver/deployment/) and [Kubernetes](https://vitaee.github.io/FastapiObserver/kubernetes/)
|
|
210
|
+
- [Benchmarks](https://vitaee.github.io/FastapiObserver/benchmarks/) and [performance tuning](https://vitaee.github.io/FastapiObserver/tuning/)
|
|
211
|
+
- [Contributing](https://vitaee.github.io/FastapiObserver/contributing/)
|
|
212
|
+
|
|
213
|
+
## Support the project
|
|
214
|
+
|
|
215
|
+
If this library saves you time, you can [buy me a coffee](https://buymeacoffee.com/FYbPCSu).
|
{fastapi_observer-1.4.1 → fastapi_observer-1.6.0}/src/fastapi_observer.egg-info/requires.txt
RENAMED
|
@@ -20,6 +20,7 @@ cryptography>=50.0.0
|
|
|
20
20
|
cryptography>=50.0.0
|
|
21
21
|
|
|
22
22
|
[dev]
|
|
23
|
+
httpx2>=2.16.0
|
|
23
24
|
loguru>=0.7.3
|
|
24
25
|
mypy>=2.4.1
|
|
25
26
|
pip-audit>=2.10.1
|
|
@@ -29,12 +30,6 @@ ruff>=0.17.3
|
|
|
29
30
|
cyclonedx-bom>=7.6.0
|
|
30
31
|
uvicorn>=0.54.0
|
|
31
32
|
|
|
32
|
-
[dev:python_version < "3.11"]
|
|
33
|
-
httpx>=0.28.1
|
|
34
|
-
|
|
35
|
-
[dev:python_version >= "3.11"]
|
|
36
|
-
httpx2>=2.16.0
|
|
37
|
-
|
|
38
33
|
[fast-json]
|
|
39
34
|
orjson>=3.11.7
|
|
40
35
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.6.0"
|
|
@@ -126,6 +126,13 @@ def install_observability(
|
|
|
126
126
|
metrics_backend,
|
|
127
127
|
)
|
|
128
128
|
|
|
129
|
+
# --- 7. Uvicorn access log ---
|
|
130
|
+
# The middleware's `request.completed` line carries the same fields, so drop
|
|
131
|
+
# uvicorn's duplicate line the same way `uvicorn --no-access-log` does.
|
|
132
|
+
uvicorn_access_logger = logging.getLogger("uvicorn.access")
|
|
133
|
+
uvicorn_access_logger.handlers = []
|
|
134
|
+
uvicorn_access_logger.propagate = False
|
|
135
|
+
|
|
129
136
|
# --- 8. Runtime control plane ---
|
|
130
137
|
if runtime_control_settings and runtime_control_settings.enabled:
|
|
131
138
|
mount_control_plane(app, runtime_control_settings)
|