6.9 KiB
6.9 KiB
name, description, x-personal-mcp
| name | description | x-personal-mcp | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| python-logging | Design, review, or refactor Python logging. Use when choosing logger names, levels, handlers, library/application boundaries, basicConfig, dictConfig, structured logs, or operational logging defaults. |
|
Python Logging
Use this skill to produce idiomatic Python logging guidance or a small logging setup for an application, library, CLI, worker, or web service.
Load references only when needed:
- Python logging overview, library guidance, handlers, and dictConfig schema: Python logging references
- Minimal network logging example with a receiver and queue-backed client: Network logging minimal example
- HTTP JSON logging example with
httpxand a queue-backed client: HTTPX logging handler example
When to Use
- A project mixes
print, root logger calls, scatteredbasicConfig, or ad hoc handlers. - You need to choose logging levels, destinations, formatter fields, or logger names.
- You need a clear boundary between library logging and application logging configuration.
- You need a centralized logging setup, including a
logging.config.dictConfigsection. - You are tuning framework or third-party loggers such as
uvicorn,sqlalchemy, or HTTP clients.
Inputs To Collect
- Runtime type: script, library, CLI, web app, worker, service, or notebook.
- Audience: humans in a terminal, operators in files, machines in JSON, or test assertions.
- Destinations: stdout/stderr, file, rotating file, queue, syslog, external collector, or none for libraries.
- Default level and verbosity controls:
INFO,DEBUG, CLI flag, environment variable, or config file. - Operational constraints: async event loop, multiprocessing, container logs, sensitive data, or high-volume paths.
If missing, assume:
- application code, not a reusable library
- stdout console logging
- human-readable formatter
- root level
INFO - no file logging unless requested
Procedure
- Classify the project boundary first: application code configures logging; library code emits logs and avoids configuring handlers.
- In modules, create loggers with
logger = logging.getLogger(__name__)so logger names follow the package hierarchy. - Use level semantics consistently:
DEBUGfor diagnosis,INFOfor normal milestones,WARNINGfor notable recoverable conditions,ERRORfor failed operations, andCRITICALfor process-threatening failures. - Prefer parameterized logging calls such as
logger.info("Processed %s items", count)so message formatting is deferred until the record is emitted. - Configure handlers and formatters once during application startup. For small scripts,
basicConfigcan be enough; for applications, prefer a centralized configuration function. - Keep third-party logger overrides explicit and narrow. Tune noisy loggers by name instead of muting broad logger hierarchies.
- Smoke-check output at expected levels and destinations, including one suppressed
DEBUGmessage and one exception path if errors are logged.
Best Practices
- Do not name a module
logging.py; it shadows the standard library package. - Do not call
basicConfigor attach handlers in every module. - Do not log to the root logger from libraries. Use named loggers and, only if needed, attach
logging.NullHandler()to the library's top-level logger. - Do not create loggers per request, user, file, or connection. Use contextual fields, adapters, or filters instead.
- Use
logger.exception(...)only inside an exception handler when the traceback is useful. - For async or high-throughput code, avoid slow network or file handlers on the hot path; consider
QueueHandlerand a listener. - Avoid custom levels unless there is a strong interoperability reason.
Using dictConfig
Use logging.config.dictConfig when configuration should be centralized, data-driven, or richer than basicConfig.
- Define one
LOGGINGdictionary in a startup-oriented module such aslogging_config.py. - Include
version: 1and usually setdisable_existing_loggers: Falseso existing named loggers are not silently disabled. - Define formatters, then handlers, then logger routing with
rootand optional namedloggers. - Call
logging.config.dictConfig(LOGGING)once during application startup. - Keep application logging calls unchanged when adding new destinations or formats.
Minimal dictConfig Baseline
import logging.config
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"console": {
"format": "%(asctime)s.%(msecs)03d %(levelname)s %(name)s %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S",
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "console",
"stream": "ext://sys.stdout",
}
},
"root": {
"level": "INFO",
"handlers": ["console"],
},
}
def configure_logging() -> None:
logging.config.dictConfig(LOGGING)
from .logging_config import configure_logging
configure_logging()
import logging
logger = logging.getLogger(__name__)
def run(count: int) -> None:
logger.info("Processing %s items", count)
Branching Guidance
- If the code is a tiny script: use
basicConfigonce near the entry point and module loggers elsewhere. - If the code is a library: remove handlers and configuration calls; document logger names and optionally add
NullHandlerat the package root. - If structured logs are required: keep the same logger and handler topology, but switch formatter output to JSON or a structured formatter.
- If console and file output are needed: add one file or rotating-file handler and attach it centrally.
- If multiple processes write to one file: use a queue/listener or process-safe collection path rather than opening the same file independently in each process.
- If logs must cross a network: send records to a receiver or collector from a queue-backed handler, keep the receiver responsible for final destinations, and avoid exposing unauthenticated logging ports.
- If a framework logger is noisy: add a named logger override with a level and leave unrelated logger propagation alone.
Completion Checks
- Modules use
logging.getLogger(__name__). - Application startup configures logging once.
- Libraries do not configure application handlers.
- Levels match the severity semantics in this skill.
- Logs include enough context to identify source, severity, and event without leaking secrets.
- Expected destinations receive messages and suppressed levels stay quiet.
- No source file or package is named
logging.py.