# Flask Logging Made Simple for Developers

> Learn how to implement proper logging in Flask, from development to production, and avoid the pitfalls of scattered print statements.

Source: https://last9.io/blog/flask-logging/

After years of building and maintaining applications, I've realized that proper logging isn't just a nice to have – it's crucial for keeping things running smoothly.

When I first started out, I used to rely on scattered print statements, but over time, I learned how to implement logging that works efficiently from development to production. Let me show you how to set it up the right way.

## Understanding Flask Logging Fundamentals

### What Makes Flask Logging Special?

Flask integrates with Python's built-in logging module but adds some special sauce. The `app.logger` is actually an extension of standard [Python logging](https://last9.io/blog/python-logging-best-practices/) that's aware of your web application's context.

Here's a basic setup I use for every new project:

```
from flask import Flask
import logging

app = Flask(__name__)

# Basic logging setup
app.logger.setLevel(logging.INFO)

@app.route('/')
def home_page():
    app.logger.info('Home page accessed')
    return 'Hello World'
```

### Where Are Flask Logs Stored?

By default, Flask logs to stderr, but in production, you'll want to configure proper file handling:

1.  Development: Console output (when `debug=True`)
2.  Production: Log files (typically in `/var/log/` or a dedicated logs directory)
3.  Cloud: Often forwarded to services like CloudWatch or Stackdriver

## Real-World Logging Configuration

Let's look at a production-ready setup I recently implemented for a client's API service:

```
def configure_logging():
    # Create formatters and handlers
    formatter = logging.Formatter('[%(asctime)s] %(levelname)s in %(module)s: %(message)s')

    # Ensure logs directory exists
    os.makedirs('logs', exist_ok=True)

    file_handler = logging.FileHandler('logs/app.log')
    file_handler.setFormatter(formatter)
    file_handler.setLevel(logging.INFO)

    return file_handler
```

### Handling Different Log Levels

In my experience, proper log levels are crucial for production debugging:

1.  **DEBUG**: Detailed information for debugging
2.  **INFO**: General operational entries
3.  **WARNING**: Something unexpected, but not critical
4.  **ERROR**: Something failed, but the application continues
5.  **CRITICAL**: The application cannot continue

## Structured Logging for Modern Applications

