134

I have a Flask server running in standalone mode (using app.run()). But, I don't want any messages in the console, like

127.0.0.1 - - [15/Feb/2013 10:52:22] "GET /index.html HTTP/1.1" 200 -
...

How do I disable verbose mode?

ATOzTOA
  • 34,814
  • 22
  • 96
  • 117
  • 12
    @DemianBrecht The thing is, the logs are send to `stderr` but they are just logging each HTTP transaction, kinda irrelevant for me... – ATOzTOA Feb 15 '13 at 15:42

15 Answers15

189

You can set level of the Werkzeug logger to ERROR, in that case only errors are logged:

import logging
log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)

Here is a fully working example tested on OSX, Python 2.7.5, Flask 0.10.0:

from flask import Flask
app = Flask(__name__)

import logging
log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()
Yogesh Aggarwal
  • 1,071
  • 2
  • 12
  • 30
Drewes
  • 2,581
  • 1
  • 18
  • 18
  • 9
    This doesn't seem to stop HTTP logs going to stderr; It DOES stop the "starting" message (which clearly has the "werkzeug" module name in the log format". – rsb Jul 28 '15 at 20:05
  • 3
    Works for me. The request debug messages are supressed. Using Python 3.5.2, Flask 0.12 and Werkzeug 0.11.11 – JackLeEmmerdeur Jan 12 '17 at 10:03
  • 5
    Also works using Python 3.6, Flask 0.12 and Werkzeug 0.11.15. – vallentin Jan 21 '17 at 14:17
  • Used to work for me until I raised `abort(500)`, so don't expect this to be working in all cases. Generally, it works but it's a workaround that sometimes fails. – Tom Wojcik Apr 10 '18 at 09:55
  • 9
    Unfortunately no longer fully works due to Flask using `click.secho` – Peter Aug 09 '18 at 00:09
  • 6
    Changing the level of logging shouldn't be the solution to avoid logging one particular request only. – gented Jun 12 '19 at 13:15
22

This solution provides you a way to get your own prints and stack traces but without information level logs from flask suck as 127.0.0.1 - - [15/Feb/2013 10:52:22] "GET /index.html HTTP/1.1" 200

from flask import Flask
import logging

app = Flask(__name__)
log = logging.getLogger('werkzeug')
log.disabled = True
iamtodor
  • 734
  • 8
  • 21
18

None of the other answers worked correctly for me, but I found a solution based off Peter's comment. Flask apparently no longer uses logging for logging, and has switched to the click package. By overriding click.echo and click.secho I eliminated Flask's startup message from app.run().

import logging

import click
from flask import Flask

app = Flask(__name__)

log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)

def secho(text, file=None, nl=None, err=None, color=None, **styles):
    pass

def echo(text, file=None, nl=None, err=None, color=None, **styles):
    pass

click.echo = echo
click.secho = secho

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

Between setting the logging level to ERROR and overriding the click methods with empty functions, all non-error log output should be prevented.

Brendan Burkhart
  • 399
  • 5
  • 11
15

To suppress Serving Flask app ...:

os.environ['WERKZEUG_RUN_MAIN'] = 'true'
app.run()
Slava V
  • 16,686
  • 14
  • 60
  • 63
  • 3
    This works for me, I used it when testing flask application (using nose2) this removes the clutter in the terminal. Thanks – crispy May 28 '19 at 16:00
  • 1
    this breaks werkzeug version 2.1.0: https://github.com/cs01/gdbgui/issues/425 – MattS Apr 03 '22 at 13:01
12

In case you are using WSGI server , please set the log to None

gevent_server = gevent.pywsgi.WSGIServer(("0.0.0.0", 8080), app, log=None)
David Ongaro
  • 3,568
  • 1
  • 24
  • 36
Ami
  • 327
  • 2
  • 7
11

@Drewes solution works most of the time, but in some cases, I still tend to get werkzeug logs. If you really don't want to see any of them, I suggest you disabling it like that.

from flask import Flask
import logging

app = Flask(__name__)
log = logging.getLogger('werkzeug')
log.disabled = True
app.logger.disabled = True

For me it failed when abort(500) was raised.

Tom Wojcik
  • 5,471
  • 4
  • 32
  • 44
10

Late answer but I found a way to suppress EACH AND EVERY CONSOLE MESSAGE (including the ones displayed during an abort(...) error).

import os
import logging

logging.getLogger('werkzeug').disabled = True
os.environ['WERKZEUG_RUN_MAIN'] = 'true'

This is basically a combination of the answers given by Slava V and Tom Wojcik

progyammer
  • 1,498
  • 3
  • 17
  • 29
  • This breaks werkzeug version 2.1.0 and newer. See https://github.com/cs01/gdbgui/issues/425 and https://github.com/pallets/werkzeug/issues/2368 – gene_wood Apr 13 '22 at 21:28
