elven-logs-interceptor-python 0.1.14__tar.gz → 0.1.16__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.14 → elven_logs_interceptor_python-0.1.16}/PKG-INFO +15 -9
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/README.md +14 -8
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/pyproject.toml +1 -1
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/application/config_service.py +2 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/filter/log_filter.py +3 -3
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/utils.py +89 -5
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/.gitignore +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/ARCHITECTURE.md +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/application/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/application/log_service.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/config.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/domain/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/domain/entities.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/domain/interfaces.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/domain/value_objects.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/buffer/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/buffer/memory_buffer.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/circuit_breaker/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/circuit_breaker/circuit_breaker.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/compression/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/compression/base.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/compression/brotli_compressor.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/compression/factory.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/compression/gzip_compressor.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/compression/noop_compressor.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/context/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/context/context_provider.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/dlq/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/dlq/file_dlq.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/dlq/memory_dlq.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/filter/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/interceptors/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/interceptors/runtime_interceptor.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/internal_capture_guard.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/log_noise_filter.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/log_record_extra.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/memory/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/memory/memory_tracker.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/metrics/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/metrics/metrics_collector.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/transport/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/transport/loki_json_transport.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/transport/loki_protobuf_transport.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/transport/otlp_json_transport.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/transport/resilient_transport.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/transport/transport_factory.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/workers/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/infrastructure/workers/worker_pool.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/integrations/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/integrations/celery.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/integrations/django.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/integrations/fastapi.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/integrations/flask.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/integrations/logging_handler.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/integrations/loguru.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/integrations/structlog.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/preload.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/presentation/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/src/logs_interceptor/presentation/factory.py +0 -0
- {elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/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.
|
|
3
|
+
Version: 0.1.16
|
|
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
|
|
@@ -123,9 +123,12 @@ logging.getLogger(__name__).info(
|
|
|
123
123
|
|
|
124
124
|
Supported aliases: `warning(...)`, `exception(...)` and `critical(...)`.
|
|
125
125
|
|
|
126
|
-
Sensitive fields such as `cpf`, `password`, `token` and `authorization` are
|
|
127
|
-
redacted by default.
|
|
128
|
-
|
|
126
|
+
Sensitive fields such as `cpf`, `cnpj`, `cpfCnpj`, `password`, `token` and `authorization` are
|
|
127
|
+
redacted by default. In messages, the library redacts only the sensitive
|
|
128
|
+
fragment/value and preserves the rest of the log. In structured context,
|
|
129
|
+
sensitive keys redact the full value. Set `LOGS_FILTER_SANITIZE=false`,
|
|
130
|
+
`LOGS_SANITIZE=false`, or `UO_LOGS_SANITIZE=false` only when raw sensitive data
|
|
131
|
+
is explicitly required and approved.
|
|
129
132
|
|
|
130
133
|
## Environment Variables
|
|
131
134
|
|
|
@@ -139,10 +142,13 @@ Required for direct Loki mode:
|
|
|
139
142
|
- `LOGS_APP_NAME`
|
|
140
143
|
|
|
141
144
|
For collector-first mode, set `LOGS_EXPORTER=otlp` (or `collector`) and use
|
|
142
|
-
`OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
`OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`. If the explicit logs endpoint is missing,
|
|
146
|
+
the library derives `/v1/logs` from `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`,
|
|
147
|
+
`OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`, or `OTEL_EXPORTER_OTLP_ENDPOINT`.
|
|
148
|
+
In this mode `LOGS_URL`, `LOKI_URL`, `LOGS_TENANT` and `LOGS_TOKEN` are not
|
|
149
|
+
required by the library. `LOGS_URL` is intentionally ignored in collector mode
|
|
150
|
+
to avoid accidentally posting OTLP logs to a direct Loki `/loki/api/v1/push`
|
|
151
|
+
endpoint. Put tenant or auth headers in
|
|
146
152
|
`OTEL_EXPORTER_OTLP_HEADERS`/`LOGS_OTLP_HEADERS` if your collector gateway
|
|
147
153
|
requires them.
|
|
148
154
|
|
|
@@ -182,7 +188,7 @@ Filter:
|
|
|
182
188
|
|
|
183
189
|
- `LOGS_FILTER_LEVELS`
|
|
184
190
|
- `LOGS_FILTER_SAMPLING_RATE`
|
|
185
|
-
- `LOGS_FILTER_SANITIZE`
|
|
191
|
+
- `LOGS_FILTER_SANITIZE` (aliases: `LOGS_SANITIZE`, `UO_LOGS_SANITIZE`)
|
|
186
192
|
- `LOGS_FILTER_MAX_MESSAGE_LENGTH`
|
|
187
193
|
- `LOGS_FILTER_EXCLUDE_LOGGER_PREFIXES` (comma-separated)
|
|
188
194
|
|
|
@@ -62,9 +62,12 @@ logging.getLogger(__name__).info(
|
|
|
62
62
|
|
|
63
63
|
Supported aliases: `warning(...)`, `exception(...)` and `critical(...)`.
|
|
64
64
|
|
|
65
|
-
Sensitive fields such as `cpf`, `password`, `token` and `authorization` are
|
|
66
|
-
redacted by default.
|
|
67
|
-
|
|
65
|
+
Sensitive fields such as `cpf`, `cnpj`, `cpfCnpj`, `password`, `token` and `authorization` are
|
|
66
|
+
redacted by default. In messages, the library redacts only the sensitive
|
|
67
|
+
fragment/value and preserves the rest of the log. In structured context,
|
|
68
|
+
sensitive keys redact the full value. Set `LOGS_FILTER_SANITIZE=false`,
|
|
69
|
+
`LOGS_SANITIZE=false`, or `UO_LOGS_SANITIZE=false` only when raw sensitive data
|
|
70
|
+
is explicitly required and approved.
|
|
68
71
|
|
|
69
72
|
## Environment Variables
|
|
70
73
|
|
|
@@ -78,10 +81,13 @@ Required for direct Loki mode:
|
|
|
78
81
|
- `LOGS_APP_NAME`
|
|
79
82
|
|
|
80
83
|
For collector-first mode, set `LOGS_EXPORTER=otlp` (or `collector`) and use
|
|
81
|
-
`OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
`OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`. If the explicit logs endpoint is missing,
|
|
85
|
+
the library derives `/v1/logs` from `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`,
|
|
86
|
+
`OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`, or `OTEL_EXPORTER_OTLP_ENDPOINT`.
|
|
87
|
+
In this mode `LOGS_URL`, `LOKI_URL`, `LOGS_TENANT` and `LOGS_TOKEN` are not
|
|
88
|
+
required by the library. `LOGS_URL` is intentionally ignored in collector mode
|
|
89
|
+
to avoid accidentally posting OTLP logs to a direct Loki `/loki/api/v1/push`
|
|
90
|
+
endpoint. Put tenant or auth headers in
|
|
85
91
|
`OTEL_EXPORTER_OTLP_HEADERS`/`LOGS_OTLP_HEADERS` if your collector gateway
|
|
86
92
|
requires them.
|
|
87
93
|
|
|
@@ -121,7 +127,7 @@ Filter:
|
|
|
121
127
|
|
|
122
128
|
- `LOGS_FILTER_LEVELS`
|
|
123
129
|
- `LOGS_FILTER_SAMPLING_RATE`
|
|
124
|
-
- `LOGS_FILTER_SANITIZE`
|
|
130
|
+
- `LOGS_FILTER_SANITIZE` (aliases: `LOGS_SANITIZE`, `UO_LOGS_SANITIZE`)
|
|
125
131
|
- `LOGS_FILTER_MAX_MESSAGE_LENGTH`
|
|
126
132
|
- `LOGS_FILTER_EXCLUDE_LOGGER_PREFIXES` (comma-separated)
|
|
127
133
|
|
{elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/pyproject.toml
RENAMED
|
@@ -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.16"
|
|
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"
|
|
@@ -5,7 +5,7 @@ import re
|
|
|
5
5
|
from ...config import ResolvedFilterConfig
|
|
6
6
|
from ...domain.entities import LogEntryEntity
|
|
7
7
|
from ...types import LogLevel
|
|
8
|
-
from ...utils import
|
|
8
|
+
from ...utils import redact_sensitive_text, sanitize_data, should_sample
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class LogFilter:
|
|
@@ -35,8 +35,8 @@ class LogFilter:
|
|
|
35
35
|
if self._config.sanitize and context is not None:
|
|
36
36
|
context = sanitize_data(context, self._config.sensitive_patterns)
|
|
37
37
|
|
|
38
|
-
if self._config.sanitize
|
|
39
|
-
message =
|
|
38
|
+
if self._config.sanitize:
|
|
39
|
+
message = redact_sensitive_text(message, self._config.sensitive_patterns)
|
|
40
40
|
|
|
41
41
|
return LogEntryEntity(
|
|
42
42
|
id=entry.id,
|
|
@@ -392,6 +392,87 @@ def detect_sensitive_data(text: str, patterns: Iterable[str]) -> bool:
|
|
|
392
392
|
return any(pattern.search(text) for pattern in common_patterns)
|
|
393
393
|
|
|
394
394
|
|
|
395
|
+
def redact_sensitive_text(text: str, sensitive_patterns: Iterable[str]) -> str:
|
|
396
|
+
"""Redact sensitive values while preserving the surrounding log message."""
|
|
397
|
+
patterns = list(sensitive_patterns)
|
|
398
|
+
redacted = text
|
|
399
|
+
|
|
400
|
+
for pattern in patterns:
|
|
401
|
+
redacted = _redact_key_value_pattern(redacted, pattern)
|
|
402
|
+
|
|
403
|
+
common_replacements: tuple[tuple[re.Pattern[str], str], ...] = (
|
|
404
|
+
(
|
|
405
|
+
re.compile(r"(Bearer)\s+[A-Za-z0-9\-._~+/=]+", re.IGNORECASE),
|
|
406
|
+
r"\1 [REDACTED]",
|
|
407
|
+
),
|
|
408
|
+
(
|
|
409
|
+
re.compile(r"(Basic)\s+[A-Za-z0-9+/=]+", re.IGNORECASE),
|
|
410
|
+
r"\1 [REDACTED]",
|
|
411
|
+
),
|
|
412
|
+
(
|
|
413
|
+
re.compile(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b"),
|
|
414
|
+
"[REDACTED]",
|
|
415
|
+
),
|
|
416
|
+
(
|
|
417
|
+
re.compile(r"\b(?:\d{4}[-\s]?){3}\d{4}\b"),
|
|
418
|
+
"[REDACTED]",
|
|
419
|
+
),
|
|
420
|
+
(
|
|
421
|
+
re.compile(r"\b\d{3}-\d{2}-\d{4}\b"),
|
|
422
|
+
"[REDACTED]",
|
|
423
|
+
),
|
|
424
|
+
(
|
|
425
|
+
re.compile(r"\b\d{3}\.\d{3}\.\d{3}-\d{2}\b"),
|
|
426
|
+
"[REDACTED]",
|
|
427
|
+
),
|
|
428
|
+
)
|
|
429
|
+
for common_pattern, replacement in common_replacements:
|
|
430
|
+
redacted = common_pattern.sub(replacement, redacted)
|
|
431
|
+
|
|
432
|
+
for pattern in patterns:
|
|
433
|
+
if _looks_like_value_pattern(pattern):
|
|
434
|
+
redacted = re.sub(pattern, "[REDACTED]", redacted, flags=re.IGNORECASE)
|
|
435
|
+
|
|
436
|
+
return redacted
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def _redact_key_value_pattern(text: str, key_pattern: str) -> str:
|
|
440
|
+
quoted = re.compile(
|
|
441
|
+
rf"(?P<prefix>(?:[\"']?{key_pattern}[\"']?)\s*[:=]\s*)(?P<quote>[\"'])(?P<value>.*?)(?P=quote)",
|
|
442
|
+
re.IGNORECASE,
|
|
443
|
+
)
|
|
444
|
+
redacted = quoted.sub(r"\g<prefix>\g<quote>[REDACTED]\g<quote>", text)
|
|
445
|
+
|
|
446
|
+
unquoted = re.compile(
|
|
447
|
+
rf"(?P<prefix>(?:[\"']?{key_pattern}[\"']?)\s*[:=]\s*)(?P<value>[^\s,;&}}\]\"']+)",
|
|
448
|
+
re.IGNORECASE,
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
def _replace_unquoted(match: re.Match[str]) -> str:
|
|
452
|
+
value = match.group("value")
|
|
453
|
+
if value.lower() in {"bearer", "basic"} or value == "[REDACTED]":
|
|
454
|
+
return match.group(0)
|
|
455
|
+
return f"{match.group('prefix')}[REDACTED]"
|
|
456
|
+
|
|
457
|
+
redacted = unquoted.sub(_replace_unquoted, redacted)
|
|
458
|
+
|
|
459
|
+
query = re.compile(
|
|
460
|
+
rf"(?P<prefix>[?&](?:{key_pattern})=)(?P<value>[^&#\s]+)",
|
|
461
|
+
re.IGNORECASE,
|
|
462
|
+
)
|
|
463
|
+
return query.sub(r"\g<prefix>[REDACTED]", redacted)
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
def _looks_like_value_pattern(pattern: str) -> bool:
|
|
467
|
+
# Plain words such as "token" and "password" are key indicators by default;
|
|
468
|
+
# redacting those words directly would destroy harmless messages like
|
|
469
|
+
# "Gerando token de acesso". Regex-looking patterns are treated as values.
|
|
470
|
+
keyish_terms = r"password|token|secret|api|key|authorization|credit|card|ssn|cpf|cnpj"
|
|
471
|
+
if re.search(keyish_terms, pattern, re.IGNORECASE):
|
|
472
|
+
return False
|
|
473
|
+
return bool(re.search(r"\\d|\[0-9|\{\d|[\^$]", pattern))
|
|
474
|
+
|
|
475
|
+
|
|
395
476
|
def sanitize_data(
|
|
396
477
|
data: dict[str, Any],
|
|
397
478
|
sensitive_patterns: Iterable[str],
|
|
@@ -415,16 +496,14 @@ def sanitize_data(
|
|
|
415
496
|
continue
|
|
416
497
|
|
|
417
498
|
if isinstance(value, str):
|
|
418
|
-
sanitized[key] =
|
|
499
|
+
sanitized[key] = redact_sensitive_text(value, sensitive_patterns)
|
|
419
500
|
continue
|
|
420
501
|
|
|
421
502
|
if isinstance(value, list):
|
|
422
503
|
transformed: list[Any] = []
|
|
423
504
|
for item in value:
|
|
424
505
|
if isinstance(item, str):
|
|
425
|
-
transformed.append(
|
|
426
|
-
"[REDACTED]" if detect_sensitive_data(item, sensitive_patterns) else item
|
|
427
|
-
)
|
|
506
|
+
transformed.append(redact_sensitive_text(item, sensitive_patterns))
|
|
428
507
|
elif isinstance(item, dict):
|
|
429
508
|
transformed.append(sanitize_data(item, sensitive_patterns, seen))
|
|
430
509
|
else:
|
|
@@ -619,7 +698,12 @@ def load_config_from_env() -> LogsInterceptorConfig:
|
|
|
619
698
|
filter=FilterConfig(
|
|
620
699
|
levels=_env_levels(env.get("LOGS_FILTER_LEVELS")),
|
|
621
700
|
sampling_rate=parse_float_range(env.get("LOGS_FILTER_SAMPLING_RATE"), 1.0, 0.0, 1.0),
|
|
622
|
-
sanitize=parse_bool(
|
|
701
|
+
sanitize=parse_bool(
|
|
702
|
+
env.get("LOGS_FILTER_SANITIZE")
|
|
703
|
+
or env.get("LOGS_SANITIZE")
|
|
704
|
+
or env.get("UO_LOGS_SANITIZE"),
|
|
705
|
+
True,
|
|
706
|
+
),
|
|
623
707
|
max_message_length=parse_int_range(
|
|
624
708
|
env.get("LOGS_FILTER_MAX_MESSAGE_LENGTH"), 8192, 64, 1_000_000
|
|
625
709
|
),
|
|
File without changes
|
{elven_logs_interceptor_python-0.1.14 → elven_logs_interceptor_python-0.1.16}/ARCHITECTURE.md
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
|