When working with microservices, I always implement [structured logging](https://last9.io/blog/structured-logging/) using JSON:

```
class JSONFormatter(logging.Formatter):
    def format(self, record):
        log_record = {
            'timestamp': self.formatTime(record),
            'level': record.levelname,
            'message': record.getMessage(),
            'module': record.module
        }
        return json.dumps(log_record)
```

## Request Logging and HTTP Context

One of the most useful patterns I've developed is logging request context:

```
@app.before_request
def log_request_info():
    app.logger.info('Headers: %s', request.headers)
    app.logger.info('Body: %s', request.get_data())
```

## Flask Logging Architecture

### The Logging System

A Flask logger is built on top of Python's logging system. When you create an `app.py`, Flask automatically configures a basic logger. Here's how the components work together:

1.  **Werkzeug**: Flask's underlying WSGI library
2.  **Application Logger**: Your custom logging configuration
3.  **Request Logger**: HTTP request/response logging

#### Basic Setup

Let's start with a simple tutorial on setting up logging in a web app:

```
# app.py
from flask import Flask
from logging.config import dictConfig

def init_app():
    app = Flask(__name__)

    # Basic logging setup
    dictConfig({
        'version': 1,
        'handlers': {
            'wsgi': {
                'class': 'logging.StreamHandler',
                'stream': 'ext://flask.logging.wsgi_errors_stream',
                'formatter': 'default'
            }
        },
        'formatters': {
            'default': {
                'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
            }
        },
        'root': {
            'level': 'INFO',
            'handlers': ['wsgi']
        }
    })
    return app

```

#### Understanding Logger Components

1.  **getLogger**: Function to create or retrieve a logger
2.  **addHandler**: Method to attach logging handlers
3.  **logging.StreamHandler**: Handler for streaming logs to console
4.  **filename**: Parameter for `FileHandler` to specify log file location

## Template Integration

When working with **HTML** templates, you might want to log render events:

```
@app.route('/')
def home():
    app.logger.info('Rendering home template')
    return render_template('home.html')
```

## Using Decorators

Decorator patterns are common in Flask logging:

```
def log_route():
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            app.logger.info(f'Route {f.__name__} called')
            return f(*args, **kwargs)
        return decorated_function
    return decorator

@app.route('/api/data')
@log_route()
def get_data():
    return {'data': 'success'}
```

## Log Levels and Messages

Understanding log messages and their appropriate levels is crucial:

**Info Level**: Regular application eventspythonCopy code

```
app.logger.info('Application started')
```

**Debug Level**: Detailed information for debuggingpythonCopy code

```
app.logger.debug('Query parameters: %s', request.args)
```

**Error Level**: Application errors

```
app.logger.error('Database connection failed')
```

## Running Flask Applications

When you execute `flask run`, several logging components activate:

1.  **Werkzeug logger** for request/response
2.  **Application logger** for your code
3.  **Extension loggers** (if any)

```
$ export FLASK_APP=app.py
$ export FLASK_ENV=development
$ flask run
```

## Advanced Configuration

### Custom Log Handlers

```
class CustomHandler(logging.Handler):
    def emit(self, record):
        # Custom logging logic
        log_entry = self.format(record)
        # Store or forward log entry
```

**Request Context Logging**

```
class RequestFormatter(logging.Formatter):
    def format(self, record):
        record.url = request.url
        record.method = request.method
        return super().format(record)
```

## Production Best Practices

After dealing with numerous production issues, here are my top logging recommendations:

**Log Rotation**: Implement it from day one

```
from logging.handlers import RotatingFileHandler

handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=3)
```

**Structured Data**: Always include key context

```
app.logger.info('User action', extra={
    'user_id': current_user.id,
    'action': 'purchase',
    'amount': 99.99
})
```

**Error Tracking**: Integrate with error tracking services

```
@app.errorhandler(Exception)
def handle_exception(e):
    app.logger.error(f'Unhandled exception: {e}', exc_info=True)
    return 'Internal Server Error', 500
```

## Debugging with Flask Logs

Here's my debugging workflow:

**Enable debug mode temporarily**:

```
app.config['DEBUG'] = True
```

**Set up detailed logging**:

```
app.logger.setLevel(logging.DEBUG)
```

**Add context-specific logging**:

```
@app.route('/api/data')
def get_data():
    app.logger.debug(f'Query parameters: {request.args}')
    # ... rest of the view code
```

## Testing Your Logging Setup

Here's how I test logging configurations:

```
def test_logging_configuration():
    with app.test_client() as client:
        response = client.get('/')
        assert 'Home page accessed' in open('logs/app.log').read()
```

## Monitoring and Alerts

For production applications, I recommend:

1.  Setting up log aggregation (ELK Stack or similar)
2.  Implementing log-based alerts
3.  Regular log analysis for patterns

## Conclusion

Proper logging in Flask is a journey, not a destination. Start simple, then gradually enhance your logging as your application grows.

Got more questions? Come [chat with us on Discord](https://discord.com/invite/W8gMppQC4b)! We have a dedicated channel where you can connect with other developers and discuss your use case.

## Additional Resources

- [Official Flask Documentation](https://flask.palletsprojects.com/)
- [Python Logging Cookbook](https://docs.python.org/3/howto/logging-cookbook.html)

## FAQs

**Q: Where can I see Flask logs?**

A: By default, they appear in your terminal. In production, check your configured log files or logging service.

**Q: Do I need to run Flask in debug mode?**

A: Only during development. Never in production!

**Q: How does logging work in Flask?**

A: Flask uses Python's logging module but provides its own logger instance (`app.logger`) that's aware of the web application context.

**Q: How do I enable logging in `views.py`?**

A: Import the logger from your app instance or use Flask's `current_app`: `python from flask import current_app current_app.logger.info('Message from view')`
