Basic Logging

When your application runs on a server, you can't open a debugger and step through the code. Logging is how you see what's happening inside your application — both during normal operation and when things go wrong.

Why Logging Matters

Print statements work during development, but they're not enough for production:

  • You need to see logs without being connected to the server
  • You need timestamps to understand when things happened
  • You need severity levels to filter important messages
  • You need structured data for searching and analysis

Proper logging gives you visibility into your running application.

Log Levels

Logging libraries provide severity levels:

  • DEBUG: Detailed information for diagnosing problems
  • INFO: Confirmation that things are working as expected
  • WARNING: Something unexpected happened, but the application continues
  • ERROR: A serious problem prevented something from working
  • CRITICAL: The application may not be able to continue

In production, you typically show INFO and above. During debugging, you might enable DEBUG.

Setting Up Logging

Python's built-in logging module is straightforward:

import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

Now you can log throughout your application:

logger.info("Application started")
logger.warning("Rate limit approaching")
logger.error("Database connection failed")

What to Log

Log events that help you understand your application's behavior:

  • Application startup and shutdown
  • Incoming requests (method, path, user)
  • Important business events (user created, order placed)
  • Errors and exceptions with context
  • Performance data (slow queries, high memory)

What NOT to Log

Some data should never appear in logs:

  • Passwords and authentication tokens
  • API keys and secrets
  • Credit card numbers
  • Personal data (depending on regulations)
  • Full request bodies that might contain sensitive data

If you accidentally log secrets, they end up in log files, log aggregation services, and potentially backups — all places attackers might look.

Logging in Practice

Here's a realistic example:

@app.route('/todos', methods=['POST'])
def create_todo():
    logger.info(f"Creating todo for user {current_user.id}")
    try:
        todo = save_todo(request.json['text'])
        logger.info(f"Created todo {todo.id}")
        return jsonify(todo.to_dict()), 201
    except Exception as e:
        logger.error(f"Failed to create todo: {e}", exc_info=True)
        return jsonify({'error': 'Failed to create todo'}), 500

The exc_info=True parameter includes the full stack trace in the log.

See More

Further Reading

You need to be signed in to leave a comment and join the discussion