PythonicOreo
PythonicOreo

Reputation: 440

Flask stderr print to file

I would like for my python flask project to have stderr print to say "stderr.txt", and stdout to "stoud.txt"

I have looked and saw print("debug stderr", sys.stderr(file)), but I am not understanding what does mean. There isn't a specific command that I want stderr to go to, I want all flask to print to stderr.txt and stoud.txt. For example, when I run python app.py, I want to be able to do cat stderr.txt and see only the errors, and when I cat stoud.txt, I would like to see the output. there is no stdin.

Thank you in advance :)

Upvotes: 0

Views: 1142

Answers (1)

anddt
anddt

Reputation: 1651

As far as I remember (need to double check) Werkzeug doesn't use a named logger in favor of a root one, hence it's possible to change root logger behavior by passing different handlers:

from flask import Flask
import logging
from logging.handlers import RotatingFileHandler

app = Flask(__name__)

class LevelFilter(object):
    def __init__(self, level):
        self.level = level

    def filter(self, record):
        return record.levelno != self.level

# Redirect stdout and stderr to files
info_handler = RotatingFileHandler("info.log", backupCount=1)
info_handler.setLevel(logging.INFO)
# Don't print stack trace in info.log - optional
info_handler.addFilter(LevelFilter(logging.ERROR))

error_handler = RotatingFileHandler("err.log", backupCount=1)
error_handler.setLevel(logging.ERROR)

logging.root.handlers = [info_handler, error_handler]

@app.route("/")
def hello_world():
    return "Hello, world"


@app.route("/error")
def error():
    len(m)  # Some dumb error
    return "No wonder it crashed..."


if __name__ == "__main__":
    app.run(port=8080, debug=False)

Running this app and visiting / will produce the following output in info.log:

 * Running on http://127.0.0.1:8080/ (Press CTRL+C to quit)
127.0.0.1 - - [06/Oct/2020 15:57:11] "[37mGET / HTTP/1.1[0m" 200 -
127.0.0.1 - - [06/Oct/2020 15:57:21] "[35m[1mGET /error HTTP/1.1[0m" 500 -

Visiting /error will print the stack trace of the error in err.log:

Exception on /error [GET]
Traceback (most recent call last):
  File "/home/anddt/.pyenv/versions/3.8.6/envs/flask-log/lib/python3.8/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/anddt/.pyenv/versions/3.8.6/envs/flask-log/lib/python3.8/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/anddt/.pyenv/versions/3.8.6/envs/flask-log/lib/python3.8/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/anddt/.pyenv/versions/3.8.6/envs/flask-log/lib/python3.8/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/home/anddt/.pyenv/versions/3.8.6/envs/flask-log/lib/python3.8/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/anddt/.pyenv/versions/3.8.6/envs/flask-log/lib/python3.8/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "app.py", line 16, in error
    len(m)  # Some dumb error
NameError: name 'm' is not defined

If you don't mind the error stack trace appearing in both logs, you can obviously spare yourself adding the filter to the handler.

Upvotes: 2

Related Questions