# High-performance Python logging library
[](https://www.paypal.com/ncp/payment/6G9Z78QHUD4RJ)
[](https://opensource.org/licenses/MIT)
[](https://pypi.python.org/pypi/pythonLogs)
[](https://pepy.tech/projects/pythonLogs)
[](https://codecov.io/gh/ddc/pythonLogs)
[](https://github.com/ddc/pythonLogs/actions/workflows/workflow.yml)
[](https://sonarcloud.io/dashboard?id=ddc_pythonLogs)
[](https://actions-badge.atrox.dev/ddc/pythonLogs/goto?ref=main)
[](https://github.com/psf/black)
[](https://www.python.org/downloads)
[](https://github.com/sponsors/ddc)
High-performance Python logging library with file rotation and optimized caching for better performance
## Table of Contents
- [Features](#features)
- [Installation](#installation)
- [Logger Types](#logger-types)
- [Basic Logger](#basic-logger)
- [Size Rotating Logger](#size-rotating-logger)
- [Timed Rotating Logger](#timed-rotating-logger)
- [Context Manager Support](#context-manager-support)
- [Advanced Factory Features](#advanced-factory-features)
- [Environment Variables](#env-variables-optional--production)
- [Memory Management](#memory-management)
- [Flexible Configuration Options](#flexible-configuration-options)
- [Migration Guide](#migration-guide)
- [Development](#development)
- [Development](#development)
- [Building from Source](#building-from-source)
- [Running Tests](#running-tests)
- [License](#license)
- [Support](#support)
# Features
โจ **Factory Pattern** - Easy logger creation with centralized configuration
๐ **High Performance** - Optimized caching for 90%+ performance improvements
๐ **File Rotation** - Automatic rotation by size or time with compression
๐ฏ **Type Safety** - Enum-based configuration with IDE support
โ๏ธ **Flexible Configuration** - Environment variables, direct parameters, or defaults
๐ **Location Tracking** - Optional filename and line number in logs
๐ **Timezone Support** - Full timezone handling including `localtime` and `UTC`
๐พ **Memory Efficient** - Logger registry and settings caching
๐ **Context Manager Support** - Automatic resource cleanup and exception safety
๐งต **Thread Safe** - Concurrent access protection for all operations
๐ง **Resource Management** - Automatic handler cleanup and memory leak prevention
# Installation
```shell
pip install pythonLogs
```
# Logger Types
## Basic Logger
Console-only logging without file output. Perfect for development and simple applications.
### Using Factory Pattern (Recommended)
```python
from pythonLogs import basic_logger, LogLevel
# Option 1: Using string (simple) (case-insensitive)
logger = basic_logger(
name="my_app",
level="debug", # "debug", "info", "warning", "error", "critical"
timezone="America/Sao_Paulo",
showlocation=False
)
logger.warning("This is a warning example")
# Option 2: Using enum (type-safe)
logger = basic_logger(
name="my_app",
level=LogLevel.DEBUG,
timezone="America/Sao_Paulo",
showlocation=False
)
logger.warning("This is a warning example")
```
### Legacy Method (Still Supported)
```python
from pythonLogs import BasicLog
logger = BasicLog(
level="debug",
name="app",
timezone="America/Sao_Paulo",
showlocation=False,
).init()
logger.warning("This is a warning example")
```
#### Example Output
`[2024-10-08T19:08:56.918-0300]:[WARNING]:[my_app]:This is a warning example`
## Size Rotating Logger
File-based logging with automatic rotation when files reach a specified size. Rotated files are compressed as `.gz`.
+ **Rotation**: Based on file size (`maxmbytes` parameter)
+ **Naming**: Rotated logs have sequence numbers: `app.log_1.gz`, `app.log_2.gz`
+ **Cleanup**: Old logs deleted based on `daystokeep` (default: 30 days)
### Using Factory Pattern (Recommended)
```python
from pythonLogs import size_rotating_logger, LogLevel
# Option 1: Using string (simple) (case-insensitive)
logger = size_rotating_logger(
name="my_app",
level="debug", # "debug", "info", "warning", "error", "critical"
directory="/app/logs",
filenames=["main.log", "app1.log"],
maxmbytes=5,
daystokeep=7,
timezone="America/Chicago",
streamhandler=True,
showlocation=False
)
logger.warning("This is a warning example")
# Option 2: Using enum (type-safe)
logger = size_rotating_logger(
name="my_app",
level=LogLevel.DEBUG,
directory="/app/logs",
filenames=["main.log", "app1.log"],
maxmbytes=5,
daystokeep=7,
timezone="America/Chicago",
streamhandler=True,
showlocation=False
)
logger.warning("This is a warning example")
```
### Legacy Method (Still Supported)
```python
from pythonLogs import SizeRotatingLog
logger = SizeRotatingLog(
level="debug",
name="app",
directory="/app/logs",
filenames=["main.log", "app1.log"],
maxmbytes=5,
daystokeep=7,
timezone="America/Chicago",
streamhandler=True,
showlocation=False
).init()
logger.warning("This is a warning example")
```
#### Example Output
`[2024-10-08T19:08:56.918-0500]:[WARNING]:[my_app]:This is a warning example`
## Timed Rotating Logger
File-based logging with automatic rotation based on time intervals. Rotated files are compressed as `.gz`.
+ **Rotation**: Based on time (`when` parameter, defaults to `midnight`)
+ **Naming**: Rotated logs have date suffix: `app_20240816.log.gz`
+ **Cleanup**: Old logs deleted based on `daystokeep` (default: 30 days)
+ **Supported Intervals**: `midnight`, `hourly`, `daily`, `W0-W6` (weekdays, 0=Monday)
### Using Factory Pattern (Recommended)
```python
from pythonLogs import timed_rotating_logger, LogLevel, RotateWhen
# Option 1: Using string (simple) (case-insensitive)
logger = timed_rotating_logger(
name="my_app",
level="debug", # "debug", "info", "warning", "error", "critical"
directory="/app/logs",
filenames=["main.log", "app2.log"],
when="midnight", # String when value
daystokeep=7,
timezone="UTC",
streamhandler=True,
showlocation=False
)
logger.warning("This is a warning example")
# Option 2: Using enum (type-safe)
logger = timed_rotating_logger(
name="my_app",
level=LogLevel.DEBUG, # Type-safe enum
directory="/app/logs",
filenames=["main.log", "app2.log"],
when=RotateWhen.MIDNIGHT, # Type-safe enum
daystokeep=7,
timezone="UTC",
streamhandler=True,
showlocation=False
)
logger.warning("This is a warning example")
```
### Legacy Method (Still Supported)
```python
from pythonLogs import TimedRotatingLog
logger = TimedRotatingLog(
level="debug",
name="app",
directory="/app/logs",
filenames=["main.log", "app2.log"],
when="midnight",
daystokeep=7,
timezone="UTC",
streamhandler=True,
showlocation=False
).init()
logger.warning("This is a warning example")
```
#### Example Output
`[2024-10-08T19:08:56.918-0000]:[WARNING]:[my_app]:This is a warning example`
# Context Manager Support
Slow, but if you want immediate, deterministic cleanup for a specific scope.\
All logger types support context managers for automatic resource cleanup and exception safety:
## Basic Usage
```python
from pythonLogs import BasicLog, SizeRotatingLog, TimedRotatingLog, LogLevel
# Automatic cleanup with context managers
with BasicLog(name="app", level=LogLevel.INFO) as logger:
logger.info("This is automatically cleaned up")
# Handlers are automatically closed on exit
with SizeRotatingLog(name="app", directory="/logs", filenames=["app.log"]) as logger:
logger.info("File handlers cleaned up automatically")
# File handlers closed and resources freed
# Exception safety - cleanup happens even if exceptions occur
try:
with TimedRotatingLog(name="app", directory="/logs") as logger:
logger.error("Error occurred")
raise ValueError("Something went wrong")
except ValueError:
pass # Logger was still cleaned up properly
```
## Benefits of Context Manager Usage
- ๐ **Automatic Cleanup** - Handlers are closed and removed automatically
- โก **Exception Safety** - Resources cleaned up even when exceptions occur
- ๐พ **Memory Management** - Prevents memory leaks from unclosed handlers
- ๐งต **Thread Safety** - Cleanup operations are thread-safe
- ๐ง **No Manual Management** - No need to manually call cleanup methods
## Factory Pattern + Context Managers
```python
from pythonLogs import LoggerFactory, LoggerType
# Create logger through factory and use with context manager
logger_instance = LoggerFactory.get_or_create_logger(
LoggerType.SIZE_ROTATING,
name="production_app",
directory="/var/log"
)
# Use the logger instance directly
with logger_instance as logger:
logger.info("Factory created logger with automatic cleanup")
```
# Advanced Factory Features
## Logger Registry (Performance Optimization)
The factory pattern includes a built-in registry that caches loggers for improved performance:
```python
from pythonLogs import get_or_create_logger, LoggerType, clear_logger_registry
# First call creates the logger
logger1 = get_or_create_logger(LoggerType.BASIC, name="cached_app")
# The Second call returns the same logger instance (90% faster)
logger2 = get_or_create_logger(LoggerType.BASIC, name="cached_app")
# Both variables point to the same logger instance
assert logger1 is logger2
# Clear registry when needed (useful for testing)
clear_logger_registry()
```
## Production Setup Example
```python
from pythonLogs import size_rotating_logger, timed_rotating_logger, LogLevel, RotateWhen
# Application logger
app_logger = size_rotating_logger(
name="production_app",
directory="/var/log/myapp",
filenames=["app.log"],
maxmbytes=50, # 50MB files
daystokeep=30, # Keep 30 days
level=LogLevel.INFO,
streamhandler=True, # Also log to console
showlocation=True, # Show file:function:line
timezone="UTC"
)
# Error logger with longer retention
error_logger = size_rotating_logger(
name="production_errors",
directory="/var/log/myapp",
filenames=["errors.log"],
maxmbytes=10,
daystokeep=90, # Keep errors longer
level=LogLevel.ERROR,
streamhandler=False
)
# Audit logger with daily rotation
audit_logger = timed_rotating_logger(
name="audit_log",
directory="/var/log/myapp",
filenames=["audit.log"],
when=RotateWhen.MIDNIGHT,
level=LogLevel.INFO
)
# Use the loggers
app_logger.info("Application started")
error_logger.error("Database connection failed")
audit_logger.info("User admin logged in")
```
## Env Variables (Optional | Production)
The .env variables file can be used by leaving all options blank when calling the function.\
If not specified inside the .env file, it will use the dafault value.\
This is a good approach for production environments, since options can be changed easily.
```python
from pythonLogs import timed_rotating_logger
log = timed_rotating_logger()
```
```
LOG_LEVEL=DEBUG
LOG_TIMEZONE=UTC
LOG_ENCODING=UTF-8
LOG_APPNAME=app
LOG_FILENAME=app.log
LOG_DIRECTORY=/app/logs
LOG_DAYS_TO_KEEP=30
LOG_DATE_FORMAT=%Y-%m-%dT%H:%M:%S
LOG_STREAM_HANDLER=True
LOG_SHOW_LOCATION=False
LOG_MAX_LOGGERS=50
LOG_LOGGER_TTL_SECONDS=1800
# SizeRotatingLog
LOG_MAX_FILE_SIZE_MB=10
# TimedRotatingLog
LOG_ROTATE_WHEN=midnight
LOG_ROTATE_AT_UTC=True
LOG_ROTATE_FILE_SUFIX="%Y%m%d"
```
# Memory Management
The library includes comprehensive memory management features to prevent memory leaks and optimize resource usage:
## Automatic Resource Cleanup
```python
from pythonLogs import clear_logger_registry, shutdown_logger, LoggerFactory
# Clear the entire logger registry with proper cleanup
clear_logger_registry()
# Shutdown specific logger and remove from registry
shutdown_logger("my_app_logger")
# Manual registry management
LoggerFactory.shutdown_logger("specific_logger")
LoggerFactory.clear_registry()
```
## Memory Optimization Features
```python
from pythonLogs import (
get_memory_stats,
clear_formatter_cache,
clear_directory_cache,
optimize_lru_cache_sizes,
force_garbage_collection
)
# Get current memory usage statistics
stats = get_memory_stats()
print(f"Registry size: {stats['registry_size']}")
print(f"Formatter cache: {stats['formatter_cache_size']}")
print(f"Active loggers: {stats['active_logger_count']}")
# Clear various caches to free memory
clear_formatter_cache() # Clear cached formatters
clear_directory_cache() # Clear directory permission cache
# Optimize LRU cache sizes for memory-constrained environments
optimize_lru_cache_sizes()
# Force garbage collection and get collection statistics
gc_stats = force_garbage_collection()
print(f"Objects collected: {gc_stats['objects_collected']}")
```
## Registry Configuration
```python
from pythonLogs import LoggerFactory
# Configure registry limits for memory management
LoggerFactory.set_memory_limits(
max_loggers=50, # Maximum cached loggers
ttl_seconds=1800 # Logger time-to-live (30 minutes)
)
# Monitor registered loggers
registered = LoggerFactory.get_registered_loggers()
print(f"Currently registered: {list(registered.keys())}")
```
# Flexible Configuration Options
You can use either enums (for type safety) or strings (for simplicity):
```python
from pythonLogs import LogLevel, RotateWhen, LoggerType
# Option 1: Type-safe enums (recommended)
LogLevel.DEBUG # "DEBUG"
LogLevel.INFO # "INFO"
LogLevel.WARNING # "WARNING"
LogLevel.ERROR # "ERROR"
LogLevel.CRITICAL # "CRITICAL"
# Option 2: String values (case-insensitive)
"debug" # Same as LogLevel.DEBUG
"info" # Same as LogLevel.INFO
"warning" # Same as LogLevel.WARNING
"warn" # Same as LogLevel.WARN (alias)
"error" # Same as LogLevel.ERROR
"critical" # Same as LogLevel.CRITICAL
"crit" # Same as LogLevel.CRIT (alias)
# Also supports: "DEBUG", "Info", "Warning", etc.
# RotateWhen values
RotateWhen.MIDNIGHT # "midnight"
RotateWhen.HOURLY # "H"
RotateWhen.DAILY # "D"
RotateWhen.MONDAY # "W0"
# ... through SUNDAY # "W6"
# String equivalents: "midnight", "H", "D", "W0"-"W6"
# LoggerType values
LoggerType.BASIC # "basic"
LoggerType.SIZE_ROTATING # "size_rotating"
LoggerType.TIMED_ROTATING # "timed_rotating"
# String equivalents: "basic", "size_rotating", "timed_rotating"
```
# Migration Guide
## Upgrading from Legacy to Factory Pattern
The factory pattern is **100% backward compatible**. Your existing code will continue to work unchanged.
### Before (Legacy - Still Works)
```python
from pythonLogs import BasicLog, SizeRotatingLog, TimedRotatingLog
# Old way
basic_logger = BasicLog(level="info", name="app").init()
size_logger = SizeRotatingLog(level="debug", name="app", directory="/logs").init()
timed_logger = TimedRotatingLog(level="warning", name="app", directory="/logs").init()
```
### After (Factory Pattern - Recommended)
```python
from pythonLogs import basic_logger, size_rotating_logger, timed_rotating_logger, LogLevel
# New way - cleaner and faster
basic_logger = basic_logger(level=LogLevel.INFO, name="app")
size_logger = size_rotating_logger(level=LogLevel.DEBUG, name="app", directory="/logs")
timed_logger = timed_rotating_logger(level=LogLevel.WARNING, name="app", directory="/logs")
```
### Benefits of Migration
- ๐ **90% faster logger creation** with registry caching
- ๐ฏ **Type safety** with enum-based parameters
- ๐ก **Better IDE support** with autocomplete and validation
- ๐ง **Cleaner API** without manual `.init()` calls
- ๐ **Centralized configuration** through factory pattern
# Development
### Building from Source
```shell
poetry build -f wheel
```
### Running Tests
```shell
poetry update --with test
poe tests
```
# License
Released under the [MIT License](LICENSE)
# Support
If you find this project helpful, consider supporting development:
- [GitHub Sponsor](https://github.com/sponsors/ddc)
- [ko-fi](https://ko-fi.com/ddcsta)
- [PayPal](https://www.paypal.com/ncp/payment/6G9Z78QHUD4RJ)
Raw data
{
"_id": null,
"home_page": null,
"name": "pythonLogs",
"maintainer": "Daniel Costa",
"docs_url": null,
"requires_python": "<4.0,>=3.12",
"maintainer_email": null,
"keywords": "python3, python-3, python, log, logging, logger, logutils, log-utils, pythonLogs",
"author": "Daniel Costa",
"author_email": "danieldcsta@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/0a/b8/27287201386f199d3c19ad237f66f964a48a400f90d0779c9e8db7c9781c/pythonlogs-5.0.1.tar.gz",
"platform": null,
"description": "# High-performance Python logging library\n\n[](https://www.paypal.com/ncp/payment/6G9Z78QHUD4RJ)\n[](https://opensource.org/licenses/MIT)\n[](https://pypi.python.org/pypi/pythonLogs)\n[](https://pepy.tech/projects/pythonLogs)\n[](https://codecov.io/gh/ddc/pythonLogs)\n[](https://github.com/ddc/pythonLogs/actions/workflows/workflow.yml)\n[](https://sonarcloud.io/dashboard?id=ddc_pythonLogs) \n[](https://actions-badge.atrox.dev/ddc/pythonLogs/goto?ref=main)\n[](https://github.com/psf/black)\n[](https://www.python.org/downloads)\n\n[](https://github.com/sponsors/ddc)\n\nHigh-performance Python logging library with file rotation and optimized caching for better performance\n\n\n## Table of Contents\n\n- [Features](#features)\n- [Installation](#installation)\n- [Logger Types](#logger-types)\n - [Basic Logger](#basic-logger)\n - [Size Rotating Logger](#size-rotating-logger)\n - [Timed Rotating Logger](#timed-rotating-logger)\n- [Context Manager Support](#context-manager-support)\n- [Advanced Factory Features](#advanced-factory-features)\n- [Environment Variables](#env-variables-optional--production)\n- [Memory Management](#memory-management)\n- [Flexible Configuration Options](#flexible-configuration-options)\n- [Migration Guide](#migration-guide)\n- [Development](#development)\n- [Development](#development)\n - [Building from Source](#building-from-source)\n - [Running Tests](#running-tests)\n- [License](#license)\n- [Support](#support)\n\n\n\n# Features\n\n\u2728 **Factory Pattern** - Easy logger creation with centralized configuration \n\ud83d\ude80 **High Performance** - Optimized caching for 90%+ performance improvements \n\ud83d\udd04 **File Rotation** - Automatic rotation by size or time with compression \n\ud83c\udfaf **Type Safety** - Enum-based configuration with IDE support \n\u2699\ufe0f **Flexible Configuration** - Environment variables, direct parameters, or defaults \n\ud83d\udccd **Location Tracking** - Optional filename and line number in logs \n\ud83c\udf0d **Timezone Support** - Full timezone handling including `localtime` and `UTC` \n\ud83d\udcbe **Memory Efficient** - Logger registry and settings caching \n\ud83d\udd12 **Context Manager Support** - Automatic resource cleanup and exception safety \n\ud83e\uddf5 **Thread Safe** - Concurrent access protection for all operations \n\ud83d\udd27 **Resource Management** - Automatic handler cleanup and memory leak prevention \n\n\n# Installation\n```shell\npip install pythonLogs\n```\n\n\n# Logger Types\n\n## Basic Logger\nConsole-only logging without file output. Perfect for development and simple applications.\n\n### Using Factory Pattern (Recommended)\n```python\nfrom pythonLogs import basic_logger, LogLevel\n\n# Option 1: Using string (simple) (case-insensitive)\nlogger = basic_logger(\n name=\"my_app\",\n level=\"debug\", # \"debug\", \"info\", \"warning\", \"error\", \"critical\"\n timezone=\"America/Sao_Paulo\",\n showlocation=False\n)\nlogger.warning(\"This is a warning example\")\n\n# Option 2: Using enum (type-safe)\nlogger = basic_logger(\n name=\"my_app\",\n level=LogLevel.DEBUG,\n timezone=\"America/Sao_Paulo\",\n showlocation=False\n)\nlogger.warning(\"This is a warning example\")\n```\n\n### Legacy Method (Still Supported)\n```python\nfrom pythonLogs import BasicLog\n\nlogger = BasicLog(\n level=\"debug\",\n name=\"app\",\n timezone=\"America/Sao_Paulo\",\n showlocation=False,\n).init()\nlogger.warning(\"This is a warning example\")\n```\n\n#### Example Output\n`[2024-10-08T19:08:56.918-0300]:[WARNING]:[my_app]:This is a warning example`\n\n\n\n\n\n## Size Rotating Logger\nFile-based logging with automatic rotation when files reach a specified size. Rotated files are compressed as `.gz`.\n\n+ **Rotation**: Based on file size (`maxmbytes` parameter)\n+ **Naming**: Rotated logs have sequence numbers: `app.log_1.gz`, `app.log_2.gz`\n+ **Cleanup**: Old logs deleted based on `daystokeep` (default: 30 days)\n\n### Using Factory Pattern (Recommended)\n```python\nfrom pythonLogs import size_rotating_logger, LogLevel\n\n# Option 1: Using string (simple) (case-insensitive)\nlogger = size_rotating_logger(\n name=\"my_app\",\n level=\"debug\", # \"debug\", \"info\", \"warning\", \"error\", \"critical\"\n directory=\"/app/logs\",\n filenames=[\"main.log\", \"app1.log\"],\n maxmbytes=5,\n daystokeep=7,\n timezone=\"America/Chicago\",\n streamhandler=True,\n showlocation=False\n)\nlogger.warning(\"This is a warning example\")\n\n# Option 2: Using enum (type-safe)\nlogger = size_rotating_logger(\n name=\"my_app\",\n level=LogLevel.DEBUG,\n directory=\"/app/logs\",\n filenames=[\"main.log\", \"app1.log\"],\n maxmbytes=5,\n daystokeep=7,\n timezone=\"America/Chicago\",\n streamhandler=True,\n showlocation=False\n)\nlogger.warning(\"This is a warning example\")\n```\n\n### Legacy Method (Still Supported)\n```python\nfrom pythonLogs import SizeRotatingLog\n\nlogger = SizeRotatingLog(\n level=\"debug\",\n name=\"app\",\n directory=\"/app/logs\",\n filenames=[\"main.log\", \"app1.log\"],\n maxmbytes=5,\n daystokeep=7,\n timezone=\"America/Chicago\",\n streamhandler=True,\n showlocation=False\n).init()\nlogger.warning(\"This is a warning example\")\n```\n\n#### Example Output\n`[2024-10-08T19:08:56.918-0500]:[WARNING]:[my_app]:This is a warning example`\n\n\n\n\n\n## Timed Rotating Logger\nFile-based logging with automatic rotation based on time intervals. Rotated files are compressed as `.gz`.\n\n+ **Rotation**: Based on time (`when` parameter, defaults to `midnight`)\n+ **Naming**: Rotated logs have date suffix: `app_20240816.log.gz` \n+ **Cleanup**: Old logs deleted based on `daystokeep` (default: 30 days)\n+ **Supported Intervals**: `midnight`, `hourly`, `daily`, `W0-W6` (weekdays, 0=Monday)\n\n### Using Factory Pattern (Recommended)\n```python\nfrom pythonLogs import timed_rotating_logger, LogLevel, RotateWhen\n\n# Option 1: Using string (simple) (case-insensitive)\nlogger = timed_rotating_logger(\n name=\"my_app\",\n level=\"debug\", # \"debug\", \"info\", \"warning\", \"error\", \"critical\"\n directory=\"/app/logs\", \n filenames=[\"main.log\", \"app2.log\"],\n when=\"midnight\", # String when value\n daystokeep=7,\n timezone=\"UTC\",\n streamhandler=True,\n showlocation=False\n)\nlogger.warning(\"This is a warning example\")\n\n# Option 2: Using enum (type-safe)\nlogger = timed_rotating_logger(\n name=\"my_app\",\n level=LogLevel.DEBUG, # Type-safe enum\n directory=\"/app/logs\", \n filenames=[\"main.log\", \"app2.log\"],\n when=RotateWhen.MIDNIGHT, # Type-safe enum\n daystokeep=7,\n timezone=\"UTC\",\n streamhandler=True,\n showlocation=False\n)\nlogger.warning(\"This is a warning example\")\n```\n\n### Legacy Method (Still Supported)\n```python\nfrom pythonLogs import TimedRotatingLog\n\nlogger = TimedRotatingLog(\n level=\"debug\",\n name=\"app\",\n directory=\"/app/logs\",\n filenames=[\"main.log\", \"app2.log\"],\n when=\"midnight\",\n daystokeep=7,\n timezone=\"UTC\",\n streamhandler=True,\n showlocation=False\n).init()\nlogger.warning(\"This is a warning example\")\n```\n\n#### Example Output\n`[2024-10-08T19:08:56.918-0000]:[WARNING]:[my_app]:This is a warning example`\n\n\n\n\n\n# Context Manager Support\n\nSlow, but if you want immediate, deterministic cleanup for a specific scope.\\\nAll logger types support context managers for automatic resource cleanup and exception safety:\n\n## Basic Usage\n```python\nfrom pythonLogs import BasicLog, SizeRotatingLog, TimedRotatingLog, LogLevel\n\n# Automatic cleanup with context managers\nwith BasicLog(name=\"app\", level=LogLevel.INFO) as logger:\n logger.info(\"This is automatically cleaned up\")\n # Handlers are automatically closed on exit\n\nwith SizeRotatingLog(name=\"app\", directory=\"/logs\", filenames=[\"app.log\"]) as logger:\n logger.info(\"File handlers cleaned up automatically\")\n # File handlers closed and resources freed\n\n# Exception safety - cleanup happens even if exceptions occur\ntry:\n with TimedRotatingLog(name=\"app\", directory=\"/logs\") as logger:\n logger.error(\"Error occurred\")\n raise ValueError(\"Something went wrong\")\nexcept ValueError:\n pass # Logger was still cleaned up properly\n```\n\n## Benefits of Context Manager Usage\n- \ud83d\udd12 **Automatic Cleanup** - Handlers are closed and removed automatically\n- \u26a1 **Exception Safety** - Resources cleaned up even when exceptions occur\n- \ud83d\udcbe **Memory Management** - Prevents memory leaks from unclosed handlers\n- \ud83e\uddf5 **Thread Safety** - Cleanup operations are thread-safe\n- \ud83d\udd27 **No Manual Management** - No need to manually call cleanup methods\n\n## Factory Pattern + Context Managers\n```python\nfrom pythonLogs import LoggerFactory, LoggerType\n\n# Create logger through factory and use with context manager\nlogger_instance = LoggerFactory.get_or_create_logger(\n LoggerType.SIZE_ROTATING,\n name=\"production_app\",\n directory=\"/var/log\"\n)\n\n# Use the logger instance directly\nwith logger_instance as logger:\n logger.info(\"Factory created logger with automatic cleanup\")\n```\n\n\n# Advanced Factory Features\n\n## Logger Registry (Performance Optimization)\nThe factory pattern includes a built-in registry that caches loggers for improved performance:\n\n```python\nfrom pythonLogs import get_or_create_logger, LoggerType, clear_logger_registry\n\n# First call creates the logger\nlogger1 = get_or_create_logger(LoggerType.BASIC, name=\"cached_app\")\n\n# The Second call returns the same logger instance (90% faster)\nlogger2 = get_or_create_logger(LoggerType.BASIC, name=\"cached_app\")\n\n# Both variables point to the same logger instance\nassert logger1 is logger2\n\n# Clear registry when needed (useful for testing)\nclear_logger_registry()\n```\n\n## Production Setup Example\n```python\nfrom pythonLogs import size_rotating_logger, timed_rotating_logger, LogLevel, RotateWhen\n\n# Application logger\napp_logger = size_rotating_logger(\n name=\"production_app\",\n directory=\"/var/log/myapp\",\n filenames=[\"app.log\"],\n maxmbytes=50, # 50MB files\n daystokeep=30, # Keep 30 days\n level=LogLevel.INFO,\n streamhandler=True, # Also log to console\n showlocation=True, # Show file:function:line\n timezone=\"UTC\"\n)\n\n# Error logger with longer retention\nerror_logger = size_rotating_logger(\n name=\"production_errors\", \n directory=\"/var/log/myapp\",\n filenames=[\"errors.log\"],\n maxmbytes=10,\n daystokeep=90, # Keep errors longer\n level=LogLevel.ERROR,\n streamhandler=False\n)\n\n# Audit logger with daily rotation\naudit_logger = timed_rotating_logger(\n name=\"audit_log\",\n directory=\"/var/log/myapp\",\n filenames=[\"audit.log\"],\n when=RotateWhen.MIDNIGHT,\n level=LogLevel.INFO\n)\n\n# Use the loggers\napp_logger.info(\"Application started\")\nerror_logger.error(\"Database connection failed\")\naudit_logger.info(\"User admin logged in\")\n```\n\n## Env Variables (Optional | Production)\nThe .env variables file can be used by leaving all options blank when calling the function.\\\nIf not specified inside the .env file, it will use the dafault value.\\\nThis is a good approach for production environments, since options can be changed easily.\n```python\nfrom pythonLogs import timed_rotating_logger\nlog = timed_rotating_logger()\n```\n\n```\nLOG_LEVEL=DEBUG\nLOG_TIMEZONE=UTC\nLOG_ENCODING=UTF-8\nLOG_APPNAME=app\nLOG_FILENAME=app.log\nLOG_DIRECTORY=/app/logs\nLOG_DAYS_TO_KEEP=30\nLOG_DATE_FORMAT=%Y-%m-%dT%H:%M:%S\nLOG_STREAM_HANDLER=True\nLOG_SHOW_LOCATION=False\nLOG_MAX_LOGGERS=50\nLOG_LOGGER_TTL_SECONDS=1800\n\n# SizeRotatingLog\nLOG_MAX_FILE_SIZE_MB=10\n\n# TimedRotatingLog\nLOG_ROTATE_WHEN=midnight\nLOG_ROTATE_AT_UTC=True\nLOG_ROTATE_FILE_SUFIX=\"%Y%m%d\"\n```\n\n\n# Memory Management\n\nThe library includes comprehensive memory management features to prevent memory leaks and optimize resource usage:\n\n## Automatic Resource Cleanup\n```python\nfrom pythonLogs import clear_logger_registry, shutdown_logger, LoggerFactory\n\n# Clear the entire logger registry with proper cleanup\nclear_logger_registry()\n\n# Shutdown specific logger and remove from registry\nshutdown_logger(\"my_app_logger\")\n\n# Manual registry management\nLoggerFactory.shutdown_logger(\"specific_logger\")\nLoggerFactory.clear_registry()\n```\n\n## Memory Optimization Features\n```python\nfrom pythonLogs import (\n get_memory_stats, \n clear_formatter_cache, \n clear_directory_cache,\n optimize_lru_cache_sizes,\n force_garbage_collection\n)\n\n# Get current memory usage statistics\nstats = get_memory_stats()\nprint(f\"Registry size: {stats['registry_size']}\")\nprint(f\"Formatter cache: {stats['formatter_cache_size']}\")\nprint(f\"Active loggers: {stats['active_logger_count']}\")\n\n# Clear various caches to free memory\nclear_formatter_cache() # Clear cached formatters\nclear_directory_cache() # Clear directory permission cache\n\n# Optimize LRU cache sizes for memory-constrained environments\noptimize_lru_cache_sizes()\n\n# Force garbage collection and get collection statistics\ngc_stats = force_garbage_collection()\nprint(f\"Objects collected: {gc_stats['objects_collected']}\")\n```\n\n## Registry Configuration\n```python\nfrom pythonLogs import LoggerFactory\n\n# Configure registry limits for memory management\nLoggerFactory.set_memory_limits(\n max_loggers=50, # Maximum cached loggers\n ttl_seconds=1800 # Logger time-to-live (30 minutes)\n)\n\n# Monitor registered loggers\nregistered = LoggerFactory.get_registered_loggers()\nprint(f\"Currently registered: {list(registered.keys())}\")\n```\n\n# Flexible Configuration Options\nYou can use either enums (for type safety) or strings (for simplicity):\n\n```python\nfrom pythonLogs import LogLevel, RotateWhen, LoggerType\n\n# Option 1: Type-safe enums (recommended)\nLogLevel.DEBUG # \"DEBUG\"\nLogLevel.INFO # \"INFO\" \nLogLevel.WARNING # \"WARNING\"\nLogLevel.ERROR # \"ERROR\"\nLogLevel.CRITICAL # \"CRITICAL\"\n\n# Option 2: String values (case-insensitive)\n\"debug\" # Same as LogLevel.DEBUG\n\"info\" # Same as LogLevel.INFO\n\"warning\" # Same as LogLevel.WARNING \n\"warn\" # Same as LogLevel.WARN (alias)\n\"error\" # Same as LogLevel.ERROR\n\"critical\" # Same as LogLevel.CRITICAL\n\"crit\" # Same as LogLevel.CRIT (alias)\n# Also supports: \"DEBUG\", \"Info\", \"Warning\", etc.\n\n# RotateWhen values\nRotateWhen.MIDNIGHT # \"midnight\"\nRotateWhen.HOURLY # \"H\"\nRotateWhen.DAILY # \"D\"\nRotateWhen.MONDAY # \"W0\"\n# ... through SUNDAY # \"W6\"\n# String equivalents: \"midnight\", \"H\", \"D\", \"W0\"-\"W6\"\n\n# LoggerType values\nLoggerType.BASIC # \"basic\"\nLoggerType.SIZE_ROTATING # \"size_rotating\" \nLoggerType.TIMED_ROTATING # \"timed_rotating\"\n# String equivalents: \"basic\", \"size_rotating\", \"timed_rotating\"\n```\n\n\n# Migration Guide\n\n## Upgrading from Legacy to Factory Pattern\n\nThe factory pattern is **100% backward compatible**. Your existing code will continue to work unchanged.\n\n### Before (Legacy - Still Works)\n```python\nfrom pythonLogs import BasicLog, SizeRotatingLog, TimedRotatingLog\n\n# Old way\nbasic_logger = BasicLog(level=\"info\", name=\"app\").init()\nsize_logger = SizeRotatingLog(level=\"debug\", name=\"app\", directory=\"/logs\").init() \ntimed_logger = TimedRotatingLog(level=\"warning\", name=\"app\", directory=\"/logs\").init()\n```\n\n### After (Factory Pattern - Recommended)\n```python\nfrom pythonLogs import basic_logger, size_rotating_logger, timed_rotating_logger, LogLevel\n\n# New way - cleaner and faster\nbasic_logger = basic_logger(level=LogLevel.INFO, name=\"app\")\nsize_logger = size_rotating_logger(level=LogLevel.DEBUG, name=\"app\", directory=\"/logs\")\ntimed_logger = timed_rotating_logger(level=LogLevel.WARNING, name=\"app\", directory=\"/logs\")\n```\n\n### Benefits of Migration\n- \ud83d\ude80 **90% faster logger creation** with registry caching\n- \ud83c\udfaf **Type safety** with enum-based parameters\n- \ud83d\udca1 **Better IDE support** with autocomplete and validation\n- \ud83d\udd27 **Cleaner API** without manual `.init()` calls\n- \ud83d\udcda **Centralized configuration** through factory pattern\n\n\n# Development\n\n### Building from Source\n```shell\npoetry build -f wheel\n```\n\n### Running Tests\n```shell\npoetry update --with test\npoe tests\n```\n\n# License\n\nReleased under the [MIT License](LICENSE)\n\n# Support\n\nIf you find this project helpful, consider supporting development:\n\n- [GitHub Sponsor](https://github.com/sponsors/ddc)\n- [ko-fi](https://ko-fi.com/ddcsta)\n- [PayPal](https://www.paypal.com/ncp/payment/6G9Z78QHUD4RJ)\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "High-performance Python logging library with file rotation and optimized caching for better performance",
"version": "5.0.1",
"project_urls": {
"Homepage": "https://pypi.org/project/pythonLogs",
"Repository": "https://github.com/ddc/pythonLogs"
},
"split_keywords": [
"python3",
" python-3",
" python",
" log",
" logging",
" logger",
" logutils",
" log-utils",
" pythonlogs"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "a40d1267fef2d47e3e8a0538f162d601d160272b9a3e05d3427361a45e6ca910",
"md5": "b63e7d3438c1c6b48891f83901eb0e4b",
"sha256": "dcdeec63cb5cd892704af290bb567c46f5faa35753a00a96e43592aa5ba162cd"
},
"downloads": -1,
"filename": "pythonlogs-5.0.1-cp312-cp312-macosx_14_0_arm64.whl",
"has_sig": false,
"md5_digest": "b63e7d3438c1c6b48891f83901eb0e4b",
"packagetype": "bdist_wheel",
"python_version": "cp312",
"requires_python": "<4.0,>=3.12",
"size": 25769,
"upload_time": "2025-07-25T15:42:17",
"upload_time_iso_8601": "2025-07-25T15:42:17.672109Z",
"url": "https://files.pythonhosted.org/packages/a4/0d/1267fef2d47e3e8a0538f162d601d160272b9a3e05d3427361a45e6ca910/pythonlogs-5.0.1-cp312-cp312-macosx_14_0_arm64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "3ed621b3ca2fab9bf3ef21c1d40ba7044bdfb19942957ee000a045fdb9ee0208",
"md5": "479645aa11076df4e198af33ea913872",
"sha256": "53f2cd52a63510e353afc7916998453017e5514ac654120520d908edc117894c"
},
"downloads": -1,
"filename": "pythonlogs-5.0.1-cp312-cp312-manylinux_2_39_x86_64.whl",
"has_sig": false,
"md5_digest": "479645aa11076df4e198af33ea913872",
"packagetype": "bdist_wheel",
"python_version": "cp312",
"requires_python": "<4.0,>=3.12",
"size": 25775,
"upload_time": "2025-07-25T15:42:18",
"upload_time_iso_8601": "2025-07-25T15:42:18.992093Z",
"url": "https://files.pythonhosted.org/packages/3e/d6/21b3ca2fab9bf3ef21c1d40ba7044bdfb19942957ee000a045fdb9ee0208/pythonlogs-5.0.1-cp312-cp312-manylinux_2_39_x86_64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "7acfeef468e217c2662a67c1169ed21ee2e169eae6e3592a99aa191aa654b9e8",
"md5": "c06dc9079b6c214c8ee324d5c5faf975",
"sha256": "3935034471da45e84bab453c4f3c1acfb13f570d6cffe4feaa0829e18996785b"
},
"downloads": -1,
"filename": "pythonlogs-5.0.1-cp312-cp312-win_amd64.whl",
"has_sig": false,
"md5_digest": "c06dc9079b6c214c8ee324d5c5faf975",
"packagetype": "bdist_wheel",
"python_version": "cp312",
"requires_python": "<4.0,>=3.12",
"size": 25921,
"upload_time": "2025-07-25T15:42:19",
"upload_time_iso_8601": "2025-07-25T15:42:19.850176Z",
"url": "https://files.pythonhosted.org/packages/7a/cf/eef468e217c2662a67c1169ed21ee2e169eae6e3592a99aa191aa654b9e8/pythonlogs-5.0.1-cp312-cp312-win_amd64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "5429e0f628a1fcdd12751b9729d52d62a52cf0639263f4e6e2939859bfd2039d",
"md5": "0754bfc1af5e72e9e5146f969eb3b2b5",
"sha256": "2a1e0e62157dc02b33c4e8fd29c10ad2dae678977af4aaf6095899827969d0d4"
},
"downloads": -1,
"filename": "pythonlogs-5.0.1-cp313-cp313-macosx_14_0_arm64.whl",
"has_sig": false,
"md5_digest": "0754bfc1af5e72e9e5146f969eb3b2b5",
"packagetype": "bdist_wheel",
"python_version": "cp313",
"requires_python": "<4.0,>=3.12",
"size": 25770,
"upload_time": "2025-07-25T15:42:20",
"upload_time_iso_8601": "2025-07-25T15:42:20.935119Z",
"url": "https://files.pythonhosted.org/packages/54/29/e0f628a1fcdd12751b9729d52d62a52cf0639263f4e6e2939859bfd2039d/pythonlogs-5.0.1-cp313-cp313-macosx_14_0_arm64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "50fef5c19d6b0d5cd2efba5ab39754847a1c96a5512170aa5802549c3201824a",
"md5": "100081ce73ba9ad06cb4ecd3b54b03ea",
"sha256": "bdf36e31e6bab962197ebd432582337a60cb0d1745a88876f0927f26e9ac77ab"
},
"downloads": -1,
"filename": "pythonlogs-5.0.1-cp313-cp313-manylinux_2_39_x86_64.whl",
"has_sig": false,
"md5_digest": "100081ce73ba9ad06cb4ecd3b54b03ea",
"packagetype": "bdist_wheel",
"python_version": "cp313",
"requires_python": "<4.0,>=3.12",
"size": 25774,
"upload_time": "2025-07-25T15:42:22",
"upload_time_iso_8601": "2025-07-25T15:42:22.262330Z",
"url": "https://files.pythonhosted.org/packages/50/fe/f5c19d6b0d5cd2efba5ab39754847a1c96a5512170aa5802549c3201824a/pythonlogs-5.0.1-cp313-cp313-manylinux_2_39_x86_64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "7f7abcc99b9b0482b5885f4ffc6d3dd981941fa43623a27d55c5fac8f227ec33",
"md5": "7076f8c4e87d505749927f0faebaa8ac",
"sha256": "b766ea73b19186a20756a00e1ea09dec3cc3b67898c92ac307b6d00c87b3b303"
},
"downloads": -1,
"filename": "pythonlogs-5.0.1-cp313-cp313-win_amd64.whl",
"has_sig": false,
"md5_digest": "7076f8c4e87d505749927f0faebaa8ac",
"packagetype": "bdist_wheel",
"python_version": "cp313",
"requires_python": "<4.0,>=3.12",
"size": 25924,
"upload_time": "2025-07-25T15:42:23",
"upload_time_iso_8601": "2025-07-25T15:42:23.153410Z",
"url": "https://files.pythonhosted.org/packages/7f/7a/bcc99b9b0482b5885f4ffc6d3dd981941fa43623a27d55c5fac8f227ec33/pythonlogs-5.0.1-cp313-cp313-win_amd64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "0ab827287201386f199d3c19ad237f66f964a48a400f90d0779c9e8db7c9781c",
"md5": "753b98fcc20a506d6f185cdf97c2037d",
"sha256": "f54ea88d056862fedabeb0d0302871f8c54d7196dd5f6afac9d46785cd1fbc68"
},
"downloads": -1,
"filename": "pythonlogs-5.0.1.tar.gz",
"has_sig": false,
"md5_digest": "753b98fcc20a506d6f185cdf97c2037d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.12",
"size": 25767,
"upload_time": "2025-07-25T15:42:24",
"upload_time_iso_8601": "2025-07-25T15:42:24.397290Z",
"url": "https://files.pythonhosted.org/packages/0a/b8/27287201386f199d3c19ad237f66f964a48a400f90d0779c9e8db7c9781c/pythonlogs-5.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-25 15:42:24",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ddc",
"github_project": "pythonLogs",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "pythonlogs"
}