Chronilog is a professional-grade logging package for Python. It brings structured logging, rotating files, Rich-powered console output, environment-aware configuration, and optional Sentry integration to your projects β with zero hassle.
Designed for developers who want reliable logs, clean setup, and real-world flexibility.
- β
 
ChroniLog(name)β get a configured logger in one line - π¨ Rich terminal output (emoji-safe, dark-theme friendly)
 - π Rotating file logs (path, size, backups all configurable)
 - π§ Supports 
.envand.chronilog.tomlfor layered config - π§ͺ Diagnostic tools for troubleshooting setup issues
 - π Optional JSON logging support
 - π‘οΈ Optional Sentry integration for exception tracking
 - π§° Developer-first: testable, extensible, production-ready
 
# Clone and install in editable mode (during development)
git clone https://github.com/BrandonAustin01/chronilog
cd chronilog
pip install -e .Add
chronilogto yourrequirements.txtorpyproject.tomlfor production use.
Chronilog is a structured, reliable logging system built for real-world Python apps.
It eliminates guesswork around log setup, integrates rotating file logs, rich console formatting,
and includes optional diagnostics and error tracking β all with sane defaults.
Use it in everything from CLI tools to production services.
from chronilog import ChroniLog
log = ChroniLog("my_app")
log.info("π App started")
log.warning("β οΈ Something might be wrong...")
log.error("β An error occurred!")Chronilog auto-configures sane defaults, file logging, and console formatting.
Want to see Chronilog in action before integrating it?
Try the Chronilog Example Project
it includes:
- π A working 
.chronilog.tomlconfig - π§ͺ A 
main.pythat logs messages at all levels - π A rotating log file system
 - β
 A beginner-friendly 
HELP.mdwith step-by-step instructions 
git clone https://github.com/yourusername/chronilog-example.git
cd chronilog-example
pip install -r requirements.txt
python main.pyThen check the logs in:
logs/app.logChronilog reads layered config in this order:
- Environment variables (
CHRONILOG_*) .chronilog.tomlfile (if present)- Internal fallback values
 
Then it builds:
- A rotating file handler (with custom path, size, backups)
 - A rich console handler (with optional emoji fallback)
 - An optional JSON or plain formatter
 - A logger with the given name (e.g. 
ChroniLog("my_app")) 
Chronilog uses Pythonβs standard logging levels:
| Level | Description | 
|---|---|
| DEBUG | Verbose info for debugging | 
| INFO | General status updates | 
| WARNING | Recoverable issues or early warnings | 
| ERROR | Errors that need attention | 
| CRITICAL | Serious failure or crash | 
You can set the level globally via:
.env:CHRONILOG_LOG_LEVEL=WARNING.toml:log_level = "ERROR"
Chronilog supports layered configuration from:
.envβ for quick dev overrides.chronilog.tomlβ for structured project configs- Internal safe defaults β as fallback
 
CHRONILOG_LOG_PATH=logs/my_app.log
CHRONILOG_LOG_LEVEL=DEBUG
CHRONILOG_LOG_MAX_MB=5
CHRONILOG_LOG_BACKUP_COUNT=3
CHRONILOG_JSON=0log_path = "logs/chronilog.log"
log_level = "DEBUG"
max_log_file_size = 5
backup_count = 3
enable_console = true
emoji_fallback = true
enable_sentry = false
sentry_dsn = ""
sentry_level = "ERROR"
sentry_traces_sample_rate = 0.0from chronilog import ChroniLog
from chronilog.core.formatter import PlainFormatter
log = ChroniLog(
    name="myapp",
    level=logging.INFO,
    file_formatter=PlainFormatter(),
    use_cache=False
)| Argument | Type | Description | 
|---|---|---|
name | 
str | 
Logger name (typically __name__) | 
level | 
int (opt) | 
Custom log level (logging.DEBUG, etc) | 
console_formatter | 
Formatter | 
Override console formatting | 
file_formatter | 
Formatter | 
Override file formatting | 
use_cache | 
bool | 
Whether to reuse logger instances by name | 
Chronilog automatically chooses the most appropriate log path:
| OS | Path Location | 
|---|---|
| Windows | %LOCALAPPDATA%\chronilog\logs\ | 
| macOS | ~/Library/Logs/chronilog/ | 
| Linux | ~/.local/share/chronilog/logs/ | 
- Install Chronilog
 - Create 
