Cron jobs are silent by design. They run in the background, produce no visible output, and if they fail the only signal is usually a missing result or a full mail queue that nobody reads.
The usual workarounds are frustrating:
tail -f to see anything, and the file grows forever.There's a simpler path: one Python import that gives the job a live stream URL.
pip install bunnylogs
Create a log stream on bunnylogs.com and grab the UUID. Then modify your cron script:
import logging
from bunnylogs import BunnyLogsHandler
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("nightly-sync")
logger.addHandler(BunnyLogsHandler("your-uuid-here"))
logger.info("nightly-sync started")
try:
run_sync()
logger.info("nightly-sync completed successfully")
except Exception as e:
logger.error(f"nightly-sync failed: {e}", exc_info=True)
Open bunnylogs.com/live/your-uuid in a browser and watch the output appear in real time as the job runs.
If you have multiple cron jobs, extract the setup into a shared module so every job gets logging with one import:
# utils/logging.py
import logging
from bunnylogs import BunnyLogsHandler
def get_job_logger(name: str, uuid: str) -> logging.Logger:
logger = logging.getLogger(name)
logger.setLevel(logging.INFO)
logger.addHandler(BunnyLogsHandler(uuid))
return logger
# jobs/nightly_sync.py
from utils.logging import get_job_logger
import os
logger = get_job_logger("nightly-sync", os.environ["BUNNYLOGS_UUID"])
logger.info("starting")
# ... rest of job
Store the UUID in an environment variable or a secrets manager — don't commit it to source control.
If the same job runs on several servers, send all of them to the same UUID so the live view aggregates output from every host:
import socket
logger = get_job_logger(f"nightly-sync/{socket.gethostname()}", BUNNYLOGS_UUID)
The program field in each log entry (set from the logger name) identifies which host sent each line.
BunnyLogs supports alerts that fire when a log line matches a pattern. Set up an alert for level=ERROR and program contains nightly-sync and you'll get a Slack or email notification within seconds of a failure — without polling, without agents, without a separate alerting service.
May 1, 2025
April 15, 2025