275 lines
24 KiB
HTML
275 lines
24 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<html lang="en" data-content_root="./">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Logging — Flask Documentation (3.2.x)</title>
|
||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=6625fa76" />
|
||
<link rel="stylesheet" type="text/css" href="_static/flask.css?v=b87c8d14" />
|
||
<script src="_static/documentation_options.js?v=56528222"></script>
|
||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||
<script data-project="flask" data-version="3.2.x" src="_static/describe_version.js?v=fa7f30d0"></script>
|
||
<link rel="icon" href="_static/shortcut-icon.png"/>
|
||
<link rel="index" title="Index" href="genindex.html" />
|
||
<link rel="search" title="Search" href="search.html" />
|
||
<link rel="next" title="Configuration Handling" href="config.html" />
|
||
<link rel="prev" title="Debugging Application Errors" href="debugging.html" />
|
||
</head><body>
|
||
<div class="related" role="navigation" aria-label="Related">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="genindex.html" title="General Index"
|
||
accesskey="I">index</a></li>
|
||
<li class="right" >
|
||
<a href="py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="config.html" title="Configuration Handling"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="debugging.html" title="Debugging Application Errors"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="index.html">Flask Documentation (3.2.x)</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Logging</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="document">
|
||
<div class="documentwrapper">
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section id="logging">
|
||
<h1>Logging<a class="headerlink" href="#logging" title="Link to this heading">¶</a></h1>
|
||
<p>Flask uses standard Python <a class="reference external" href="https://docs.python.org/3/library/logging.html#module-logging" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging</span></code></a>. Messages about your Flask
|
||
application are logged with <a class="reference internal" href="api.html#flask.Flask.logger" title="flask.Flask.logger"><code class="xref py py-meth docutils literal notranslate"><span class="pre">app.logger</span></code></a>,
|
||
which takes the same name as <a class="reference internal" href="api.html#flask.Flask.name" title="flask.Flask.name"><code class="xref py py-attr docutils literal notranslate"><span class="pre">app.name</span></code></a>. This
|
||
logger can also be used to log your own messages.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/login'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'POST'</span><span class="p">])</span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">login</span><span class="p">():</span>
|
||
<span class="n">user</span> <span class="o">=</span> <span class="n">get_user</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">'username'</span><span class="p">])</span>
|
||
|
||
<span class="k">if</span> <span class="n">user</span><span class="o">.</span><span class="n">check_password</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">'password'</span><span class="p">]):</span>
|
||
<span class="n">login_user</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
|
||
<span class="n">app</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'</span><span class="si">%s</span><span class="s1"> logged in successfully'</span><span class="p">,</span> <span class="n">user</span><span class="o">.</span><span class="n">username</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s1">'index'</span><span class="p">))</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="n">app</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'</span><span class="si">%s</span><span class="s1"> failed to log in'</span><span class="p">,</span> <span class="n">user</span><span class="o">.</span><span class="n">username</span><span class="p">)</span>
|
||
<span class="n">abort</span><span class="p">(</span><span class="mi">401</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If you don’t configure logging, Python’s default log level is usually
|
||
‘warning’. Nothing below the configured level will be visible.</p>
|
||
<section id="basic-configuration">
|
||
<h2>Basic Configuration<a class="headerlink" href="#basic-configuration" title="Link to this heading">¶</a></h2>
|
||
<p>When you want to configure logging for your project, you should do it as soon
|
||
as possible when the program starts. If <a class="reference internal" href="api.html#flask.Flask.logger" title="flask.Flask.logger"><code class="xref py py-meth docutils literal notranslate"><span class="pre">app.logger</span></code></a>
|
||
is accessed before logging is configured, it will add a default handler. If
|
||
possible, configure logging before creating the application object.</p>
|
||
<p>This example uses <a class="reference external" href="https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">dictConfig()</span></code></a> to create a logging
|
||
configuration similar to Flask’s default, except for all logs:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">logging.config</span><span class="w"> </span><span class="kn">import</span> <span class="n">dictConfig</span>
|
||
|
||
<span class="n">dictConfig</span><span class="p">({</span>
|
||
<span class="s1">'version'</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
|
||
<span class="s1">'formatters'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'default'</span><span class="p">:</span> <span class="p">{</span>
|
||
<span class="s1">'format'</span><span class="p">:</span> <span class="s1">'[</span><span class="si">%(asctime)s</span><span class="s1">] </span><span class="si">%(levelname)s</span><span class="s1"> in </span><span class="si">%(module)s</span><span class="s1">: </span><span class="si">%(message)s</span><span class="s1">'</span><span class="p">,</span>
|
||
<span class="p">}},</span>
|
||
<span class="s1">'handlers'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'wsgi'</span><span class="p">:</span> <span class="p">{</span>
|
||
<span class="s1">'class'</span><span class="p">:</span> <span class="s1">'logging.StreamHandler'</span><span class="p">,</span>
|
||
<span class="s1">'stream'</span><span class="p">:</span> <span class="s1">'ext://flask.logging.wsgi_errors_stream'</span><span class="p">,</span>
|
||
<span class="s1">'formatter'</span><span class="p">:</span> <span class="s1">'default'</span>
|
||
<span class="p">}},</span>
|
||
<span class="s1">'root'</span><span class="p">:</span> <span class="p">{</span>
|
||
<span class="s1">'level'</span><span class="p">:</span> <span class="s1">'INFO'</span><span class="p">,</span>
|
||
<span class="s1">'handlers'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'wsgi'</span><span class="p">]</span>
|
||
<span class="p">}</span>
|
||
<span class="p">})</span>
|
||
|
||
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<section id="default-configuration">
|
||
<h3>Default Configuration<a class="headerlink" href="#default-configuration" title="Link to this heading">¶</a></h3>
|
||
<p>If you do not configure logging yourself, Flask will add a
|
||
<a class="reference external" href="https://docs.python.org/3/library/logging.handlers.html#logging.StreamHandler" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamHandler</span></code></a> to <a class="reference internal" href="api.html#flask.Flask.logger" title="flask.Flask.logger"><code class="xref py py-meth docutils literal notranslate"><span class="pre">app.logger</span></code></a>
|
||
automatically. During requests, it will write to the stream specified by the
|
||
WSGI server in <code class="docutils literal notranslate"><span class="pre">environ['wsgi.errors']</span></code> (which is usually
|
||
<a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.stderr" title="(in Python v3.13)"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.stderr</span></code></a>). Outside a request, it will log to <a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.stderr" title="(in Python v3.13)"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.stderr</span></code></a>.</p>
|
||
</section>
|
||
<section id="removing-the-default-handler">
|
||
<h3>Removing the Default Handler<a class="headerlink" href="#removing-the-default-handler" title="Link to this heading">¶</a></h3>
|
||
<p>If you configured logging after accessing
|
||
<a class="reference internal" href="api.html#flask.Flask.logger" title="flask.Flask.logger"><code class="xref py py-meth docutils literal notranslate"><span class="pre">app.logger</span></code></a>, and need to remove the default
|
||
handler, you can import and remove it:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">flask.logging</span><span class="w"> </span><span class="kn">import</span> <span class="n">default_handler</span>
|
||
|
||
<span class="n">app</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">removeHandler</span><span class="p">(</span><span class="n">default_handler</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="email-errors-to-admins">
|
||
<h2>Email Errors to Admins<a class="headerlink" href="#email-errors-to-admins" title="Link to this heading">¶</a></h2>
|
||
<p>When running the application on a remote server for production, you probably
|
||
won’t be looking at the log messages very often. The WSGI server will probably
|
||
send log messages to a file, and you’ll only check that file if a user tells
|
||
you something went wrong.</p>
|
||
<p>To be proactive about discovering and fixing bugs, you can configure a
|
||
<a class="reference external" href="https://docs.python.org/3/library/logging.handlers.html#logging.handlers.SMTPHandler" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">logging.handlers.SMTPHandler</span></code></a> to send an email when errors and higher
|
||
are logged.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
|
||
<span class="kn">from</span><span class="w"> </span><span class="nn">logging.handlers</span><span class="w"> </span><span class="kn">import</span> <span class="n">SMTPHandler</span>
|
||
|
||
<span class="n">mail_handler</span> <span class="o">=</span> <span class="n">SMTPHandler</span><span class="p">(</span>
|
||
<span class="n">mailhost</span><span class="o">=</span><span class="s1">'127.0.0.1'</span><span class="p">,</span>
|
||
<span class="n">fromaddr</span><span class="o">=</span><span class="s1">'server-error@example.com'</span><span class="p">,</span>
|
||
<span class="n">toaddrs</span><span class="o">=</span><span class="p">[</span><span class="s1">'admin@example.com'</span><span class="p">],</span>
|
||
<span class="n">subject</span><span class="o">=</span><span class="s1">'Application Error'</span>
|
||
<span class="p">)</span>
|
||
<span class="n">mail_handler</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">ERROR</span><span class="p">)</span>
|
||
<span class="n">mail_handler</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span>
|
||
<span class="s1">'[</span><span class="si">%(asctime)s</span><span class="s1">] </span><span class="si">%(levelname)s</span><span class="s1"> in </span><span class="si">%(module)s</span><span class="s1">: </span><span class="si">%(message)s</span><span class="s1">'</span>
|
||
<span class="p">))</span>
|
||
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">app</span><span class="o">.</span><span class="n">debug</span><span class="p">:</span>
|
||
<span class="n">app</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">mail_handler</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This requires that you have an SMTP server set up on the same server. See the
|
||
Python docs for more information about configuring the handler.</p>
|
||
</section>
|
||
<section id="injecting-request-information">
|
||
<h2>Injecting Request Information<a class="headerlink" href="#injecting-request-information" title="Link to this heading">¶</a></h2>
|
||
<p>Seeing more information about the request, such as the IP address, may help
|
||
debugging some errors. You can subclass <a class="reference external" href="https://docs.python.org/3/library/logging.html#logging.Formatter" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">logging.Formatter</span></code></a> to inject
|
||
your own fields that can be used in messages. You can change the formatter for
|
||
Flask’s default handler, the mail handler defined above, or any other
|
||
handler.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">flask</span><span class="w"> </span><span class="kn">import</span> <span class="n">has_request_context</span><span class="p">,</span> <span class="n">request</span>
|
||
<span class="kn">from</span><span class="w"> </span><span class="nn">flask.logging</span><span class="w"> </span><span class="kn">import</span> <span class="n">default_handler</span>
|
||
|
||
<span class="k">class</span><span class="w"> </span><span class="nc">RequestFormatter</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">):</span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">format</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">record</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="n">has_request_context</span><span class="p">():</span>
|
||
<span class="n">record</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">url</span>
|
||
<span class="n">record</span><span class="o">.</span><span class="n">remote_addr</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">remote_addr</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="n">record</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="kc">None</span>
|
||
<span class="n">record</span><span class="o">.</span><span class="n">remote_addr</span> <span class="o">=</span> <span class="kc">None</span>
|
||
|
||
<span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">record</span><span class="p">)</span>
|
||
|
||
<span class="n">formatter</span> <span class="o">=</span> <span class="n">RequestFormatter</span><span class="p">(</span>
|
||
<span class="s1">'[</span><span class="si">%(asctime)s</span><span class="s1">] </span><span class="si">%(remote_addr)s</span><span class="s1"> requested </span><span class="si">%(url)s</span><span class="se">\n</span><span class="s1">'</span>
|
||
<span class="s1">'</span><span class="si">%(levelname)s</span><span class="s1"> in </span><span class="si">%(module)s</span><span class="s1">: </span><span class="si">%(message)s</span><span class="s1">'</span>
|
||
<span class="p">)</span>
|
||
<span class="n">default_handler</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
|
||
<span class="n">mail_handler</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="other-libraries">
|
||
<h2>Other Libraries<a class="headerlink" href="#other-libraries" title="Link to this heading">¶</a></h2>
|
||
<p>Other libraries may use logging extensively, and you want to see relevant
|
||
messages from those logs too. The simplest way to do this is to add handlers
|
||
to the root logger instead of only the app logger.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">flask.logging</span><span class="w"> </span><span class="kn">import</span> <span class="n">default_handler</span>
|
||
|
||
<span class="n">root</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span>
|
||
<span class="n">root</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">default_handler</span><span class="p">)</span>
|
||
<span class="n">root</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">mail_handler</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Depending on your project, it may be more useful to configure each logger you
|
||
care about separately, instead of configuring only the root logger.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">logger</span> <span class="ow">in</span> <span class="p">(</span>
|
||
<span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">name</span><span class="p">),</span>
|
||
<span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">'sqlalchemy'</span><span class="p">),</span>
|
||
<span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">'other_package'</span><span class="p">),</span>
|
||
<span class="p">):</span>
|
||
<span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">default_handler</span><span class="p">)</span>
|
||
<span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">mail_handler</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<section id="werkzeug">
|
||
<h3>Werkzeug<a class="headerlink" href="#werkzeug" title="Link to this heading">¶</a></h3>
|
||
<p>Werkzeug logs basic request/response information to the <code class="docutils literal notranslate"><span class="pre">'werkzeug'</span></code> logger.
|
||
If the root logger has no handlers configured, Werkzeug adds a
|
||
<a class="reference external" href="https://docs.python.org/3/library/logging.handlers.html#logging.StreamHandler" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamHandler</span></code></a> to its logger.</p>
|
||
</section>
|
||
<section id="flask-extensions">
|
||
<h3>Flask Extensions<a class="headerlink" href="#flask-extensions" title="Link to this heading">¶</a></h3>
|
||
<p>Depending on the situation, an extension may choose to log to
|
||
<a class="reference internal" href="api.html#flask.Flask.logger" title="flask.Flask.logger"><code class="xref py py-meth docutils literal notranslate"><span class="pre">app.logger</span></code></a> or its own named logger. Consult each
|
||
extension’s documentation for details.</p>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
<div class="clearer"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<span id="sidebar-top"></span>
|
||
<div class="sphinxsidebar" role="navigation" aria-label="Main">
|
||
<div class="sphinxsidebarwrapper">
|
||
|
||
|
||
<p class="logo"><a href="index.html">
|
||
<img class="logo" src="_static/flask-vertical.png" alt="Logo of Flask"/>
|
||
</a></p>
|
||
|
||
|
||
<h3>Contents</h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">Logging</a><ul>
|
||
<li><a class="reference internal" href="#basic-configuration">Basic Configuration</a><ul>
|
||
<li><a class="reference internal" href="#default-configuration">Default Configuration</a></li>
|
||
<li><a class="reference internal" href="#removing-the-default-handler">Removing the Default Handler</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#email-errors-to-admins">Email Errors to Admins</a></li>
|
||
<li><a class="reference internal" href="#injecting-request-information">Injecting Request Information</a></li>
|
||
<li><a class="reference internal" href="#other-libraries">Other Libraries</a><ul>
|
||
<li><a class="reference internal" href="#werkzeug">Werkzeug</a></li>
|
||
<li><a class="reference internal" href="#flask-extensions">Flask Extensions</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li><a href="index.html">Overview</a>
|
||
<ul>
|
||
<li>Previous: <a href="debugging.html" title="previous chapter">Debugging Application Errors</a>
|
||
<li>Next: <a href="config.html" title="next chapter">Configuration Handling</a>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<search id="searchbox" style="display: none" role="search">
|
||
<h3 id="searchlabel">Quick search</h3>
|
||
<div class="searchformwrapper">
|
||
<form class="search" action="search.html" method="get">
|
||
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</search>
|
||
<script>document.getElementById('searchbox').style.display = "block"</script><div id="ethical-ad-placement"></div>
|
||
</div>
|
||
</div>
|
||
<div class="clearer"></div>
|
||
</div>
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2010 Pallets.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||
</div>
|
||
</body>
|
||
</html>
|