yapl-kit 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.
Files changed (54) hide show
  1. yapl_kit-0.1.0/PKG-INFO +345 -0
  2. yapl_kit-0.1.0/README.md +331 -0
  3. yapl_kit-0.1.0/pyproject.toml +37 -0
  4. yapl_kit-0.1.0/pyproject.toml.orig +36 -0
  5. yapl_kit-0.1.0/src/yapl/__init__.py +97 -0
  6. yapl_kit-0.1.0/src/yapl/config.py +266 -0
  7. yapl_kit-0.1.0/src/yapl/extensions/buffering/__init__.py +24 -0
  8. yapl_kit-0.1.0/src/yapl/extensions/buffering/capture.py +66 -0
  9. yapl_kit-0.1.0/src/yapl/extensions/buffering/context.py +162 -0
  10. yapl_kit-0.1.0/src/yapl/extensions/buffering/flush.py +71 -0
  11. yapl_kit-0.1.0/src/yapl/extensions/buffering/models.py +65 -0
  12. yapl_kit-0.1.0/src/yapl/extensions/coloring/__init__.py +45 -0
  13. yapl_kit-0.1.0/src/yapl/extensions/coloring/colors.py +86 -0
  14. yapl_kit-0.1.0/src/yapl/extensions/coloring/models.py +121 -0
  15. yapl_kit-0.1.0/src/yapl/extensions/coloring/plain.py +113 -0
  16. yapl_kit-0.1.0/src/yapl/extensions/coloring/policy.py +31 -0
  17. yapl_kit-0.1.0/src/yapl/extensions/coloring/registry.py +119 -0
  18. yapl_kit-0.1.0/src/yapl/extensions/coloring/structured.py +100 -0
  19. yapl_kit-0.1.0/src/yapl/extensions/coloring/text.py +36 -0
  20. yapl_kit-0.1.0/src/yapl/extensions/coloring/themes.py +111 -0
  21. yapl_kit-0.1.0/src/yapl/extensions/formatting/__init__.py +54 -0
  22. yapl_kit-0.1.0/src/yapl/extensions/formatting/_helpers.py +53 -0
  23. yapl_kit-0.1.0/src/yapl/extensions/formatting/_types.py +21 -0
  24. yapl_kit-0.1.0/src/yapl/extensions/formatting/formatters.py +115 -0
  25. yapl_kit-0.1.0/src/yapl/extensions/formatting/json.py +6 -0
  26. yapl_kit-0.1.0/src/yapl/extensions/formatting/logfmt.py +6 -0
  27. yapl_kit-0.1.0/src/yapl/extensions/formatting/plain.py +103 -0
  28. yapl_kit-0.1.0/src/yapl/extensions/formatting/processors.py +391 -0
  29. yapl_kit-0.1.0/src/yapl/extensions/formatting/structured.py +656 -0
  30. yapl_kit-0.1.0/src/yapl/extensions/formatting/text.py +6 -0
  31. yapl_kit-0.1.0/src/yapl/extensions/queueing/__init__.py +25 -0
  32. yapl_kit-0.1.0/src/yapl/extensions/queueing/handler.py +276 -0
  33. yapl_kit-0.1.0/src/yapl/extensions/queueing/models.py +126 -0
  34. yapl_kit-0.1.0/src/yapl/extensions/queueing/policy.py +22 -0
  35. yapl_kit-0.1.0/src/yapl/extensions/queueing/queue.py +101 -0
  36. yapl_kit-0.1.0/src/yapl/extensions/queueing/worker.py +50 -0
  37. yapl_kit-0.1.0/src/yapl/extensions/webhook/__init__.py +54 -0
  38. yapl_kit-0.1.0/src/yapl/extensions/webhook/client.py +159 -0
  39. yapl_kit-0.1.0/src/yapl/extensions/webhook/handler.py +244 -0
  40. yapl_kit-0.1.0/src/yapl/extensions/webhook/models.py +210 -0
  41. yapl_kit-0.1.0/src/yapl/extensions/webhook/payloads.py +252 -0
  42. yapl_kit-0.1.0/src/yapl/factory.py +367 -0
  43. yapl_kit-0.1.0/src/yapl/filters/__init__.py +22 -0
  44. yapl_kit-0.1.0/src/yapl/filters/enrichment.py +116 -0
  45. yapl_kit-0.1.0/src/yapl/filters/suppression.py +69 -0
  46. yapl_kit-0.1.0/src/yapl/levels.py +134 -0
  47. yapl_kit-0.1.0/src/yapl/logger.py +247 -0
  48. yapl_kit-0.1.0/src/yapl/py.typed +1 -0
  49. yapl_kit-0.1.0/src/yapl/stack/__init__.py +14 -0
  50. yapl_kit-0.1.0/src/yapl/stack/callsite.py +75 -0
  51. yapl_kit-0.1.0/src/yapl/stack/tracer.py +157 -0
  52. yapl_kit-0.1.0/src/yapl/types.py +41 -0
  53. yapl_kit-0.1.0/src/yapl_kit/__init__.py +2 -0
  54. yapl_kit-0.1.0/src/yapl_kit/py.typed +1 -0
