Eric Gottesman
Eric Gottesman

Reputation: 123

Simple log filtering with Flask

I'm new to Flask and I'm having trouble filtering out some logs. My use case is simple: I don't want to log health check queries, which hit the route /health.

Here's what I have:

from flask import Flask
from flask.logging import logging

class NoHealth(logging.Filter):
    def filter(self, record):
        return 'GET /health' not in record.getMessage()

no_health = NoHealth()
app = Flask(__name__)
app.logger.addFilter(no_health)
app.logger.setLevel('INFO')

@app.route('/health')
def health_check():
    return "OK"

The logs I want to drop look like this:

127.0.0.1 - - [31/Mar/2020 17:51:03] "GET /health HTTP/1.1" 200 -

They're still coming through, however. What am I missing?

Upvotes: 6

Views: 2689

Answers (3)

Brandon
Brandon

Reputation: 175

The accepted answer worked for me too, but wanted to share my own scenario for completeness.

I was trying to suppress log statements for 'static' assets (images, CSS, JS, etc.).

import logging
from logging import Filter
from logging.config import dictConfig
import os

class ExcludeStaticAssets(Filter):
    def filter(self, record):
        return 'GET /static/' not in record.getMessage()

def configure_logging(app):
    exclude_static_assets = ExcludeStaticAssets()

    flask_debug = os.getenv('FLASK_DEBUG', 0)
    log_level = logging.DEBUG if flask_debug == 1 else logging.INFO 

    dictConfig({
        'version': 1,
        'formatters': {
            'default': {
                'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
            }
        },
        'handlers': {
            'wsgi': {
                'class': 'logging.StreamHandler',
                'stream': 'ext://flask.logging.wsgi_errors_stream',
                'formatter': 'default',
            },
        },
        'root': {
            'level': log_level,
            'handlers': ['wsgi']
        }
    })

    logging.getLogger('werkzeug').addFilter(exclude_static_assets)

    logging.getLogger('flask.app').setLevel(log_level)

Upvotes: 1

wiedehopf
wiedehopf

Reputation: 11

As the accepted answer in conjunction with the code in the question doesn't quite work (at least not with flask 2.2.2), here is the code that worked for me:

from flask.logging import logging as flask_logging

# don't log static assets
class NoStatic(flask_logging.Filter):
    def filter(record):
        return 'GET /static' not in record.getMessage()
flask_logging.getLogger("werkzeug").addFilter(NoStatic)

For the filter function definition the argument self was omitted. As in the python documentation, logging filter functions should only have the record argument: https://docs.python.org/3/library/logging.html#filter-objects

Upvotes: 1

Nazar Gondaruk
Nazar Gondaruk

Reputation: 147

Access logs are written by werzeug (web server running flask app in this case). So, better option would be to increase logging level to warning:

logging.getLogger("werkzeug").setLevel('WARNING')

In case you really want to use custom filter NoHealth, you can go with following solution:

logging.getLogger("werkzeug").addFilter(NoHealth())

Upvotes: 6

Related Questions