admin管理员组

文章数量:1305096

I am trying to add the client IP address to the logging for a Python/Flask app

logging.py

import logging
from flask import request, has_request_context


class RequestFormatter(logging.Formatter):
    def format(self, record):
        if has_request_context():
            record.remote_addr = request.remote_addr
        else:
            record.remote_addr = 'unknown'
        return super().format(record)

stream_handler = logging.StreamHandler()

formatter = RequestFormatter('{"logger": "%(name)s", "level": "%(levelname)s", "timestamp": "%(asctime)s", "message": "%(message)s", "ip": "%(remote_addr)s", "filename": "%(filename)s", "function": "%(funcName)s", "line": %(lineno)d}')
stream_handler.setFormatter(formatter)


logging.basicConfig(level=logging.NOTSET, handlers=[stream_handler])


loggers = [logging.getLogger(name) for name in logging.root.manager.loggerDict]
for logger in loggers:
    logger.handlers = []
    logger.addHandler(stream_handler)
    logger.propagate = False


logging.getLogger().handlers = []
logging.getLogger().addHandler(stream_handler)

As of now the RequestFormatter sets the record.remote_addr to unknown because has_request_context() always returns False. I tried moving the RequestFormatting class into the app.py file, but it did not help. What am I doing wrong?

I am trying to add the client IP address to the logging for a Python/Flask app

logging.py

import logging
from flask import request, has_request_context


class RequestFormatter(logging.Formatter):
    def format(self, record):
        if has_request_context():
            record.remote_addr = request.remote_addr
        else:
            record.remote_addr = 'unknown'
        return super().format(record)

stream_handler = logging.StreamHandler()

formatter = RequestFormatter('{"logger": "%(name)s", "level": "%(levelname)s", "timestamp": "%(asctime)s", "message": "%(message)s", "ip": "%(remote_addr)s", "filename": "%(filename)s", "function": "%(funcName)s", "line": %(lineno)d}')
stream_handler.setFormatter(formatter)


logging.basicConfig(level=logging.NOTSET, handlers=[stream_handler])


loggers = [logging.getLogger(name) for name in logging.root.manager.loggerDict]
for logger in loggers:
    logger.handlers = []
    logger.addHandler(stream_handler)
    logger.propagate = False


logging.getLogger().handlers = []
logging.getLogger().addHandler(stream_handler)

As of now the RequestFormatter sets the record.remote_addr to unknown because has_request_context() always returns False. I tried moving the RequestFormatting class into the app.py file, but it did not help. What am I doing wrong?

Share Improve this question edited Feb 5 at 9:47 Kovy Jacob 1,1218 silver badges24 bronze badges asked Feb 4 at 16:28 Nephi AppelNephi Appel 11 bronze badge
Add a comment  | 

1 Answer 1

Reset to default 0

You did almost correct. I think, request context is not available in werkzeug, that's why IP is unknown. You should also change formatter of flask's default handler. You can also use .clear() for removing all handlers. I would also recommend to use your flask app's logger (e.g. app.logger.info(...).

Here is edited code by me:

import logging

from flask.logging import default_handler
from flask import Flask, request, has_request_context


LOGGING_FORMAT: str = '{"logger": "%(name)s", "level": "%(levelname)s", "timestamp": "%(asctime)s", "message": "%(message)s", "ip": "%(remote_addr)s", "filename": "%(filename)s", "function": "%(funcName)s", "line": %(lineno)d}'


class RequestFormatter(logging.Formatter):
    def format(self, record):
        if has_request_context():
            record.remote_addr = request.remote_addr
        else:
            record.remote_addr = "unknown"
        return super().format(record)


def setup_logging() -> None:
    stream_handler = logging.StreamHandler()
    logging.basicConfig(level=logging.NOTSET, handlers=[stream_handler])

    formatter = RequestFormatter(LOGGING_FORMAT)

    stream_handler.setFormatter(formatter)
    default_handler.setFormatter(formatter)

    for logger_name in logging.root.manager.loggerDict:
        logger = logging.getLogger(logger_name)
        logger.handlers.clear()
        logger.addHandler(stream_handler)
        logger.propagate = False


def make_app() -> Flask:
    app = Flask(__name__)

    @app.route("/")
    def root():
        app.logger.info("Logging works!")

        return "hello"

    return app


if __name__ == "__main__":
    setup_logging()
    make_app().run(debug=True, port=2121)

Honestly, I did not fully understand your approach. If you need JSON format logging, you can just log it in some file instead of stdout, which you can easily integrate with logging/monitoring solutions. But in stdout it looks awful.

本文标签: pythonAdding Client IP address to Flask loggingStack Overflow