# How Request Logging Is Implemented in Debug Mode: mini-shop-server Source Code Analysis

> Discover how mini-shop-server implements request logging in debug mode. Analyze the source code to understand captured timing metrics, client IP addresses, and full request payloads when DEBUG is true.

- Repository: [A粒麦子/mini-shop-server](https://github.com/allen7d/mini-shop-server)
- Tags: internals
- Published: 2026-02-24

---

**The mini-shop-server Flask application implements request logging exclusively in debug mode by registering `before_request` and `after_request` hooks via the `apply_request_log` function in [`app/core/logger.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/core/logger.py), capturing timing metrics, client IP addresses, and full request payloads only when `app.config['DEBUG']` is `True`.**

The mini-shop-server repository demonstrates a production-safe approach to HTTP request logging in Flask. By leveraging Flask's request lifecycle hooks and conditional initialization, the application provides comprehensive debugging information during development while maintaining zero overhead in production environments. This implementation activates automatically when running the server with debug flags enabled.

## Activating Request Logging Through Debug Mode Configuration

The request logging system remains dormant unless the application explicitly runs in debug mode. This conditional activation prevents performance degradation and sensitive data exposure in production deployments.

### Configuration Detection in app/__init__.py

The activation logic resides in [`app/__init__.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/__init__.py) within the `register_plugin` function (lines 69-75). During application initialization, the code evaluates the `DEBUG` configuration flag:

```python

# app/__init__.py

def register_plugin(app):
    if app.config['DEBUG']:
        from app.core.logger import apply_request_log
        apply_request_log(app)

```

This conditional import ensures that `apply_request_log` only executes when `app.config['DEBUG']` evaluates to `True`, ensuring production servers incur no performance penalty from request timing calculations or console output operations.

### CLI Integration in server.py

The debug flag originates from the command-line interface defined in [`server.py`](https://github.com/allen7d/mini-shop-server/blob/main/server.py) (lines 16-22). When starting the server with the `--debug` option, the flag propagates to Flask's internal configuration:

```python

# server.py

@app.cli.command()
@click.option('--debug', is_flag=True, help='Enable debug mode')
def run(debug):
    app.run(debug=debug)

```

Alternatively, setting `DEBUG = True` directly in the Flask configuration file achieves the same result, automatically triggering the request logging hooks during the `register_plugin` initialization phase.

## The Request Logging Mechanism in app/core/logger.py

The core implementation resides in the `apply_request_log` function within [`app/core/logger.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/core/logger.py) (lines 99-126). This function registers Flask `before_request` and `after_request` hooks to capture comprehensive request telemetry.

### Hook Registration via apply_request_log

The `apply_request_log` function attaches two critical hooks to the Flask application instance:

```python

# app/core/logger.py – lines 99-126

def apply_request_log(app):
    @app.before_request
    def request_cost_time():
        g.request_start_time = time.time()
        g.request_time = lambda: "%.5f" % (time.time() - g.request_start_time)

    @app.after_request
    def log_response(res):
        # Detailed logging implementation follows

        return res

```

This architecture separates timing initialization from data capture, ensuring accurate performance metrics without interfering with route handler execution.

### Timing Capture with before_request

The `before_request` hook initializes request timing by storing the start timestamp in Flask's application context `g` object:

- **`g.request_start_time`**: Stores the Unix timestamp when the request begins using `time.time()`
- **`g.request_time`**: A lambda function defined as `lambda: "%.5f" % (time.time() - g.request_start_time)` that computes elapsed duration with microsecond precision

This mechanism persists timing data across the request lifecycle without requiring global variables or thread-unsafe storage.

### Data Capture and Formatting with after_request

The `after_request` hook constructs the comprehensive log entry after the response generates but before transmission to the client:

```python
@app.after_request
def log_response(res):
    message = '[%s] -> [%s] from:%s costs:%.3f ms' % (
        request.method,
        request.path,
        request.remote_addr,
        float(g.request_time()) * 1000
    )
    
    # Capture request payload

    req_body = request.get_json() if request.get_json() else {}
    data = {
        'path': request.view_args,
        'query': request.args,
        'body': req_body
    }
    message += '\n\"data\": ' + json.dumps(data, indent=4, ensure_ascii=False)
    
    # Output with blue ANSI color codes

    print('\033[0;34m')
    if request.method in ('GET', 'POST', 'PUT', 'DELETE'):
        print(message)
    print('\033[0m')
    
    return res

```

The log entry includes the HTTP method, request path, client IP address, execution time in milliseconds, and a JSON representation of path parameters, query strings, and request body content.

## Console Output Format

When debug mode is active, the console displays color-coded output for each HTTP request:

```text
[POST] -> [/api/v1/user/login] from:127.0.0.1 costs:12.345 ms
"data": {
    "path": null,
    "query": {},
    "body": {
        "username": "admin",
        "password": "******"
    }
}

```

The blue color coding (ANSI `\033[0;34m`) improves terminal readability during development sessions. The structured JSON payload provides immediate visibility into API interactions, while the millisecond timing helps identify performance bottlenecks.

## Enabling Debug Request Logging

To activate request logging, start the server with the debug flag:

```bash
python server.py run --debug

```

Or using the Flask CLI:

```bash
flask run --debug

```

Without the `--debug` flag, the `apply_request_log` function never executes, ensuring zero logging overhead in production environments where `DEBUG` defaults to `False`.

## Summary

- **Conditional activation**: Request logging only activates when `app.config['DEBUG']` is `True`, checked in [`app/__init__.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/__init__.py) (lines 69-75).
- **Hook-based implementation**: The `apply_request_log` function in [`app/core/logger.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/core/logger.py) (lines 99-126) registers Flask `before_request` and `after_request` hooks.
- **Performance metrics**: Captures request start time using `g.request_start_time` and calculates duration via the `g.request_time` lambda function.
- **Comprehensive data**: Logs HTTP method, path, client IP, execution time in milliseconds, path parameters, query arguments, and JSON body content.
- **Development-only output**: Uses ANSI color codes (`\033[0;34m`) for terminal readability and only processes standard HTTP methods (GET, POST, PUT, DELETE).
- **Zero production impact**: No logging code executes when the server starts without the `--debug` flag, ensuring optimal production performance.

## Frequently Asked Questions

### Why is request logging restricted to debug mode only?

The implementation restricts logging to debug mode to prevent sensitive data exposure and eliminate I/O overhead in production. As implemented in [`app/__init__.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/__init__.py), the `apply_request_log` function only imports and executes when `app.config['DEBUG']` evaluates to `True`. This ensures production servers incur no performance penalty from request timing calculations, JSON serialization, or console output operations.

### What specific request data does the logger capture?

According to the `log_response` function in [`app/core/logger.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/core/logger.py), the logger captures four categories of data: HTTP method and path from the request object, client IP address via `request.remote_addr`, execution time calculated from `g.request_start_time`, and payload data including path parameters (`request.view_args`), query string arguments (`request.args`), and JSON body content (`request.get_json()`).

### How does the server calculate request execution time?

The timing mechanism uses Flask's application context `g` object to persist state across hooks. The `before_request` hook sets `g.request_start_time = time.time()` when the request begins, while the `after_request` hook invokes `g.request_time()`—a lambda defined as `lambda: "%.5f" % (time.time() - g.request_start_time)`—to compute the elapsed duration in seconds, which is then converted to milliseconds for the log output.

### Can I modify the log output format or destination?

The current implementation in [`app/core/logger.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/core/logger.py) uses Python's built-in `print()` function with ANSI color codes (`\033[0;34m`) to output logs to the console. To modify the format, edit the `message` string construction and `json.dumps()` configuration within the `log_response` function. To redirect output to a file or standard logging framework, replace the `print()` statements with Python logging module calls or custom file handlers, while maintaining the debug-mode conditional check to avoid production overhead.