elven-logs-interceptor-python 0.1.8__tar.gz → 0.1.9__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.
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/PKG-INFO +2 -1
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/README.md +1 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/pyproject.toml +1 -1
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/__init__.py +3 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/application/config_service.py +5 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/config.py +2 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/transport/loki_json_transport.py +4 -3
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/utils.py +3 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_config_service.py +16 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_loki_json_transport.py +38 -2
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_utils_extra.py +2 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/.gitignore +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/ARCHITECTURE.md +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/examples/basic_app.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/examples/fastapi_integration.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/examples/full_config_reference.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/examples/high_volume.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/examples/tracking_usage.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/scripts/publish.sh +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/application/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/application/log_service.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/domain/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/domain/entities.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/domain/interfaces.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/domain/value_objects.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/buffer/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/buffer/memory_buffer.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/circuit_breaker/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/circuit_breaker/circuit_breaker.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/compression/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/compression/base.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/compression/brotli_compressor.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/compression/factory.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/compression/gzip_compressor.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/compression/noop_compressor.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/context/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/context/context_provider.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/dlq/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/dlq/file_dlq.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/dlq/memory_dlq.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/filter/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/filter/log_filter.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/interceptors/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/interceptors/runtime_interceptor.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/internal_capture_guard.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/log_noise_filter.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/log_record_extra.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/memory/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/memory/memory_tracker.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/metrics/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/metrics/metrics_collector.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/transport/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/transport/loki_protobuf_transport.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/transport/resilient_transport.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/transport/transport_factory.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/workers/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/infrastructure/workers/worker_pool.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/integrations/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/integrations/celery.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/integrations/django.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/integrations/fastapi.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/integrations/flask.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/integrations/logging_handler.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/integrations/loguru.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/integrations/structlog.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/preload.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/presentation/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/presentation/factory.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/src/logs_interceptor/types.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/test-apps/elven-live-demo/.env.example +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/test-apps/elven-live-demo/README.md +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/test-apps/elven-live-demo/app.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/test-apps/elven-live-demo/run.sh +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/test-apps/elven-observability-smoke/.env.example +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/test-apps/elven-observability-smoke/README.md +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/test-apps/elven-observability-smoke/app.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/test-apps/elven-observability-smoke/run.sh +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/integration/test_api.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_circuit_breaker_extra.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_core_components.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_env_config.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_integration_filters.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_log_filter_extra.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_log_service_unit.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_loguru_sink.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_memory_buffer_extra.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_protobuf_transport_safety.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_resilient_transport.py +0 -0
- {elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/tests/unit/test_runtime_interceptor.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: elven-logs-interceptor-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: Production-grade logs interceptor for Python with Loki transport, resilience, batching, and framework integrations.
|
|
5
5
|
Author: Elven Observability
|
|
6
6
|
License: MIT
|
|
@@ -154,6 +154,7 @@ Transport:
|
|
|
154
154
|
- `LOGS_WORKER_TIMEOUT`
|
|
155
155
|
- `LOGS_CONNECTION_POOLING`
|
|
156
156
|
- `LOGS_MAX_SOCKETS`
|
|
157
|
+
- `LOGS_ENABLE_STRUCTURED_METADATA` (`false` by default; enable only when Loki allows `limits_config.allow_structured_metadata`)
|
|
157
158
|
- `LOGS_TIMEOUT`
|
|
158
159
|
- `LOGS_MAX_RETRIES`
|
|
159
160
|
- `LOGS_RETRY_DELAY`
|
|
@@ -93,6 +93,7 @@ Transport:
|
|
|
93
93
|
- `LOGS_WORKER_TIMEOUT`
|
|
94
94
|
- `LOGS_CONNECTION_POOLING`
|
|
95
95
|
- `LOGS_MAX_SOCKETS`
|
|
96
|
+
- `LOGS_ENABLE_STRUCTURED_METADATA` (`false` by default; enable only when Loki allows `limits_config.allow_structured_metadata`)
|
|
96
97
|
- `LOGS_TIMEOUT`
|
|
97
98
|
- `LOGS_MAX_RETRIES`
|
|
98
99
|
- `LOGS_RETRY_DELAY`
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "elven-logs-interceptor-python"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.9"
|
|
8
8
|
description = "Production-grade logs interceptor for Python with Loki transport, resilience, batching, and framework integrations."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -104,6 +104,9 @@ def _coerce_config(user_config: LogsInterceptorConfig | dict[str, Any] | None) -
|
|
|
104
104
|
transport_raw, "enable_connection_pooling", "enableConnectionPooling"
|
|
105
105
|
),
|
|
106
106
|
max_sockets=_pick(transport_raw, "max_sockets", "maxSockets"),
|
|
107
|
+
enable_structured_metadata=_pick(
|
|
108
|
+
transport_raw, "enable_structured_metadata", "enableStructuredMetadata"
|
|
109
|
+
),
|
|
107
110
|
),
|
|
108
111
|
app_name=_pick(user_config, "app_name", "appName", ""),
|
|
109
112
|
version=_pick(user_config, "version", "version"),
|
|
@@ -170,6 +170,11 @@ class ConfigService:
|
|
|
170
170
|
True if transport.enable_connection_pooling is None else transport.enable_connection_pooling
|
|
171
171
|
),
|
|
172
172
|
max_sockets=transport.max_sockets if transport.max_sockets is not None else 50,
|
|
173
|
+
enable_structured_metadata=(
|
|
174
|
+
False
|
|
175
|
+
if transport.enable_structured_metadata is None
|
|
176
|
+
else transport.enable_structured_metadata
|
|
177
|
+
),
|
|
173
178
|
)
|
|
174
179
|
|
|
175
180
|
@staticmethod
|
|
@@ -26,6 +26,7 @@ class TransportConfig:
|
|
|
26
26
|
worker_timeout: int | None = None
|
|
27
27
|
enable_connection_pooling: bool | None = None
|
|
28
28
|
max_sockets: int | None = None
|
|
29
|
+
enable_structured_metadata: bool | None = None
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
@dataclass(slots=True)
|
|
@@ -131,6 +132,7 @@ class ResolvedTransportConfig:
|
|
|
131
132
|
worker_timeout: int
|
|
132
133
|
enable_connection_pooling: bool
|
|
133
134
|
max_sockets: int
|
|
135
|
+
enable_structured_metadata: bool = False
|
|
134
136
|
|
|
135
137
|
|
|
136
138
|
@dataclass(slots=True)
|
|
@@ -210,9 +210,10 @@ class LokiJsonTransport:
|
|
|
210
210
|
|
|
211
211
|
timestamp_ns = self._timestamp_to_ns(entry.timestamp)
|
|
212
212
|
value: list[Any] = [str(timestamp_ns), self._dumps(payload).decode("utf-8")]
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
213
|
+
if self._config.enable_structured_metadata:
|
|
214
|
+
structured_metadata = self._format_structured_metadata(entry.metadata)
|
|
215
|
+
if structured_metadata:
|
|
216
|
+
value.append(structured_metadata)
|
|
216
217
|
values_map[key].append(value)
|
|
217
218
|
streams[key] = labels
|
|
218
219
|
|
|
@@ -530,6 +530,9 @@ def load_config_from_env() -> LogsInterceptorConfig:
|
|
|
530
530
|
enable_connection_pooling=parse_bool(env.get("LOGS_CONNECTION_POOLING"), True),
|
|
531
531
|
max_sockets=parse_int_range(env.get("LOGS_MAX_SOCKETS"), 50, 1, 1024),
|
|
532
532
|
worker_timeout=parse_int_range(env.get("LOGS_WORKER_TIMEOUT"), 30_000, 1000, 300_000),
|
|
533
|
+
enable_structured_metadata=parse_bool(
|
|
534
|
+
env.get("LOGS_ENABLE_STRUCTURED_METADATA"), False
|
|
535
|
+
),
|
|
533
536
|
),
|
|
534
537
|
app_name=env.get("LOGS_APP_NAME", ""),
|
|
535
538
|
version=env.get("LOGS_APP_VERSION", "1.0.0"),
|
|
@@ -47,6 +47,7 @@ def test_resolve_applies_defaults() -> None:
|
|
|
47
47
|
|
|
48
48
|
assert resolved.transport.timeout == 10_000
|
|
49
49
|
assert resolved.transport.max_retries == 3
|
|
50
|
+
assert resolved.transport.enable_structured_metadata is False
|
|
50
51
|
assert resolved.buffer.max_size == 100
|
|
51
52
|
assert resolved.filter.sampling_rate == 1.0
|
|
52
53
|
assert "httpx" in resolved.filter.exclude_logger_prefixes
|
|
@@ -55,6 +56,21 @@ def test_resolve_applies_defaults() -> None:
|
|
|
55
56
|
assert resolved.performance.max_concurrent_flushes == 3
|
|
56
57
|
|
|
57
58
|
|
|
59
|
+
def test_resolve_enables_structured_metadata_only_when_requested() -> None:
|
|
60
|
+
resolved = ConfigService.resolve(
|
|
61
|
+
LogsInterceptorConfig(
|
|
62
|
+
transport=TransportConfig(
|
|
63
|
+
url="https://loki.example.com/loki/api/v1/push",
|
|
64
|
+
tenant_id="tenant",
|
|
65
|
+
enable_structured_metadata=True,
|
|
66
|
+
),
|
|
67
|
+
app_name="app",
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
assert resolved.transport.enable_structured_metadata is True
|
|
72
|
+
|
|
73
|
+
|
|
58
74
|
def test_validate_extended_ranges() -> None:
|
|
59
75
|
config = LogsInterceptorConfig(
|
|
60
76
|
transport=TransportConfig(
|
|
@@ -20,7 +20,10 @@ class _Response:
|
|
|
20
20
|
text: str = ""
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
def _config(
|
|
23
|
+
def _config(
|
|
24
|
+
compression: str = "gzip",
|
|
25
|
+
enable_structured_metadata: bool = False,
|
|
26
|
+
) -> ResolvedTransportConfig:
|
|
24
27
|
return ResolvedTransportConfig(
|
|
25
28
|
url="https://loki.example.com/loki/api/v1/push",
|
|
26
29
|
tenant_id="tenant",
|
|
@@ -36,6 +39,7 @@ def _config(compression: str = "gzip") -> ResolvedTransportConfig:
|
|
|
36
39
|
worker_timeout=100,
|
|
37
40
|
enable_connection_pooling=False,
|
|
38
41
|
max_sockets=10,
|
|
42
|
+
enable_structured_metadata=enable_structured_metadata,
|
|
39
43
|
)
|
|
40
44
|
|
|
41
45
|
|
|
@@ -92,7 +96,7 @@ def test_loki_json_transport_suppresses_internal_capture_during_request(
|
|
|
92
96
|
assert observed == [True]
|
|
93
97
|
|
|
94
98
|
|
|
95
|
-
def
|
|
99
|
+
def test_loki_json_transport_keeps_correlation_metadata_in_log_line_by_default() -> None:
|
|
96
100
|
transport = LokiJsonTransport(_config())
|
|
97
101
|
payload = transport._format_for_loki(
|
|
98
102
|
[
|
|
@@ -121,6 +125,38 @@ def test_loki_json_transport_uses_structured_metadata_for_correlation_ids() -> N
|
|
|
121
125
|
stream = payload["streams"][0]
|
|
122
126
|
assert stream["stream"] == {"service": "billing"}
|
|
123
127
|
value = stream["values"][0]
|
|
128
|
+
assert len(value) == 2
|
|
129
|
+
|
|
130
|
+
line = json.loads(value[1])
|
|
131
|
+
assert line["traceId"] == "trace-123"
|
|
132
|
+
assert line["spanId"] == "span-123"
|
|
133
|
+
assert line["requestId"] == "req-123"
|
|
134
|
+
assert line["metadata"]["trace_id"] == "trace-123"
|
|
135
|
+
assert line["metadata"]["span_id"] == "span-123"
|
|
136
|
+
assert line["metadata"]["request_id"] == "req-123"
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def test_loki_json_transport_uses_structured_metadata_when_explicitly_enabled() -> None:
|
|
140
|
+
transport = LokiJsonTransport(_config(enable_structured_metadata=True))
|
|
141
|
+
payload = transport._format_for_loki(
|
|
142
|
+
[
|
|
143
|
+
LogEntryEntity(
|
|
144
|
+
id="1",
|
|
145
|
+
timestamp="2026-01-01T00:00:00.000000+00:00",
|
|
146
|
+
level="info",
|
|
147
|
+
message="hello",
|
|
148
|
+
labels={"service": "billing"},
|
|
149
|
+
metadata={
|
|
150
|
+
"trace_id": "trace-123",
|
|
151
|
+
"span_id": "span-123",
|
|
152
|
+
"request_id": "req-123",
|
|
153
|
+
"ignored": None,
|
|
154
|
+
},
|
|
155
|
+
)
|
|
156
|
+
]
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
value = payload["streams"][0]["values"][0]
|
|
124
160
|
assert value[2] == {
|
|
125
161
|
"trace_id": "trace-123",
|
|
126
162
|
"span_id": "span-123",
|
|
@@ -207,9 +207,11 @@ def test_env_levels_and_env_loader_branches(monkeypatch: pytest.MonkeyPatch) ->
|
|
|
207
207
|
monkeypatch.setenv("LOGS_APP_NAME", "app")
|
|
208
208
|
monkeypatch.setenv("LOGS_COMPRESSION", "invalid")
|
|
209
209
|
monkeypatch.setenv("LOGS_DLQ_TYPE", "invalid")
|
|
210
|
+
monkeypatch.setenv("LOGS_ENABLE_STRUCTURED_METADATA", "true")
|
|
210
211
|
|
|
211
212
|
cfg = load_config_from_env()
|
|
212
213
|
assert cfg.transport.compression == "gzip"
|
|
214
|
+
assert cfg.transport.enable_structured_metadata is True
|
|
213
215
|
assert cfg.dead_letter_queue is not None
|
|
214
216
|
assert cfg.dead_letter_queue.type == "memory"
|
|
215
217
|
|
|
File without changes
|
|
File without changes
|
{elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/examples/basic_app.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/examples/high_volume.py
RENAMED
|
File without changes
|
|
File without changes
|
{elven_logs_interceptor_python-0.1.8 → elven_logs_interceptor_python-0.1.9}/scripts/publish.sh
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
|
|
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
|