logging-metrics 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 thaissateodoro
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.
@@ -0,0 +1,565 @@
1
+ Metadata-Version: 2.4
2
+ Name: logging-metrics
3
+ Version: 0.1.0
4
+ Summary: Advanced logging utilities for robust, standardized logs in Python projects, APIs, data engineering, and more.
5
+ Author-email: Thaissa Ferreira <thaissa.teodoro@hotmail.com>
6
+ License-Expression: MIT
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Topic :: Software Development :: Libraries
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: pyspark>=3.0.0
16
+ Requires-Dist: pytz
17
+ Provides-Extra: dev
18
+ Requires-Dist: pytest; extra == "dev"
19
+ Requires-Dist: pytest-cov; extra == "dev"
20
+ Dynamic: license-file
21
+
22
+
23
+ # logging-metrics - Utilities Library for Logging Configuration and Management
24
+
25
+ This module provides functions and classes to configure logging for different environments and use cases:
26
+
27
+ - Colored logs for the terminal
28
+ - Rotating log files (by time or size)
29
+ - Customizable settings for different verbosity levels
30
+ - Text or JSON formatters compatible with external analysis tools
31
+ - Utilities for timing operations and collecting custom metrics
32
+ - **Utility functions for logging PySpark DataFrames** (e.g., row count, schema, samples, and basic statistics)
33
+
34
+ Main Components:
35
+ ----------------
36
+ - `ColoredFormatter`: Colorized terminal output for quick identification of log levels
37
+ - `JSONFormatter`: JSON-formatted logs for external tool integration
38
+ - Functions to create handlers (console, file, rotation by time or size)
39
+ - `LogTimer`: Measure execution time of code blocks (context manager or decorator)
40
+ - `LogMetrics`: Collect and log custom metrics (counters, timers, values)
41
+ - **`log_spark_dataframe_info`: Easy, structured logging for PySpark DataFrames**
42
+
43
+ This toolkit is recommended for data pipelines, ETLs, and projects where traceability, auditability, and log performance are critical requirements.
44
+
45
+ ---
46
+
47
+ This README.md covers:
48
+
49
+ - Purpose
50
+ - Installation
51
+ - Main Features
52
+ - Best Practices
53
+ - Usage Example
54
+ - Spark Integration
55
+ - Dependencies & License
56
+
57
+ ---
58
+
59
+ # Logging-Toolkit
60
+
61
+ A library for configuring and managing logs in Python, focused on simplicity and performance.
62
+
63
+ ---
64
+
65
+ #### โœจ Features
66
+
67
+ - ๐ŸŽจ Colored logs for the terminal with different levels
68
+ - ๐Ÿ“ Automatic file rotation by time or size
69
+ - โšก PySpark DataFrame integration
70
+ - ๐Ÿ“Š JSON format for observability systems
71
+ - โฑ๏ธ Timing with LogTimer
72
+ - ๐Ÿ“ˆ Metrics monitoring with LogMetrics
73
+ - ๐Ÿ”ง Hierarchical logger configuration
74
+ - ๐Ÿš€ Optimized performance for critical applications
75
+
76
+ ---
77
+
78
+ ## ๐Ÿ“ฆ Installation
79
+
80
+ #### Install via pip:
81
+ ```bash
82
+ pip install logging-toolkit
83
+ ```
84
+
85
+ #### For development:
86
+ ```bash
87
+ git clone https://github.com/thaissateodoro/logging-toolkit.git
88
+ cd logging-toolkit
89
+ pip install -e ".[dev]"
90
+ ```
91
+
92
+ ---
93
+ ## ๐Ÿ“‹ Functions and Classes Overview
94
+
95
+ Main Functions
96
+ ```
97
+ | Name | Type | Description |
98
+ |---------------------------|----------|--------------------------------------------------------------------------------------|
99
+ | `configure_basic_logging` | Function | Configures root logger for colored console logging. |
100
+ | `setup_file_logging` | Function | Configures a logger with file output (rotation), optional console, JSON formatting. |
101
+ | `LogTimer` | Class | Context manager and decorator to log execution time of code blocks or functions. |
102
+ | `log_spark_dataframe_info`| Function | Logs schema, sample, stats of a PySpark DataFrame (row count, sample, stats, etc). |
103
+ | `LogMetrics` | Class | Utility for collecting, incrementing, timing, and logging custom processing metrics. |
104
+ | `get_logger` | Function | Returns a logger with custom handlers and caplog-friendly mode for pytest. |
105
+ ```
106
+ ---
107
+
108
+ ### Utility Classes
109
+ #### LogTimer
110
+ - Context manager: with LogTimer(logger, "operation"):
111
+ - Decorator: @LogTimer.decorator(logger, "function")
112
+ - Manual: timer.start() / timer.stop()
113
+
114
+ #### LogMetrics
115
+ - Counters: metrics.increment('counter')
116
+ - Timers: metrics.start('timer') / metrics.stop('timer')
117
+ - Context manager: with metrics.timer('operation'):
118
+ - Report: metrics.log_all()
119
+
120
+ ---
121
+
122
+ ## ๐Ÿš€ Quick Start
123
+
124
+ ```python
125
+ import logging
126
+ from logging_metrics import setup_file_logging, LogTimer
127
+
128
+ # Basic configuration
129
+ logger = setup_file_logging(
130
+ logger_name="my_app",
131
+ log_dir="./logs",
132
+ console_level=logging.INFO, # Less verbose in console
133
+ level=logging.DEBUG # More detailed in the file
134
+ )
135
+
136
+ # Simple usage
137
+ logger.info("Application started!")
138
+
139
+ # Timing operations
140
+ with LogTimer(logger, "Critical operation"):
141
+ # your code here
142
+ pass
143
+ ```
144
+
145
+ ---
146
+
147
+ ## ๐Ÿ“– Main Features
148
+
149
+ 1. Logging configuration:
150
+ ```python
151
+ import logging
152
+ from logging-metrics import configure_basic_logging
153
+ logger = configure_basic_logging()
154
+ logger.debug("Debug message") # Gray
155
+ logger.info("Info") # Green
156
+ logger.warning("Warning") # Yellow
157
+ logger.error("Error") # Red
158
+ logger.critical("Critical") # Bold red
159
+ ```
160
+
161
+ 2. Automatic Log Rotation:
162
+ ```python
163
+ from logging-metrics import setup_file_logging, LogTimer
164
+ # Size-based rotation
165
+ logger = setup_file_logging(
166
+ logger_name="app",
167
+ log_dir="./logs",
168
+ max_bytes=10*1024*1024, # 10MB
169
+ rotation='size'
170
+ )
171
+
172
+ # Time-based rotation
173
+ logger = setup_file_logging(
174
+ logger_name="app",
175
+ log_dir="./logs",
176
+ rotation='time'
177
+ )
178
+ ```
179
+
180
+ 3. Spark/Databricks Integration:
181
+ ```python
182
+ from pyspark.sql import SparkSession
183
+ from logging_metrics import configure_basic_logging, log_spark_dataframe_info
184
+
185
+ spark = SparkSession.builder.getOrCreate()
186
+ df = spark.createDataFrame([(1, "Ana"), (2, "Bruno")], ["id", "nome"])
187
+
188
+ logger = configure_basic_logging()
189
+ print("Logger:", logger)
190
+
191
+ log_spark_dataframe_info(
192
+ df = df,logger = logger, name ="spark_app")
193
+
194
+ logger.info("Spark processing started")
195
+ ```
196
+
197
+ 4. โฑ Timing with LogTimer:
198
+ ```python
199
+ from logging_metrics import LogTimer, configure_basic_logging
200
+
201
+ logger = configure_basic_logging()
202
+ # As a context manager
203
+ with LogTimer(logger, "DB query"):
204
+ logger.info("Test")
205
+
206
+ # As a decorator
207
+ @LogTimer.as_decorator(logger, "Data processing")
208
+ def process_data(data):
209
+ return data.transform()
210
+ ```
211
+
212
+ 5. ๐Ÿ“ˆ Metrics Monitoring:
213
+ ```python
214
+ from logging_metrics import LogMetrics, configure_basic_logging
215
+ import time
216
+
217
+ logger = configure_basic_logging()
218
+
219
+ metrics = LogMetrics(logger)
220
+
221
+ items = [10, 5, 80, 60, 'test1', 'test2']
222
+
223
+ # Start timer for total operation
224
+ metrics.start('total_processing')
225
+
226
+
227
+ for item in items:
228
+ # Increments the processed records counter
229
+ metrics.increment('records_processed')
230
+
231
+ # If it is an error (simulation)
232
+ if isinstance(item, str):
233
+ metrics.increment('errors')
234
+
235
+ # Simulates item processing
236
+ time.sleep(0.1)
237
+
238
+ # Custom value example
239
+ metrics.set('last_item', item)
240
+
241
+
242
+ # Finalize and log all metrics
243
+ elapsed = metrics.stop('total_processing')
244
+
245
+ # Logs all collected metrics
246
+ metrics.log_all()
247
+
248
+ # Output:
249
+ # --- Processing Metrics ---
250
+ # Counters:
251
+ # - records_processed: 6
252
+ # - errors_found: 2
253
+ # Values:
254
+ # - last_item: test2
255
+ # Completed timers:
256
+ # - total_processing: 0.60 seconds
257
+ ```
258
+
259
+ 6. Hierarchical Configuration:
260
+ ```python
261
+ from logging_metrics import setup_file_logging
262
+ import logging
263
+
264
+ # Main logger
265
+ main_logger = setup_file_logging("my_app", log_dir="./logs")
266
+
267
+ # Sub-loggers organized hierarchically
268
+ db_logger = logging.getLogger("my_app.database")
269
+ api_logger = logging.getLogger("my_app.api")
270
+ auth_logger = logging.getLogger("my_app.auth")
271
+
272
+ # Module-specific configuration
273
+ db_logger.setLevel(logging.DEBUG) # More verbose for DB
274
+ api_logger.setLevel(logging.INFO) # Normal for API
275
+ auth_logger.setLevel(logging.WARNING) # Only warnings/errors for auth
276
+
277
+ db_logger.debug("querying the database")
278
+ db_logger.info("consultation successfully completed")
279
+ db_logger.error("Error connecting to database!")
280
+
281
+ auth_logger.debug("doing authentication")
282
+ auth_logger.info("authentication successfully completed")
283
+ api_logger.debug("querying the api")
284
+ api_logger.info("consultation successfully completed")
285
+ api_logger.error("Error querying the api")
286
+ auth_logger.error("Auth error!")
287
+ ```
288
+
289
+ 7. ๐Ÿ“Š JSON Format for Observability:
290
+ ```python
291
+ from logging_metrics import setup_file_logging
292
+
293
+ # JSON logs for integration with ELK, Grafana, etc.
294
+ logger = setup_file_logging(
295
+ logger_name="microservice",
296
+ log_dir="./logs",
297
+ json_format = True
298
+ )
299
+
300
+ logger.info("User logged in", extra={"user_id": 12345, "action": "login"})
301
+
302
+ # Example JSON output:
303
+ # {
304
+ # "timestamp": "2024-08-05T10:30:00.123Z",
305
+ # "level": "INFO",
306
+ # "name": "microservice",
307
+ # "message": "User logged in",
308
+ # "module": "user-api",
309
+ # "function": "<module>",
310
+ # "line": 160,
311
+ # "taskName": null,
312
+ # "user_id": 12345,
313
+ # "action": "login"
314
+ # }
315
+ ```
316
+
317
+ ---
318
+
319
+ ## ๐Ÿ† Best Practices
320
+
321
+ 1. Configure logging once at the start:
322
+ ```python
323
+ # In main.py or __init__.py
324
+ logger = setup_file_logging("my_app", log_dir="./logs")
325
+ ```
326
+
327
+ 2. Use logger hierarchy:
328
+ ```python
329
+ # Organize by modules/features
330
+ db_logger = logging.getLogger("app.database")
331
+ api_logger = logging.getLogger("app.api")
332
+ ```
333
+
334
+ 3. Different levels for console and file:
335
+ ```python
336
+ logger = setup_file_logging(
337
+ console_level=logging.WARNING, # Less verbose in console
338
+ level=logging.DEBUG # More detailed in the file
339
+ )
340
+ ```
341
+
342
+ 4. Use LogTimer for critical operations:
343
+ ```python
344
+ with LogTimer(logger, "Complex query"):
345
+ result = run_heavy_query()
346
+ ```
347
+
348
+ 5. Monitor metrics in long processes:
349
+ ```python
350
+ metrics = LogMetrics(logger)
351
+ for batch in batches:
352
+ with metrics.timer('batch_processing'):
353
+ process_batch(batch)
354
+ ```
355
+
356
+ ---
357
+
358
+ ## โŒ Avoid
359
+ - Configuring loggers multiple times
360
+ - Using print() instead of logger
361
+ - Excessive logging in critical loops
362
+ - Exposing sensitive information in logs
363
+ - Ignoring log file rotation
364
+
365
+ ---
366
+
367
+ ## ๐Ÿ”ง Advanced Configuration
368
+
369
+ Example of full configuration:
370
+ ```python
371
+ from logging_metrics import setup_file_logging, LogMetrics
372
+ import logging
373
+
374
+ # Main configuration with all options
375
+ logger = setup_file_logging(
376
+ logger_name="my_app",
377
+ log_folder: str = "unknown/"
378
+ log_dir="./logs",
379
+ level=logging.DEBUG,
380
+ console_level=logging.INFO,
381
+ rotation='time',
382
+ log_format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
383
+ date_format="%Y-%m-%d %H:%M:%S",
384
+ max_bytes=50*1024*1024, # 50MB
385
+ backup_count=10,
386
+ add_console= True
387
+ )
388
+
389
+ # Sub-module configuration
390
+ modules = ['database', 'api', 'auth', 'cache']
391
+ for module in modules:
392
+ module_logger = logging.getLogger(f"my_app.{module}")
393
+ module_logger.setLevel(logging.INFO)
394
+ ```
395
+
396
+ ---
397
+
398
+ ## ๐Ÿงช Complete Example
399
+
400
+ ```python
401
+ import logging
402
+ from logging_metrics import setup_file_logging, LogTimer, LogMetrics
403
+
404
+ def main():
405
+ # Initial configuration
406
+ logger = setup_file_logging(
407
+ logger_name="data_processor",
408
+ log_dir="./logs",
409
+ console_level=logging.INFO,
410
+ level=logging.DEBUG
411
+ )
412
+
413
+ # Sub-loggers
414
+ db_logger = logging.getLogger("data_processor.database")
415
+ api_logger = logging.getLogger("data_processor.api")
416
+
417
+ # Metrics
418
+ metrics = LogMetrics(logger)
419
+
420
+ logger.info("Application started")
421
+
422
+ try:
423
+ # Main processing with timing
424
+ with LogTimer(logger, "Full processing"):
425
+ metrics.start('total_processing')
426
+
427
+ # Simulate processing
428
+ for i in range(1000):
429
+ metrics.increment('records_processed')
430
+
431
+ if i % 100 == 0:
432
+ logger.info(f"Processed {i} records")
433
+
434
+ # Simulate occasional error
435
+ if i % 250 == 0:
436
+ metrics.increment('errors_recovered')
437
+ logger.warning(f"Recovered error at record {i}")
438
+
439
+ metrics.stop('total_processing')
440
+ metrics.log_all()
441
+
442
+ logger.info("Processing successfully completed")
443
+
444
+ except Exception as e:
445
+ logger.error(f"Error during processing: {e}", exc_info=True)
446
+ raise
447
+
448
+ if __name__ == "__main__":
449
+ main()
450
+ ```
451
+
452
+ ---
453
+
454
+ ## ๐Ÿงช Tests
455
+
456
+ The library has a complete test suite to ensure quality and reliability.
457
+
458
+ #### Running the tests:
459
+ ```bash
460
+ # Install development dependencies
461
+ pip install -e ".[dev]"
462
+
463
+ # Run all tests
464
+ make test
465
+
466
+ # Tests with coverage
467
+ make test-cov
468
+
469
+ # Specific tests
470
+ pytest test/test_file_logging.py -v
471
+
472
+ # Tests with different verbosity levels
473
+ pytest test/ -v # Verbose
474
+ pytest test/ -s # No output capture
475
+ pytest test/ --tb=short # Short traceback
476
+ ```
477
+
478
+ #### Test Structure
479
+ ```
480
+ test/
481
+ โ”œโ”€โ”€ conftest.py # Shared pytest fixtures and test configurations
482
+ โ”œโ”€โ”€ Makefile # Automation commands for testing, linting, and build tasks
483
+ โ”œโ”€โ”€ pytest.ini # Global pytest configuration settings
484
+ โ”œโ”€โ”€ run_tests.py # Script to run all tests automatically
485
+ โ”œโ”€โ”€ test-requirements.txt # Development and test dependencies
486
+ โ”œโ”€โ”€ TEST_GUIDE.md # Quick guide: how to run and interpret tests
487
+ โ””โ”€โ”€ test_logging_metrics.py # Automated tests for the logging_metrics library
488
+ ```
489
+
490
+ #### Current coverage
491
+ ```
492
+ # Coverage report
493
+ Name Stmts Miss Cover
494
+ -----------------------------------------------
495
+ src/logging_metrics/__init__.py 12 0 100%
496
+ src/logging_metrics/console.py 45 2 96%
497
+ src/logging_metrics/file.py 78 3 96%
498
+ src/logging_metrics/spark.py 32 1 97%
499
+ src/logging_metrics/timer.py 56 2 96%
500
+ src/logging_metrics/metrics.py 89 4 96%
501
+ -----------------------------------------------
502
+ TOTAL 312 12 96%
503
+ ```
504
+
505
+ #### Running tests in different environments
506
+ ```bash
507
+ # Test in multiple Python versions with tox
508
+ pip install tox
509
+
510
+ tox
511
+
512
+ # Specific configurations
513
+ tox -e py38 # Python 3.8
514
+ tox -e py39 # Python 3.9
515
+ tox -e py310 # Python 3.10
516
+ tox -e py311 # Python 3.11
517
+ tox -e py312 # Python 3.12
518
+ tox -e lint # Only linting
519
+ tox -e coverage # Only coverage
520
+ ```
521
+
522
+ #### Running tests in CI/CD
523
+ Tests are run automatically in:
524
+
525
+ ---
526
+
527
+
528
+ ## ๐Ÿ”ง Requirements
529
+
530
+ Python: >= 3.8
531
+
532
+ Dependencies:
533
+
534
+ - pytz (for timezone handling)
535
+ - pyspark
536
+
537
+ ---
538
+
539
+ ## ๐Ÿ“ Changelog
540
+
541
+ v0.1.2 (Current)
542
+ - Initial stable version
543
+ - LogTimer and LogMetrics
544
+ - Spark integration
545
+ - Colored logs
546
+ - JSON log support
547
+ - Fixed file rotation bug on Windows
548
+ - Expanded documentation with more examples
549
+
550
+ ---
551
+
552
+ ## ๐Ÿค Contributing
553
+
554
+ #### Contributions are welcome!
555
+ 1. Fork the project
556
+ 2. Create your feature branch (`git checkout -b feature/logging-toolkit`)
557
+ 3. Commit your changes (`git commit -m 'Add logging-toolkit'`)
558
+ 4. Push to the branch (`git push origin feature/logging-toolkit`)
559
+ 5. Open a Pull Request
560
+
561
+ ---
562
+
563
+ ## License
564
+
565
+ MIT License. See LICENSE for details.