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 usingtime.time()g.request_time: A lambda function defined aslambda: "%.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']isTrue, checked inapp/__init__.py(lines 69-75). - Hook-based implementation: The
apply_request_logfunction inapp/core/logger.py(lines 99-126) registers Flaskbefore_requestandafter_requesthooks. - Performance metrics: Captures request start time using
g.request_start_timeand calculates duration via theg.request_timelambda 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
--debugflag, 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →