elven-logs-interceptor-python 0.1.12__tar.gz → 0.1.14__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.12 → elven_logs_interceptor_python-0.1.14}/PKG-INFO +1 -1
  2. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/pyproject.toml +1 -1
  3. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/interceptors/runtime_interceptor.py +4 -0
  4. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/integrations/logging_handler.py +4 -0
  5. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/utils.py +35 -4
  6. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/.gitignore +0 -0
  7. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/ARCHITECTURE.md +0 -0
  8. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/README.md +0 -0
  9. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/__init__.py +0 -0
  10. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/application/__init__.py +0 -0
  11. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/application/config_service.py +0 -0
  12. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/application/log_service.py +0 -0
  13. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/config.py +0 -0
  14. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/domain/__init__.py +0 -0
  15. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/domain/entities.py +0 -0
  16. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/domain/interfaces.py +0 -0
  17. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/domain/value_objects.py +0 -0
  18. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/__init__.py +0 -0
  19. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/buffer/__init__.py +0 -0
  20. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/buffer/memory_buffer.py +0 -0
  21. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/circuit_breaker/__init__.py +0 -0
  22. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/circuit_breaker/circuit_breaker.py +0 -0
  23. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/compression/__init__.py +0 -0
  24. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/compression/base.py +0 -0
  25. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/compression/brotli_compressor.py +0 -0
  26. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/compression/factory.py +0 -0
  27. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/compression/gzip_compressor.py +0 -0
  28. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/compression/noop_compressor.py +0 -0
  29. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/context/__init__.py +0 -0
  30. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/context/context_provider.py +0 -0
  31. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/dlq/__init__.py +0 -0
  32. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/dlq/file_dlq.py +0 -0
  33. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/dlq/memory_dlq.py +0 -0
  34. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/filter/__init__.py +0 -0
  35. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/filter/log_filter.py +0 -0
  36. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/interceptors/__init__.py +0 -0
  37. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/internal_capture_guard.py +0 -0
  38. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/log_noise_filter.py +0 -0
  39. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/log_record_extra.py +0 -0
  40. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/memory/__init__.py +0 -0
  41. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/memory/memory_tracker.py +0 -0
  42. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/metrics/__init__.py +0 -0
  43. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/metrics/metrics_collector.py +0 -0
  44. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/transport/__init__.py +0 -0
  45. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/transport/loki_json_transport.py +0 -0
  46. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/transport/loki_protobuf_transport.py +0 -0
  47. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/transport/otlp_json_transport.py +0 -0
  48. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/transport/resilient_transport.py +0 -0
  49. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/transport/transport_factory.py +0 -0
  50. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/workers/__init__.py +0 -0
  51. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/infrastructure/workers/worker_pool.py +0 -0
  52. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/integrations/__init__.py +0 -0
  53. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/integrations/celery.py +0 -0
  54. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/integrations/django.py +0 -0
  55. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/integrations/fastapi.py +0 -0
  56. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/integrations/flask.py +0 -0
  57. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/integrations/loguru.py +0 -0
  58. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/integrations/structlog.py +0 -0
  59. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/preload.py +0 -0
  60. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/presentation/__init__.py +0 -0
  61. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/src/logs_interceptor/presentation/factory.py +0 -0
  62. {elven_logs_interceptor_python-0.1.12 → elven_logs_interceptor_python-0.1.14}/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.12
3
+ Version: 0.1.14
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "elven-logs-interceptor-python"
7
- version = "0.1.12"
7
+ version = "0.1.14"
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(
@@ -82,6 +82,17 @@ def _normalize_logs_exporter(value: str | None) -> str:
82
82
  return "loki"
83
83
 
84
84
 
85
+ def _resolve_logs_exporter(env: Mapping[str, str]) -> str:
86
+ explicit = env.get("LOGS_EXPORTER") or env.get("LOGS_TRANSPORT") or env.get("OTEL_LOGS_EXPORTER")
87
+ if explicit:
88
+ return _normalize_logs_exporter(explicit)
89
+ if env.get("LOGS_URL"):
90
+ return "loki"
91
+ if _resolve_otlp_logs_url(env):
92
+ return "otlp"
93
+ return "loki"
94
+
95
+
85
96
  def _parse_kv_csv(raw: str | None) -> dict[str, str]:
86
97
  headers: dict[str, str] = {}
87
98
  if not raw:
@@ -99,7 +110,29 @@ def _parse_kv_csv(raw: str | None) -> dict[str, str]:
99
110
  def _resolve_logs_url(env: Mapping[str, str], exporter: str) -> str:
100
111
  if exporter != "otlp":
101
112
  return env.get("LOGS_URL", "")
102
- return env.get("OTEL_EXPORTER_OTLP_LOGS_ENDPOINT", "")
113
+ return _resolve_otlp_logs_url(env)
114
+
115
+
116
+ def _resolve_otlp_logs_url(env: Mapping[str, str]) -> str:
117
+ return (
118
+ env.get("OTEL_EXPORTER_OTLP_LOGS_ENDPOINT")
119
+ or _derive_otlp_logs_endpoint(
120
+ env.get("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT")
121
+ or env.get("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT")
122
+ or env.get("OTEL_EXPORTER_OTLP_ENDPOINT")
123
+ )
124
+ )
125
+
126
+
127
+ def _derive_otlp_logs_endpoint(endpoint: str | None) -> str:
128
+ if not endpoint:
129
+ return ""
130
+ normalized = endpoint.rstrip("/")
131
+ if normalized.endswith("/v1/logs"):
132
+ return normalized
133
+ if normalized.endswith("/v1/traces") or normalized.endswith("/v1/metrics"):
134
+ return normalized.rsplit("/", 1)[0] + "/logs"
135
+ return normalized + "/v1/logs"
103
136
 
104
137
 
105
138
  def is_debug_enabled() -> bool:
@@ -534,9 +567,7 @@ def load_config_from_env() -> LogsInterceptorConfig:
534
567
  if compression_value not in {"none", "gzip", "brotli", "snappy"}:
535
568
  compression_value = "gzip"
536
569
 
537
- exporter = _normalize_logs_exporter(
538
- env.get("LOGS_EXPORTER") or env.get("LOGS_TRANSPORT") or env.get("OTEL_LOGS_EXPORTER")
539
- )
570
+ exporter = _resolve_logs_exporter(env)
540
571
  headers = {
541
572
  **_parse_kv_csv(env.get("LOGS_HEADERS")),
542
573
  **_parse_kv_csv(env.get("LOGS_OTLP_HEADERS")),