elven-logs-interceptor-python 0.1.11__tar.gz → 0.1.13__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.
Files changed (62) hide show
  1. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/PKG-INFO +9 -7
  2. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/README.md +8 -6
  3. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/pyproject.toml +1 -1
  4. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/interceptors/runtime_interceptor.py +4 -0
  5. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/integrations/logging_handler.py +4 -0
  6. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/utils.py +1 -17
  7. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/.gitignore +0 -0
  8. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/ARCHITECTURE.md +0 -0
  9. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/__init__.py +0 -0
  10. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/application/__init__.py +0 -0
  11. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/application/config_service.py +0 -0
  12. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/application/log_service.py +0 -0
  13. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/config.py +0 -0
  14. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/domain/__init__.py +0 -0
  15. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/domain/entities.py +0 -0
  16. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/domain/interfaces.py +0 -0
  17. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/domain/value_objects.py +0 -0
  18. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/__init__.py +0 -0
  19. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/buffer/__init__.py +0 -0
  20. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/buffer/memory_buffer.py +0 -0
  21. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/circuit_breaker/__init__.py +0 -0
  22. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/circuit_breaker/circuit_breaker.py +0 -0
  23. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/compression/__init__.py +0 -0
  24. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/compression/base.py +0 -0
  25. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/compression/brotli_compressor.py +0 -0
  26. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/compression/factory.py +0 -0
  27. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/compression/gzip_compressor.py +0 -0
  28. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/compression/noop_compressor.py +0 -0
  29. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/context/__init__.py +0 -0
  30. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/context/context_provider.py +0 -0
  31. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/dlq/__init__.py +0 -0
  32. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/dlq/file_dlq.py +0 -0
  33. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/dlq/memory_dlq.py +0 -0
  34. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/filter/__init__.py +0 -0
  35. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/filter/log_filter.py +0 -0
  36. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/interceptors/__init__.py +0 -0
  37. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/internal_capture_guard.py +0 -0
  38. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/log_noise_filter.py +0 -0
  39. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/log_record_extra.py +0 -0
  40. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/memory/__init__.py +0 -0
  41. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/memory/memory_tracker.py +0 -0
  42. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/metrics/__init__.py +0 -0
  43. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/metrics/metrics_collector.py +0 -0
  44. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/transport/__init__.py +0 -0
  45. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/transport/loki_json_transport.py +0 -0
  46. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/transport/loki_protobuf_transport.py +0 -0
  47. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/transport/otlp_json_transport.py +0 -0
  48. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/transport/resilient_transport.py +0 -0
  49. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/transport/transport_factory.py +0 -0
  50. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/workers/__init__.py +0 -0
  51. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/infrastructure/workers/worker_pool.py +0 -0
  52. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/integrations/__init__.py +0 -0
  53. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/integrations/celery.py +0 -0
  54. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/integrations/django.py +0 -0
  55. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/integrations/fastapi.py +0 -0
  56. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/integrations/flask.py +0 -0
  57. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/integrations/loguru.py +0 -0
  58. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/integrations/structlog.py +0 -0
  59. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/preload.py +0 -0
  60. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/presentation/__init__.py +0 -0
  61. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/presentation/factory.py +0 -0
  62. {elven_logs_interceptor_python-0.1.11 → elven_logs_interceptor_python-0.1.13}/src/logs_interceptor/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elven-logs-interceptor-python
3
- Version: 0.1.11
3
+ Version: 0.1.13
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
@@ -132,17 +132,19 @@ data is explicitly required and approved.
132
132
  The package supports the Python `LOGS_*` configuration surface aligned with
133
133
  the JS v3 design where applicable.
134
134
 
135
- Required:
135
+ Required for direct Loki mode:
136
136
 
137
137
  - `LOGS_URL`
138
138
  - `LOGS_TENANT`
139
139
  - `LOGS_APP_NAME`
140
140
 
141
141
  For collector-first mode, set `LOGS_EXPORTER=otlp` (or `collector`) and use
142
- `OTEL_EXPORTER_OTLP_ENDPOINT` or `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`. In this
143
- mode `LOGS_TENANT` and `LOGS_TOKEN` are not required by the library; put tenant
144
- or auth headers in `OTEL_EXPORTER_OTLP_HEADERS`/`LOGS_OTLP_HEADERS` if your
145
- collector gateway requires them.
142
+ `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`. In this mode `LOGS_URL`, `LOKI_URL`,
143
+ `LOGS_TENANT` and `LOGS_TOKEN` are not required by the library. `LOGS_URL` is
144
+ intentionally ignored in collector mode to avoid accidentally posting OTLP logs
145
+ to a direct Loki `/loki/api/v1/push` endpoint. Put tenant or auth headers in
146
+ `OTEL_EXPORTER_OTLP_HEADERS`/`LOGS_OTLP_HEADERS` if your collector gateway
147
+ requires them.
146
148
 
147
149
  Core:
148
150
 
@@ -153,7 +155,7 @@ Core:
153
155
  Transport:
154
156
 
155
157
  - `LOGS_EXPORTER` (`loki|otlp`, aliases: `collector`, `otel`)
156
- - `LOGS_OTLP_ENDPOINT` (explicit OTLP logs endpoint, e.g. `http://collector:4318/v1/logs`)
158
+ - `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` (collector logs endpoint, e.g. `http://collector:4318/v1/logs`)
157
159
  - `LOGS_OTLP_HEADERS` (comma-separated headers, e.g. `x-tenant=team-a`)
158
160
  - `LOGS_COMPRESSION` (`none|gzip|brotli|snappy`)
159
161
  - `LOGS_COMPRESSION_LEVEL`