.envor.chronilog.tomlin your project root - Add 
from chronilog import ChroniLog - Use 
log = ChroniLog(__name__) - Start logging with 
log.info(...), etc. 
That's it β file and console logs will be active instantly.
| Variable Name | Description | 
|---|---|
| CHRONILOG_LOG_PATH | File log location | 
| CHRONILOG_LOG_LEVEL | Log level (e.g., INFO, DEBUG) | 
| CHRONILOG_LOG_MAX_MB | Max file size in MB before rotating | 
| CHRONILOG_LOG_BACKUP_COUNT | Number of rotated logs to keep | 
| CHRONILOG_JSON | Use JSON formatter (1 or 0) | 
| CHRONILOG_DISABLE_CONSOLE | If true, disables console output | 
| CHRONILOG_EMOJI_FALLBACK | Replaces emojis on incompatible systems | 
| CHRONILOG_ENABLE_SENTRY | Enables Sentry integration | 
| CHRONILOG_SENTRY_DSN | Your Sentry DSN string | 
| CHRONILOG_SENTRY_LEVEL | Min level to send to Sentry | 
| CHRONILOG_SENTRY_SAMPLE_RATE | Tracing sample rate (0.0 to 1.0) | 
Chronilog includes first-class support for Sentry, a powerful error tracking system.
- Install the SDK:
 
pip install sentry-sdk- Add to 
.chronilog.toml: 
enable_sentry = true
sentry_dsn = "https://your_dsn_here@sentry.io/project_id"
sentry_level = "ERROR"
sentry_traces_sample_rate = 0.0- You can also trigger Sentry manually:
 
from chronilog.integrations.sentry import init_sentry
init_sentry()from chronilog.integrations.sentry import capture_exception
try:
    raise ValueError("Something went wrong")
except Exception as e:
    capture_exception(e)Chronilog gracefully disables Sentry if sentry-sdk is missing.
All related tests will automatically be skipped.
Need to verify your setup?
from chronilog.diagnostics import print_diagnostics
print_diagnostics()You'll get a Rich-powered terminal table showing:
- Logger name
 - Log level
 - Handlers active
 - File path
 - Config source
 
Run tests:
pytest tests/Built-in usage example:
python examples/usage.pyUse caplog to capture output:
def test_warning(caplog):
    log = ChroniLog("test")
    log.warning("uh oh!")
    assert "uh oh!" in caplog.textPatch config:
monkeypatch.setattr("chronilog.integrations.sentry._get_config", lambda key: {
    "enable_sentry": "true",
    "sentry_dsn": "invalid"
}.get(key))Chronilog uses the following priority for resolving config:
.envoverrides.chronilog.toml- Hardcoded defaults
 
Any of these can be bypassed using keyword args in ChroniLog(...).
β Nothing appears in logs?
- Check 
log_level - Check that 
log_pathis writeable 
β Unicode errors on Windows?
- Set 
emoji_fallback = true 
π§ͺ Use print_diagnostics() for verification
from flask import Flask
from chronilog import ChroniLog
app = Flask(__name__)
log = ChroniLog("flask_app")
@app.route("/")
def home():
    log.info("Homepage accessed")
    return "Hello from Chronilog!"myapp/
βββ main.py
βββ .env
βββ .chronilog.toml
βββ logs/
β   βββ chronilog.log # or myapp.log
βββ requirements.txt
βββ tests/Chronilog includes a powerful CLI to help manage configuration and setup.
Interactive setup wizard to generate a .chronilog.toml file:
chronilog initIt prompts for:
- Log path (e.g., 
logs/chronilog.log) - Log level (
DEBUG,INFO, etc.) - Max log size (in MB)
 - Backup count
 - Console output toggle
 - Emoji fallback toggle
 - Sentry enable + DSN + level + trace sample rate
 
It creates .chronilog.toml in your working directory or a custom path.
| Flag | Description | 
|---|---|
--dry-run | 
Preview the config it would generate, without writing a file | 
--config PATH | 
Specify an alternate config file location | 
chronilog init --dry-runShows the generated config as TOML without saving.
chronilog init --config .config/chronilog.tomlSaves to a custom path.
If a .chronilog.toml already exists, Chronilog will:
- Prompt you to overwrite, skip, or cancel
 - Validate the structure before writing
 - Include comments in the output
 
Chronilog's CLI is expanding soon with:
chronilog config set key=valuechronilog config delete keychronilog diagnosticsβ full environment + logger auditchronilog viewβ visual JSON log viewer with filters- Profile-based config switching
 
MIT License β open-source, free for commercial and personal use.
Built with β€οΈ by Brandon McKinney
Feedback welcome β open an issue or contribute anytime!