Logging is one of those things on which all developers agree, what we don’t agree with is the format.
You can log using “free text”, agree on a structure of use full JSON.
I tend to use a combination of free text and structured logging. My favorite logging library so far is lograge for Rails which funnily enough is described by the authors as "An attempt to tame Rails' default policy to log everything"
.
Flask definitely doesn’t get logging right by default and I think it has to do also with how complicated Python’s default logging which honestly I never completely understood.
Anyway, back on the scope of the article. Lograge is pretty neat because it turns this:
Started GET "/" for 127.0.0.1 at 2012-03-10 14:28:14 +0100Processing by HomeController#index as HTMLRendered text template within layouts/application (0.0ms)Rendered layouts/_assets.html.erb (2.0ms)Rendered layouts/_top.html.erb (2.6ms)Rendered layouts/_about.html.erb (0.3ms)Rendered layouts/_google_analytics.html.erb (0.4ms)Completed 200 OK in 79ms (Views: 78.8ms | ActiveRecord: 0.0ms)Started GET "/" for 127.0.0.1 at 2012-03-10 14:28:14 +0100 Processing by HomeController#index as HTML Rendered text template within layouts/application (0.0ms) Rendered layouts/_assets.html.erb (2.0ms) Rendered layouts/_top.html.erb (2.6ms) Rendered layouts/_about.html.erb (0.3ms) Rendered layouts/_google_analytics.html.erb (0.4ms) Completed 200 OK in 79ms (Views: 78.8ms | ActiveRecord: 0.0ms)Started GET "/" for 127.0.0.1 at 2012-03-10 14:28:14 +0100 Processing by HomeController#index as HTML Rendered text template within layouts/application (0.0ms) Rendered layouts/_assets.html.erb (2.0ms) Rendered layouts/_top.html.erb (2.6ms) Rendered layouts/_about.html.erb (0.3ms) Rendered layouts/_google_analytics.html.erb (0.4ms) Completed 200 OK in 79ms (Views: 78.8ms | ActiveRecord: 0.0ms)
Enter fullscreen mode Exit fullscreen mode
into this:
method=GET path=/jobs/833552.json format=json controller=JobsController action=show status=200 duration=58.33 view=40.43 db=15.26method=GET path=/jobs/833552.json format=json controller=JobsController action=show status=200 duration=58.33 view=40.43 db=15.26method=GET path=/jobs/833552.json format=json controller=JobsController action=show status=200 duration=58.33 view=40.43 db=15.26
Enter fullscreen mode Exit fullscreen mode
I wanted to replicate that with the latest released version of Flask (v0.12.2) and add some coloring to get to this:
Info to collect
As you can see from the image we need:
- request method
- request path
- response status code
- request time
- time stamp in RFC339 format
- request ip
- request host
- request params
How to collect it in Flask
Flask has hooks to inject your code at different stages of requests. A bit like Rails request filters.
We’re going to use before_request and after_request.
The first thing we’re going to collect it the timestamp of the beginning of the request:
<span>@app.before_request</span><span>def</span> <span>start_timer</span><span>():</span><span>g</span><span>.</span><span>start</span> <span>=</span> <span>time</span><span>.</span><span>time</span><span>()</span><span>@app.before_request</span> <span>def</span> <span>start_timer</span><span>():</span> <span>g</span><span>.</span><span>start</span> <span>=</span> <span>time</span><span>.</span><span>time</span><span>()</span>@app.before_request def start_timer(): g.start = time.time()
Enter fullscreen mode Exit fullscreen mode
app
is the Flask app, g
is the flask global object and time.time()
well… you know 🙂
The rest of the information can be collected after the request is finished with:
<span>@app.after_request</span><span>def</span> <span>log_request</span><span>(</span><span>response</span><span>):</span><span>if</span> <span>request</span><span>.</span><span>path</span> <span>==</span> <span>'</span><span>/favicon.ico</span><span>'</span><span>:</span><span>return</span> <span>response</span><span>elif</span> <span>request</span><span>.</span><span>path</span><span>.</span><span>startswith</span><span>(</span><span>'</span><span>/static</span><span>'</span><span>):</span><span>return</span> <span>response</span><span>now</span> <span>=</span> <span>time</span><span>.</span><span>time</span><span>()</span><span>duration</span> <span>=</span> <span>round</span><span>(</span><span>now</span> <span>-</span> <span>g</span><span>.</span><span>start</span><span>,</span> <span>2</span><span>)</span><span>dt</span> <span>=</span> <span>datetime</span><span>.</span><span>datetime</span><span>.</span><span>fromtimestamp</span><span>(</span><span>now</span><span>)</span><span>timestamp</span> <span>=</span> <span>rfc3339</span><span>(</span><span>dt</span><span>,</span> <span>utc</span><span>=</span><span>True</span><span>)</span><span>ip</span> <span>=</span> <span>request</span><span>.</span><span>headers</span><span>.</span><span>get</span><span>(</span><span>'</span><span>X-Forwarded-For</span><span>'</span><span>,</span> <span>request</span><span>.</span><span>remote_addr</span><span>)</span><span>host</span> <span>=</span> <span>request</span><span>.</span><span>host</span><span>.</span><span>split</span><span>(</span><span>'</span><span>:</span><span>'</span><span>,</span> <span>1</span><span>)[</span><span>0</span><span>]</span><span>args</span> <span>=</span> <span>dict</span><span>(</span><span>request</span><span>.</span><span>args</span><span>)</span><span>@app.after_request</span> <span>def</span> <span>log_request</span><span>(</span><span>response</span><span>):</span> <span>if</span> <span>request</span><span>.</span><span>path</span> <span>==</span> <span>'</span><span>/favicon.ico</span><span>'</span><span>:</span> <span>return</span> <span>response</span> <span>elif</span> <span>request</span><span>.</span><span>path</span><span>.</span><span>startswith</span><span>(</span><span>'</span><span>/static</span><span>'</span><span>):</span> <span>return</span> <span>response</span> <span>now</span> <span>=</span> <span>time</span><span>.</span><span>time</span><span>()</span> <span>duration</span> <span>=</span> <span>round</span><span>(</span><span>now</span> <span>-</span> <span>g</span><span>.</span><span>start</span><span>,</span> <span>2</span><span>)</span> <span>dt</span> <span>=</span> <span>datetime</span><span>.</span><span>datetime</span><span>.</span><span>fromtimestamp</span><span>(</span><span>now</span><span>)</span> <span>timestamp</span> <span>=</span> <span>rfc3339</span><span>(</span><span>dt</span><span>,</span> <span>utc</span><span>=</span><span>True</span><span>)</span> <span>ip</span> <span>=</span> <span>request</span><span>.</span><span>headers</span><span>.</span><span>get</span><span>(</span><span>'</span><span>X-Forwarded-For</span><span>'</span><span>,</span> <span>request</span><span>.</span><span>remote_addr</span><span>)</span> <span>host</span> <span>=</span> <span>request</span><span>.</span><span>host</span><span>.</span><span>split</span><span>(</span><span>'</span><span>:</span><span>'</span><span>,</span> <span>1</span><span>)[</span><span>0</span><span>]</span> <span>args</span> <span>=</span> <span>dict</span><span>(</span><span>request</span><span>.</span><span>args</span><span>)</span>@app.after_request def log_request(response): if request.path == '/favicon.ico': return response elif request.path.startswith('/static'): return response now = time.time() duration = round(now - g.start, 2) dt = datetime.datetime.fromtimestamp(now) timestamp = rfc3339(dt, utc=True) ip = request.headers.get('X-Forwarded-For', request.remote_addr) host = request.host.split(':', 1)[0] args = dict(request.args)
Enter fullscreen mode Exit fullscreen mode
- This does not log the favicon or requests for static files. You might want to keep them
- The timestamp is in UTC, you might want it in a specific timezone but I tend to like logs in UTC. I use rfc3339 library
- It retrieves the IP address from
X-Forwarded-For
to give precedence to proxied requests, defaults to Flask’s remote address - Host is retrieved without the optional port
The next step is to create the params and add coloring:
<span>log_params</span> <span>=</span> <span>[</span><span>(</span><span>'</span><span>method</span><span>'</span><span>,</span> <span>request</span><span>.</span><span>method</span><span>,</span> <span>'</span><span>blue</span><span>'</span><span>),</span><span>(</span><span>'</span><span>path</span><span>'</span><span>,</span> <span>request</span><span>.</span><span>path</span><span>,</span> <span>'</span><span>blue</span><span>'</span><span>),</span><span>(</span><span>'</span><span>status</span><span>'</span><span>,</span> <span>response</span><span>.</span><span>status_code</span><span>,</span> <span>'</span><span>yellow</span><span>'</span><span>),</span><span>(</span><span>'</span><span>duration</span><span>'</span><span>,</span> <span>duration</span><span>,</span> <span>'</span><span>green</span><span>'</span><span>),</span><span>(</span><span>'</span><span>time</span><span>'</span><span>,</span> <span>timestamp</span><span>,</span> <span>'</span><span>magenta</span><span>'</span><span>),</span><span>(</span><span>'</span><span>ip</span><span>'</span><span>,</span> <span>ip</span><span>,</span> <span>'</span><span>red</span><span>'</span><span>),</span><span>(</span><span>'</span><span>host</span><span>'</span><span>,</span> <span>host</span><span>,</span> <span>'</span><span>red</span><span>'</span><span>),</span><span>(</span><span>'</span><span>params</span><span>'</span><span>,</span> <span>args</span><span>,</span> <span>'</span><span>blue</span><span>'</span><span>)</span><span>]</span><span>request_id</span> <span>=</span> <span>request</span><span>.</span><span>headers</span><span>.</span><span>get</span><span>(</span><span>'</span><span>X-Request-ID</span><span>'</span><span>)</span><span>if</span> <span>request_id</span><span>:</span><span>log_params</span><span>.</span><span>append</span><span>((</span><span>'</span><span>request_id</span><span>'</span><span>,</span> <span>request_id</span><span>,</span> <span>'</span><span>yellow</span><span>'</span><span>))</span><span>log_params</span> <span>=</span> <span>[</span> <span>(</span><span>'</span><span>method</span><span>'</span><span>,</span> <span>request</span><span>.</span><span>method</span><span>,</span> <span>'</span><span>blue</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>path</span><span>'</span><span>,</span> <span>request</span><span>.</span><span>path</span><span>,</span> <span>'</span><span>blue</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>status</span><span>'</span><span>,</span> <span>response</span><span>.</span><span>status_code</span><span>,</span> <span>'</span><span>yellow</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>duration</span><span>'</span><span>,</span> <span>duration</span><span>,</span> <span>'</span><span>green</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>time</span><span>'</span><span>,</span> <span>timestamp</span><span>,</span> <span>'</span><span>magenta</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>ip</span><span>'</span><span>,</span> <span>ip</span><span>,</span> <span>'</span><span>red</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>host</span><span>'</span><span>,</span> <span>host</span><span>,</span> <span>'</span><span>red</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>params</span><span>'</span><span>,</span> <span>args</span><span>,</span> <span>'</span><span>blue</span><span>'</span><span>)</span> <span>]</span> <span>request_id</span> <span>=</span> <span>request</span><span>.</span><span>headers</span><span>.</span><span>get</span><span>(</span><span>'</span><span>X-Request-ID</span><span>'</span><span>)</span> <span>if</span> <span>request_id</span><span>:</span> <span>log_params</span><span>.</span><span>append</span><span>((</span><span>'</span><span>request_id</span><span>'</span><span>,</span> <span>request_id</span><span>,</span> <span>'</span><span>yellow</span><span>'</span><span>))</span>log_params = [ ('method', request.method, 'blue'), ('path', request.path, 'blue'), ('status', response.status_code, 'yellow'), ('duration', duration, 'green'), ('time', timestamp, 'magenta'), ('ip', ip, 'red'), ('host', host, 'red'), ('params', args, 'blue') ] request_id = request.headers.get('X-Request-ID') if request_id: log_params.append(('request_id', request_id, 'yellow'))
Enter fullscreen mode Exit fullscreen mode
I also optionally log the request id
which is set by Heroku.
The last part is actually building the line and outputting it:
<span>parts</span> <span>=</span> <span>[]</span> <span># as any dev I hate naming temporary variables :-) </span> <span>for</span> <span>name</span><span>,</span> <span>value</span><span>,</span> <span>color</span> <span>in</span> <span>log_params</span><span>:</span><span>part</span> <span>=</span> <span>color</span><span>(</span><span>"</span><span>{}={}</span><span>"</span><span>.</span><span>format</span><span>(</span><span>name</span><span>,</span> <span>value</span><span>),</span> <span>fg</span><span>=</span><span>color</span><span>)</span><span>parts</span><span>.</span><span>append</span><span>(</span><span>part</span><span>)</span><span>line</span> <span>=</span> <span>"</span><span> </span><span>"</span><span>.</span><span>join</span><span>(</span><span>parts</span><span>)</span><span>app</span><span>.</span><span>logger</span><span>.</span><span>info</span><span>(</span><span>line</span><span>)</span><span>parts</span> <span>=</span> <span>[]</span> <span># as any dev I hate naming temporary variables :-) </span> <span>for</span> <span>name</span><span>,</span> <span>value</span><span>,</span> <span>color</span> <span>in</span> <span>log_params</span><span>:</span> <span>part</span> <span>=</span> <span>color</span><span>(</span><span>"</span><span>{}={}</span><span>"</span><span>.</span><span>format</span><span>(</span><span>name</span><span>,</span> <span>value</span><span>),</span> <span>fg</span><span>=</span><span>color</span><span>)</span> <span>parts</span><span>.</span><span>append</span><span>(</span><span>part</span><span>)</span> <span>line</span> <span>=</span> <span>"</span><span> </span><span>"</span><span>.</span><span>join</span><span>(</span><span>parts</span><span>)</span> <span>app</span><span>.</span><span>logger</span><span>.</span><span>info</span><span>(</span><span>line</span><span>)</span>parts = [] # as any dev I hate naming temporary variables :-) for name, value, color in log_params: part = color("{}={}".format(name, value), fg=color) parts.append(part) line = " ".join(parts) app.logger.info(line)
Enter fullscreen mode Exit fullscreen mode
color
comes from the ansicolors library.
This is the whole snippet:
<span>import</span> <span>datetime</span><span>import</span> <span>time</span><span>import</span> <span>colors</span><span>from</span> <span>flask</span> <span>import</span> <span>g</span><span>,</span> <span>request</span><span>from</span> <span>rfc3339</span> <span>import</span> <span>rfc3339</span><span>app</span> <span>=</span> <span>create_your_flask_app</span><span>()</span><span>@app.before_request</span><span>def</span> <span>start_timer</span><span>():</span><span>g</span><span>.</span><span>start</span> <span>=</span> <span>time</span><span>.</span><span>time</span><span>()</span><span>@app.after_request</span><span>def</span> <span>log_request</span><span>(</span><span>response</span><span>):</span><span>if</span> <span>request</span><span>.</span><span>path</span> <span>==</span> <span>'</span><span>/favicon.ico</span><span>'</span><span>:</span><span>return</span> <span>response</span><span>elif</span> <span>request</span><span>.</span><span>path</span><span>.</span><span>startswith</span><span>(</span><span>'</span><span>/static</span><span>'</span><span>):</span><span>return</span> <span>response</span><span>now</span> <span>=</span> <span>time</span><span>.</span><span>time</span><span>()</span><span>duration</span> <span>=</span> <span>round</span><span>(</span><span>now</span> <span>-</span> <span>g</span><span>.</span><span>start</span><span>,</span> <span>2</span><span>)</span><span>dt</span> <span>=</span> <span>datetime</span><span>.</span><span>datetime</span><span>.</span><span>fromtimestamp</span><span>(</span><span>now</span><span>)</span><span>timestamp</span> <span>=</span> <span>rfc3339</span><span>(</span><span>dt</span><span>,</span> <span>utc</span><span>=</span><span>True</span><span>)</span><span>ip</span> <span>=</span> <span>request</span><span>.</span><span>headers</span><span>.</span><span>get</span><span>(</span><span>'</span><span>X-Forwarded-For</span><span>'</span><span>,</span> <span>request</span><span>.</span><span>remote_addr</span><span>)</span><span>host</span> <span>=</span> <span>request</span><span>.</span><span>host</span><span>.</span><span>split</span><span>(</span><span>'</span><span>:</span><span>'</span><span>,</span> <span>1</span><span>)[</span><span>0</span><span>]</span><span>args</span> <span>=</span> <span>dict</span><span>(</span><span>request</span><span>.</span><span>args</span><span>)</span><span>log_params</span> <span>=</span> <span>[</span><span>(</span><span>'</span><span>method</span><span>'</span><span>,</span> <span>request</span><span>.</span><span>method</span><span>,</span> <span>'</span><span>blue</span><span>'</span><span>),</span><span>(</span><span>'</span><span>path</span><span>'</span><span>,</span> <span>request</span><span>.</span><span>path</span><span>,</span> <span>'</span><span>blue</span><span>'</span><span>),</span><span>(</span><span>'</span><span>status</span><span>'</span><span>,</span> <span>response</span><span>.</span><span>status_code</span><span>,</span> <span>'</span><span>yellow</span><span>'</span><span>),</span><span>(</span><span>'</span><span>duration</span><span>'</span><span>,</span> <span>duration</span><span>,</span> <span>'</span><span>green</span><span>'</span><span>),</span><span>(</span><span>'</span><span>time</span><span>'</span><span>,</span> <span>timestamp</span><span>,</span> <span>'</span><span>magenta</span><span>'</span><span>),</span><span>(</span><span>'</span><span>ip</span><span>'</span><span>,</span> <span>ip</span><span>,</span> <span>'</span><span>red</span><span>'</span><span>),</span><span>(</span><span>'</span><span>host</span><span>'</span><span>,</span> <span>host</span><span>,</span> <span>'</span><span>red</span><span>'</span><span>),</span><span>(</span><span>'</span><span>params</span><span>'</span><span>,</span> <span>args</span><span>,</span> <span>'</span><span>blue</span><span>'</span><span>)</span><span>]</span><span>request_id</span> <span>=</span> <span>request</span><span>.</span><span>headers</span><span>.</span><span>get</span><span>(</span><span>'</span><span>X-Request-ID</span><span>'</span><span>)</span><span>if</span> <span>request_id</span><span>:</span><span>log_params</span><span>.</span><span>append</span><span>((</span><span>'</span><span>request_id</span><span>'</span><span>,</span> <span>request_id</span><span>,</span> <span>'</span><span>yellow</span><span>'</span><span>))</span><span>parts</span> <span>=</span> <span>[]</span><span>for</span> <span>name</span><span>,</span> <span>value</span><span>,</span> <span>color</span> <span>in</span> <span>log_params</span><span>:</span><span>part</span> <span>=</span> <span>colors</span><span>.</span><span>color</span><span>(</span><span>"</span><span>{}={}</span><span>"</span><span>.</span><span>format</span><span>(</span><span>name</span><span>,</span> <span>value</span><span>),</span> <span>fg</span><span>=</span><span>color</span><span>)</span><span>parts</span><span>.</span><span>append</span><span>(</span><span>part</span><span>)</span><span>line</span> <span>=</span> <span>"</span><span> </span><span>"</span><span>.</span><span>join</span><span>(</span><span>parts</span><span>)</span><span>app</span><span>.</span><span>logger</span><span>.</span><span>info</span><span>(</span><span>line</span><span>)</span><span>return</span> <span>response</span><span>import</span> <span>datetime</span> <span>import</span> <span>time</span> <span>import</span> <span>colors</span> <span>from</span> <span>flask</span> <span>import</span> <span>g</span><span>,</span> <span>request</span> <span>from</span> <span>rfc3339</span> <span>import</span> <span>rfc3339</span> <span>app</span> <span>=</span> <span>create_your_flask_app</span><span>()</span> <span>@app.before_request</span> <span>def</span> <span>start_timer</span><span>():</span> <span>g</span><span>.</span><span>start</span> <span>=</span> <span>time</span><span>.</span><span>time</span><span>()</span> <span>@app.after_request</span> <span>def</span> <span>log_request</span><span>(</span><span>response</span><span>):</span> <span>if</span> <span>request</span><span>.</span><span>path</span> <span>==</span> <span>'</span><span>/favicon.ico</span><span>'</span><span>:</span> <span>return</span> <span>response</span> <span>elif</span> <span>request</span><span>.</span><span>path</span><span>.</span><span>startswith</span><span>(</span><span>'</span><span>/static</span><span>'</span><span>):</span> <span>return</span> <span>response</span> <span>now</span> <span>=</span> <span>time</span><span>.</span><span>time</span><span>()</span> <span>duration</span> <span>=</span> <span>round</span><span>(</span><span>now</span> <span>-</span> <span>g</span><span>.</span><span>start</span><span>,</span> <span>2</span><span>)</span> <span>dt</span> <span>=</span> <span>datetime</span><span>.</span><span>datetime</span><span>.</span><span>fromtimestamp</span><span>(</span><span>now</span><span>)</span> <span>timestamp</span> <span>=</span> <span>rfc3339</span><span>(</span><span>dt</span><span>,</span> <span>utc</span><span>=</span><span>True</span><span>)</span> <span>ip</span> <span>=</span> <span>request</span><span>.</span><span>headers</span><span>.</span><span>get</span><span>(</span><span>'</span><span>X-Forwarded-For</span><span>'</span><span>,</span> <span>request</span><span>.</span><span>remote_addr</span><span>)</span> <span>host</span> <span>=</span> <span>request</span><span>.</span><span>host</span><span>.</span><span>split</span><span>(</span><span>'</span><span>:</span><span>'</span><span>,</span> <span>1</span><span>)[</span><span>0</span><span>]</span> <span>args</span> <span>=</span> <span>dict</span><span>(</span><span>request</span><span>.</span><span>args</span><span>)</span> <span>log_params</span> <span>=</span> <span>[</span> <span>(</span><span>'</span><span>method</span><span>'</span><span>,</span> <span>request</span><span>.</span><span>method</span><span>,</span> <span>'</span><span>blue</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>path</span><span>'</span><span>,</span> <span>request</span><span>.</span><span>path</span><span>,</span> <span>'</span><span>blue</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>status</span><span>'</span><span>,</span> <span>response</span><span>.</span><span>status_code</span><span>,</span> <span>'</span><span>yellow</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>duration</span><span>'</span><span>,</span> <span>duration</span><span>,</span> <span>'</span><span>green</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>time</span><span>'</span><span>,</span> <span>timestamp</span><span>,</span> <span>'</span><span>magenta</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>ip</span><span>'</span><span>,</span> <span>ip</span><span>,</span> <span>'</span><span>red</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>host</span><span>'</span><span>,</span> <span>host</span><span>,</span> <span>'</span><span>red</span><span>'</span><span>),</span> <span>(</span><span>'</span><span>params</span><span>'</span><span>,</span> <span>args</span><span>,</span> <span>'</span><span>blue</span><span>'</span><span>)</span> <span>]</span> <span>request_id</span> <span>=</span> <span>request</span><span>.</span><span>headers</span><span>.</span><span>get</span><span>(</span><span>'</span><span>X-Request-ID</span><span>'</span><span>)</span> <span>if</span> <span>request_id</span><span>:</span> <span>log_params</span><span>.</span><span>append</span><span>((</span><span>'</span><span>request_id</span><span>'</span><span>,</span> <span>request_id</span><span>,</span> <span>'</span><span>yellow</span><span>'</span><span>))</span> <span>parts</span> <span>=</span> <span>[]</span> <span>for</span> <span>name</span><span>,</span> <span>value</span><span>,</span> <span>color</span> <span>in</span> <span>log_params</span><span>:</span> <span>part</span> <span>=</span> <span>colors</span><span>.</span><span>color</span><span>(</span><span>"</span><span>{}={}</span><span>"</span><span>.</span><span>format</span><span>(</span><span>name</span><span>,</span> <span>value</span><span>),</span> <span>fg</span><span>=</span><span>color</span><span>)</span> <span>parts</span><span>.</span><span>append</span><span>(</span><span>part</span><span>)</span> <span>line</span> <span>=</span> <span>"</span><span> </span><span>"</span><span>.</span><span>join</span><span>(</span><span>parts</span><span>)</span> <span>app</span><span>.</span><span>logger</span><span>.</span><span>info</span><span>(</span><span>line</span><span>)</span> <span>return</span> <span>response</span>import datetime import time import colors from flask import g, request from rfc3339 import rfc3339 app = create_your_flask_app() @app.before_request def start_timer(): g.start = time.time() @app.after_request def log_request(response): if request.path == '/favicon.ico': return response elif request.path.startswith('/static'): return response now = time.time() duration = round(now - g.start, 2) dt = datetime.datetime.fromtimestamp(now) timestamp = rfc3339(dt, utc=True) ip = request.headers.get('X-Forwarded-For', request.remote_addr) host = request.host.split(':', 1)[0] args = dict(request.args) log_params = [ ('method', request.method, 'blue'), ('path', request.path, 'blue'), ('status', response.status_code, 'yellow'), ('duration', duration, 'green'), ('time', timestamp, 'magenta'), ('ip', ip, 'red'), ('host', host, 'red'), ('params', args, 'blue') ] request_id = request.headers.get('X-Request-ID') if request_id: log_params.append(('request_id', request_id, 'yellow')) parts = [] for name, value, color in log_params: part = colors.color("{}={}".format(name, value), fg=color) parts.append(part) line = " ".join(parts) app.logger.info(line) return response
Enter fullscreen mode Exit fullscreen mode
暂无评论内容