Flask日志-werkzeug和flask應用的日志為什么會輸出到一個日志文件


日志的配置

logger.py

import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)
# log_path =''
log_name = 'loger.log'
fh = logging.FileHandler(log_name, mode='a')
fh.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
fh.setFormatter(formatter)
logger.addHandler(fh)

app.py

from flask import Flask

from logger import logger

app = Flask(__name__)

@app.route('/route')
def hello():
    logger.info('123')
    app.logger.warning('456')
    return 'hello world!'

訪問/route日志是這樣的

2021-04-26 14:59:51,629 - _internal.py[line:113] - WARNING:  * Debugger is active!
2021-04-26 14:59:51,641 - _internal.py[line:113] - INFO:  * Debugger PIN: 332-792-581
2021-04-26 14:59:51,684 - _internal.py[line:113] - INFO:  * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
2021-04-26 15:03:52,962 - __init__.py[line:32] - INFO: 123
2021-04-26 15:03:52,962 - __init__.py[line:33] - WARNING: 456
2021-04-26 15:03:52,964 - _internal.py[line:113] - INFO: 127.0.0.1 - - [26/Apr/2021 15:03:52] "GET /route HTTP/1.1" 200 -

werkzeug日志

2021-04-26 15:03:52,964 - _internal.py[line:113] - INFO: 127.0.0.1 - - [26/Apr/2021 15:03:52] "GET /route HTTP/1.1" 200 -

這條日志是werkzeug產生的,在_internal.py可以看到

def _log(type, message, *args, **kwargs):
    """Log into the internal werkzeug logger."""
    global _logger
    if _logger is None:
        import logging
        _logger = logging.getLogger('werkzeug')
        # Only set up a default log handler if the
        # end-user application didn't set anything up.
        if not logging.root.handlers and _logger.level == logging.NOTSET:
            _logger.setLevel(logging.INFO)
            handler = logging.StreamHandler()
            _logger.addHandler(handler)
    getattr(_logger, type)(message.rstrip(), *args, **kwargs)

可以看到,該logger使用的name是werkzeug
logging.root.handlerslogging.RootLogger對象不存在時,會為logger添加StreamHandler,從而我們在控制台可以看到該信息
當存在logging.RootLogger對象時,會根據RootLogger定義的格式,輸出到文件或控制台

app日志

falsk創建日志對象

def logger(self):
    return create_logger(self)


def create_logger(app):
    logger = logging.getLogger(app.name)

    # 1.1.0 changes name of logger, warn if config is detected for old
    # name and not new name
    for old_name in ("flask.app", "flask"):
        old_logger = logging.getLogger(old_name)

        if _has_config(old_logger) and not _has_config(logger):
            warnings.warn(
                "'app.logger' is named '{name}' for this application,"
                " but configuration was found for '{old_name}', which"
                " no longer has an effect. The logging configuration"
                " should be moved to '{name}'.".format(name=app.name, old_name=old_name)
            )
            break

    if app.debug and not logger.level:
        logger.setLevel(logging.DEBUG)

    if not has_level_handler(logger):
        logger.addHandler(default_handler)

    return logger

可以看到,該logger使用的name是app.name

為什么兩個不同的logger會輸出到同一個日志文件?

我們看`logging.getLogger()的代碼

def getLogger(name=None):
    """
    Return a logger with the specified name, creating it if necessary.

    If no name is specified, return the root logger.
    """
    if not name or isinstance(name, str) and name == root.name:
        return root
    return Logger.manager.getLogger(name)

class RootLogger(Logger):
    """
    A root logger is not that different to any other logger, except that
    it must have a logging level and there is only one instance of it in
    the hierarchy.
    """
    def __init__(self, level):
        """
        Initialize the logger with the name "root".
        """
        Logger.__init__(self, "root", level)

可以看到,當getlogger()不傳入參數時,會返回一個<logging.RootLogger object at 0x22189d0>
Logger是層次結構的,使用 '.' 點號分割

import logging
root = logging.getLogger()
logger = logging.getLogger(__name__)
logger1 = logging.getLogger(__name__ + ".child")
print(root.name,type(root),root.parent,id(root))
root <class 'logging.RootLogger'> None 2265089600672
print(logger.name, type(logger), id(logger), id((logger.parent)))
__main__ <class 'logging.Logger'> 2265139887408 2265089600672
print(logger1.name, type(logger1), id(logger1), id((logger1.parent)))
__main__.child <class 'logging.Logger'> 2265139884384 2265139887408

子對象會將記錄共享到父對象,所以RootLogger會包含所有子對象的記錄並將其記錄到文件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM