fastapi-observer 0.3.0__tar.gz → 0.3.1__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-0.3.0/src/fastapi_observer.egg-info → fastapi_observer-0.3.1}/PKG-INFO +2 -2
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/README.md +1 -1
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/pyproject.toml +0 -1
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1/src/fastapi_observer.egg-info}/PKG-INFO +2 -2
- fastapi_observer-0.3.1/src/fastapiobserver/_version.py +1 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_fastapi_install.py +9 -5
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_graphql_integrations.py +23 -17
- fastapi_observer-0.3.0/src/fastapiobserver/_version.py +0 -1
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/LICENSE +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/setup.cfg +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapi_observer.egg-info/SOURCES.txt +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapi_observer.egg-info/dependency_links.txt +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapi_observer.egg-info/requires.txt +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapi_observer.egg-info/top_level.txt +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/__init__.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/config.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/control_plane.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/fastapi.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/integrations/__init__.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/integrations/strawberry.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/logging.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/loguru.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/metrics.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/middleware.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/otel/__init__.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/otel/lifecycle.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/otel/logs.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/otel/metrics.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/otel/resource.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/otel/settings.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/otel/tracing.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/otel/types.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/plugins.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/propagation.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/py.typed +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/request_context.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/security.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/sinks.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/utils.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_body_media_allowlist.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_config_settings.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_excluded_url_precedence.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_log_queue_controls.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_logging_schema_contract.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_logtail_dlq.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_loguru_bridge.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_metrics_optional_dependency.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_middleware.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_negotiate_content_type.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_otel_integration.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_otel_lifecycle.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_otel_log_correlation.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_otel_logs_from_env.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_otel_logs_pipeline.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_otel_metrics_from_env.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_otlp_export_integration.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_plugin_isolation.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_propagation.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_redaction_presets.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_route_template_cardinality.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_runtime_control_auth.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_security_redaction.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_sink_circuit_breaker.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_sinks.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_trust_boundary.py +0 -0
- {fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/tests/test_utils_refactors.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-observer
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Zero-glue FastAPI observability with security presets and runtime controls
|
|
5
5
|
Author-email: Vitaee <opensource@vitaee.dev>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -963,7 +963,7 @@ Reproducible benchmark harness and methodology:
|
|
|
963
963
|
- `0.2.x`: OTel interoperability, security presets, allowlists
|
|
964
964
|
- `1.0.0`: dynamic runtime controls and plugin stability
|
|
965
965
|
|
|
966
|
-
Current release version: `0.3.
|
|
966
|
+
Current release version: `0.3.1`
|
|
967
967
|
|
|
968
968
|
## Changelog Policy
|
|
969
969
|
|
|
@@ -894,7 +894,7 @@ Reproducible benchmark harness and methodology:
|
|
|
894
894
|
- `0.2.x`: OTel interoperability, security presets, allowlists
|
|
895
895
|
- `1.0.0`: dynamic runtime controls and plugin stability
|
|
896
896
|
|
|
897
|
-
Current release version: `0.3.
|
|
897
|
+
Current release version: `0.3.1`
|
|
898
898
|
|
|
899
899
|
## Changelog Policy
|
|
900
900
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-observer
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Zero-glue FastAPI observability with security presets and runtime controls
|
|
5
5
|
Author-email: Vitaee <opensource@vitaee.dev>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -963,7 +963,7 @@ Reproducible benchmark harness and methodology:
|
|
|
963
963
|
- `0.2.x`: OTel interoperability, security presets, allowlists
|
|
964
964
|
- `1.0.0`: dynamic runtime controls and plugin stability
|
|
965
965
|
|
|
966
|
-
Current release version: `0.3.
|
|
966
|
+
Current release version: `0.3.1`
|
|
967
967
|
|
|
968
968
|
## Changelog Policy
|
|
969
969
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.1"
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import asyncio
|
|
4
|
+
|
|
4
5
|
import pytest
|
|
6
|
+
from fastapi import FastAPI
|
|
5
7
|
|
|
6
8
|
import fastapiobserver.fastapi as fastapi_module
|
|
7
9
|
from fastapiobserver import (
|
|
@@ -135,8 +137,7 @@ def test_install_observability_installs_otel_metrics_when_enabled(
|
|
|
135
137
|
assert calls["otel_settings"] is None
|
|
136
138
|
|
|
137
139
|
|
|
138
|
-
|
|
139
|
-
async def test_install_observability_registers_logging_shutdown_hook_once(
|
|
140
|
+
def test_install_observability_registers_logging_shutdown_hook_once(
|
|
140
141
|
monkeypatch: pytest.MonkeyPatch,
|
|
141
142
|
) -> None:
|
|
142
143
|
app = FastAPI()
|
|
@@ -155,7 +156,10 @@ async def test_install_observability_registers_logging_shutdown_hook_once(
|
|
|
155
156
|
assert app in fastapi_module._REGISTERED_APPS
|
|
156
157
|
|
|
157
158
|
# Verify the shutdown hook actively works when application teardown runs
|
|
158
|
-
async
|
|
159
|
-
|
|
159
|
+
async def _run_lifespan() -> None:
|
|
160
|
+
async with app.router.lifespan_context(app):
|
|
161
|
+
pass
|
|
162
|
+
|
|
163
|
+
asyncio.run(_run_lifespan())
|
|
160
164
|
|
|
161
165
|
assert len(mock_calls) == 1
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import asyncio
|
|
3
4
|
import pytest
|
|
4
5
|
from unittest.mock import MagicMock, patch
|
|
5
6
|
|
|
@@ -12,8 +13,20 @@ def clean_context() -> None:
|
|
|
12
13
|
clear_user_context()
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
def _drive_on_operation(
|
|
17
|
+
extension: StrawberryObservabilityExtension,
|
|
18
|
+
) -> dict[str, object] | None:
|
|
19
|
+
async def _run() -> dict[str, object] | None:
|
|
20
|
+
generator = extension.on_operation()
|
|
21
|
+
await generator.__anext__()
|
|
22
|
+
context = get_user_context()
|
|
23
|
+
await generator.aclose()
|
|
24
|
+
return context
|
|
25
|
+
|
|
26
|
+
return asyncio.run(_run())
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_strawberry_extension_injects_operation_name_into_log_context() -> None:
|
|
17
30
|
# 1. Setup simulated execution context (Duck Typing Strawberry)
|
|
18
31
|
mock_context = MagicMock()
|
|
19
32
|
mock_context.operation_name = "GetUsersQuery"
|
|
@@ -26,44 +39,37 @@ async def test_strawberry_extension_injects_operation_name_into_log_context() ->
|
|
|
26
39
|
extension = StrawberryObservabilityExtension(execution_context=mock_context)
|
|
27
40
|
|
|
28
41
|
# 4. Run the async generator hook
|
|
29
|
-
|
|
30
|
-
await generator.__anext__()
|
|
42
|
+
final_context = _drive_on_operation(extension)
|
|
31
43
|
|
|
32
44
|
# 5. Assert the observability context updated correctly
|
|
33
|
-
final_context = get_user_context()
|
|
34
45
|
assert final_context is not None
|
|
35
46
|
assert final_context["tenant"] == "acme"
|
|
36
47
|
assert "graphql" in final_context
|
|
37
48
|
assert final_context["graphql"]["operation_name"] == "GetUsersQuery"
|
|
38
49
|
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
async def test_strawberry_extension_handles_missing_operation_name() -> None:
|
|
51
|
+
def test_strawberry_extension_handles_missing_operation_name() -> None:
|
|
42
52
|
mock_context = MagicMock()
|
|
43
53
|
# E.g. a malformed query where Strawberry couldn't parse the operation
|
|
44
|
-
mock_context.operation_name = None
|
|
54
|
+
mock_context.operation_name = None
|
|
45
55
|
|
|
46
56
|
extension = StrawberryObservabilityExtension(execution_context=mock_context)
|
|
47
|
-
|
|
48
|
-
await generator.__anext__()
|
|
57
|
+
final_context = _drive_on_operation(extension)
|
|
49
58
|
|
|
50
|
-
final_context = get_user_context()
|
|
51
59
|
assert final_context is not None
|
|
52
60
|
assert final_context["graphql"]["operation_name"] == "AnonymousOperation"
|
|
53
61
|
|
|
54
62
|
|
|
55
|
-
@pytest.mark.asyncio
|
|
56
63
|
@patch("fastapiobserver.integrations.strawberry.get_user_context")
|
|
57
|
-
|
|
64
|
+
def test_strawberry_extension_swallows_parsing_exceptions(mock_get: MagicMock) -> None:
|
|
58
65
|
mock_context = MagicMock()
|
|
59
66
|
# Force an exception on property access
|
|
60
67
|
type(mock_context).operation_name = property(
|
|
61
68
|
lambda self: (_ for _ in ()).throw(RuntimeError("boom"))
|
|
62
69
|
)
|
|
63
|
-
|
|
70
|
+
|
|
64
71
|
extension = StrawberryObservabilityExtension(execution_context=mock_context)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
_drive_on_operation(extension)
|
|
73
|
+
|
|
68
74
|
# It shouldn't crash. It should just gracefully yield and mark it anonymous.
|
|
69
75
|
mock_get.assert_called_once()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.3.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapi_observer.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapi_observer.egg-info/requires.txt
RENAMED
|
File without changes
|
{fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapi_observer.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/integrations/__init__.py
RENAMED
|
File without changes
|
{fastapi_observer-0.3.0 → fastapi_observer-0.3.1}/src/fastapiobserver/integrations/strawberry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|