flask/flask-docs/installation.html
2025-04-11 03:04:22 +00:00

275 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 &#8212; 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> &#187;</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">&#39;/login&#39;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;POST&#39;</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">&#39;username&#39;</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">&#39;password&#39;</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">&#39;</span><span class="si">%s</span><span class="s1"> logged in successfully&#39;</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">&#39;index&#39;</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">&#39;</span><span class="si">%s</span><span class="s1"> failed to log in&#39;</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 dont configure logging, Pythons 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 Flasks 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">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="s1">&#39;formatters&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;default&#39;</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;[</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">&#39;</span><span class="p">,</span>
<span class="p">}},</span>
<span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;wsgi&#39;</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.StreamHandler&#39;</span><span class="p">,</span>
<span class="s1">&#39;stream&#39;</span><span class="p">:</span> <span class="s1">&#39;ext://flask.logging.wsgi_errors_stream&#39;</span><span class="p">,</span>
<span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;default&#39;</span>
<span class="p">}},</span>
<span class="s1">&#39;root&#39;</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;INFO&#39;</span><span class="p">,</span>
<span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;wsgi&#39;</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
wont be looking at the log messages very often. The WSGI server will probably
send log messages to a file, and youll 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">&#39;127.0.0.1&#39;</span><span class="p">,</span>
<span class="n">fromaddr</span><span class="o">=</span><span class="s1">&#39;server-error@example.com&#39;</span><span class="p">,</span>
<span class="n">toaddrs</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;admin@example.com&#39;</span><span class="p">],</span>
<span class="n">subject</span><span class="o">=</span><span class="s1">&#39;Application Error&#39;</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">&#39;[</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">&#39;</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
Flasks 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">&#39;[</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">&#39;</span>
<span class="s1">&#39;</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">&#39;</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">&#39;sqlalchemy&#39;</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">&#39;other_package&#39;</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
extensions 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">
&#169; Copyright 2010 Pallets.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
</div>
</body>
</html>