pythonLogs 4.0.1__tar.gz → 4.0.2__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.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pythonLogs
3
- Version: 4.0.1
4
- Summary: A modern, high-performance Python logging library with automatic file rotation, factory pattern for easy logger creation, and optimized caching for better performance.
3
+ Version: 4.0.2
4
+ Summary: High-performance Python logging library with file rotation and optimized caching for better performance
5
5
  License: MIT
6
6
  Keywords: python3,python-3,python,log,logging,logger,logutils,log-utils,pythonLogs
7
7
  Author: Daniel Costa
@@ -21,6 +21,7 @@ Classifier: Programming Language :: Python :: 3.12
21
21
  Classifier: Programming Language :: Python :: 3.13
22
22
  Classifier: Programming Language :: Python :: 3 :: Only
23
23
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Dist: pydantic (>=2.11.7,<3.0.0)
24
25
  Requires-Dist: pydantic-settings (>=2.10.1,<3.0.0)
25
26
  Requires-Dist: python-dotenv (>=1.1.1,<2.0.0)
26
27
  Project-URL: Homepage, https://pypi.org/project/pythonLogs
@@ -40,7 +41,7 @@ Description-Content-Type: text/markdown
40
41
 
41
42
  [![Support me on GitHub](https://img.shields.io/badge/Support_me_on_GitHub-154c79?style=for-the-badge&logo=github)](https://github.com/sponsors/ddc)
42
43
 
43
- A modern, high-performance Python logging library with automatic file rotation, context manager support, and memory optimization.
44
+ High-performance Python logging library with file rotation and optimized caching for better performance
44
45
 
45
46
 
46
47
  ## Table of Contents
@@ -413,18 +414,28 @@ error_logger.error("Database connection failed")
413
414
  audit_logger.info("User admin logged in")
414
415
  ```
415
416
 
416
- ## Env Variables (Optional)
417
+ ## Env Variables (Optional | Production)
418
+ .env variables can be used by leaving all options blank when calling the function
419
+ If not specified inside the .env file, it will use the dafault value
420
+ This is a good approach for production environments, since options can be changed easily
421
+ ```python
422
+ from pythonLogs import timed_rotating_logger
423
+ log = timed_rotating_logger()
424
+ ```
425
+
417
426
  ```
418
427
  LOG_LEVEL=DEBUG
419
- LOG_TIMEZONE=America/Chicago
428
+ LOG_TIMEZONE=UTC
420
429
  LOG_ENCODING=UTF-8
421
430
  LOG_APPNAME=app
422
431
  LOG_FILENAME=app.log
423
432
  LOG_DIRECTORY=/app/logs
424
433
  LOG_DAYS_TO_KEEP=30
434
+ LOG_DATE_FORMAT=%Y-%m-%dT%H:%M:%S
425
435
  LOG_STREAM_HANDLER=True
426
436
  LOG_SHOW_LOCATION=False
427
- LOG_DATE_FORMAT=%Y-%m-%dT%H:%M:%S
437
+ LOG_MAX_LOGGERS=50
438
+ LOG_LOGGER_TTL_SECONDS=1800
428
439
 
429
440
  # SizeRotatingLog
430
441
  LOG_MAX_FILE_SIZE_MB=10
@@ -432,6 +443,7 @@ LOG_MAX_FILE_SIZE_MB=10
432
443
  # TimedRotatingLog
433
444
  LOG_ROTATE_WHEN=midnight
434
445
  LOG_ROTATE_AT_UTC=True
446
+ LOG_ROTATE_FILE_SUFIX="%Y%m%d"
435
447
  ```
436
448
 
437
449
 
@@ -11,7 +11,7 @@
11
11
 
12
12
  [![Support me on GitHub](https://img.shields.io/badge/Support_me_on_GitHub-154c79?style=for-the-badge&logo=github)](https://github.com/sponsors/ddc)
13
13
 
14
- A modern, high-performance Python logging library with automatic file rotation, context manager support, and memory optimization.
14
+ High-performance Python logging library with file rotation and optimized caching for better performance
15
15
 
16
16
 
17
17
  ## Table of Contents
@@ -384,18 +384,28 @@ error_logger.error("Database connection failed")
384
384
  audit_logger.info("User admin logged in")
385
385
  ```
386
386
 
387
- ## Env Variables (Optional)
387
+ ## Env Variables (Optional | Production)
388
+ .env variables can be used by leaving all options blank when calling the function
389
+ If not specified inside the .env file, it will use the dafault value
390
+ This is a good approach for production environments, since options can be changed easily
391
+ ```python
392
+ from pythonLogs import timed_rotating_logger
393
+ log = timed_rotating_logger()
394
+ ```
395
+
388
396
  ```
389
397
  LOG_LEVEL=DEBUG
390
- LOG_TIMEZONE=America/Chicago
398
+ LOG_TIMEZONE=UTC
391
399
  LOG_ENCODING=UTF-8
392
400
  LOG_APPNAME=app
393
401
  LOG_FILENAME=app.log
394
402
  LOG_DIRECTORY=/app/logs
395
403
  LOG_DAYS_TO_KEEP=30
404
+ LOG_DATE_FORMAT=%Y-%m-%dT%H:%M:%S
396
405
  LOG_STREAM_HANDLER=True
397
406
  LOG_SHOW_LOCATION=False
398
- LOG_DATE_FORMAT=%Y-%m-%dT%H:%M:%S
407
+ LOG_MAX_LOGGERS=50
408
+ LOG_LOGGER_TTL_SECONDS=1800
399
409
 
400
410
  # SizeRotatingLog
401
411
  LOG_MAX_FILE_SIZE_MB=10
@@ -403,6 +413,7 @@ LOG_MAX_FILE_SIZE_MB=10
403
413
  # TimedRotatingLog
404
414
  LOG_ROTATE_WHEN=midnight
405
415
  LOG_ROTATE_AT_UTC=True
416
+ LOG_ROTATE_FILE_SUFIX="%Y%m%d"
406
417
  ```
407
418
 
408
419
 
@@ -5,8 +5,8 @@ build-backend = "poetry.core.masonry.api"
5
5
 
6
6
  [tool.poetry]
7
7
  name = "pythonLogs"
8
- version = "4.0.1"
9
- description = "A modern, high-performance Python logging library with automatic file rotation, factory pattern for easy logger creation, and optimized caching for better performance."
8
+ version = "4.0.2"
9
+ description = "High-performance Python logging library with file rotation and optimized caching for better performance"
10
10
  license = "MIT"
11
11
  readme = "README.md"
12
12
  authors = ["Daniel Costa <danieldcsta@gmail.com>"]
@@ -34,6 +34,7 @@ classifiers = [
34
34
 
35
35
  [tool.poetry.dependencies]
36
36
  python = "^3.10"
37
+ pydantic = "^2.11.7"
37
38
  pydantic-settings = "^2.10.1"
38
39
  python-dotenv = "^1.1.1"
39
40
 
@@ -48,6 +49,12 @@ pytest = "^8.4.1"
48
49
  [tool.poetry.group.test]
49
50
  optional = true
50
51
 
52
+
53
+ [tool.black]
54
+ line-length = 120
55
+ skip-string-normalization = true
56
+
57
+
51
58
  [tool.pytest.ini_options]
52
59
  markers = [
53
60
  "slow: marks tests as slow (deselect with '-m \"not slow\"')"
@@ -60,6 +67,12 @@ omit = [
60
67
  ]
61
68
 
62
69
 
70
+ [tool.coverage.report]
71
+ exclude_lines = [
72
+ "pragma: no cover",
73
+ ]
74
+
75
+
63
76
  [tool.poe.tasks]
64
77
  _test = "coverage run -m pytest -v"
65
78
  _coverage_report = "coverage report"
@@ -5,9 +5,11 @@ LOG_APPNAME=app
5
5
  LOG_FILENAME=app.log
6
6
  LOG_DIRECTORY=/app/logs
7
7
  LOG_DAYS_TO_KEEP=30
8
+ LOG_DATE_FORMAT=%Y-%m-%dT%H:%M:%S
8
9
  LOG_STREAM_HANDLER=True
9
10
  LOG_SHOW_LOCATION=False
10
- LOG_DATE_FORMAT=%Y-%m-%dT%H:%M:%S
11
+ LOG_MAX_LOGGERS=50
12
+ LOG_LOGGER_TTL_SECONDS=1800
11
13
 
12
14
  # SizeRotatingLog
13
15
  LOG_MAX_FILE_SIZE_MB=10
@@ -15,3 +17,4 @@ LOG_MAX_FILE_SIZE_MB=10
15
17
  # TimedRotatingLog
16
18
  LOG_ROTATE_WHEN=midnight
17
19
  LOG_ROTATE_AT_UTC=True
20
+ LOG_ROTATE_FILE_SUFIX="%Y%m%d"
@@ -1,4 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ import atexit
2
3
  import logging
3
4
  import threading
4
5
  import time
@@ -28,6 +29,23 @@ class LoggerFactory:
28
29
  # Memory optimization settings
29
30
  _max_loggers = 100 # Maximum number of cached loggers
30
31
  _logger_ttl = 3600 # Logger TTL in seconds (1 hour)
32
+ _initialized = False # Flag to track if memory limits have been initialized
33
+ _atexit_registered = False # Flag to track if atexit cleanup is registered
34
+
35
+ @classmethod
36
+ def _ensure_initialized(cls) -> None:
37
+ """Ensure memory limits are initialized from settings on first use."""
38
+ if not cls._initialized:
39
+ from pythonLogs.settings import get_log_settings
40
+ settings = get_log_settings()
41
+ cls._max_loggers = settings.max_loggers
42
+ cls._logger_ttl = settings.logger_ttl_seconds
43
+ cls._initialized = True
44
+
45
+ # Register atexit cleanup on first use
46
+ if not cls._atexit_registered:
47
+ atexit.register(cls._atexit_cleanup)
48
+ cls._atexit_registered = True
31
49
 
32
50
  @classmethod
33
51
  def get_or_create_logger(
@@ -54,6 +72,9 @@ class LoggerFactory:
54
72
 
55
73
  # Thread-safe check-and-create operation
56
74
  with cls._registry_lock:
75
+ # Initialize memory limits from settings on first use
76
+ cls._ensure_initialized()
77
+
57
78
  # Clean up expired loggers first
58
79
  cls._cleanup_expired_loggers()
59
80
 
@@ -114,7 +135,7 @@ class LoggerFactory:
114
135
 
115
136
  @classmethod
116
137
  def set_memory_limits(cls, max_loggers: int = 100, ttl_seconds: int = 3600) -> None:
117
- """Configure memory management limits for the logger registry.
138
+ """Configure memory management limits for the logger registry at runtime.
118
139
 
119
140
  Args:
120
141
  max_loggers: Maximum number of cached loggers
@@ -123,10 +144,20 @@ class LoggerFactory:
123
144
  with cls._registry_lock:
124
145
  cls._max_loggers = max_loggers
125
146
  cls._logger_ttl = ttl_seconds
147
+ cls._initialized = True # Mark as manually configured
126
148
  # Clean up immediately with new settings
127
149
  cls._cleanup_expired_loggers()
128
150
  cls._enforce_size_limit()
129
151
 
152
+ @classmethod
153
+ def _atexit_cleanup(cls) -> None:
154
+ """Cleanup function registered with atexit to ensure proper resource cleanup."""
155
+ try:
156
+ cls.clear_registry()
157
+ except Exception:
158
+ # Silently ignore exceptions during shutdown cleanup
159
+ pass
160
+
130
161
  @staticmethod
131
162
  def _cleanup_logger(logger: logging.Logger) -> None:
132
163
  """Clean up logger resources by closing all handlers."""
@@ -23,15 +23,18 @@ class LogSettings(BaseSettings):
23
23
  """If any ENV variable is omitted, it falls back to default values here"""
24
24
 
25
25
  level: Optional[LogLevel] = Field(default=LogLevel.INFO)
26
+ timezone: Optional[str] = Field(default=DEFAULT_TIMEZONE)
27
+ encoding: Optional[str] = Field(default=DEFAULT_ENCODING)
26
28
  appname: Optional[str] = Field(default="app")
27
- directory: Optional[str] = Field(default="/app/logs")
28
29
  filename: Optional[str] = Field(default="app.log")
29
- encoding: Optional[str] = Field(default=DEFAULT_ENCODING)
30
- date_format: Optional[str] = Field(default=DEFAULT_DATE_FORMAT)
30
+ directory: Optional[str] = Field(default="/app/logs")
31
31
  days_to_keep: Optional[int] = Field(default=DEFAULT_BACKUP_COUNT)
32
- timezone: Optional[str] = Field(default=DEFAULT_TIMEZONE)
32
+ date_format: Optional[str] = Field(default=DEFAULT_DATE_FORMAT)
33
33
  stream_handler: Optional[bool] = Field(default=True)
34
34
  show_location: Optional[bool] = Field(default=False)
35
+ # Memory management
36
+ max_loggers: Optional[int] = Field(default=100)
37
+ logger_ttl_seconds: Optional[int] = Field(default=3600)
35
38
 
36
39
  # SizeRotatingLog
37
40
  max_file_size_mb: Optional[int] = Field(default=10)
File without changes