3

The Flask tutorial has an example of emailing yourself when an error occurs. I would like to add some information from request, but kept receiving an error:

RuntimeError: working outside of request context

Here is what I have:

if  __name__ == '__main__':
    if not app.debug:  

        # create mail handler
        import logging
        from logging.handlers import SMTPHandler
        mail_handler = SMTPHandler('127.0.0.1',
                               '[email protected]',
                               ['[email protected]'], 'YourApplication Failed')

        # Log format
        from logging import Formatter
        mail_handler.setFormatter(Formatter('''
        Message type:       %(levelname)s
        Location:           %(pathname)s:%(lineno)d
        Module:             %(module)s
        Function:           %(funcName)s
        Time:               %(asctime)s

        Message:

        %(message)s
        ''' % request.headers ))   # Added request here

        # Attach log handler to app
        mail_handler.setLevel(logging.ERROR)
        app.logger.addHandler(mail_handler)

How do I get the request context for logging?

1
  • were you able to solve this problem? I'm running into the same problem. Commented Nov 10, 2015 at 3:13

1 Answer 1

9

You actually need to add a filter to add what you want to the logger:

import logging

class ContextualFilter(logging.Filter):
    def filter(self, log_record):
        log_record.url = request.path
        log_record.method = request.method
        log_record.ip = request.environ.get("REMOTE_ADDR")
        log_record.headers = request.headers

        return True

Then you can register the filter with the app's logger:

context_provider = ContextualFilter()
app.logger.addFilter(context_provider)

And use the extra keys you added to the context in your formatter:

mail_handler.setFormatter(Formatter('''
    Message type:       %(levelname)s
    Location:           %(pathname)s:%(lineno)d
    Module:             %(module)s
    Function:           %(funcName)s
    Time:               %(asctime)s
    URL:                %(url)s
    Method:             %(method)s
    Headers:            %(headers)s

    Message:

    %(message)s
    '''))

Why can't I just add request.headers to my formatter

Two reasons:

  1. There is no request context when you're setting up the logger since no request is inbound
  2. Even if there was, that code won't actually do what you want it to do. It will add the request headers from the request in scope when you set up the logger (so all requests will be that first request).

See also: https://realpython.com/blog/python/python-web-applications-with-flask-part-iii/

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.