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

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, 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 within the register_plugin function (lines 69-75). During application initialization, the code evaluates the DEBUG configuration flag:


# 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 (lines 16-22). When starting the server with the --debug option, the flag propagates to Flask's internal configuration:


# 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 (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:


# 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:

@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:

[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:

python server.py run --debug

Or using the Flask CLI:

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 (lines 69-75).
  • Hook-based implementation: The apply_request_log function in 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, 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, 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →