0

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 :)

Nic3500
  • 8,144
  • 10
  • 29
  • 40
PythonicOreo
  • 422
  • 1
  • 4
  • 14
  • 1
    Does this answer your question? [Redirect stdout to a file in Python?](https://stackoverflow.com/questions/4675728/redirect-stdout-to-a-file-in-python) –  Oct 05 '20 at 21:06
  • i wish, but the problem is getting it to work with flask. I'm not sure how that works. – PythonicOreo Oct 05 '20 at 21:08
  • https://stackoverflow.com/questions/7152762/how-to-redirect-print-output-to-a-file-using-python –  Oct 05 '20 at 21:09
  • You can use all the normal logging stuff with flask, like RotatingFileHandlers. There's a tutorial [here](https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-vii-error-handling) although it gets to the bit about logging with flask a little way down the page :) – monsieuralfonse64 Oct 05 '20 at 21:18
  • 1
    Regarding flask logging, have a look at the links in the comments to [this related answer](https://stackoverflow.com/a/28022068/6340496). Personally, I found them very helpful in a recent project. – S3DEV Oct 05 '20 at 22:21

1 Answers1

1

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.

anddt
  • 1,589
  • 1
  • 9
  • 26
  • this is a pretty basic example but `logging` supports more complex configuration via [`dictConfig`](https://docs.python.org/3/library/logging.config.html). Check [here](https://stackoverflow.com/a/7507842/9046275) for an example. – anddt Oct 06 '20 at 20:25