pylogkit 0.1.0__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.
- pylogkit-0.1.0/.claude/settings.local.json +29 -0
- pylogkit-0.1.0/.github/workflows/ci.yml +42 -0
- pylogkit-0.1.0/.gitignore +33 -0
- pylogkit-0.1.0/CHANGELOG.md +25 -0
- pylogkit-0.1.0/LICENSE +21 -0
- pylogkit-0.1.0/PKG-INFO +341 -0
- pylogkit-0.1.0/README.md +305 -0
- pylogkit-0.1.0/pyproject.toml +111 -0
- pylogkit-0.1.0/src/pylogkit/__init__.py +68 -0
- pylogkit-0.1.0/src/pylogkit/_constants.py +31 -0
- pylogkit-0.1.0/src/pylogkit/config.py +156 -0
- pylogkit-0.1.0/src/pylogkit/filters.py +207 -0
- pylogkit-0.1.0/src/pylogkit/formatters.py +125 -0
- pylogkit-0.1.0/src/pylogkit/handlers.py +228 -0
- pylogkit-0.1.0/src/pylogkit/py.typed +0 -0
- pylogkit-0.1.0/tests/__init__.py +0 -0
- pylogkit-0.1.0/tests/conftest.py +44 -0
- pylogkit-0.1.0/tests/test_config.py +124 -0
- pylogkit-0.1.0/tests/test_filters.py +242 -0
- pylogkit-0.1.0/tests/test_formatters.py +144 -0
- pylogkit-0.1.0/tests/test_handlers.py +146 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"WebSearch",
|
|
5
|
+
"WebFetch(domain:browniebroke.com)",
|
|
6
|
+
"WebFetch(domain:nhairs.github.io)",
|
|
7
|
+
"WebFetch(domain:www.structlog.org)",
|
|
8
|
+
"WebFetch(domain:betterstack.com)",
|
|
9
|
+
"WebFetch(domain:www.toptal.com)",
|
|
10
|
+
"WebFetch(domain:docs.slack.dev)",
|
|
11
|
+
"WebFetch(domain:www.core27.co)",
|
|
12
|
+
"WebFetch(domain:rednafi.com)",
|
|
13
|
+
"Read(//opt/homebrew/bin/**)",
|
|
14
|
+
"Read(//usr/local/bin/**)",
|
|
15
|
+
"Bash(python3.12 -m venv .venv)",
|
|
16
|
+
"Bash(source .venv/bin/activate)",
|
|
17
|
+
"Bash(pip install:*)",
|
|
18
|
+
"Bash(python -m pytest tests/ -v)",
|
|
19
|
+
"Bash(python -m pytest tests/ --cov=pylogkit --cov-report=term-missing)",
|
|
20
|
+
"Bash(ruff check:*)",
|
|
21
|
+
"Bash(ruff format:*)",
|
|
22
|
+
"Bash(mypy src/pylogkit/)",
|
|
23
|
+
"Bash(python -m pytest tests/ -v --cov=pylogkit --cov-report=term-missing)",
|
|
24
|
+
"Bash(git add:*)",
|
|
25
|
+
"Bash(git commit:*)",
|
|
26
|
+
"Bash(git push:*)"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
- run: pip install ruff
|
|
18
|
+
- run: ruff check src/ tests/
|
|
19
|
+
- run: ruff format --check src/ tests/
|
|
20
|
+
|
|
21
|
+
typecheck:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
- uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.12"
|
|
28
|
+
- run: pip install -e ".[dev]" mypy
|
|
29
|
+
- run: mypy src/pylogkit/
|
|
30
|
+
|
|
31
|
+
test:
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
strategy:
|
|
34
|
+
matrix:
|
|
35
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
- uses: actions/setup-python@v5
|
|
39
|
+
with:
|
|
40
|
+
python-version: ${{ matrix.python-version }}
|
|
41
|
+
- run: pip install -e ".[dev]"
|
|
42
|
+
- run: pytest tests/ --cov=pylogkit --cov-report=term-missing --cov-fail-under=80
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg-info/
|
|
7
|
+
*.egg
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
.eggs/
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# Testing
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
htmlcov/
|
|
21
|
+
.mypy_cache/
|
|
22
|
+
.ruff_cache/
|
|
23
|
+
|
|
24
|
+
# IDE
|
|
25
|
+
.idea/
|
|
26
|
+
.vscode/
|
|
27
|
+
*.swp
|
|
28
|
+
*.swo
|
|
29
|
+
*~
|
|
30
|
+
|
|
31
|
+
# OS
|
|
32
|
+
.DS_Store
|
|
33
|
+
Thumbs.db
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-03-31
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `setup_logging()` — one-call logging configuration with auto-format detection
|
|
13
|
+
- `get_logger()` — get logger with optional bound context fields
|
|
14
|
+
- `JsonFormatter` — structured JSON output for production (ISO 8601 UTC timestamps)
|
|
15
|
+
- `ColoredFormatter` — human-readable colored output for development
|
|
16
|
+
- `ContextFilter` — inject static context fields into every log record
|
|
17
|
+
- `ContextVarsFilter` — inject request-scoped context via `contextvars`
|
|
18
|
+
- `RateLimitFilter` — token bucket rate limiting per unique message
|
|
19
|
+
- `DeduplicationFilter` — suppress duplicate messages within a time window
|
|
20
|
+
- `SlackHandler` — async Slack notifications with background thread, queue, and exponential backoff
|
|
21
|
+
- Support for both Slack Bot token and incoming webhook authentication
|
|
22
|
+
- Auto-detection of output format (JSON for non-TTY, colored for TTY)
|
|
23
|
+
- Per-logger level overrides
|
|
24
|
+
- Graceful degradation when optional dependencies are missing
|
|
25
|
+
- Comprehensive test suite (71 tests, 85% coverage)
|
pylogkit-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Laba
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pylogkit-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pylogkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Structured logging with Slack integration, rate limiting, and deduplication
|
|
5
|
+
Project-URL: Changelog, https://github.com/analytics-team-global/pylogkit/blob/main/CHANGELOG.md
|
|
6
|
+
Project-URL: Repository, https://github.com/analytics-team-global/pylogkit
|
|
7
|
+
Author: Laba
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: System :: Logging
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Requires-Dist: python-json-logger<4.0,>=2.0
|
|
21
|
+
Provides-Extra: all
|
|
22
|
+
Requires-Dist: colorlog>=6.0; extra == 'all'
|
|
23
|
+
Requires-Dist: slack-sdk>=3.20; extra == 'all'
|
|
24
|
+
Provides-Extra: color
|
|
25
|
+
Requires-Dist: colorlog>=6.0; extra == 'color'
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: colorlog>=6.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
32
|
+
Requires-Dist: slack-sdk>=3.20; extra == 'dev'
|
|
33
|
+
Provides-Extra: slack
|
|
34
|
+
Requires-Dist: slack-sdk>=3.20; extra == 'slack'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# pylogkit
|
|
38
|
+
|
|
39
|
+
[](https://github.com/analytics-team-global/pylogkit/actions/workflows/ci.yml)
|
|
40
|
+
[](https://www.python.org/downloads/)
|
|
41
|
+
[](LICENSE)
|
|
42
|
+
|
|
43
|
+
Structured logging with Slack integration, rate limiting, and deduplication.
|
|
44
|
+
|
|
45
|
+
Built on top of Python's standard `logging` module — no custom APIs to learn.
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Core (JSON + colored formatters)
|
|
51
|
+
pip install pylogkit
|
|
52
|
+
|
|
53
|
+
# With Slack support
|
|
54
|
+
pip install pylogkit[slack]
|
|
55
|
+
|
|
56
|
+
# With colored output
|
|
57
|
+
pip install pylogkit[color]
|
|
58
|
+
|
|
59
|
+
# Everything
|
|
60
|
+
pip install pylogkit[all]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Or as a git dependency:
|
|
64
|
+
|
|
65
|
+
```toml
|
|
66
|
+
# pyproject.toml
|
|
67
|
+
dependencies = [
|
|
68
|
+
"pylogkit[all] @ git+ssh://git@github.com/analytics-team-global/pylogkit.git",
|
|
69
|
+
]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Quick Start
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
import os
|
|
76
|
+
from pylogkit import setup_logging, get_logger
|
|
77
|
+
|
|
78
|
+
setup_logging(
|
|
79
|
+
level="INFO",
|
|
80
|
+
service_name="my-api",
|
|
81
|
+
slack_token=os.environ.get("SLACK_BOT_TOKEN"),
|
|
82
|
+
slack_channel="#errors",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
logger = get_logger(__name__)
|
|
86
|
+
|
|
87
|
+
logger.info("Server started", extra={"port": 8000})
|
|
88
|
+
logger.error("Request failed", extra={"endpoint": "/users", "status": 500})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Features
|
|
92
|
+
|
|
93
|
+
### Auto-detect output format
|
|
94
|
+
|
|
95
|
+
- **TTY (development)**: colored human-readable output with extras
|
|
96
|
+
- **Non-TTY (production/Docker)**: structured JSON
|
|
97
|
+
|
|
98
|
+
Force a specific format:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
setup_logging(json_format=True) # always JSON
|
|
102
|
+
setup_logging(json_format=False) # always colored
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Structured logging with extra fields
|
|
106
|
+
|
|
107
|
+
Extra fields are included in both JSON and colored output:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
logger.info("Deal processed", extra={
|
|
111
|
+
"deal_id": "123",
|
|
112
|
+
"pipeline": "laba_czech",
|
|
113
|
+
"duration": 1.23,
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**JSON output:**
|
|
118
|
+
```json
|
|
119
|
+
{"timestamp": "2026-03-18T12:00:00+00:00", "level": "INFO", "logger": "myapp.deals", "message": "Deal processed", "deal_id": "123", "pipeline": "laba_czech", "duration": 1.23}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Colored output:**
|
|
123
|
+
```
|
|
124
|
+
2026-03-18 12:00:00 INFO myapp.deals — Deal processed [deal_id=123 pipeline=laba_czech duration=1.23]
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Logger with static context
|
|
128
|
+
|
|
129
|
+
Bind context fields to a logger — they appear in every message:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
logger = get_logger(__name__, pipeline="laba_czech", env="production")
|
|
133
|
+
|
|
134
|
+
logger.info("Course synced")
|
|
135
|
+
# All messages from this logger will include pipeline= and env=
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Calling `get_logger()` again with the same name updates the context:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
logger = get_logger(__name__, pipeline="v2")
|
|
142
|
+
# pipeline is now "v2", env remains from the previous call
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Request-scoped context with contextvars
|
|
146
|
+
|
|
147
|
+
Inject request-scoped fields (request_id, user_id, etc.) without passing `extra={}` to every log call:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
import contextvars
|
|
151
|
+
from pylogkit import setup_logging
|
|
152
|
+
|
|
153
|
+
log_context: contextvars.ContextVar[dict] = contextvars.ContextVar(
|
|
154
|
+
"log_context", default={}
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
setup_logging(
|
|
158
|
+
service_name="my-api",
|
|
159
|
+
ctx_var=log_context,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# In your request handler / middleware:
|
|
163
|
+
log_context.set({"request_id": "abc-123", "user_id": "42"})
|
|
164
|
+
logger.info("Processing request")
|
|
165
|
+
# Output includes request_id and user_id automatically
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Works with async frameworks (FastAPI, aiohttp) — each coroutine gets its own context.
|
|
169
|
+
|
|
170
|
+
### Slack notifications
|
|
171
|
+
|
|
172
|
+
ERROR and CRITICAL logs go to Slack with:
|
|
173
|
+
- Color-coded attachments (yellow/red/dark red)
|
|
174
|
+
- Module and line number
|
|
175
|
+
- Extra fields as "Context" block
|
|
176
|
+
- Formatted traceback
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
setup_logging(
|
|
180
|
+
slack_token="xoxb-...",
|
|
181
|
+
slack_channel="#alerts",
|
|
182
|
+
slack_level="ERROR", # minimum level (default: ERROR)
|
|
183
|
+
)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Or use incoming webhook (simpler, scoped to one channel):
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
setup_logging(
|
|
190
|
+
slack_webhook_url="https://hooks.slack.com/services/T.../B.../xxx",
|
|
191
|
+
)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**How it works internally:**
|
|
195
|
+
- Messages are queued and sent from a background thread (non-blocking)
|
|
196
|
+
- Respects Slack's 1 msg/sec rate limit
|
|
197
|
+
- Exponential backoff on consecutive failures (up to 5 min)
|
|
198
|
+
- If queue is full (100 messages) — drops silently, never blocks the app
|
|
199
|
+
- If Slack is unreachable — prints to stderr, never crashes
|
|
200
|
+
- Flushes remaining messages on shutdown
|
|
201
|
+
|
|
202
|
+
### Rate limiting
|
|
203
|
+
|
|
204
|
+
Prevents Slack spam. Each unique message can fire at most N times per period:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
setup_logging(
|
|
208
|
+
slack_token="xoxb-...",
|
|
209
|
+
slack_channel="#alerts",
|
|
210
|
+
slack_rate_limit=1, # max 1 message per period (default)
|
|
211
|
+
slack_rate_period=60.0, # per 60 seconds (default)
|
|
212
|
+
)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
If the same error fires 500 times in a minute — only the first one goes to Slack.
|
|
216
|
+
|
|
217
|
+
### Deduplication
|
|
218
|
+
|
|
219
|
+
Suppresses identical errors within a time window. When the window expires, the next message includes the suppressed count:
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
setup_logging(
|
|
223
|
+
slack_token="xoxb-...",
|
|
224
|
+
slack_channel="#alerts",
|
|
225
|
+
slack_dedupe_window=300.0, # 5 minutes (default)
|
|
226
|
+
)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Example: `"Connection refused (suppressed 47 duplicates)"`
|
|
230
|
+
|
|
231
|
+
Set to `0` to disable deduplication.
|
|
232
|
+
|
|
233
|
+
### Per-logger level overrides
|
|
234
|
+
|
|
235
|
+
Silence noisy third-party libraries:
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
setup_logging(
|
|
239
|
+
level="INFO",
|
|
240
|
+
loggers={
|
|
241
|
+
"httpx": "WARNING",
|
|
242
|
+
"sqlalchemy.engine": "WARNING",
|
|
243
|
+
"celery": "INFO",
|
|
244
|
+
},
|
|
245
|
+
)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Static context fields
|
|
249
|
+
|
|
250
|
+
Add fields to every log record in the application:
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
setup_logging(
|
|
254
|
+
service_name="my-api",
|
|
255
|
+
extra_context={
|
|
256
|
+
"env": "production",
|
|
257
|
+
"region": "eu-west-1",
|
|
258
|
+
},
|
|
259
|
+
)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Advanced: using components directly
|
|
263
|
+
|
|
264
|
+
All components can be used independently without `setup_logging()`:
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
import logging
|
|
268
|
+
from pylogkit import JsonFormatter, ColoredFormatter, RateLimitFilter, DeduplicationFilter
|
|
269
|
+
from pylogkit import SlackHandler # lazy import, requires slack-sdk
|
|
270
|
+
|
|
271
|
+
# Custom handler with JSON
|
|
272
|
+
handler = logging.StreamHandler()
|
|
273
|
+
handler.setFormatter(JsonFormatter())
|
|
274
|
+
|
|
275
|
+
# Slack with custom filters
|
|
276
|
+
slack = SlackHandler(token="xoxb-...", channel="#alerts")
|
|
277
|
+
slack.addFilter(RateLimitFilter(rate=3, period=120))
|
|
278
|
+
slack.addFilter(DeduplicationFilter(window=600))
|
|
279
|
+
|
|
280
|
+
logging.getLogger().addHandler(handler)
|
|
281
|
+
logging.getLogger().addHandler(slack)
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Celery integration
|
|
285
|
+
|
|
286
|
+
Prevent Celery from hijacking your logging setup:
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
from celery.signals import setup_logging as celery_setup_logging
|
|
290
|
+
from pylogkit import setup_logging
|
|
291
|
+
|
|
292
|
+
@celery_setup_logging.connect
|
|
293
|
+
def configure_celery_logging(**kwargs):
|
|
294
|
+
setup_logging(
|
|
295
|
+
service_name="worker",
|
|
296
|
+
slack_token=os.environ.get("SLACK_BOT_TOKEN"),
|
|
297
|
+
slack_channel="#worker-errors",
|
|
298
|
+
)
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## `setup_logging()` parameters
|
|
302
|
+
|
|
303
|
+
| Parameter | Type | Default | Description |
|
|
304
|
+
|-----------------------|----------------|-----------|--------------------------------------------------------|
|
|
305
|
+
| `level` | `str` | `"INFO"` | Root log level |
|
|
306
|
+
| `service_name` | `str` | `None` | Added to every record as `service` field |
|
|
307
|
+
| `json_format` | `bool` | auto | `True` = JSON, `False` = colored, `None` = auto-detect |
|
|
308
|
+
| `slack_token` | `str` | `None` | Slack Bot token (`xoxb-...`) |
|
|
309
|
+
| `slack_channel` | `str` | `None` | Slack channel (required with token) |
|
|
310
|
+
| `slack_webhook_url` | `str` | `None` | Incoming webhook URL (alternative to token) |
|
|
311
|
+
| `slack_level` | `str` | `"ERROR"` | Minimum level for Slack |
|
|
312
|
+
| `slack_rate_limit` | `int` | `1` | Max messages per period |
|
|
313
|
+
| `slack_rate_period` | `float` | `60.0` | Rate limit window (seconds) |
|
|
314
|
+
| `slack_dedupe_window` | `float` | `300.0` | Deduplication window (seconds), `0` to disable |
|
|
315
|
+
| `extra_context` | `dict` | `None` | Static fields for every record |
|
|
316
|
+
| `loggers` | `dict` | `None` | Per-logger level overrides |
|
|
317
|
+
| `ctx_var` | `ContextVar` | `None` | Request-scoped context variable |
|
|
318
|
+
|
|
319
|
+
## Development
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
# Install with dev dependencies
|
|
323
|
+
pip install -e ".[dev]"
|
|
324
|
+
|
|
325
|
+
# Run tests
|
|
326
|
+
pytest
|
|
327
|
+
|
|
328
|
+
# Run tests with coverage
|
|
329
|
+
pytest --cov=pylogkit --cov-report=term-missing
|
|
330
|
+
|
|
331
|
+
# Lint
|
|
332
|
+
ruff check src/ tests/
|
|
333
|
+
ruff format src/ tests/
|
|
334
|
+
|
|
335
|
+
# Type check
|
|
336
|
+
mypy src/pylogkit/
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## License
|
|
340
|
+
|
|
341
|
+
[MIT](LICENSE)
|