A guide to python isolated logging with StayPresent's dedicated logger — no root logger mutation, what gets logged, and how to configure it.
How StayPresent's Logging Works (Without Breaking Yours)
A surprisingly common way for a third-party package to quietly break your application's logging is by calling logging.basicConfig() somewhere in its own code — which mutates the root logger and can silently change formatting, duplicate output, or override handlers you already configured for your own loggers. StayPresent avoids this entirely through python isolated logging: everything it logs goes through its own dedicated logger, never the root one.
Table of Contents
- The Problem with
logging.basicConfig() - StayPresent's Dedicated Logger
- What Gets Logged, and at What Level
- Adjusting Verbosity
- Attaching Your Own Handler
- Logging During Multi-Bot Runs
- Logging During Shutdown
- Full Example
- Best Practices
- Common Mistakes
- FAQs
- Conclusion
The Problem with logging.basicConfig()
logging.basicConfig() configures the root logger, which every other logger in your process falls back to unless it's explicitly configured otherwise. If your bot calls it once at startup, and a dependency somewhere else in your stack calls it again, whichever call happens first usually "wins" silently — no error, just unexpected formatting or duplicate log lines that are hard to trace back to their cause. A well-behaved library avoids touching the root logger at all, and instead logs through its own named logger.
StayPresent's Dedicated Logger
StayPresent logs exclusively through a logger named "staypresent", configured with a single dedicated StreamHandler and logger.propagate = False. It never calls logging.basicConfig(), and it never touches the root logger in any way. This means it cannot clobber, duplicate, or reformat log output your own script has already configured for its own, unrelated loggers — StayPresent's logs and your bot's logs coexist without interfering with each other.
What Gets Logged, and at What Level
The "staypresent" logger reports on:
- Web server startup — whether
waitressor the Flask dev-server fallback is being used, and which host/port it bound to. - Each bot process starting, crashing, restarting, exhausting its restart budget, or exiting cleanly.
- Signal-triggered shutdowns (
SIGINT/SIGTERM), including a previously-installed handler being chained afterward, if one exists. - Unexpected web-server thread failures, both at startup and later during the run.
- Cron pinger start/stop events (at
INFO) and individual failed pings (atWARNING, viaping()'s own logging). - A one-time
WARNINGper directory, the first timeweb.html()/web.markdown()exposes it as a static-asset fallback.
Adjusting Verbosity
Because it's a normal, named Python logger, you configure it exactly like any other:
import logging
logging.getLogger("staypresent").setLevel(logging.DEBUG)
Turn it down in a quiet production environment:
logging.getLogger("staypresent").setLevel(logging.WARNING)
This setting only affects StayPresent's own log output — it has no effect on your bot's separate loggers, and vice versa.
Attaching Your Own Handler
Since it's a real logger object, you can attach additional handlers — to forward StayPresent's events to a file, a monitoring service, or a Discord webhook, for example:
import logging
file_handler = logging.FileHandler("staypresent.log")
file_handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
logging.getLogger("staypresent").addHandler(file_handler)
This adds to StayPresent's existing dedicated StreamHandler rather than replacing it, so console output and your new handler both receive events unless you explicitly remove the default one.
Logging During Multi-Bot Runs
When running several bots at once, log lines identify which bot they refer to using a label — normally just the filename (bot[0] 'worker.py'), or the dotted module path for bot_module-based bots (bot[0] 'mypkg.bot'). If two bots share an identical filename, StayPresent automatically switches to logging the full file path for every bot sharing that name, specifically so crash/restart messages stay distinguishable in the logs rather than becoming ambiguous.
Logging During Shutdown
On SIGINT/SIGTERM, the shutdown sequence itself is logged — including whether a previously-installed signal handler is being chained afterward. active_cron_handles() is also checked during shutdown, and any pinger still running at that point is logged purely for visibility (it isn't stopped or waited on, since cron pingers run on daemon threads that exit automatically with the process).
Full Example
import logging
import staypresent
# Turn up StayPresent's own logs for a specific debugging session
logging.getLogger("staypresent").setLevel(logging.DEBUG)
# Your bot's own logger, configured completely independently
bot_logger = logging.getLogger("mybot")
bot_logger.setLevel(logging.INFO)
bot_logger.addHandler(logging.StreamHandler())
staypresent.web.json({"status": "running"})
staypresent.run("bot.py")
Both loggers coexist cleanly — turning StayPresent's level up or down has zero effect on mybot's own output.
Best Practices
- Turn
"staypresent"up toDEBUGtemporarily when diagnosing a deployment issue (a bot that won't stay up, a crash loop), then back down once resolved. - Attach a
FileHandleror remote-logging handler to"staypresent"if you want restart/crash events specifically forwarded somewhere durable, separate from your bot's own application logs. - Don't call
logging.basicConfig()in your own bot script expecting it to also configure StayPresent's output — it won't, by design; configure"staypresent"directly instead.
Common Mistakes
-
Assuming
logging.basicConfig()in your own code affects StayPresent's logs. It doesn't — StayPresent never falls back to root logger configuration, since it never propagates to the root logger at all. -
Setting the level on the wrong logger.
logging.getLogger("staypresent"), notlogging.getLogger()(the root logger) or your own bot's logger name, controls StayPresent's verbosity specifically. -
Expecting bot subprocess output to appear through the
"staypresent"logger. Your bot runs as a separate subprocess with its own stdout/stderr —"staypresent"logs StayPresent's own orchestration events, not your bot's internal application logs.
FAQs
Does StayPresent ever call logging.basicConfig()?
No, never — this is a deliberate design choice specifically to avoid interfering with logging you've already configured elsewhere in your application.
Can I completely silence StayPresent's logs?
Yes — set the level above CRITICAL, or remove/replace its handlers directly if you want full control over its output destination.
Does the logging level affect what StayPresent actually does?
No — logging is purely observational. Crash recovery, restarts, and shutdown behavior all happen the same way regardless of what level "staypresent" is set to.
Conclusion
Python isolated logging is a small design detail that saves real debugging time — StayPresent's dedicated "staypresent" logger means you can turn its verbosity up or down, attach your own handlers, and trust that none of it touches the logging you've already built for your bot's own code.
pip install staypresent[prod]
Top comments (0)