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
.env
and.chronilog.toml
for 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
chronilog
to yourrequirements.txt
orpyproject.toml
for 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.toml
config - π§ͺ A
main.py
that logs messages at all levels - π A rotating log file system
- β
A beginner-friendly
HELP.md
with step-by-step instructions
git clone https://github.com/yourusername/chronilog-example.git
cd chronilog-example
pip install -r requirements.txt
python main.py
Then check the logs in:
logs/app.log
Chronilog reads layered config in this order:
- Environment variables (
CHRONILOG_*
) .chronilog.toml
file (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=0
log_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.0
from 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
.env
or.chronilog.toml
in 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://[email protected]/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.py
Use caplog
to capture output:
def test_warning(caplog):
log = ChroniLog("test")
log.warning("uh oh!")
assert "uh oh!" in caplog.text
Patch 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:
.env
overrides.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_path
is 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 init
It 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-run
Shows the generated config as TOML without saving.
chronilog init --config .config/chronilog.toml
Saves 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=value
chronilog config delete key
chronilog 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!