A comprehensive logging utility for project that provides:
- Timestamp information in logs
- User ID tracking for authenticated requests
- File name and line number of the log call
- Clean and consistent log formatting
- Multiple usage patterns for different scenarios
- Contextual Information: Every log includes timestamp, log level, file name, and line number
- Timezone Support: Configure timestamps to display in any timezone (UTC, US/Pacific, Europe/London, etc.)
- Authentication Awareness: Can include user ID in logs when available
- Format String Support: Supports Python's standard string formatting with %s, %d, etc.
- Flexible Configuration: Configurable output destination (terminal and/or file)
- Consistent API: Familiar logging methods (debug, info, warning, error, critical)
- Colored Output: Color-coded log levels for better readability in terminal
pip install loggioThen import in your code:
from loggio import get_loggerTo use standalone, use as a fork.
To get updates, use as a submodule.
Go to inside your project.
Clone the repository:
git clone https://github.com/xcollantes/loggio loggioGo to where you want to dependency.
Clone the repository as submodule:
loggio must be maintained since Python import statements don't work
work hyphens.
git submodule add https://github.com/xcollantes/loggio loggioClone the repository with submodules:
git clone --recursive https://github.com/xcollantes/my-project-with-submodulesRemember --recursive for submodules.
If you clone without --recursive:
git submodule update --init --recursive# Create virtual environment.
python3 -m venv env
# Activate virtual environment.
# On macOS/Linux:
source env/bin/activate
# On Windows:
# venv\Scripts\activatepip install -r requirements.txtCreate a .env file in the project root with the required environment
variables. The following variables are used by the application:
python3 main.pyFor utility functions, background tasks, or non-authenticated endpoints:
from loggio import get_logger
# Create a logger instance.
logger = get_logger(name="module.name")
# Log messages with different levels
logger.debug("This is a debug message.")
logger.info("This is an info message.")
logger.warning("This is a warning message.")Output example:
INFO:2023-05-01 14:30:45:example.py:24:This is an info message.
The logger supports Python's standard string formatting:
from loggio import get_logger
logger = get_logger(name="module.formatter")
# Using format strings
item_id = "A123"
priority = 2
logger.info("Processing item %s with priority %d", item_id, priority)Output example:
INFO:2023-05-01 14:31:22:formatter.py:15:Processing item A123 with priority 2
When you have authentication info:
from loggio import get_logger
# Create a logger instance.
logger = get_logger(name="module.auth")
# Get user info from somewhere (e.g., decoded token)
user_info = {"uid": "user123", "email": "user@example.com"}
# Log with user context
logger.info("User performed an action.", user_context=user_info)Output example:
INFO:2023-05-01 14:32:10:auth_service.py:45:user123: User performed an action.
Combining format strings with user context:
logger.info("Processing file %s for action %s", filename, action, user_context=user_info)try:
# Some risky operation
result = perform_risky_operation()
logger.info(f"Operation successful: {result}")
except Exception as e:
logger.error(f"Operation failed: {str(e)}")
# Handle or re-raise as appropriateWhen creating a logger instance, you can configure:
name: Logger name for filtering and organization (e.g., "api.auth", "service.processor")level: Minimum log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) - defaults to "INFO"fileout_path: Path for log file. Set toNoneto disable file logging (default: "logs/app.log")terminal: Whether to output logs to the terminal/console (default: True)timezone: Timezone for timestamps (e.g., "UTC", "US/Pacific", "Europe/London"). Defaults to None (local time)use_colors: Whether to use colored output in terminal (default: True)truncate: Whether to truncate long messages (default: True)truncate_length: Maximum message length before truncation (default: 10000)json_format: Whether to format arguments as JSON (default: False)
Example with custom configuration:
logger = get_logger(
name="batch.processor",
level="DEBUG",
fileout_path="logs/batch_processor.log",
terminal=True,
timezone="UTC"
)The logger produces logs in the following format:
LEVEL:[TIMESTAMP]FILENAME:LINE_NUMBER:MESSAGE
Timestamps include timezone information with both timezone name and UTC offset:
INFO:[2025-12-14 00:20:03 PST-0800]demo.py:42:This is a log message
INFO:[2025-12-14 08:20:03 UTC+0000]demo.py:42:Same message in UTC
INFO:[2025-12-14 17:20:03 JST+0900]demo.py:42:Same message in Tokyo time
With user context:
INFO:[2025-12-14 14:35:22 UTC+0000]auth_routes.py:28:user123: Processing
protected resource request
By default, logs use your local system timezone. You can configure any IANA timezone identifier:
from loggio import get_logger
# Use UTC
logger = get_logger(timezone="UTC")
logger.info("This log is in UTC")
# Use US Pacific time
logger = get_logger(timezone="US/Pacific")
logger.info("This log is in Pacific time")
# Use Tokyo time
logger = get_logger(timezone="Asia/Tokyo")
logger.info("This log is in Tokyo time")The logger uses Python's zoneinfo module with the IANA timezone database.
You can validate timezone strings before using them:
from loggio import get_logger, is_valid_timezone, get_available_timezones
# Check if a timezone is valid
if is_valid_timezone("America/New_York"):
logger = get_logger(timezone="America/New_York")
logger.info("Using valid timezone")
# Get all available timezones (598 total)
timezones = get_available_timezones()
print(f"Total timezones: {len(timezones)}")
# Find timezones for a region
europe_tzs = [tz for tz in timezones if tz.startswith("Europe")]
print(f"European timezones: {europe_tzs[:5]}")Since the logger is a singleton, reconfiguring it will update the timezone for all subsequent logs:
# Start with UTC
logger = get_logger(timezone="UTC")
logger.info("Log in UTC")
# Switch to Pacific time
logger = get_logger(timezone="US/Pacific")
logger.info("Now logging in Pacific time")IANA Timezone Format:
All timezone identifiers follow the IANA timezone database format:
Region/City (e.g., America/New_York, Europe/London)
Americas:
America/New_York(EST/EDT)America/Chicago(CST/CDT)America/Denver(MST/MDT)America/Los_Angeles(PST/PDT)US/Pacific,US/Eastern,US/Central,US/Mountain(POSIX-style)
Europe:
Europe/London(GMT/BST)Europe/Paris(CET/CEST)Europe/Berlin(CET/CEST)Europe/Moscow(MSK)
Asia:
Asia/Tokyo(JST)Asia/Shanghai(CST)Asia/Hong_Kong(HKT)Asia/Singapore(SGT)
Pacific:
Australia/Sydney(AEDT/AEST)Pacific/Auckland(NZDT/NZST)
Special:
UTC- Coordinated Universal Time
Note: Abbreviations like "PST" or "EST" are NOT valid IANA identifiers.
Use America/Los_Angeles or US/Pacific instead of "PST", and
America/New_York or US/Eastern instead of "EST".
For a complete list of 598+ available timezones, use
get_available_timezones() or see the
IANA timezone database.
- Use a hierarchical naming scheme for loggers (e.g.,
api.auth,service.processor) - Include meaningful context in log messages
- Use the appropriate log level for different scenarios:
- DEBUG: Detailed information for debugging
- INFO: Confirmation that things are working as expected
- WARNING: Something unexpected happened, but the application can continue
- ERROR: A more serious problem that prevented a function from working
- CRITICAL: A very serious error that might prevent the program from continuing
- Include user context when available for better traceability
- Include error details when logging exceptions
- Consider using UTC timezone for production systems to avoid confusion across different timezones
The Enhanced Logger builds on Python's built-in logging module with custom formatting and context handling. It uses:
stacklevel=2to ensure the correct file and line number are recorded in the logs rather than showing the logger implementation file itself- Python's
zoneinfomodule (Python 3.9+) for timezone support, providing access to the IANA timezone database - ANSI color codes for terminal output with automatic color removal for file logging
- Singleton pattern to ensure consistent configuration across the application
Publishing is handled automatically via GitHub Actions when a GitHub Release is created. The workflow sets the version from the release tag, builds the package, and publishes to PyPI using trusted publishing (no API token required).
- Merge all changes to
main - Create and push a tag:
git tag 2025.12.14 git push origin 2025.12.14
- On GitHub, go to Releases → Draft a new release
- Select the tag you just pushed
- Publish the release — the workflow triggers and publishes to PyPI
The version in loggio/__init__.py is set automatically from the release tag.
Do not manually edit __version__ before releasing.
If you need to build and publish locally:
# Install build tools
pip install build twine
# Build the distribution
python -m build
# Upload to PyPI (requires API token)
twine upload dist/*The dist/ directory will contain both a source archive (.tar.gz) and a
wheel (.whl). Verify the build looks correct before uploading:
twine check dist/*