Flask服务中Python Logger自定义字段不更新问题及优化咨询
Let me break down what's going wrong here, and show you a more robust way to add custom fields to your Flask logs.
First, the issue with your current code: While LoggerAdapter is supposed to merge the extra parameter you pass to info() with the initial extra dict, Flask's debug mode can interfere with your logging setup, or the adapter's merge logic isn't triggering correctly. That's why your data field is stuck on the initial value 0 instead of updating to 23.
Better Approach: Use a Custom Log Filter
Instead of relying on LoggerAdapter, a custom logging.Filter is more reliable and flexible—especially in Flask, where you might want to automatically include request-related context (like path, method, or client IP) alongside your custom data.
Here's a step-by-step implementation:
1. Create a Custom Filter
This filter will inject default values for custom fields, automatically add request context data when available, and respect any custom values you pass explicitly:
from flask import Flask, request, has_request_context from flask_cors import CORS import logging import json class CustomLogFilter(logging.Filter): def filter(self, record): # Set a default value for 'data' if none is provided if not hasattr(record, 'data'): record.data = 0 # Add Flask request context fields when a request is active if has_request_context(): record.request_path = request.path record.request_method = request.method record.remote_addr = request.remote_addr return True
2. Configure Your Logger Properly
Set up the logger with a valid JSON formatter, attach your custom filter, and clean up Flask's default handlers to avoid duplicate logs:
logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) # Remove Flask's default handlers to prevent conflicting log output for handler in logger.handlers[:]: logger.removeHandler(handler) # Create a stream handler and attach our custom filter ch = logging.StreamHandler() ch.addFilter(CustomLogFilter()) # Fix the JSON formatter (fix syntax errors and add proper quotes for valid JSON) formatter = logging.Formatter("""{ "name": "%(name)s", "module_name": "%(module)s", "pid": %(process)d, "level": %(levelno)d, "level_name": "%(levelname)s", "msg": "%(message)s", "data": %(data)s, "time": "%(asctime)s", "src": { "file": "%(pathname)s", "line": %(lineno)d }, "function": "%(funcName)s", "request_path": "%(request_path)s", "request_method": "%(request_method)s", "remote_addr": "%(remote_addr)s" }""") ch.setFormatter(formatter) logger.addHandler(ch)
3. Use the Logger in Your Flask Routes
Now you can pass custom data directly via the extra parameter whenever you log:
app = Flask(__name__) CORS(app) @app.route('/home', methods=["GET"]) def home(): logger.info("OK", extra={"data": 0}) return "OK" @app.route('/user', methods=["POST"]) def user_check(): req_data = json.loads(request.data) logger.info("User check request received", extra={"data": 23}) return "Check Complete" if __name__ == "__main__": app.run('0.0.0.0', debug=True)
Why This Works Better
- Flexibility: Automatically adds request context fields (like path, method, and client IP) to every log generated during a request—critical for debugging Flask apps.
- Reliability: No more issues with
LoggerAdapter's dict merging; custom fields passed viaextrawill always be respected. - Valid JSON: The formatter now produces properly formatted JSON, making it easy to parse logs with tools like ELK, Splunk, or even just
jq.
Fixing Your Original LoggerAdapter Code (If You Prefer)
If you want to stick with LoggerAdapter, the main fix is to remove Flask's default handlers before adding your own, and clean up the formatter's syntax errors:
# After creating your logger, remove default handlers for handler in logger.handlers[:]: logger.removeHandler(handler) # Then create your adapter as before adapter = logging.LoggerAdapter(logger=logger, extra=dict(data_=0))
Also fix the typo in your formatter: change "name":,%(name)s, to "name": "%(name)s", to avoid invalid JSON. This should make the data_ field update correctly when you pass extra=dict(data_=23).
内容的提问来源于stack exchange,提问作者Sociopath