@@ -0,0 +1,345 @@
1
+ Metadata-Version: 2.3
2
+ Name: yapl-kit
3
+ Version: 0.1.0
4
+ Summary: YetAnotherPythonLogger - a minimal, extensible logging toolkit built on top of Python's standard logging module.
5
+ Author: SirKaiMartin
6
+ Requires-Dist: httpx>=0.28.1 ; extra == 'webhook'
7
+ Requires-Python: >=3.13
8
+ Provides-Extra: buffering
9
+ Provides-Extra: coloring
10
+ Provides-Extra: formatting
11
+ Provides-Extra: queueing
12
+ Provides-Extra: webhook
13
+ Description-Content-Type: text/markdown
14
+
15
+ <p align="center">
16
+ <img src="../docs/assets/yapl_banner.png" alt="YAPL banner">
17
+ </p>
18
+
19
+ # YAPL
20
+
21
+ ### Yet Another Python Logger
22
+
23
+ > A modern, minimal, and extensible logging library built on top of Python's standard `logging` module.
24
+
25
+ YAPL keeps the stdlib logging ecosystem intact while splitting the project into a small core and opt-in modules.
26
+
27
+ - core setup stays dependency-free
28
+ - additional behavior is imported from `yapl.stack` and `yapl.extensions.*`
29
+ - buffering, queueing, formatting, coloring, and webhook delivery stay off the application hot path
30
+
31
+ YAPL does not replace Python logging. It uses stdlib handlers, formatters, filters, and propagation exactly as they are.
32
+
33
+ ## Design principles
34
+
35
+ - Configuration is explicit: setup arguments override a `YaplConfig` for one call
36
+ without mutating it.
37
+ - Structured fields are built once at the logger boundary, then remain ordinary
38
+ `LogRecord` attributes for every handler and formatter.
39
+ - The default queue path performs only a bounded, non-blocking enqueue on the
40
+ application thread. Formatting, file output, webhooks, and file-overflow
41
+ fallback run on workers. Choose `overflow_policy="block"` only when deliberate
42
+ backpressure is more important than application latency.
43
+ - `shutdown_logging()` flushes and closes root handlers configured by YAPL; it
44
+ does not invoke the stdlib's process-wide `logging.shutdown()`.
45
+
46
+ ## Guarantees and non-guarantees
47
+
48
+ In the default queued configuration, remote and sink I/O never runs on the
49
+ caller thread, and queue insertion does not intentionally wait. This is an
50
+ operational guarantee for YAPL's queue and built-in webhook path, not an
51
+ absolute claim that logging can never block under every configuration.
52
+
53
+ Guaranteed by default:
54
+
55
+ - Queue-backed delivery has a bounded number of records. Queue insertion uses
56
+ non-blocking insertion under the default overflow policy.
57
+ - Formatting, file/console delivery, webhook payload work, HTTP, DNS, and retry
58
+ waits happen on background workers.
59
+ - Webhook retry attempts and retry delays are bounded. A handler reuses one
60
+ lazily created HTTP client while it is active.
61
+ - Shutdown waiting is bounded by `shutdown_timeout_seconds`. When that deadline
62
+ expires, queued records may be discarded so the caller can continue.
63
+
64
+ Not guaranteed:
65
+
66
+ - Delivery of every record during overload, remote failure, or shutdown.
67
+ - A fixed byte-level memory limit. Queue sizes bound record count, while queued
68
+ records retain message arguments, `extra`, exceptions, tracebacks, and any
69
+ object graphs they reference.
70
+ - Termination of arbitrary custom handlers already blocked forever. Python
71
+ cannot safely kill user handler code. During forced reconfiguration YAPL emits
72
+ one `RuntimeWarning` if it observes an old queue worker still alive after its
73
+ bounded close wait; the new configuration uses new workers.
74
+
75
+ Explicit opt-outs:
76
+
77
+ - `overflow_policy="block"` deliberately enables application-level backpressure.
78
+ It may block the caller, indefinitely when `enqueue_timeout_seconds=None`.
79
+ - `queue_enabled=False` runs normal stdlib handlers directly, so file, console,
80
+ or custom sink work can occur on the caller thread.
81
+
82
+ Custom handlers are different from built-in transports: YAPL keeps their calls
83
+ behind its queue by default, but cannot bound how long their own code takes once
84
+ a worker enters it. Keep custom handlers non-blocking or give them their own
85
+ timeouts.
86
+
87
+ ---
88
+
89
+ # Architecture
90
+
91
+ ## Core
92
+
93
+ Import the base package when you only need standard logging setup:
94
+
95
+ ```python
96
+ import yapl
97
+
98
+ log = yapl.setup_logging(level="INFO", outputs=("stdout",), format="text")
99
+
100
+ log.info("hello world")
101
+ log.warning("something happened")
102
+ ```
103
+
104
+ Core imports stay small:
105
+
106
+ - `yapl.setup_logging`
107
+ - `yapl.shutdown_logging`
108
+ - `yapl.get_logger`
109
+ - `yapl.config`
110
+ - `yapl.levels`
111
+ - `yapl.logger`
112
+ - `yapl.types`
113
+
114
+ ## Optional modules
115
+
116
+ Import concrete modules when you want extra behavior:
117
+
118
+ ```python
119
+ from yapl.stack import FunctionCallTracer, get_callsite
120
+ from yapl.extensions.buffering import BufferedLogs, BufferingConfig
121
+ from yapl.extensions.formatting import JSONFormatter, StructuredFormatterConfig
122
+ from yapl.extensions.coloring import install_color_structured_console
123
+ from yapl.extensions.queueing import QueueingConfig
124
+ from yapl.extensions.webhook import WebhookConfig
125
+ ```
126
+
127
+ The `yapl.extensions` package is only a namespace. The concrete features live in submodules.
128
+
129
+ ---
130
+
131
+ # Quick Start
132
+
133
+ ```python
134
+ import yapl
135
+
136
+ yapl.setup_logging(level="INFO", outputs=("stdout",), format="text")
137
+ log = yapl.get_logger(__name__)
138
+
139
+ log.info("Hello world")
140
+ log.warning("Something happened")
141
+ ```
142
+
143
+ Structured calls work too:
144
+
145
+ ```python
146
+ log.info("user_login", user_id=123, ip="1.2.3.4")
147
+ log.error("payment_failed", order_id="A-17", exc_info=True)
148
+ ```
149
+
150
+ For typed configuration and a webhook-enabled application, the common imports
151
+ are available directly from `yapl`:
152
+
153
+ ```python
154
+ from yapl import WebhookConfig, YaplConfig, get_logger, setup_logging
155
+
156
+ config = YaplConfig(
157
+ queue_max_size=2_000,
158
+ webhook=WebhookConfig("https://example.com/webhook", min_level="ERROR"),
159
+ )
160
+ setup_logging(config, outputs=("stdout", "webhook"))
161
+
162
+ logger = get_logger(__name__)
163
+ logger.info("Application started")
164
+ ```
165
+
166
+ Call `shutdown_logging()` during an orderly application shutdown when you want
167
+ to give queued work its configured bounded drain window. It is safe to call
168
+ more than once; records remaining at its deadline may be discarded.
169
+
170
+ ---
171
+
172
+ # Buffering
173
+
174
+ Buffering captures log records during a block and replays or discards them on exit:
175
+
176
+ ```python
177
+ from yapl.extensions.buffering import BufferedLogs, BufferingConfig, install_buffering
178
+
179
+ install_buffering()
180
+
181
+ with BufferedLogs(BufferingConfig(flush_mode="ordered")):
182
+ log.info("preflight", phase="warmup")
183
+ log.warning("preflight_warning", stage=1)
184
+ ```
185
+
186
+ The default behavior flushes buffered records on success and on error. Use the config to
187
+ discard instead when a block should stay silent.
188
+
189
+ ---
190
+
191
+ # Extended Levels
192
+
193
+ YAPL can register extra development levels:
194
+
195
+ ```python
196
+ yapl.setup_logging(level_mode="extended")
197
+
198
+ log.trace("trace message")
199
+ log.dev("dev message")
200
+ ```
201
+
202
+ The built-in extended levels are:
203
+
204
+ | Level | Value |
205
+ | ----- | ----- |
206
+ | TRACE | 5 |
207
+ | DEV | 15 |
208
+
209
+ ---
210
+
211
+ # Stack Helpers
212
+
213
+ Callsite and tracing live in `yapl.stack`:
214
+
215
+ ```python
216
+ from yapl.stack import FunctionCallTracer, get_callsite
217
+
218
+ callsite = get_callsite()
219
+
220
+ with FunctionCallTracer():
221
+ run_complex_operation()
222
+ ```
223
+
224
+ ---
225
+
226
+ # Formatting
227
+
228
+ Structured, text, JSON Lines, and logfmt output live in `yapl.extensions.formatting`:
229
+
230
+ ```python
231
+ from yapl.extensions.formatting import JSONFormatter, LogfmtFormatter, TextFormatter
232
+
233
+ formatter = JSONFormatter()
234
+ ```
235
+
236
+ Use sink profiles when one process needs both a human terminal and a machine stream:
237
+
238
+ ```python
239
+ import yapl
240
+ from yapl import OutputConfig, YaplConfig
241
+
242
+ config = YaplConfig(
243
+ sinks=(
244
+ OutputConfig("stdout", format="text", color="auto", theme_name="dark"),
245
+ OutputConfig("file", format="jsonl", file_path="service.jsonl"),
246
+ ),
247
+ resource={
248
+ "service.name": "billing",
249
+ "deployment.environment": "production",
250
+ },
251
+ )
252
+
253
+ log = yapl.setup_logging(config)
254
+ log.info("payment_processed", request_id="req-42")
255
+ ```
256
+
257
+ `color="auto"` emits ANSI only to a TTY and respects `NO_COLOR`. Color is
258
+ restricted to `text` and `plain` stdout/stderr sinks; `json`, `jsonl`, `logfmt`,
259
+ files, and webhooks remain machine-readable.
260
+
261
+ Use `resource` for stable source metadata such as service, environment, region,
262
+ or cluster. Keep request IDs, user IDs, trace IDs, and other high-cardinality
263
+ values as normal structured fields. This keeps JSON streams portable while
264
+ allowing Grafana Alloy, OpenTelemetry Collector, or another shipper to choose
265
+ safe index labels.
266
+
267
+ [`examples/grafana_alloy.river`](examples/grafana_alloy.river) shows a file-based
268
+ Alloy pipeline. It keeps the source label static and stores request/trace
269
+ identifiers as structured metadata. See
270
+ [`examples/grafana_alloy_events.md`](examples/grafana_alloy_events.md) for
271
+ representative JSONL events, field definitions, and the corresponding Alloy
272
+ extraction. [`examples/log_output_examples.md`](examples/log_output_examples.md)
273
+ is a comprehensive output reference covering terminal text and color, JSONL,
274
+ logfmt, traces, stacks, redaction, queues, and webhooks.
275
+
276
+ ---
277
+
278
+ # Queueing
279
+
280
+ Queue-backed handlers keep application threads fast:
281
+
282
+ ```python
283
+ from yapl.extensions.queueing import QueueingConfig, QueueingHandler
284
+ ```
285
+
286
+ Use the queue when you want formatting, file writes, or webhook delivery to happen behind a worker. The queue capacity limits records, not bytes; avoid placing unbounded object graphs in log arguments or structured fields when memory limits matter.
287
+
288
+ ---
289
+
290
+ # Webhooks
291
+
292
+ Webhook delivery lives in `yapl.extensions.webhook`:
293
+
294
+ ```python
295
+ from yapl.extensions.webhook import WebhookConfig
296
+
297
+ webhook = WebhookConfig(url="https://example.com/webhook", min_level="ERROR")
298
+ log = yapl.setup_logging(webhook=webhook)
299
+ ```
300
+
301
+ Webhook work runs in the background so application threads do not intentionally
302
+ wait for network I/O. HTTP clients are reused per active webhook handler, and
303
+ timeouts/retries are bounded.
304
+
305
+ ---
306
+
307
+ # Tests
308
+
309
+ The functional suite is in `tests/` and is the default target for `pytest`.
310
+ The original feedback-oriented coverage is preserved in `user_tests/` and can
311
+ be run explicitly when checking the historical user-facing scenarios:
312
+
313
+ ```bash
314
+ uv run pytest
315
+ uv run pytest user_tests
316
+ ```
317
+
318
+ ---
319
+
320
+ # Installation
321
+
322
+ Core:
323
+
324
+ ```bash
325
+ pip install yapl
326
+ ```
327
+
328
+ With extensions:
329
+
330
+ ```bash
331
+ pip install yapl[formatting,coloring,buffering,queueing,webhook]
332
+ ```
333
+
334
+ ---
335
+
336
+ # Examples
337
+
338
+ See:
339
+
340
+ - `examples/basic_demo.py`
341
+ - `examples/buffering_demo.py`
342
+ - `examples/extended_demo.py`
343
+ - `examples/benchmark_demo.py`
344
+
345
+ The demos are configured from a small block at the top so you can turn features on and off quickly.
@@ -0,0 +1,331 @@
1
+ <p align="center">
2
+ <img src="../docs/assets/yapl_banner.png" alt="YAPL banner">
3
+ </p>
4
+
5
+ # YAPL
6
+
7
+ ### Yet Another Python Logger
8
+
9
+ > A modern, minimal, and extensible logging library built on top of Python's standard `logging` module.
10
+
11
+ YAPL keeps the stdlib logging ecosystem intact while splitting the project into a small core and opt-in modules.
12
+
13
+ - core setup stays dependency-free
14
+ - additional behavior is imported from `yapl.stack` and `yapl.extensions.*`
15
+ - buffering, queueing, formatting, coloring, and webhook delivery stay off the application hot path
16
+
17
+ YAPL does not replace Python logging. It uses stdlib handlers, formatters, filters, and propagation exactly as they are.
18
+
19
+ ## Design principles
20
+
21
+ - Configuration is explicit: setup arguments override a `YaplConfig` for one call
22
+ without mutating it.
23
+ - Structured fields are built once at the logger boundary, then remain ordinary
24
+ `LogRecord` attributes for every handler and formatter.
25
+ - The default queue path performs only a bounded, non-blocking enqueue on the
26
+ application thread. Formatting, file output, webhooks, and file-overflow
27
+ fallback run on workers. Choose `overflow_policy="block"` only when deliberate
28
+ backpressure is more important than application latency.
29
+ - `shutdown_logging()` flushes and closes root handlers configured by YAPL; it
30
+ does not invoke the stdlib's process-wide `logging.shutdown()`.
31
+
32
+ ## Guarantees and non-guarantees
33
+
34
+ In the default queued configuration, remote and sink I/O never runs on the
35
+ caller thread, and queue insertion does not intentionally wait. This is an
36
+ operational guarantee for YAPL's queue and built-in webhook path, not an
37
+ absolute claim that logging can never block under every configuration.
38
+
39
+ Guaranteed by default:
40
+
41
+ - Queue-backed delivery has a bounded number of records. Queue insertion uses
42
+ non-blocking insertion under the default overflow policy.
43
+ - Formatting, file/console delivery, webhook payload work, HTTP, DNS, and retry
44
+ waits happen on background workers.
45
+ - Webhook retry attempts and retry delays are bounded. A handler reuses one
46
+ lazily created HTTP client while it is active.
47
+ - Shutdown waiting is bounded by `shutdown_timeout_seconds`. When that deadline
48
+ expires, queued records may be discarded so the caller can continue.
49
+
50
+ Not guaranteed:
51
+
52
+ - Delivery of every record during overload, remote failure, or shutdown.
53
+ - A fixed byte-level memory limit. Queue sizes bound record count, while queued
54
+ records retain message arguments, `extra`, exceptions, tracebacks, and any
55
+ object graphs they reference.
56
+ - Termination of arbitrary custom handlers already blocked forever. Python
57
+ cannot safely kill user handler code. During forced reconfiguration YAPL emits
58
+ one `RuntimeWarning` if it observes an old queue worker still alive after its
59
+ bounded close wait; the new configuration uses new workers.
60
+
61
+ Explicit opt-outs:
62
+
63
+ - `overflow_policy="block"` deliberately enables application-level backpressure.
64
+ It may block the caller, indefinitely when `enqueue_timeout_seconds=None`.
65
+ - `queue_enabled=False` runs normal stdlib handlers directly, so file, console,
66
+ or custom sink work can occur on the caller thread.
67
+
68
+ Custom handlers are different from built-in transports: YAPL keeps their calls
69
+ behind its queue by default, but cannot bound how long their own code takes once
70
+ a worker enters it. Keep custom handlers non-blocking or give them their own
71
+ timeouts.
72
+
73
+ ---
74
+
75
+ # Architecture
76
+
77
+ ## Core
78
+
79
+ Import the base package when you only need standard logging setup:
80
+
81
+ ```python
82
+ import yapl
83
+
84
+ log = yapl.setup_logging(level="INFO", outputs=("stdout",), format="text")
85
+
86
+ log.info("hello world")
87
+ log.warning("something happened")
88
+ ```
89
+
90
+ Core imports stay small:
91
+
92
+ - `yapl.setup_logging`
93
+ - `yapl.shutdown_logging`
94
+ - `yapl.get_logger`
95
+ - `yapl.config`
96
+ - `yapl.levels`
97
+ - `yapl.logger`
98
+ - `yapl.types`
99
+
100
+ ## Optional modules
101
+
102
+ Import concrete modules when you want extra behavior:
103
+
104
+ ```python
105
+ from yapl.stack import FunctionCallTracer, get_callsite
106
+ from yapl.extensions.buffering import BufferedLogs, BufferingConfig
107
+ from yapl.extensions.formatting import JSONFormatter, StructuredFormatterConfig
108
+ from yapl.extensions.coloring import install_color_structured_console
109
+ from yapl.extensions.queueing import QueueingConfig
110
+ from yapl.extensions.webhook import WebhookConfig
111
+ ```
112
+
113
+ The `yapl.extensions` package is only a namespace. The concrete features live in submodules.
114
+
115
+ ---
116
+
117
+ # Quick Start
118
+
119
+ ```python
120
+ import yapl
121
+
122
+ yapl.setup_logging(level="INFO", outputs=("stdout",), format="text")
123
+ log = yapl.get_logger(__name__)
124
+
125
+ log.info("Hello world")
126
+ log.warning("Something happened")
127
+ ```
128
+
129
+ Structured calls work too:
130
+
131
+ ```python
132
+ log.info("user_login", user_id=123, ip="1.2.3.4")
133
+ log.error("payment_failed", order_id="A-17", exc_info=True)
134
+ ```
135
+
136
+ For typed configuration and a webhook-enabled application, the common imports
137
+ are available directly from `yapl`:
138
+
139
+ ```python
140
+ from yapl import WebhookConfig, YaplConfig, get_logger, setup_logging
141
+
142
+ config = YaplConfig(
143
+ queue_max_size=2_000,
144
+ webhook=WebhookConfig("https://example.com/webhook", min_level="ERROR"),
145
+ )
146
+ setup_logging(config, outputs=("stdout", "webhook"))
147
+
148
+ logger = get_logger(__name__)
149
+ logger.info("Application started")
150
+ ```
151
+
152
+ Call `shutdown_logging()` during an orderly application shutdown when you want
153
+ to give queued work its configured bounded drain window. It is safe to call
154
+ more than once; records remaining at its deadline may be discarded.
155
+
156
+ ---
157
+
158
+ # Buffering
159
+
160
+ Buffering captures log records during a block and replays or discards them on exit:
161
+
162
+ ```python
163
+ from yapl.extensions.buffering import BufferedLogs, BufferingConfig, install_buffering
164
+
165
+ install_buffering()
166
+
167
+ with BufferedLogs(BufferingConfig(flush_mode="ordered")):
168
+ log.info("preflight", phase="warmup")
169
+ log.warning("preflight_warning", stage=1)
170
+ ```
171
+
172
+ The default behavior flushes buffered records on success and on error. Use the config to
173
+ discard instead when a block should stay silent.
174
+
175
+ ---
176
+
177
+ # Extended Levels
178
+
179
+ YAPL can register extra development levels:
180
+
181
+ ```python
182
+ yapl.setup_logging(level_mode="extended")
183
+
184
+ log.trace("trace message")
185
+ log.dev("dev message")
186
+ ```
187
+
188
+ The built-in extended levels are:
189
+
190
+ | Level | Value |
191
+ | ----- | ----- |
192
+ | TRACE | 5 |
193
+ | DEV | 15 |
194
+
195
+ ---
196
+
197
+ # Stack Helpers
198
+
199
+ Callsite and tracing live in `yapl.stack`:
200
+
201
+ ```python
202
+ from yapl.stack import FunctionCallTracer, get_callsite
203
+
204
+ callsite = get_callsite()
205
+
206
+ with FunctionCallTracer():
207
+ run_complex_operation()
208
+ ```
209
+
210
+ ---
211
+
212
+ # Formatting
213
+
214
+ Structured, text, JSON Lines, and logfmt output live in `yapl.extensions.formatting`:
215
+
216
+ ```python
217
+ from yapl.extensions.formatting import JSONFormatter, LogfmtFormatter, TextFormatter
218
+
219
+ formatter = JSONFormatter()
220
+ ```
221
+
222
+ Use sink profiles when one process needs both a human terminal and a machine stream:
223
+
224
+ ```python
225
+ import yapl
226
+ from yapl import OutputConfig, YaplConfig
227
+
228
+ config = YaplConfig(
229
+ sinks=(
230
+ OutputConfig("stdout", format="text", color="auto", theme_name="dark"),
231
+ OutputConfig("file", format="jsonl", file_path="service.jsonl"),
232
+ ),
233
+ resource={
234
+ "service.name": "billing",
235
+ "deployment.environment": "production",
236
+ },
237
+ )
238
+
239
+ log = yapl.setup_logging(config)
240
+ log.info("payment_processed", request_id="req-42")
241
+ ```
242
+
243
+ `color="auto"` emits ANSI only to a TTY and respects `NO_COLOR`. Color is
244
+ restricted to `text` and `plain` stdout/stderr sinks; `json`, `jsonl`, `logfmt`,
245
+ files, and webhooks remain machine-readable.
246
+
247
+ Use `resource` for stable source metadata such as service, environment, region,
248
+ or cluster. Keep request IDs, user IDs, trace IDs, and other high-cardinality
249
+ values as normal structured fields. This keeps JSON streams portable while
250
+ allowing Grafana Alloy, OpenTelemetry Collector, or another shipper to choose
251
+ safe index labels.
252
+
253
+ [`examples/grafana_alloy.river`](examples/grafana_alloy.river) shows a file-based
254
+ Alloy pipeline. It keeps the source label static and stores request/trace
255
+ identifiers as structured metadata. See
256
+ [`examples/grafana_alloy_events.md`](examples/grafana_alloy_events.md) for
257
+ representative JSONL events, field definitions, and the corresponding Alloy
258
+ extraction. [`examples/log_output_examples.md`](examples/log_output_examples.md)
259
+ is a comprehensive output reference covering terminal text and color, JSONL,
260
+ logfmt, traces, stacks, redaction, queues, and webhooks.
261
+
262
+ ---
263
+
264
+ # Queueing
265
+
266
+ Queue-backed handlers keep application threads fast:
267
+
268
+ ```python
269
+ from yapl.extensions.queueing import QueueingConfig, QueueingHandler
270
+ ```
271
+
272
+ Use the queue when you want formatting, file writes, or webhook delivery to happen behind a worker. The queue capacity limits records, not bytes; avoid placing unbounded object graphs in log arguments or structured fields when memory limits matter.
273
+
274
+ ---
275
+
276
+ # Webhooks
277
+
278
+ Webhook delivery lives in `yapl.extensions.webhook`:
279
+
280
+ ```python
281
+ from yapl.extensions.webhook import WebhookConfig
282
+
283
+ webhook = WebhookConfig(url="https://example.com/webhook", min_level="ERROR")
284
+ log = yapl.setup_logging(webhook=webhook)
285
+ ```
286
+
287
+ Webhook work runs in the background so application threads do not intentionally
288
+ wait for network I/O. HTTP clients are reused per active webhook handler, and
289
+ timeouts/retries are bounded.
290
+
291
+ ---
292
+
293
+ # Tests
294
+
295
+ The functional suite is in `tests/` and is the default target for `pytest`.
296
+ The original feedback-oriented coverage is preserved in `user_tests/` and can
297
+ be run explicitly when checking the historical user-facing scenarios:
298
+
299
+ ```bash
300
+ uv run pytest
301
+ uv run pytest user_tests
302
+ ```
303
+
304
+ ---
305
+
306
+ # Installation
307
+
308
+ Core:
309
+
310
+ ```bash
311
+ pip install yapl
312
+ ```
313
+
314
+ With extensions:
315
+
316
+ ```bash
317
+ pip install yapl[formatting,coloring,buffering,queueing,webhook]
318
+ ```
319
+
320
+ ---
321
+
322
+ # Examples
323
+
324
+ See:
325
+
326
+ - `examples/basic_demo.py`
327
+ - `examples/buffering_demo.py`
328
+ - `examples/extended_demo.py`
329
+ - `examples/benchmark_demo.py`
330
+
331
+ The demos are configured from a small block at the top so you can turn features on and off quickly.
@@ -0,0 +1,37 @@
1
+ [project]
2
+ name = "yapl-kit"
3
+ version = "0.1.0"
4
+ description = "YetAnotherPythonLogger - a minimal, extensible logging toolkit built on top of Python's standard logging module."
5
+ readme = "README.md"
6
+ requires-python = ">=3.13"
7
+ dependencies = []
8
+
9
+ [[project.authors]]
10
+ name = "SirKaiMartin"
11
+
12
+ [project.optional-dependencies]
13
+ formatting = []
14
+ coloring = []
15
+ buffering = []
16
+ queueing = []
17
+ webhook = ["httpx>=0.28.1"]
18
+
19
+ [build-system]
20
+ requires = ["uv_build>=0.12.16,<0.13.0"]
21
+ build-backend = "uv_build"
22
+
23
+ [tool.uv.build-backend]
24
+ module-name = [
25
+ "yapl",
26
+ "yapl_kit",
27
+ ]
28
+
29
+ [tool.pytest.ini_options]
30
+ testpaths = ["tests"]
31
+
32
+ [dependency-groups]
33
+ dev = [
34
+ "pytest>=9.1.1",
35
+ "ruff>=0.16.8",
36
+ "ty>=0.0.82",
37
+ ]