@@ -71,17 +71,19 @@ data is explicitly required and approved.
71
71
  The package supports the Python `LOGS_*` configuration surface aligned with
72
72
  the JS v3 design where applicable.
73
73
 
74
- Required:
74
+ Required for direct Loki mode:
75
75
 
76
76
  - `LOGS_URL`
77
77
  - `LOGS_TENANT`
78
78
  - `LOGS_APP_NAME`
79
79
 
80
80
  For collector-first mode, set `LOGS_EXPORTER=otlp` (or `collector`) and use
81
- `OTEL_EXPORTER_OTLP_ENDPOINT` or `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`. In this
82
- mode `LOGS_TENANT` and `LOGS_TOKEN` are not required by the library; put tenant
83
- or auth headers in `OTEL_EXPORTER_OTLP_HEADERS`/`LOGS_OTLP_HEADERS` if your
84
- collector gateway requires them.
81
+ `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`. In this mode `LOGS_URL`, `LOKI_URL`,
82
+ `LOGS_TENANT` and `LOGS_TOKEN` are not required by the library. `LOGS_URL` is
83
+ intentionally ignored in collector mode to avoid accidentally posting OTLP logs
84
+ to a direct Loki `/loki/api/v1/push` endpoint. Put tenant or auth headers in
85
+ `OTEL_EXPORTER_OTLP_HEADERS`/`LOGS_OTLP_HEADERS` if your collector gateway
86
+ requires them.
85
87
 
86
88
  Core:
87
89
 
@@ -92,7 +94,7 @@ Core:
92
94
  Transport:
93
95
 
94
96
  - `LOGS_EXPORTER` (`loki|otlp`, aliases: `collector`, `otel`)
95
- - `LOGS_OTLP_ENDPOINT` (explicit OTLP logs endpoint, e.g. `http://collector:4318/v1/logs`)
97
+ - `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` (collector logs endpoint, e.g. `http://collector:4318/v1/logs`)
96
98
  - `LOGS_OTLP_HEADERS` (comma-separated headers, e.g. `x-tenant=team-a`)
97
99
  - `LOGS_COMPRESSION` (`none|gzip|brotli|snappy`)
98
100
  - `LOGS_COMPRESSION_LEVEL`
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "elven-logs-interceptor-python"
7
- version = "0.1.11"
7
+ version = "0.1.13"
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"
@@ -14,6 +14,8 @@ from ..internal_capture_guard import is_internal_log_capture_suppressed
14
14
  from ..log_noise_filter import normalize_excluded_logger_prefixes, should_drop_log_record
15
15
  from ..log_record_extra import extract_log_record_extra
16
16
 
17
+ _LOG_RECORD_CAPTURED_ATTR = "_elven_uo_captured"
18
+
17
19
 
18
20
  class _BridgeLoggingHandler(logging.Handler):
19
21
  def __init__(self, logger: ILogger, exclude_prefixes: list[str] | None = None) -> None:
@@ -23,6 +25,8 @@ class _BridgeLoggingHandler(logging.Handler):
23
25
 
24
26
  def emit(self, record: logging.LogRecord) -> None:
25
27
  try:
28
+ if getattr(record, _LOG_RECORD_CAPTURED_ATTR, False):
29
+ return
26
30
  if is_internal_log_capture_suppressed():
27
31
  return
28
32
  if should_drop_log_record(
@@ -13,6 +13,8 @@ from ..infrastructure.log_noise_filter import (
13
13
  from ..infrastructure.log_record_extra import extract_log_record_extra
14
14
  from ..types import LogLevel
15
15
 
16
+ _LOG_RECORD_CAPTURED_ATTR = "_elven_uo_captured"
17
+
16
18
 
17
19
  class LoggingHandler(logging.Handler):
18
20
  def __init__(self, logger: ILogger, exclude_prefixes: list[str] | None = None) -> None:
@@ -22,6 +24,8 @@ class LoggingHandler(logging.Handler):
22
24
 
23
25
  def emit(self, record: logging.LogRecord) -> None:
24
26
  try:
27
+ if getattr(record, _LOG_RECORD_CAPTURED_ATTR, False):
28
+ return
25
29
  if is_internal_log_capture_suppressed():
26
30
  return
27
31
  if should_drop_log_record(
@@ -96,26 +96,10 @@ def _parse_kv_csv(raw: str | None) -> dict[str, str]:
96
96
  return headers
97
97
 
98
98
 
99
- def _otlp_logs_endpoint_from_base(endpoint: str | None) -> str:
100
- if not endpoint:
101
- return ""
102
- normalized = endpoint.rstrip("/")
103
- if normalized.endswith("/v1/logs"):
104
- return normalized
105
- if normalized.endswith("/v1/traces") or normalized.endswith("/v1/metrics"):
106
- return normalized.rsplit("/", 1)[0] + "/logs"
107
- return normalized + "/v1/logs"
108
-
109
-
110
99
  def _resolve_logs_url(env: Mapping[str, str], exporter: str) -> str:
111
100
  if exporter != "otlp":
112
101
  return env.get("LOGS_URL", "")
113
- return (
114
- env.get("LOGS_URL")
115
- or env.get("LOGS_OTLP_ENDPOINT")
116
- or env.get("OTEL_EXPORTER_OTLP_LOGS_ENDPOINT")
117
- or _otlp_logs_endpoint_from_base(env.get("OTEL_EXPORTER_OTLP_ENDPOINT"))
118
- )
102
+ return env.get("OTEL_EXPORTER_OTLP_LOGS_ENDPOINT", "")
119
103
 
120
104
 
121
105
  def is_debug_enabled() -> bool: