d5DetectabilityOperational debt — how invisible misuse is to your safety net
Closest to 'default linter catches the common case' (d5), pylint/ruff flag print() statements (T201) and basic logging misuse, but structured logging gaps and f-string-in-log issues need specialist rules (e.g., ruff's G/PLE rules) — slightly above d3 because not all anti-patterns are caught by defaults.
e5EffortRemediation debt — work required to fix once spotted
Closest to 'touches multiple files / significant refactor in one component' (e5), per quick_fix replacing print() with logging plus configuring JSON formatter, named loggers per module, and handler setup is not a one-line change — it touches every module that logs.
b5BurdenStructural debt — long-term weight of choosing wrong
Closest to 'persistent productivity tax' (b5), logging applies across web and cli contexts and affects every module; misconfigured root logger or library logging creates ongoing friction for observability work.
t6TrapCognitive debt — how counter-intuitive correct behaviour is
Closest to 'serious trap' (t7), misconception is strong (print() seems fine and removable) and f-string interpolation looks idiomatic but defeats lazy evaluation — contradicts normal Python style guidance, a non-obvious gotcha most devs only learn after production pain.
Python's built-in logging module provides a structured, configurable way to emit log messages at different severity levels — replacing print() for production code.
Explanation
The logging hierarchy (DEBUG, INFO, WARNING, ERROR, CRITICAL) lets you filter verbosity by environment. Loggers are named (logging.getLogger(__name__)) creating a hierarchy matching the module structure. Handlers direct output to files, streams, or external services. Formatters define the output format. Never use print() for operational logging — it has no severity, no filtering, no structured output, and cannot be silenced in production without code changes.
Common Misconception
✗ print() is fine for quick debugging and can be removed later — print() accumulates in codebases and has no off switch; logging.debug() can be suppressed at the handler level.
Why It Matters
Structured logging with the logging module integrates with log aggregation tools (ELK, Loki, Datadog) and enables filtering by severity in production — print() cannot.
Common Mistakes
Using the root logger (logging.info()) instead of a named logger — root logger pollution breaks third-party library logging.
Configuring logging in library code — libraries should add NullHandler only; applications configure logging.
f-string interpolation in log messages: logger.debug(f'Value: {x}') — evaluated even when DEBUG is disabled; use % formatting.
Not setting log level for third-party libraries — they default to WARNING; chatty libraries need explicit suppression.
Code Examples
✗ Vulnerable
# print() for logging — no severity, no filtering:
def process_order(order_id):
print(f'Processing order {order_id}') # No level, no off switch
result = do_processing()
print(f'Result: {result}') # Pollutes production output
✓ Fixed
# Named logger with structured output:
import logging
logger = logging.getLogger(__name__) # Named after module
def process_order(order_id: int) -> None:
logger.info('Processing order', extra={'order_id': order_id})
try:
result = do_processing()
logger.debug('Processing result', extra={'order_id': order_id, 'result': result})
except ProcessingError:
logger.error('Order processing failed', extra={'order_id': order_id}, exc_info=True)
💬 Logging output is a primary input consumed by observability platforms (logs alongside metrics and traces), so py_logging feeding into observability fits the input→aggregate shape of 'feeds'. Direction is correct: logs flow into the observability aggregate, not the reverse.
🧱FUNDAMENTALS— new to this? Start with the ground floor.
PythongeneralPython is a programming language known for readable syntax and versatility, used for web development, data science, automation, and more.
Python's gentle learning curve makes it an ideal first language, while its vast ecosystem keeps it relevant for machine learning, APIs, and DevOps. Skills transfer directly to professional environments because Python runs in production at companies of every size.
💡 When Python throws IndentationError, check that every block uses the same whitespace style—pick spaces (preferably 4) and stick with them everywhere.
Use Python's logging module with a JSON formatter for structured logs — never use print() for application logging; configure log level per module not globally