elven-logs-interceptor-python 0.1.9__tar.gz → 0.1.10__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.9 → elven_logs_interceptor_python-0.1.10}/PKG-INFO +6 -6
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/pyproject.toml +11 -11
- elven_logs_interceptor_python-0.1.9/examples/basic_app.py +0 -18
- elven_logs_interceptor_python-0.1.9/examples/fastapi_integration.py +0 -26
- elven_logs_interceptor_python-0.1.9/examples/full_config_reference.py +0 -67
- elven_logs_interceptor_python-0.1.9/examples/high_volume.py +0 -30
- elven_logs_interceptor_python-0.1.9/examples/tracking_usage.py +0 -14
- elven_logs_interceptor_python-0.1.9/scripts/publish.sh +0 -180
- elven_logs_interceptor_python-0.1.9/test-apps/elven-live-demo/.env.example +0 -49
- elven_logs_interceptor_python-0.1.9/test-apps/elven-live-demo/README.md +0 -17
- elven_logs_interceptor_python-0.1.9/test-apps/elven-live-demo/app.py +0 -97
- elven_logs_interceptor_python-0.1.9/test-apps/elven-live-demo/run.sh +0 -21
- elven_logs_interceptor_python-0.1.9/test-apps/elven-observability-smoke/.env.example +0 -167
- elven_logs_interceptor_python-0.1.9/test-apps/elven-observability-smoke/README.md +0 -27
- elven_logs_interceptor_python-0.1.9/test-apps/elven-observability-smoke/app.py +0 -90
- elven_logs_interceptor_python-0.1.9/test-apps/elven-observability-smoke/run.sh +0 -21
- elven_logs_interceptor_python-0.1.9/tests/integration/test_api.py +0 -122
- elven_logs_interceptor_python-0.1.9/tests/unit/test_circuit_breaker_extra.py +0 -48
- elven_logs_interceptor_python-0.1.9/tests/unit/test_config_service.py +0 -144
- elven_logs_interceptor_python-0.1.9/tests/unit/test_core_components.py +0 -77
- elven_logs_interceptor_python-0.1.9/tests/unit/test_env_config.py +0 -59
- elven_logs_interceptor_python-0.1.9/tests/unit/test_integration_filters.py +0 -119
- elven_logs_interceptor_python-0.1.9/tests/unit/test_log_filter_extra.py +0 -68
- elven_logs_interceptor_python-0.1.9/tests/unit/test_log_service_unit.py +0 -578
- elven_logs_interceptor_python-0.1.9/tests/unit/test_loguru_sink.py +0 -137
- elven_logs_interceptor_python-0.1.9/tests/unit/test_loki_json_transport.py +0 -179
- elven_logs_interceptor_python-0.1.9/tests/unit/test_memory_buffer_extra.py +0 -145
- elven_logs_interceptor_python-0.1.9/tests/unit/test_protobuf_transport_safety.py +0 -141
- elven_logs_interceptor_python-0.1.9/tests/unit/test_resilient_transport.py +0 -211
- elven_logs_interceptor_python-0.1.9/tests/unit/test_runtime_interceptor.py +0 -88
- elven_logs_interceptor_python-0.1.9/tests/unit/test_utils_extra.py +0 -276
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/.gitignore +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/ARCHITECTURE.md +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/README.md +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/application/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/application/config_service.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/application/log_service.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/config.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/domain/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/domain/entities.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/domain/interfaces.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/domain/value_objects.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/buffer/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/buffer/memory_buffer.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/circuit_breaker/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/circuit_breaker/circuit_breaker.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/compression/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/compression/base.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/compression/brotli_compressor.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/compression/factory.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/compression/gzip_compressor.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/compression/noop_compressor.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/context/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/context/context_provider.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/dlq/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/dlq/file_dlq.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/dlq/memory_dlq.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/filter/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/filter/log_filter.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/interceptors/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/interceptors/runtime_interceptor.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/internal_capture_guard.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/log_noise_filter.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/log_record_extra.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/memory/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/memory/memory_tracker.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/metrics/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/metrics/metrics_collector.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/transport/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/transport/loki_json_transport.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/transport/loki_protobuf_transport.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/transport/resilient_transport.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/transport/transport_factory.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/workers/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/infrastructure/workers/worker_pool.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/integrations/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/integrations/celery.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/integrations/django.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/integrations/fastapi.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/integrations/flask.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/integrations/logging_handler.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/integrations/loguru.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/integrations/structlog.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/preload.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/presentation/__init__.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/presentation/factory.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/types.py +0 -0
- {elven_logs_interceptor_python-0.1.9 → elven_logs_interceptor_python-0.1.10}/src/logs_interceptor/utils.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.10
|
|
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
|
|
@@ -14,20 +14,20 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
15
|
Classifier: Topic :: System :: Logging
|
|
16
16
|
Requires-Python: >=3.10
|
|
17
|
-
Requires-Dist: httpx
|
|
17
|
+
Requires-Dist: httpx<0.29.0,>=0.24.1
|
|
18
18
|
Requires-Dist: typing-extensions>=4.12.0
|
|
19
19
|
Provides-Extra: all
|
|
20
20
|
Requires-Dist: brotli>=1.1.0; extra == 'all'
|
|
21
21
|
Requires-Dist: celery>=5.4.0; extra == 'all'
|
|
22
22
|
Requires-Dist: django>=4.2; extra == 'all'
|
|
23
|
-
Requires-Dist: fastapi>=0.
|
|
23
|
+
Requires-Dist: fastapi>=0.100.0; extra == 'all'
|
|
24
24
|
Requires-Dist: flask>=3.0.0; extra == 'all'
|
|
25
25
|
Requires-Dist: loguru>=0.7.2; extra == 'all'
|
|
26
26
|
Requires-Dist: opentelemetry-api>=1.24.0; extra == 'all'
|
|
27
27
|
Requires-Dist: orjson>=3.10.0; extra == 'all'
|
|
28
28
|
Requires-Dist: protobuf>=5.0.0; extra == 'all'
|
|
29
29
|
Requires-Dist: python-snappy>=0.7.1; extra == 'all'
|
|
30
|
-
Requires-Dist: starlette>=0.
|
|
30
|
+
Requires-Dist: starlette>=0.27.0; extra == 'all'
|
|
31
31
|
Requires-Dist: structlog>=24.0.0; extra == 'all'
|
|
32
32
|
Provides-Extra: celery
|
|
33
33
|
Requires-Dist: celery>=5.4.0; extra == 'celery'
|
|
@@ -42,8 +42,8 @@ Requires-Dist: twine>=5.1.1; extra == 'dev'
|
|
|
42
42
|
Provides-Extra: django
|
|
43
43
|
Requires-Dist: django>=4.2; extra == 'django'
|
|
44
44
|
Provides-Extra: fastapi
|
|
45
|
-
Requires-Dist: fastapi>=0.
|
|
46
|
-
Requires-Dist: starlette>=0.
|
|
45
|
+
Requires-Dist: fastapi>=0.100.0; extra == 'fastapi'
|
|
46
|
+
Requires-Dist: starlette>=0.27.0; extra == 'fastapi'
|
|
47
47
|
Provides-Extra: flask
|
|
48
48
|
Requires-Dist: flask>=3.0.0; extra == 'flask'
|
|
49
49
|
Provides-Extra: loguru
|
|
@@ -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.10"
|
|
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"
|
|
@@ -32,7 +32,7 @@ classifiers = [
|
|
|
32
32
|
"Topic :: System :: Logging",
|
|
33
33
|
]
|
|
34
34
|
dependencies = [
|
|
35
|
-
"httpx>=0.
|
|
35
|
+
"httpx>=0.24.1,<0.29.0",
|
|
36
36
|
"typing-extensions>=4.12.0",
|
|
37
37
|
]
|
|
38
38
|
|
|
@@ -47,8 +47,8 @@ otel = [
|
|
|
47
47
|
"opentelemetry-api>=1.24.0",
|
|
48
48
|
]
|
|
49
49
|
fastapi = [
|
|
50
|
-
"fastapi>=0.
|
|
51
|
-
"starlette>=0.
|
|
50
|
+
"fastapi>=0.100.0",
|
|
51
|
+
"starlette>=0.27.0",
|
|
52
52
|
]
|
|
53
53
|
django = [
|
|
54
54
|
"django>=4.2",
|
|
@@ -71,8 +71,8 @@ all = [
|
|
|
71
71
|
"python-snappy>=0.7.1",
|
|
72
72
|
"brotli>=1.1.0",
|
|
73
73
|
"opentelemetry-api>=1.24.0",
|
|
74
|
-
"fastapi>=0.
|
|
75
|
-
"starlette>=0.
|
|
74
|
+
"fastapi>=0.100.0",
|
|
75
|
+
"starlette>=0.27.0",
|
|
76
76
|
"django>=4.2",
|
|
77
77
|
"flask>=3.0.0",
|
|
78
78
|
"celery>=5.4.0",
|
|
@@ -93,22 +93,22 @@ dev = [
|
|
|
93
93
|
packages = ["src/logs_interceptor"]
|
|
94
94
|
|
|
95
95
|
[tool.hatch.build.targets.sdist]
|
|
96
|
-
include = [
|
|
96
|
+
only-include = [
|
|
97
97
|
"/ARCHITECTURE.md",
|
|
98
98
|
"/README.md",
|
|
99
|
-
"/examples",
|
|
100
99
|
"/pyproject.toml",
|
|
101
|
-
"/scripts",
|
|
102
100
|
"/src",
|
|
103
|
-
"/test-apps",
|
|
104
|
-
"/tests",
|
|
105
101
|
]
|
|
106
102
|
exclude = [
|
|
103
|
+
"/.mypy_cache",
|
|
104
|
+
"/.pytest_cache",
|
|
105
|
+
"/.ruff_cache",
|
|
107
106
|
"/.venv*",
|
|
108
107
|
"/.logs-dlq",
|
|
109
108
|
"/build",
|
|
110
109
|
"/collector",
|
|
111
110
|
"/dist",
|
|
111
|
+
"/test-apps",
|
|
112
112
|
]
|
|
113
113
|
|
|
114
114
|
[tool.pytest.ini_options]
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from logs_interceptor import init
|
|
2
|
-
|
|
3
|
-
init(
|
|
4
|
-
{
|
|
5
|
-
"appName": "my-service",
|
|
6
|
-
"interceptConsole": True,
|
|
7
|
-
"transport": {
|
|
8
|
-
"url": "http://localhost:3100/loki/api/v1/push",
|
|
9
|
-
"tenantId": "my-tenant",
|
|
10
|
-
"compression": "gzip",
|
|
11
|
-
"enableConnectionPooling": True,
|
|
12
|
-
},
|
|
13
|
-
"deadLetterQueue": {"enabled": True, "type": "file"},
|
|
14
|
-
"circuitBreaker": {"enabled": True},
|
|
15
|
-
}
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
print("service started")
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
from fastapi import FastAPI
|
|
2
|
-
|
|
3
|
-
from logs_interceptor import init, logger
|
|
4
|
-
from logs_interceptor.integrations import FastAPIMiddleware
|
|
5
|
-
|
|
6
|
-
init(
|
|
7
|
-
{
|
|
8
|
-
"transport": {
|
|
9
|
-
"url": "http://localhost:3100/loki/api/v1/push",
|
|
10
|
-
"tenantId": "my-tenant",
|
|
11
|
-
"compression": "brotli",
|
|
12
|
-
},
|
|
13
|
-
"appName": "my-api",
|
|
14
|
-
"interceptConsole": True,
|
|
15
|
-
"deadLetterQueue": {"enabled": True, "type": "file"},
|
|
16
|
-
}
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
app = FastAPI()
|
|
20
|
-
app.add_middleware(FastAPIMiddleware, logger=logger)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@app.get("/ping")
|
|
24
|
-
def ping() -> dict[str, str]:
|
|
25
|
-
logger.info("ping called")
|
|
26
|
-
return {"message": "pong"}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
from logs_interceptor import init
|
|
2
|
-
|
|
3
|
-
init(
|
|
4
|
-
{
|
|
5
|
-
"appName": "my-service-name",
|
|
6
|
-
"version": "1.2.0",
|
|
7
|
-
"environment": "production",
|
|
8
|
-
"interceptConsole": True,
|
|
9
|
-
"preserveOriginalConsole": True,
|
|
10
|
-
"silentErrors": False,
|
|
11
|
-
"debug": False,
|
|
12
|
-
"labels": {"region": "us-east-1", "tier": "gold"},
|
|
13
|
-
"dynamicLabels": {
|
|
14
|
-
"pod_id": lambda: "unknown",
|
|
15
|
-
},
|
|
16
|
-
"transport": {
|
|
17
|
-
"url": "http://localhost:3100/loki/api/v1/push",
|
|
18
|
-
"tenantId": "my-tenant-id",
|
|
19
|
-
"timeout": 10000,
|
|
20
|
-
"maxRetries": 3,
|
|
21
|
-
"retryDelay": 1000,
|
|
22
|
-
"enableConnectionPooling": True,
|
|
23
|
-
"maxSockets": 50,
|
|
24
|
-
"compression": "snappy",
|
|
25
|
-
"compressionLevel": 6,
|
|
26
|
-
"compressionThreshold": 1024,
|
|
27
|
-
"useWorkers": True,
|
|
28
|
-
"maxWorkers": 2,
|
|
29
|
-
"workerTimeout": 30000,
|
|
30
|
-
},
|
|
31
|
-
"buffer": {
|
|
32
|
-
"maxSize": 1000,
|
|
33
|
-
"flushInterval": 5000,
|
|
34
|
-
"maxMemoryMB": 50,
|
|
35
|
-
"maxAge": 30000,
|
|
36
|
-
"autoFlush": True,
|
|
37
|
-
},
|
|
38
|
-
"filter": {
|
|
39
|
-
"levels": ["info", "warn", "error", "fatal"],
|
|
40
|
-
"patterns": ["health/check"],
|
|
41
|
-
"samplingRate": 1.0,
|
|
42
|
-
"sanitize": True,
|
|
43
|
-
"sensitivePatterns": ["password", "token", "secret"],
|
|
44
|
-
"maxMessageLength": 8192,
|
|
45
|
-
},
|
|
46
|
-
"circuitBreaker": {
|
|
47
|
-
"enabled": True,
|
|
48
|
-
"failureThreshold": 20,
|
|
49
|
-
"resetTimeout": 30000,
|
|
50
|
-
"halfOpenRequests": 3,
|
|
51
|
-
},
|
|
52
|
-
"deadLetterQueue": {
|
|
53
|
-
"enabled": True,
|
|
54
|
-
"type": "file",
|
|
55
|
-
"basePath": "./.logs-dlq",
|
|
56
|
-
"maxSize": 1000,
|
|
57
|
-
"maxRetries": 10,
|
|
58
|
-
},
|
|
59
|
-
"performance": {
|
|
60
|
-
"useWorkers": True,
|
|
61
|
-
"maxConcurrentFlushes": 5,
|
|
62
|
-
"workerTimeout": 30000,
|
|
63
|
-
},
|
|
64
|
-
"enableMetrics": True,
|
|
65
|
-
"enableHealthCheck": True,
|
|
66
|
-
}
|
|
67
|
-
)
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
from logs_interceptor import init, logger
|
|
2
|
-
|
|
3
|
-
init(
|
|
4
|
-
{
|
|
5
|
-
"appName": "high-volume-service",
|
|
6
|
-
"interceptConsole": True,
|
|
7
|
-
"transport": {
|
|
8
|
-
"url": "http://localhost:3100/loki/api/v1/push",
|
|
9
|
-
"tenantId": "production",
|
|
10
|
-
"compression": "snappy",
|
|
11
|
-
"maxSockets": 100,
|
|
12
|
-
"timeout": 10000,
|
|
13
|
-
"useWorkers": True,
|
|
14
|
-
"maxWorkers": 4,
|
|
15
|
-
"compressionThreshold": 4096,
|
|
16
|
-
"compressionLevel": 6,
|
|
17
|
-
},
|
|
18
|
-
"buffer": {
|
|
19
|
-
"maxSize": 2000,
|
|
20
|
-
"flushInterval": 2000,
|
|
21
|
-
"maxMemoryMB": 512,
|
|
22
|
-
},
|
|
23
|
-
"performance": {
|
|
24
|
-
"maxConcurrentFlushes": 10,
|
|
25
|
-
},
|
|
26
|
-
}
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
for i in range(10000):
|
|
30
|
-
logger.info("High volume event", {"index": i})
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
from logs_interceptor import init, logger
|
|
2
|
-
|
|
3
|
-
init(
|
|
4
|
-
{
|
|
5
|
-
"appName": "analytics-service",
|
|
6
|
-
"transport": {
|
|
7
|
-
"url": "http://localhost:3100/loki/api/v1/push",
|
|
8
|
-
"tenantId": "analytics",
|
|
9
|
-
},
|
|
10
|
-
}
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
logger.track_event("user_signup", {"user_id": "u_123", "plan": "pro"})
|
|
14
|
-
logger.track_event("api_request", {"endpoint": "/users", "status_code": 200})
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -Eeuo pipefail
|
|
3
|
-
|
|
4
|
-
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
-
cd "${ROOT_DIR}"
|
|
6
|
-
|
|
7
|
-
PYTHON_BIN="${PYTHON_BIN:-python3}"
|
|
8
|
-
REPOSITORY="testpypi"
|
|
9
|
-
TOKEN_ENV=""
|
|
10
|
-
SKIP_CHECKS=0
|
|
11
|
-
SKIP_BUILD=0
|
|
12
|
-
DRY_RUN=0
|
|
13
|
-
SKIP_EXISTING=1
|
|
14
|
-
|
|
15
|
-
TEST_PYPI_URL="https://test.pypi.org/legacy/"
|
|
16
|
-
PYPI_URL="https://upload.pypi.org/legacy/"
|
|
17
|
-
|
|
18
|
-
usage() {
|
|
19
|
-
cat <<'EOF'
|
|
20
|
-
Usage:
|
|
21
|
-
./scripts/publish.sh [options]
|
|
22
|
-
|
|
23
|
-
Options:
|
|
24
|
-
--repository {testpypi|pypi} Publish target (default: testpypi)
|
|
25
|
-
--token-env NAME Env var with API token
|
|
26
|
-
--skip-checks Skip ruff + mypy + pytest
|
|
27
|
-
--skip-build Skip build and twine check steps
|
|
28
|
-
--no-skip-existing Do not pass --skip-existing to twine upload
|
|
29
|
-
--dry-run Run validations/build but do not upload
|
|
30
|
-
-h, --help Show this message
|
|
31
|
-
|
|
32
|
-
Env:
|
|
33
|
-
PYTHON_BIN Python executable (default: python3)
|
|
34
|
-
TEST_PYPI_API_TOKEN Default token env for --repository testpypi
|
|
35
|
-
PYPI_API_TOKEN Default token env for --repository pypi
|
|
36
|
-
EOF
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
require_python_module() {
|
|
40
|
-
local module_name="$1"
|
|
41
|
-
if ! "${PYTHON_BIN}" -c "import ${module_name}" >/dev/null 2>&1; then
|
|
42
|
-
echo "Missing Python module: ${module_name}" >&2
|
|
43
|
-
echo "Install dependencies with: ${PYTHON_BIN} -m pip install -e \".[dev]\"" >&2
|
|
44
|
-
exit 1
|
|
45
|
-
fi
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
run_checks() {
|
|
49
|
-
echo "[publish] running quality gates..."
|
|
50
|
-
"${PYTHON_BIN}" -m ruff check .
|
|
51
|
-
"${PYTHON_BIN}" -m mypy src
|
|
52
|
-
"${PYTHON_BIN}" -m pytest -q
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
clean_artifacts() {
|
|
56
|
-
rm -rf build dist
|
|
57
|
-
find . -maxdepth 1 -type d -name "*.egg-info" -exec rm -rf {} +
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
build_artifacts() {
|
|
61
|
-
echo "[publish] building distribution artifacts..."
|
|
62
|
-
clean_artifacts
|
|
63
|
-
"${PYTHON_BIN}" -m build
|
|
64
|
-
"${PYTHON_BIN}" -m twine check dist/*
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
resolve_repository_url() {
|
|
68
|
-
if [[ "${REPOSITORY}" == "testpypi" ]]; then
|
|
69
|
-
echo "${TEST_PYPI_URL}"
|
|
70
|
-
return
|
|
71
|
-
fi
|
|
72
|
-
echo "${PYPI_URL}"
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
resolve_token_env() {
|
|
76
|
-
if [[ -n "${TOKEN_ENV}" ]]; then
|
|
77
|
-
echo "${TOKEN_ENV}"
|
|
78
|
-
return
|
|
79
|
-
fi
|
|
80
|
-
if [[ "${REPOSITORY}" == "testpypi" ]]; then
|
|
81
|
-
echo "TEST_PYPI_API_TOKEN"
|
|
82
|
-
return
|
|
83
|
-
fi
|
|
84
|
-
echo "PYPI_API_TOKEN"
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
while [[ $# -gt 0 ]]; do
|
|
88
|
-
case "$1" in
|
|
89
|
-
--repository)
|
|
90
|
-
REPOSITORY="$2"
|
|
91
|
-
shift 2
|
|
92
|
-
;;
|
|
93
|
-
--token-env)
|
|
94
|
-
TOKEN_ENV="$2"
|
|
95
|
-
shift 2
|
|
96
|
-
;;
|
|
97
|
-
--skip-checks)
|
|
98
|
-
SKIP_CHECKS=1
|
|
99
|
-
shift
|
|
100
|
-
;;
|
|
101
|
-
--skip-build)
|
|
102
|
-
SKIP_BUILD=1
|
|
103
|
-
shift
|
|
104
|
-
;;
|
|
105
|
-
--no-skip-existing)
|
|
106
|
-
SKIP_EXISTING=0
|
|
107
|
-
shift
|
|
108
|
-
;;
|
|
109
|
-
--dry-run)
|
|
110
|
-
DRY_RUN=1
|
|
111
|
-
shift
|
|
112
|
-
;;
|
|
113
|
-
-h|--help)
|
|
114
|
-
usage
|
|
115
|
-
exit 0
|
|
116
|
-
;;
|
|
117
|
-
*)
|
|
118
|
-
echo "Unknown option: $1" >&2
|
|
119
|
-
usage
|
|
120
|
-
exit 1
|
|
121
|
-
;;
|
|
122
|
-
esac
|
|
123
|
-
done
|
|
124
|
-
|
|
125
|
-
if [[ "${REPOSITORY}" != "testpypi" && "${REPOSITORY}" != "pypi" ]]; then
|
|
126
|
-
echo "Invalid --repository value: ${REPOSITORY}" >&2
|
|
127
|
-
exit 1
|
|
128
|
-
fi
|
|
129
|
-
|
|
130
|
-
if [[ "${SKIP_CHECKS}" -eq 0 ]]; then
|
|
131
|
-
require_python_module "ruff"
|
|
132
|
-
require_python_module "mypy"
|
|
133
|
-
require_python_module "pytest"
|
|
134
|
-
fi
|
|
135
|
-
|
|
136
|
-
if [[ "${SKIP_BUILD}" -eq 0 ]]; then
|
|
137
|
-
require_python_module "build"
|
|
138
|
-
require_python_module "twine"
|
|
139
|
-
elif [[ "${DRY_RUN}" -eq 0 ]]; then
|
|
140
|
-
require_python_module "twine"
|
|
141
|
-
fi
|
|
142
|
-
|
|
143
|
-
if [[ "${SKIP_CHECKS}" -eq 0 ]]; then
|
|
144
|
-
run_checks
|
|
145
|
-
fi
|
|
146
|
-
|
|
147
|
-
if [[ "${SKIP_BUILD}" -eq 0 ]]; then
|
|
148
|
-
build_artifacts
|
|
149
|
-
fi
|
|
150
|
-
|
|
151
|
-
if [[ "${DRY_RUN}" -eq 1 ]]; then
|
|
152
|
-
echo "[publish] dry-run enabled, upload skipped."
|
|
153
|
-
echo "[publish] built files:"
|
|
154
|
-
ls -1 dist/* 2>/dev/null || true
|
|
155
|
-
exit 0
|
|
156
|
-
fi
|
|
157
|
-
|
|
158
|
-
repository_url="$(resolve_repository_url)"
|
|
159
|
-
token_env_name="$(resolve_token_env)"
|
|
160
|
-
token_value="${!token_env_name-}"
|
|
161
|
-
|
|
162
|
-
if [[ -z "${token_value}" ]]; then
|
|
163
|
-
echo "Missing publish token in env var: ${token_env_name}" >&2
|
|
164
|
-
exit 1
|
|
165
|
-
fi
|
|
166
|
-
|
|
167
|
-
twine_args=(
|
|
168
|
-
upload
|
|
169
|
-
--repository-url "${repository_url}"
|
|
170
|
-
--non-interactive
|
|
171
|
-
)
|
|
172
|
-
if [[ "${SKIP_EXISTING}" -eq 1 ]]; then
|
|
173
|
-
twine_args+=(--skip-existing)
|
|
174
|
-
fi
|
|
175
|
-
twine_args+=(dist/*)
|
|
176
|
-
|
|
177
|
-
echo "[publish] uploading to ${REPOSITORY} (${repository_url})..."
|
|
178
|
-
TWINE_USERNAME="__token__" TWINE_PASSWORD="${token_value}" "${PYTHON_BIN}" -m twine "${twine_args[@]}"
|
|
179
|
-
|
|
180
|
-
echo "[publish] done."
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
LOGS_URL=https://loki.elvenobservability.com/loki/api/v1/push
|
|
2
|
-
LOGS_TENANT=elven
|
|
3
|
-
LOGS_TOKEN=replace-with-your-token
|
|
4
|
-
LOGS_APP_NAME=elven-live-demo
|
|
5
|
-
LOGS_APP_VERSION=1.0.0
|
|
6
|
-
LOGS_ENVIRONMENT=local
|
|
7
|
-
|
|
8
|
-
LOGS_COMPRESSION=gzip
|
|
9
|
-
LOGS_COMPRESSION_LEVEL=4
|
|
10
|
-
LOGS_COMPRESSION_THRESHOLD=1024
|
|
11
|
-
LOGS_CONNECTION_POOLING=true
|
|
12
|
-
LOGS_MAX_SOCKETS=50
|
|
13
|
-
LOGS_TIMEOUT=10000
|
|
14
|
-
LOGS_MAX_RETRIES=3
|
|
15
|
-
LOGS_RETRY_DELAY=1000
|
|
16
|
-
|
|
17
|
-
LOGS_BUFFER_MAX_SIZE=25
|
|
18
|
-
LOGS_BUFFER_FLUSH_INTERVAL=1500
|
|
19
|
-
LOGS_BUFFER_MAX_MEMORY_MB=128
|
|
20
|
-
LOGS_BUFFER_MAX_AGE=30000
|
|
21
|
-
LOGS_BUFFER_AUTO_FLUSH=true
|
|
22
|
-
|
|
23
|
-
LOGS_FILTER_LEVELS=debug,info,warn,error,fatal
|
|
24
|
-
LOGS_FILTER_SAMPLING_RATE=1.0
|
|
25
|
-
LOGS_FILTER_SANITIZE=true
|
|
26
|
-
LOGS_FILTER_MAX_MESSAGE_LENGTH=8192
|
|
27
|
-
|
|
28
|
-
LOGS_CIRCUIT_BREAKER_ENABLED=true
|
|
29
|
-
LOGS_CIRCUIT_BREAKER_FAILURE_THRESHOLD=20
|
|
30
|
-
LOGS_CIRCUIT_BREAKER_RESET_TIMEOUT=15000
|
|
31
|
-
LOGS_CIRCUIT_BREAKER_HALF_OPEN_REQUESTS=3
|
|
32
|
-
|
|
33
|
-
LOGS_DLQ_ENABLED=true
|
|
34
|
-
LOGS_DLQ_TYPE=file
|
|
35
|
-
LOGS_DLQ_MAX_SIZE=1000
|
|
36
|
-
LOGS_DLQ_MAX_RETRIES=3
|
|
37
|
-
LOGS_DLQ_BASE_PATH=./.logs-dlq
|
|
38
|
-
|
|
39
|
-
LOGS_MAX_CONCURRENT_FLUSHES=5
|
|
40
|
-
LOGS_INTERCEPT_CONSOLE=true
|
|
41
|
-
LOGS_PRESERVE_ORIGINAL_CONSOLE=true
|
|
42
|
-
LOGS_ENABLE_METRICS=true
|
|
43
|
-
LOGS_ENABLE_HEALTH_CHECK=true
|
|
44
|
-
LOGS_DEBUG=false
|
|
45
|
-
LOGS_SILENT_ERRORS=false
|
|
46
|
-
LOGS_ENABLED=true
|
|
47
|
-
|
|
48
|
-
LOGS_LABEL_SERVICE=elven-live-demo
|
|
49
|
-
LOGS_LABEL_ENVIRONMENT=local
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# Elven Live Demo
|
|
2
|
-
|
|
3
|
-
Local Python app to exercise `elven-logs-interceptor-python` against the Elven Loki endpoint.
|
|
4
|
-
|
|
5
|
-
## Run
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
cd /Users/leonardozwirtes/Documents/Projects/logs-interceptor-python
|
|
9
|
-
chmod +x test-apps/elven-live-demo/run.sh
|
|
10
|
-
./test-apps/elven-live-demo/run.sh
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Notes
|
|
14
|
-
|
|
15
|
-
- The tracked config template is `.env.example`.
|
|
16
|
-
- The real token lives only in local `.env`, which is ignored by Git.
|
|
17
|
-
- The package import remains `logs_interceptor`.
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import asyncio
|
|
4
|
-
import random
|
|
5
|
-
import time
|
|
6
|
-
|
|
7
|
-
from logs_interceptor import destroy, init, logger
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def emit_startup_logs() -> None:
|
|
11
|
-
logger.info("demo app started", {"component": "startup"})
|
|
12
|
-
logger.track_event("demo_started", {"source": "local-run", "at": time.time()})
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def emit_business_logs() -> None:
|
|
16
|
-
for idx in range(10):
|
|
17
|
-
logger.info(
|
|
18
|
-
"processing item",
|
|
19
|
-
{
|
|
20
|
-
"idx": idx,
|
|
21
|
-
"value": random.randint(100, 999),
|
|
22
|
-
"duration_ms": round(random.uniform(5, 30), 2),
|
|
23
|
-
},
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
logger.warn("slow dependency detected", {"dependency": "inventory-service", "latency_ms": 187})
|
|
27
|
-
|
|
28
|
-
try:
|
|
29
|
-
raise RuntimeError("simulated business exception")
|
|
30
|
-
except RuntimeError as exc:
|
|
31
|
-
logger.error(
|
|
32
|
-
"handled domain error",
|
|
33
|
-
{
|
|
34
|
-
"error": str(exc),
|
|
35
|
-
"kind": "business",
|
|
36
|
-
},
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def emit_sync_context_logs() -> None:
|
|
41
|
-
def _run() -> None:
|
|
42
|
-
logger.info("sync request started", {"method": "GET", "path": "/products"})
|
|
43
|
-
print("plain print still works and is intercepted")
|
|
44
|
-
|
|
45
|
-
logger.with_context(
|
|
46
|
-
{
|
|
47
|
-
"request_id": "demo-sync-request-1",
|
|
48
|
-
"trace_id": "demo-sync-trace-1",
|
|
49
|
-
"span_id": "demo-sync-span-1",
|
|
50
|
-
},
|
|
51
|
-
_run,
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
async def emit_async_context_logs() -> None:
|
|
56
|
-
async def _run() -> None:
|
|
57
|
-
logger.info("async job started", {"job": "catalog-refresh"})
|
|
58
|
-
await asyncio.sleep(0.05)
|
|
59
|
-
logger.track_event("catalog_refresh_finished", {"ok": True})
|
|
60
|
-
|
|
61
|
-
await logger.with_context_async(
|
|
62
|
-
{
|
|
63
|
-
"request_id": "demo-async-request-1",
|
|
64
|
-
"trace_id": "demo-async-trace-1",
|
|
65
|
-
"span_id": "demo-async-span-1",
|
|
66
|
-
},
|
|
67
|
-
_run,
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def print_runtime_summary() -> None:
|
|
72
|
-
metrics = logger.get_metrics()
|
|
73
|
-
health = logger.get_health()
|
|
74
|
-
print(
|
|
75
|
-
{
|
|
76
|
-
"processed": metrics.get("logs_processed"),
|
|
77
|
-
"dropped": metrics.get("logs_dropped"),
|
|
78
|
-
"flush_count": metrics.get("flush_count"),
|
|
79
|
-
"error_count": metrics.get("error_count"),
|
|
80
|
-
}
|
|
81
|
-
)
|
|
82
|
-
print({"health": health})
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def main() -> None:
|
|
86
|
-
init()
|
|
87
|
-
emit_startup_logs()
|
|
88
|
-
emit_business_logs()
|
|
89
|
-
emit_sync_context_logs()
|
|
90
|
-
asyncio.run(emit_async_context_logs())
|
|
91
|
-
logger.flush()
|
|
92
|
-
print_runtime_summary()
|
|
93
|
-
destroy()
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if __name__ == "__main__":
|
|
97
|
-
main()
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -Eeuo pipefail
|
|
3
|
-
|
|
4
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
-
ROOT_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
6
|
-
|
|
7
|
-
if [[ ! -f "${SCRIPT_DIR}/.env" ]]; then
|
|
8
|
-
echo "Missing .env at ${SCRIPT_DIR}/.env" >&2
|
|
9
|
-
if [[ -f "${SCRIPT_DIR}/.env.example" ]]; then
|
|
10
|
-
echo "Create it with: cp ${SCRIPT_DIR}/.env.example ${SCRIPT_DIR}/.env" >&2
|
|
11
|
-
fi
|
|
12
|
-
exit 1
|
|
13
|
-
fi
|
|
14
|
-
|
|
15
|
-
set -a
|
|
16
|
-
source "${SCRIPT_DIR}/.env"
|
|
17
|
-
set +a
|
|
18
|
-
|
|
19
|
-
export PYTHONPATH="${ROOT_DIR}/src:${PYTHONPATH:-}"
|
|
20
|
-
|
|
21
|
-
python3 "${SCRIPT_DIR}/app.py"
|