8

Another reason you may want to change the logging output is for tests, and redirect the server logs to a log file.

I couldn't get the suggestion above to work either, it looks like loggers are setup as part of the app starting. I was able to get it working by changing the log levels after starting the app:

... (in setUpClass)
server = Thread(target=lambda: app.run(host=hostname, port=port, threaded=True))
server.daemon = True
server.start()
wait_for_boot(hostname, port)  # curls a health check endpoint

log_names = ['werkzeug']
app_logs = map(lambda logname: logging.getLogger(logname), log_names)
file_handler = logging.FileHandler('log/app.test.log', 'w')

for app_log in app_logs:
    for hdlr in app_log.handlers[:]:  # remove all old handlers
        app_log.removeHandler(hdlr)

    app_log.addHandler(file_handler)

Unfortunately the * Running on localhost:9151 and the first health check is still printed to standard out, but when running lots of tests it cleans up the output a ton.

"So why log_names?", you ask. In my case there were some extra logs I needed to get rid of. I was able to find which loggers to add to log_names via:

from flask import Flask
app = Flask(__name__)

import logging
print(logging.Logger.manager.loggerDict)

Side note: It would be nice if there was a flaskapp.getLogger() or something so this was more robust across versions. Any ideas?

Some more key words: flask test log remove stdout output

thanks to:

Community
  • 1
  • 1
daicoden
  • 404
  • 3
  • 10
4

I spent absolute ages trying to get rid of these response logs with all the different solutions, but as it turns out it wasn't Flask / Werkzeug but Gunicorn access logs dumped on stderr...

The solution was replacing the default access log handler with NullHandler by adding this block in the Gunicorn config file:

logconfig_dict = {
    "version": 1,
    "disable_existing_loggers": False,
    "handlers": {
        "console": {"class": "logging.StreamHandler", "level": "INFO"},
        "null": {"class": "logging.NullHandler"},
    },
    "loggers": {
        "gunicorn.error": {"level": "INFO", "propagate": False, "handlers": ["console"]},
        "gunicorn.access": {"level": "INFO", "propagate": False, "handlers": ["null"]},
    },
}
dain
  • 6,475
  • 1
  • 38
  • 47
4

somehow none of the above options, including .disabled = True, worked for me.

The following did the trick though:

logging.getLogger('werkzeug').setLevel(logging.CRITICAL)

Using the latest versions as of November 2021 under Python 3.7.3:

pip3 list | grep -E "(connexion|Flask|Werkzeug)"
connexion2               2.10.0
Flask                    2.0.2
Werkzeug                 2.0.2
sfuerte
  • 729
  • 5
  • 5
3

Here's the answer to disable all logging, including on werkzeug version 2.1.0 and newer:

import flask.cli
flask.cli.show_server_banner = lambda *args: None

import logging
logging.getLogger("werkzeug").disabled = True
Mike Conigliaro
  • 1,144
  • 1
  • 13
  • 28
1

My current workaround to silence Flask as of 2022-10.

It disables the logging and the startup banner:

class WSServer:

    ...

    @staticmethod
    def _disabled_server_banner(*args, **kwargs):
        """
        Mock for the show_server_banner method to suppress spam to stdout
        """
        pass

    def _run_server(self):
        """
        Winds-up the server.
        """
        # disable general logging
        log = logging.getLogger('werkzeug') 
        log.setLevel(logging.CRITICAL)
        # disable start-up banner
        from flask import cli
        if hasattr(cli, "show_server_banner"):
            cli.show_server_banner = self._disabled_server_banner
        ...
Alyxion
  • 66
  • 1
0

I merged custom logs and flask logs so as to provide same log format.

sample log message

For mote details: https://github.com/senthilkumarimuth/logging_for_python

  • Please provide the relevant portions of the linked sources here, to both improve searchability and protect against changes to the linked content. – sloppypasta Mar 11 '23 at 00:26
-1

A brute force way to do it if you really don't want anything to log into the console beside print() statements is to logging.basicConfig(level=logging.FATAL). This would disable all logs that are of status under fatal. It would not disable printing but yeah, just a thought :/

EDIT: I realized it would be selfish of me not to put a link to the documentation I used :) https://docs.python.org/3/howto/logging.html#logging-basic-tutorial

-3

The first point: In according to official Flask documentation, you shouldn't run Flask application using app.run(). The best solution is using uwsgi, so you can disable default flask logs using command "--disable-logging"

For example:

uwsgi --socket 0.0.0.0:8001 --disable-logging --protocol=http -w app:app

Anton Erjomin
  • 183
  • 1
  • 1
  • 9