miu-logger 0.1.6__tar.gz → 0.2.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.
- miu_logger-0.2.0/PKG-INFO +287 -0
- miu_logger-0.2.0/README.md +270 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/pyproject.toml +1 -1
- miu_logger-0.2.0/src/miu_logger.egg-info/PKG-INFO +287 -0
- miu_logger-0.1.6/PKG-INFO +0 -151
- miu_logger-0.1.6/README.md +0 -134
- miu_logger-0.1.6/src/miu_logger.egg-info/PKG-INFO +0 -151
- {miu_logger-0.1.6 → miu_logger-0.2.0}/LICENSE +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/setup.cfg +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger/__init__.py +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger/conditional.py +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger/config.py +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger/filters.py +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger/formatters.py +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger/listener.py +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger/logger_factory.py +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger/repository.py +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger/stubgen.py +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger.egg-info/SOURCES.txt +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger.egg-info/dependency_links.txt +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger.egg-info/requires.txt +0 -0
- {miu_logger-0.1.6 → miu_logger-0.2.0}/src/miu_logger.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: miu-logger
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Multiprocessing-safe domain-based logging framework with QueueListener architecture
|
|
5
|
+
Author-email: Bruno Miura <brumiura@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: logging,multiprocessing,queue,structured-logging,python-logging
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Topic :: System :: Logging
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: colorama
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# miu-logger
|
|
19
|
+
|
|
20
|
+
**Multiprocessing-safe, domain-driven structured logging for Python services**
|
|
21
|
+
|
|
22
|
+
`miu-logger` is a logging framework designed for **real systems**:
|
|
23
|
+
|
|
24
|
+
* Multiprocessing- and multithreading-safe
|
|
25
|
+
* Domain-separated loggers (`app`, `db`, `task`, etc.)
|
|
26
|
+
* Per-level log files (`debug.log`, `info.log`, `error.log`, …)
|
|
27
|
+
* Central queue listener to avoid file collisions
|
|
28
|
+
* Clean IDE autocomplete for both domains and log levels
|
|
29
|
+
* Minimal setup in application code
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Why use `miu-logger`
|
|
34
|
+
|
|
35
|
+
Python's standard logging is powerful but breaks down when:
|
|
36
|
+
|
|
37
|
+
* Multiple processes or threads write to the same log files
|
|
38
|
+
* You want **domain-specific log files**
|
|
39
|
+
* You want **centralized log routing**
|
|
40
|
+
* You want IDE autocomplete for domains and levels
|
|
41
|
+
|
|
42
|
+
`miu-logger` solves this by:
|
|
43
|
+
|
|
44
|
+
> Logging through a **central queue listener**, separating **domains** and **levels**, while exposing a **typed repository** for IDE-friendly access.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uv add miu-logger
|
|
52
|
+
# or
|
|
53
|
+
pip install miu-logger
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Configuring Logging Domains
|
|
59
|
+
|
|
60
|
+
Domains represent **areas of your system** (not log levels). Examples: `app`, `db`, `redis`, `task`.
|
|
61
|
+
|
|
62
|
+
Define them in `LogConfig`:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import logging
|
|
66
|
+
from miu_logger.config import LogConfig
|
|
67
|
+
from miu_logger.repository import LoggingRepository
|
|
68
|
+
|
|
69
|
+
config = LogConfig(
|
|
70
|
+
log_dir="logs", # folder to store logs
|
|
71
|
+
domains=["app", "db", "redis"], # your custom domains
|
|
72
|
+
level=logging.DEBUG, # base log level for all domains
|
|
73
|
+
debug_enabled=True, # toggle debug messages
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
repo = LoggingRepository(config)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Accessing Domain Loggers
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
repo.app.info("Application started")
|
|
83
|
+
repo.db.error("Database connection failed")
|
|
84
|
+
repo.redis.debug("Cache initialized")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
* Accessing a domain not defined in `config.domains` raises a `ValueError`:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
repo.get("api") # ❌ ValueError if "api" not in config.domains
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
* Domains can also be dynamically retrieved:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
task_logger = repo.get("task") # Must be defined in config.domains
|
|
97
|
+
task_logger.info("Task started")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## IDE Autocomplete with Stub Generation
|
|
103
|
+
|
|
104
|
+
Domains are dynamic, so editors cannot know them automatically.
|
|
105
|
+
Use the **stub generator** to enable autocomplete:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from miu_logger.stubgen import generate_repository_stub
|
|
109
|
+
|
|
110
|
+
generate_repository_stub(
|
|
111
|
+
domains=["app", "db", "redis", "task"], # all your domains
|
|
112
|
+
out_dir="typings", # directory for generated stubs
|
|
113
|
+
)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
This creates:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
typings/miu_logger/repository.pyi
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Tell your editor where the typings are:
|
|
123
|
+
|
|
124
|
+
* **VSCode / Pyright**:
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"python.analysis.extraPaths": ["typings"]
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
* **pyproject.toml (Pyright)**:
|
|
133
|
+
|
|
134
|
+
```toml
|
|
135
|
+
[tool.pyright]
|
|
136
|
+
extraPaths = ["typings"]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
After this, your IDE knows both:
|
|
140
|
+
|
|
141
|
+
* Domains: `repo.app`, `repo.db`, …
|
|
142
|
+
* Log methods: `.debug()`, `.info()`, `.warning()`, `.error()`, `.exception()`
|
|
143
|
+
|
|
144
|
+
Regenerate stubs whenever you add new domains.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Multiprocessing Usage
|
|
149
|
+
|
|
150
|
+
The repository uses a **central QueueListener** for safe multiprocessing logging.
|
|
151
|
+
|
|
152
|
+
**Main process:**
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
repo = LoggingRepository(config)
|
|
156
|
+
queue = repo.get_queue()
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Worker processes:**
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
worker_repo = LoggingRepository(config, use_listener=False, queue=queue)
|
|
163
|
+
worker_repo.task.info("Worker started")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
All processes log safely to the same listener and files.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Debug Control
|
|
171
|
+
|
|
172
|
+
Only `.debug()` messages are conditional via `debug_enabled`:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
config.debug_enabled = False
|
|
176
|
+
repo.app.debug("Won't appear")
|
|
177
|
+
repo.app.info("Will appear")
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Useful for toggling debug messages in production.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Output Structure
|
|
185
|
+
|
|
186
|
+
Logs are written in:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
logs/
|
|
190
|
+
├─ app.log # domain logs
|
|
191
|
+
├─ db.log
|
|
192
|
+
├─ redis.log
|
|
193
|
+
├─ debug.log # per-level logs
|
|
194
|
+
├─ info.log
|
|
195
|
+
├─ warning.log
|
|
196
|
+
└─ error.log
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Console output is **colorized** by level:
|
|
200
|
+
|
|
201
|
+
* DEBUG → blue
|
|
202
|
+
* INFO → green
|
|
203
|
+
* WARNING → yellow
|
|
204
|
+
* ERROR → red
|
|
205
|
+
|
|
206
|
+
Files remain clean.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Graceful Shutdown
|
|
211
|
+
|
|
212
|
+
The repository automatically shuts down on process exit and supports manual shutdown:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
repo.shutdown()
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Typical Usage Example
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
repo.app.info("Service starting")
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
connect_db()
|
|
227
|
+
except Exception:
|
|
228
|
+
repo.db.exception("DB connection failed")
|
|
229
|
+
|
|
230
|
+
repo.redis.debug("Cache size: %d", cache_size)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Multiprocessing workers:**
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
def worker(queue):
|
|
237
|
+
repo = LoggingRepository(config, use_listener=False, queue=queue)
|
|
238
|
+
repo.task.info("Worker task started")
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Project Structure
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
miu_logger/
|
|
247
|
+
├─ repository.py # main LoggingRepository
|
|
248
|
+
├─ listener.py # QueueListener and handler setup
|
|
249
|
+
├─ logger_factory.py # logger creation functions
|
|
250
|
+
├─ conditional.py # ConditionalLogger
|
|
251
|
+
├─ filters.py # Logger filters
|
|
252
|
+
├─ formatters.py # ColoredFormatter
|
|
253
|
+
├─ config.py # LogConfig definition
|
|
254
|
+
└─ stubgen.py # stub generator for IDE autocomplete
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## When to Use
|
|
260
|
+
|
|
261
|
+
* Services with many subsystems
|
|
262
|
+
* Multiprocessing ingestion pipelines
|
|
263
|
+
* Long-running daemons
|
|
264
|
+
* Kubernetes / systemd services
|
|
265
|
+
* Need for clear operational logs
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## When Not to Use
|
|
270
|
+
|
|
271
|
+
* Single-file scripts
|
|
272
|
+
* No multiprocessing
|
|
273
|
+
* No domain separation required
|
|
274
|
+
|
|
275
|
+
Plain `logging` is sufficient in those cases.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## License
|
|
280
|
+
|
|
281
|
+
MIT
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Author
|
|
286
|
+
|
|
287
|
+
**Bruno Miura**
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# miu-logger
|
|
2
|
+
|
|
3
|
+
**Multiprocessing-safe, domain-driven structured logging for Python services**
|
|
4
|
+
|
|
5
|
+
`miu-logger` is a logging framework designed for **real systems**:
|
|
6
|
+
|
|
7
|
+
* Multiprocessing- and multithreading-safe
|
|
8
|
+
* Domain-separated loggers (`app`, `db`, `task`, etc.)
|
|
9
|
+
* Per-level log files (`debug.log`, `info.log`, `error.log`, …)
|
|
10
|
+
* Central queue listener to avoid file collisions
|
|
11
|
+
* Clean IDE autocomplete for both domains and log levels
|
|
12
|
+
* Minimal setup in application code
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Why use `miu-logger`
|
|
17
|
+
|
|
18
|
+
Python's standard logging is powerful but breaks down when:
|
|
19
|
+
|
|
20
|
+
* Multiple processes or threads write to the same log files
|
|
21
|
+
* You want **domain-specific log files**
|
|
22
|
+
* You want **centralized log routing**
|
|
23
|
+
* You want IDE autocomplete for domains and levels
|
|
24
|
+
|
|
25
|
+
`miu-logger` solves this by:
|
|
26
|
+
|
|
27
|
+
> Logging through a **central queue listener**, separating **domains** and **levels**, while exposing a **typed repository** for IDE-friendly access.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
uv add miu-logger
|
|
35
|
+
# or
|
|
36
|
+
pip install miu-logger
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Configuring Logging Domains
|
|
42
|
+
|
|
43
|
+
Domains represent **areas of your system** (not log levels). Examples: `app`, `db`, `redis`, `task`.
|
|
44
|
+
|
|
45
|
+
Define them in `LogConfig`:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import logging
|
|
49
|
+
from miu_logger.config import LogConfig
|
|
50
|
+
from miu_logger.repository import LoggingRepository
|
|
51
|
+
|
|
52
|
+
config = LogConfig(
|
|
53
|
+
log_dir="logs", # folder to store logs
|
|
54
|
+
domains=["app", "db", "redis"], # your custom domains
|
|
55
|
+
level=logging.DEBUG, # base log level for all domains
|
|
56
|
+
debug_enabled=True, # toggle debug messages
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
repo = LoggingRepository(config)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Accessing Domain Loggers
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
repo.app.info("Application started")
|
|
66
|
+
repo.db.error("Database connection failed")
|
|
67
|
+
repo.redis.debug("Cache initialized")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
* Accessing a domain not defined in `config.domains` raises a `ValueError`:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
repo.get("api") # ❌ ValueError if "api" not in config.domains
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
* Domains can also be dynamically retrieved:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
task_logger = repo.get("task") # Must be defined in config.domains
|
|
80
|
+
task_logger.info("Task started")
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## IDE Autocomplete with Stub Generation
|
|
86
|
+
|
|
87
|
+
Domains are dynamic, so editors cannot know them automatically.
|
|
88
|
+
Use the **stub generator** to enable autocomplete:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from miu_logger.stubgen import generate_repository_stub
|
|
92
|
+
|
|
93
|
+
generate_repository_stub(
|
|
94
|
+
domains=["app", "db", "redis", "task"], # all your domains
|
|
95
|
+
out_dir="typings", # directory for generated stubs
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
This creates:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
typings/miu_logger/repository.pyi
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Tell your editor where the typings are:
|
|
106
|
+
|
|
107
|
+
* **VSCode / Pyright**:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"python.analysis.extraPaths": ["typings"]
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
* **pyproject.toml (Pyright)**:
|
|
116
|
+
|
|
117
|
+
```toml
|
|
118
|
+
[tool.pyright]
|
|
119
|
+
extraPaths = ["typings"]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
After this, your IDE knows both:
|
|
123
|
+
|
|
124
|
+
* Domains: `repo.app`, `repo.db`, …
|
|
125
|
+
* Log methods: `.debug()`, `.info()`, `.warning()`, `.error()`, `.exception()`
|
|
126
|
+
|
|
127
|
+
Regenerate stubs whenever you add new domains.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Multiprocessing Usage
|
|
132
|
+
|
|
133
|
+
The repository uses a **central QueueListener** for safe multiprocessing logging.
|
|
134
|
+
|
|
135
|
+
**Main process:**
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
repo = LoggingRepository(config)
|
|
139
|
+
queue = repo.get_queue()
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Worker processes:**
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
worker_repo = LoggingRepository(config, use_listener=False, queue=queue)
|
|
146
|
+
worker_repo.task.info("Worker started")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
All processes log safely to the same listener and files.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Debug Control
|
|
154
|
+
|
|
155
|
+
Only `.debug()` messages are conditional via `debug_enabled`:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
config.debug_enabled = False
|
|
159
|
+
repo.app.debug("Won't appear")
|
|
160
|
+
repo.app.info("Will appear")
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Useful for toggling debug messages in production.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Output Structure
|
|
168
|
+
|
|
169
|
+
Logs are written in:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
logs/
|
|
173
|
+
├─ app.log # domain logs
|
|
174
|
+
├─ db.log
|
|
175
|
+
├─ redis.log
|
|
176
|
+
├─ debug.log # per-level logs
|
|
177
|
+
├─ info.log
|
|
178
|
+
├─ warning.log
|
|
179
|
+
└─ error.log
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Console output is **colorized** by level:
|
|
183
|
+
|
|
184
|
+
* DEBUG → blue
|
|
185
|
+
* INFO → green
|
|
186
|
+
* WARNING → yellow
|
|
187
|
+
* ERROR → red
|
|
188
|
+
|
|
189
|
+
Files remain clean.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Graceful Shutdown
|
|
194
|
+
|
|
195
|
+
The repository automatically shuts down on process exit and supports manual shutdown:
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
repo.shutdown()
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Typical Usage Example
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
repo.app.info("Service starting")
|
|
207
|
+
|
|
208
|
+
try:
|
|
209
|
+
connect_db()
|
|
210
|
+
except Exception:
|
|
211
|
+
repo.db.exception("DB connection failed")
|
|
212
|
+
|
|
213
|
+
repo.redis.debug("Cache size: %d", cache_size)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Multiprocessing workers:**
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
def worker(queue):
|
|
220
|
+
repo = LoggingRepository(config, use_listener=False, queue=queue)
|
|
221
|
+
repo.task.info("Worker task started")
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Project Structure
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
miu_logger/
|
|
230
|
+
├─ repository.py # main LoggingRepository
|
|
231
|
+
├─ listener.py # QueueListener and handler setup
|
|
232
|
+
├─ logger_factory.py # logger creation functions
|
|
233
|
+
├─ conditional.py # ConditionalLogger
|
|
234
|
+
├─ filters.py # Logger filters
|
|
235
|
+
├─ formatters.py # ColoredFormatter
|
|
236
|
+
├─ config.py # LogConfig definition
|
|
237
|
+
└─ stubgen.py # stub generator for IDE autocomplete
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## When to Use
|
|
243
|
+
|
|
244
|
+
* Services with many subsystems
|
|
245
|
+
* Multiprocessing ingestion pipelines
|
|
246
|
+
* Long-running daemons
|
|
247
|
+
* Kubernetes / systemd services
|
|
248
|
+
* Need for clear operational logs
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## When Not to Use
|
|
253
|
+
|
|
254
|
+
* Single-file scripts
|
|
255
|
+
* No multiprocessing
|
|
256
|
+
* No domain separation required
|
|
257
|
+
|
|
258
|
+
Plain `logging` is sufficient in those cases.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## License
|
|
263
|
+
|
|
264
|
+
MIT
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Author
|
|
269
|
+
|
|
270
|
+
**Bruno Miura**
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: miu-logger
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Multiprocessing-safe domain-based logging framework with QueueListener architecture
|
|
5
|
+
Author-email: Bruno Miura <brumiura@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: logging,multiprocessing,queue,structured-logging,python-logging
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Topic :: System :: Logging
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: colorama
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# miu-logger
|
|
19
|
+
|
|
20
|
+
**Multiprocessing-safe, domain-driven structured logging for Python services**
|
|
21
|
+
|
|
22
|
+
`miu-logger` is a logging framework designed for **real systems**:
|
|
23
|
+
|
|
24
|
+
* Multiprocessing- and multithreading-safe
|
|
25
|
+
* Domain-separated loggers (`app`, `db`, `task`, etc.)
|
|
26
|
+
* Per-level log files (`debug.log`, `info.log`, `error.log`, …)
|
|
27
|
+
* Central queue listener to avoid file collisions
|
|
28
|
+
* Clean IDE autocomplete for both domains and log levels
|
|
29
|
+
* Minimal setup in application code
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Why use `miu-logger`
|
|
34
|
+
|
|
35
|
+
Python's standard logging is powerful but breaks down when:
|
|
36
|
+
|
|
37
|
+
* Multiple processes or threads write to the same log files
|
|
38
|
+
* You want **domain-specific log files**
|
|
39
|
+
* You want **centralized log routing**
|
|
40
|
+
* You want IDE autocomplete for domains and levels
|
|
41
|
+
|
|
42
|
+
`miu-logger` solves this by:
|
|
43
|
+
|
|
44
|
+
> Logging through a **central queue listener**, separating **domains** and **levels**, while exposing a **typed repository** for IDE-friendly access.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uv add miu-logger
|
|
52
|
+
# or
|
|
53
|
+
pip install miu-logger
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Configuring Logging Domains
|
|
59
|
+
|
|
60
|
+
Domains represent **areas of your system** (not log levels). Examples: `app`, `db`, `redis`, `task`.
|
|
61
|
+
|
|
62
|
+
Define them in `LogConfig`:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import logging
|
|
66
|
+
from miu_logger.config import LogConfig
|
|
67
|
+
from miu_logger.repository import LoggingRepository
|
|
68
|
+
|
|
69
|
+
config = LogConfig(
|
|
70
|
+
log_dir="logs", # folder to store logs
|
|
71
|
+
domains=["app", "db", "redis"], # your custom domains
|
|
72
|
+
level=logging.DEBUG, # base log level for all domains
|
|
73
|
+
debug_enabled=True, # toggle debug messages
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
repo = LoggingRepository(config)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Accessing Domain Loggers
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
repo.app.info("Application started")
|
|
83
|
+
repo.db.error("Database connection failed")
|
|
84
|
+
repo.redis.debug("Cache initialized")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
* Accessing a domain not defined in `config.domains` raises a `ValueError`:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
repo.get("api") # ❌ ValueError if "api" not in config.domains
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
* Domains can also be dynamically retrieved:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
task_logger = repo.get("task") # Must be defined in config.domains
|
|
97
|
+
task_logger.info("Task started")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## IDE Autocomplete with Stub Generation
|
|
103
|
+
|
|
104
|
+
Domains are dynamic, so editors cannot know them automatically.
|
|
105
|
+
Use the **stub generator** to enable autocomplete:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from miu_logger.stubgen import generate_repository_stub
|
|
109
|
+
|
|
110
|
+
generate_repository_stub(
|
|
111
|
+
domains=["app", "db", "redis", "task"], # all your domains
|
|
112
|
+
out_dir="typings", # directory for generated stubs
|
|
113
|
+
)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
This creates:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
typings/miu_logger/repository.pyi
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Tell your editor where the typings are:
|
|
123
|
+
|
|
124
|
+
* **VSCode / Pyright**:
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"python.analysis.extraPaths": ["typings"]
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
* **pyproject.toml (Pyright)**:
|
|
133
|
+
|
|
134
|
+
```toml
|
|
135
|
+
[tool.pyright]
|
|
136
|
+
extraPaths = ["typings"]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
After this, your IDE knows both:
|
|
140
|
+
|
|
141
|
+
* Domains: `repo.app`, `repo.db`, …
|
|
142
|
+
* Log methods: `.debug()`, `.info()`, `.warning()`, `.error()`, `.exception()`
|
|
143
|
+
|
|
144
|
+
Regenerate stubs whenever you add new domains.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Multiprocessing Usage
|
|
149
|
+
|
|
150
|
+
The repository uses a **central QueueListener** for safe multiprocessing logging.
|
|
151
|
+
|
|
152
|
+
**Main process:**
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
repo = LoggingRepository(config)
|
|
156
|
+
queue = repo.get_queue()
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Worker processes:**
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
worker_repo = LoggingRepository(config, use_listener=False, queue=queue)
|
|
163
|
+
worker_repo.task.info("Worker started")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
All processes log safely to the same listener and files.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Debug Control
|
|
171
|
+
|
|
172
|
+
Only `.debug()` messages are conditional via `debug_enabled`:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
config.debug_enabled = False
|
|
176
|
+
repo.app.debug("Won't appear")
|
|
177
|
+
repo.app.info("Will appear")
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Useful for toggling debug messages in production.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Output Structure
|
|
185
|
+
|
|
186
|
+
Logs are written in:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
logs/
|
|
190
|
+
├─ app.log # domain logs
|
|
191
|
+
├─ db.log
|
|
192
|
+
├─ redis.log
|
|
193
|
+
├─ debug.log # per-level logs
|
|
194
|
+
├─ info.log
|
|
195
|
+
├─ warning.log
|
|
196
|
+
└─ error.log
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Console output is **colorized** by level:
|
|
200
|
+
|
|
201
|
+
* DEBUG → blue
|
|
202
|
+
* INFO → green
|
|
203
|
+
* WARNING → yellow
|
|
204
|
+
* ERROR → red
|
|
205
|
+
|
|
206
|
+
Files remain clean.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Graceful Shutdown
|
|
211
|
+
|
|
212
|
+
The repository automatically shuts down on process exit and supports manual shutdown:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
repo.shutdown()
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Typical Usage Example
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
repo.app.info("Service starting")
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
connect_db()
|
|
227
|
+
except Exception:
|
|
228
|
+
repo.db.exception("DB connection failed")
|
|
229
|
+
|
|
230
|
+
repo.redis.debug("Cache size: %d", cache_size)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Multiprocessing workers:**
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
def worker(queue):
|
|
237
|
+
repo = LoggingRepository(config, use_listener=False, queue=queue)
|
|
238
|
+
repo.task.info("Worker task started")
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Project Structure
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
miu_logger/
|
|
247
|
+
├─ repository.py # main LoggingRepository
|
|
248
|
+
├─ listener.py # QueueListener and handler setup
|
|
249
|
+
├─ logger_factory.py # logger creation functions
|
|
250
|
+
├─ conditional.py # ConditionalLogger
|
|
251
|
+
├─ filters.py # Logger filters
|
|
252
|
+
├─ formatters.py # ColoredFormatter
|
|
253
|
+
├─ config.py # LogConfig definition
|
|
254
|
+
└─ stubgen.py # stub generator for IDE autocomplete
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## When to Use
|
|
260
|
+
|
|
261
|
+
* Services with many subsystems
|
|
262
|
+
* Multiprocessing ingestion pipelines
|
|
263
|
+
* Long-running daemons
|
|
264
|
+
* Kubernetes / systemd services
|
|
265
|
+
* Need for clear operational logs
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## When Not to Use
|
|
270
|
+
|
|
271
|
+
* Single-file scripts
|
|
272
|
+
* No multiprocessing
|
|
273
|
+
* No domain separation required
|
|
274
|
+
|
|
275
|
+
Plain `logging` is sufficient in those cases.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## License
|
|
280
|
+
|
|
281
|
+
MIT
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Author
|
|
286
|
+
|
|
287
|
+
**Bruno Miura**
|
miu_logger-0.1.6/PKG-INFO
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: miu-logger
|
|
3
|
-
Version: 0.1.6
|
|
4
|
-
Summary: Multiprocessing-safe domain-based logging framework with QueueListener architecture
|
|
5
|
-
Author-email: Bruno Miura <brumiura@gmail.com>
|
|
6
|
-
License-Expression: MIT
|
|
7
|
-
Keywords: logging,multiprocessing,queue,structured-logging,python-logging
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Classifier: Topic :: System :: Logging
|
|
12
|
-
Requires-Python: >=3.10
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: colorama
|
|
16
|
-
Dynamic: license-file
|
|
17
|
-
|
|
18
|
-
```python
|
|
19
|
-
repo = LoggingRepository(config)
|
|
20
|
-
queue = repo.get_queue()
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
**Worker processes:**
|
|
24
|
-
|
|
25
|
-
```python
|
|
26
|
-
worker_repo = LoggingRepository(config, use_listener=False, queue=queue)
|
|
27
|
-
worker_repo.task.info("Worker started")
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
All processes log safely to the same listener and files.
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## Debug Control
|
|
35
|
-
|
|
36
|
-
Only `.debug()` messages are conditional via `debug_enabled`:
|
|
37
|
-
|
|
38
|
-
```python
|
|
39
|
-
config.debug_enabled = False
|
|
40
|
-
repo.app.debug("Won't appear")
|
|
41
|
-
repo.app.info("Will appear")
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Useful for toggling debug messages in production.
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## Output Structure
|
|
49
|
-
|
|
50
|
-
Logs are written in:
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
logs/
|
|
54
|
-
├─ app.log # domain logs
|
|
55
|
-
├─ db.log
|
|
56
|
-
├─ redis.log
|
|
57
|
-
├─ debug.log # per-level logs
|
|
58
|
-
├─ info.log
|
|
59
|
-
├─ warning.log
|
|
60
|
-
└─ error.log
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Console output is **colorized** by level:
|
|
64
|
-
|
|
65
|
-
* DEBUG → blue
|
|
66
|
-
* INFO → green
|
|
67
|
-
* WARNING → yellow
|
|
68
|
-
* ERROR → red
|
|
69
|
-
|
|
70
|
-
Files remain clean.
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
|
|
74
|
-
## Graceful Shutdown
|
|
75
|
-
|
|
76
|
-
The repository automatically shuts down on process exit and supports manual shutdown:
|
|
77
|
-
|
|
78
|
-
```python
|
|
79
|
-
repo.shutdown()
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## Typical Usage Example
|
|
85
|
-
|
|
86
|
-
```python
|
|
87
|
-
repo.app.info("Service starting")
|
|
88
|
-
|
|
89
|
-
try:
|
|
90
|
-
connect_db()
|
|
91
|
-
except Exception:
|
|
92
|
-
repo.db.exception("DB connection failed")
|
|
93
|
-
|
|
94
|
-
repo.redis.debug("Cache size: %d", cache_size)
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
**Multiprocessing workers:**
|
|
98
|
-
|
|
99
|
-
```python
|
|
100
|
-
def worker(queue):
|
|
101
|
-
repo = LoggingRepository(config, use_listener=False, queue=queue)
|
|
102
|
-
repo.task.info("Worker task started")
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## Project Structure
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
miu_logger/
|
|
111
|
-
├─ repository.py # main LoggingRepository
|
|
112
|
-
├─ listener.py # QueueListener and handler setup
|
|
113
|
-
├─ logger_factory.py # logger creation functions
|
|
114
|
-
├─ conditional.py # ConditionalLogger
|
|
115
|
-
├─ filters.py # Logger filters
|
|
116
|
-
├─ formatters.py # ColoredFormatter
|
|
117
|
-
├─ config.py # LogConfig definition
|
|
118
|
-
└─ stubgen.py # stub generator for IDE autocomplete
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
|
-
## When to Use
|
|
124
|
-
|
|
125
|
-
* Services with many subsystems
|
|
126
|
-
* Multiprocessing ingestion pipelines
|
|
127
|
-
* Long-running daemons
|
|
128
|
-
* Kubernetes / systemd services
|
|
129
|
-
* Need for clear operational logs
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
## When Not to Use
|
|
134
|
-
|
|
135
|
-
* Single-file scripts
|
|
136
|
-
* No multiprocessing
|
|
137
|
-
* No domain separation required
|
|
138
|
-
|
|
139
|
-
Plain `logging` is sufficient in those cases.
|
|
140
|
-
|
|
141
|
-
---
|
|
142
|
-
|
|
143
|
-
## License
|
|
144
|
-
|
|
145
|
-
MIT
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Author
|
|
150
|
-
|
|
151
|
-
**Bruno Miura**
|
miu_logger-0.1.6/README.md
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
```python
|
|
2
|
-
repo = LoggingRepository(config)
|
|
3
|
-
queue = repo.get_queue()
|
|
4
|
-
```
|
|
5
|
-
|
|
6
|
-
**Worker processes:**
|
|
7
|
-
|
|
8
|
-
```python
|
|
9
|
-
worker_repo = LoggingRepository(config, use_listener=False, queue=queue)
|
|
10
|
-
worker_repo.task.info("Worker started")
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
All processes log safely to the same listener and files.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Debug Control
|
|
18
|
-
|
|
19
|
-
Only `.debug()` messages are conditional via `debug_enabled`:
|
|
20
|
-
|
|
21
|
-
```python
|
|
22
|
-
config.debug_enabled = False
|
|
23
|
-
repo.app.debug("Won't appear")
|
|
24
|
-
repo.app.info("Will appear")
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Useful for toggling debug messages in production.
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
## Output Structure
|
|
32
|
-
|
|
33
|
-
Logs are written in:
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
logs/
|
|
37
|
-
├─ app.log # domain logs
|
|
38
|
-
├─ db.log
|
|
39
|
-
├─ redis.log
|
|
40
|
-
├─ debug.log # per-level logs
|
|
41
|
-
├─ info.log
|
|
42
|
-
├─ warning.log
|
|
43
|
-
└─ error.log
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Console output is **colorized** by level:
|
|
47
|
-
|
|
48
|
-
* DEBUG → blue
|
|
49
|
-
* INFO → green
|
|
50
|
-
* WARNING → yellow
|
|
51
|
-
* ERROR → red
|
|
52
|
-
|
|
53
|
-
Files remain clean.
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## Graceful Shutdown
|
|
58
|
-
|
|
59
|
-
The repository automatically shuts down on process exit and supports manual shutdown:
|
|
60
|
-
|
|
61
|
-
```python
|
|
62
|
-
repo.shutdown()
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## Typical Usage Example
|
|
68
|
-
|
|
69
|
-
```python
|
|
70
|
-
repo.app.info("Service starting")
|
|
71
|
-
|
|
72
|
-
try:
|
|
73
|
-
connect_db()
|
|
74
|
-
except Exception:
|
|
75
|
-
repo.db.exception("DB connection failed")
|
|
76
|
-
|
|
77
|
-
repo.redis.debug("Cache size: %d", cache_size)
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
**Multiprocessing workers:**
|
|
81
|
-
|
|
82
|
-
```python
|
|
83
|
-
def worker(queue):
|
|
84
|
-
repo = LoggingRepository(config, use_listener=False, queue=queue)
|
|
85
|
-
repo.task.info("Worker task started")
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
## Project Structure
|
|
91
|
-
|
|
92
|
-
```
|
|
93
|
-
miu_logger/
|
|
94
|
-
├─ repository.py # main LoggingRepository
|
|
95
|
-
├─ listener.py # QueueListener and handler setup
|
|
96
|
-
├─ logger_factory.py # logger creation functions
|
|
97
|
-
├─ conditional.py # ConditionalLogger
|
|
98
|
-
├─ filters.py # Logger filters
|
|
99
|
-
├─ formatters.py # ColoredFormatter
|
|
100
|
-
├─ config.py # LogConfig definition
|
|
101
|
-
└─ stubgen.py # stub generator for IDE autocomplete
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## When to Use
|
|
107
|
-
|
|
108
|
-
* Services with many subsystems
|
|
109
|
-
* Multiprocessing ingestion pipelines
|
|
110
|
-
* Long-running daemons
|
|
111
|
-
* Kubernetes / systemd services
|
|
112
|
-
* Need for clear operational logs
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## When Not to Use
|
|
117
|
-
|
|
118
|
-
* Single-file scripts
|
|
119
|
-
* No multiprocessing
|
|
120
|
-
* No domain separation required
|
|
121
|
-
|
|
122
|
-
Plain `logging` is sufficient in those cases.
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## License
|
|
127
|
-
|
|
128
|
-
MIT
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
## Author
|
|
133
|
-
|
|
134
|
-
**Bruno Miura**
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: miu-logger
|
|
3
|
-
Version: 0.1.6
|
|
4
|
-
Summary: Multiprocessing-safe domain-based logging framework with QueueListener architecture
|
|
5
|
-
Author-email: Bruno Miura <brumiura@gmail.com>
|
|
6
|
-
License-Expression: MIT
|
|
7
|
-
Keywords: logging,multiprocessing,queue,structured-logging,python-logging
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Classifier: Topic :: System :: Logging
|
|
12
|
-
Requires-Python: >=3.10
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: colorama
|
|
16
|
-
Dynamic: license-file
|
|
17
|
-
|
|
18
|
-
```python
|
|
19
|
-
repo = LoggingRepository(config)
|
|
20
|
-
queue = repo.get_queue()
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
**Worker processes:**
|
|
24
|
-
|
|
25
|
-
```python
|
|
26
|
-
worker_repo = LoggingRepository(config, use_listener=False, queue=queue)
|
|
27
|
-
worker_repo.task.info("Worker started")
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
All processes log safely to the same listener and files.
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## Debug Control
|
|
35
|
-
|
|
36
|
-
Only `.debug()` messages are conditional via `debug_enabled`:
|
|
37
|
-
|
|
38
|
-
```python
|
|
39
|
-
config.debug_enabled = False
|
|
40
|
-
repo.app.debug("Won't appear")
|
|
41
|
-
repo.app.info("Will appear")
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Useful for toggling debug messages in production.
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## Output Structure
|
|
49
|
-
|
|
50
|
-
Logs are written in:
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
logs/
|
|
54
|
-
├─ app.log # domain logs
|
|
55
|
-
├─ db.log
|
|
56
|
-
├─ redis.log
|
|
57
|
-
├─ debug.log # per-level logs
|
|
58
|
-
├─ info.log
|
|
59
|
-
├─ warning.log
|
|
60
|
-
└─ error.log
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Console output is **colorized** by level:
|
|
64
|
-
|
|
65
|
-
* DEBUG → blue
|
|
66
|
-
* INFO → green
|
|
67
|
-
* WARNING → yellow
|
|
68
|
-
* ERROR → red
|
|
69
|
-
|
|
70
|
-
Files remain clean.
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
|
|
74
|
-
## Graceful Shutdown
|
|
75
|
-
|
|
76
|
-
The repository automatically shuts down on process exit and supports manual shutdown:
|
|
77
|
-
|
|
78
|
-
```python
|
|
79
|
-
repo.shutdown()
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## Typical Usage Example
|
|
85
|
-
|
|
86
|
-
```python
|
|
87
|
-
repo.app.info("Service starting")
|
|
88
|
-
|
|
89
|
-
try:
|
|
90
|
-
connect_db()
|
|
91
|
-
except Exception:
|
|
92
|
-
repo.db.exception("DB connection failed")
|
|
93
|
-
|
|
94
|
-
repo.redis.debug("Cache size: %d", cache_size)
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
**Multiprocessing workers:**
|
|
98
|
-
|
|
99
|
-
```python
|
|
100
|
-
def worker(queue):
|
|
101
|
-
repo = LoggingRepository(config, use_listener=False, queue=queue)
|
|
102
|
-
repo.task.info("Worker task started")
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## Project Structure
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
miu_logger/
|
|
111
|
-
├─ repository.py # main LoggingRepository
|
|
112
|
-
├─ listener.py # QueueListener and handler setup
|
|
113
|
-
├─ logger_factory.py # logger creation functions
|
|
114
|
-
├─ conditional.py # ConditionalLogger
|
|
115
|
-
├─ filters.py # Logger filters
|
|
116
|
-
├─ formatters.py # ColoredFormatter
|
|
117
|
-
├─ config.py # LogConfig definition
|
|
118
|
-
└─ stubgen.py # stub generator for IDE autocomplete
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
|
-
## When to Use
|
|
124
|
-
|
|
125
|
-
* Services with many subsystems
|
|
126
|
-
* Multiprocessing ingestion pipelines
|
|
127
|
-
* Long-running daemons
|
|
128
|
-
* Kubernetes / systemd services
|
|
129
|
-
* Need for clear operational logs
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
## When Not to Use
|
|
134
|
-
|
|
135
|
-
* Single-file scripts
|
|
136
|
-
* No multiprocessing
|
|
137
|
-
* No domain separation required
|
|
138
|
-
|
|
139
|
-
Plain `logging` is sufficient in those cases.
|
|
140
|
-
|
|
141
|
-
---
|
|
142
|
-
|
|
143
|
-
## License
|
|
144
|
-
|
|
145
|
-
MIT
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Author
|
|
150
|
-
|
|
151
|
-
**Bruno Miura**
|
|
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
|