66

好的,这是我设置所有内容的代码:

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

    applogger = app.logger

    file_handler = FileHandler("error.log")
    file_handler.setLevel(logging.DEBUG)

    applogger.setLevel(logging.DEBUG)
    applogger.addHandler(file_handler)

    app.run(host='0.0.0.0')

发生的事情是

  1. error.log 被创建
  2. 从来没有写过任何东西
  3. 尽管没有添加 StreamHandler 并将 debug 设置为 false 我仍然将所有内容都发送到 STDOUT(这可能是正确的,但仍然看起来很奇怪)

我是完全离开这里还是发生了什么事?

4

7 回答 7

119

为什么不这样做:

if __name__ == '__main__':
    init_db()  # or whatever you need to do

    import logging
    logging.basicConfig(filename='error.log',level=logging.DEBUG)

    app.run(host="0.0.0.0")

如果您现在启动应用程序,您将看到 error.log 包含:

INFO:werkzeug: * Running on http://0.0.0.0:5000/

有关更多信息,请访问http://docs.python.org/2/howto/logging.html

好的,因为您坚持使用我向您展示的方法不能有两个处理程序,所以我将添加一个示例来说明这一点。首先,将此日志记录代码添加到您的主代码中:

import logging, logging.config, yaml
logging.config.dictConfig(yaml.load(open('logging.conf')))

现在还添加一些调试代码,以便我们看到我们的设置有效:

logfile    = logging.getLogger('file')
logconsole = logging.getLogger('console')
logfile.debug("Debug FILE")
logconsole.debug("Debug CONSOLE")

剩下的就是“logging.conf”程序。让我们使用它:

version: 1
formatters:
  hiformat:
    format: 'HI %(asctime)s - %(name)s - %(levelname)s - %(message)s'
  simple:
    format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:
  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: hiformat
    stream: ext://sys.stdout
  file:
    class: logging.FileHandler
    level: DEBUG
    formatter: simple
    filename: errors.log
loggers:
  console:
    level: DEBUG
    handlers: [console]
    propagate: no
  file:
    level: DEBUG
    handlers: [file]
    propagate: no
root:
  level: DEBUG
  handlers: [console,file]

这个配置比需要的更复杂,但它也显示了日志记录模块的一些特性。

现在,当我们运行我们的应用程序时,我们会看到这个输出(werkzeug 和控制台记录器):

HI 2013-07-22 16:36:13,475 - console - DEBUG - Debug CONSOLE
HI 2013-07-22 16:36:13,477 - werkzeug - INFO -  * Running on http://0.0.0.0:5000/

另请注意,使用了带有“HI”的自定义格式化程序。

现在查看“errors.log”文件。它包含:

2013-07-22 16:36:13,475 - file - DEBUG - Debug FILE
2013-07-22 16:36:13,477 - werkzeug - INFO -  * Running on http://0.0.0.0:5000/
于 2013-07-22T10:15:32.233 回答
16

好吧,我的失败源于两个误解:

1) Flask 显然会忽略所有自定义日志记录,除非它在生产模式下运行

2) debug=False 不足以让它在生产模式下运行。您必须将应用程序包装在任何类型的 WSGI 服务器中才能这样做

在我从 gevent 的 WSGI 服务器启动应用程序(并将日志记录初始化移动到更合适的位置)之后,一切似乎都运行良好

于 2013-07-22T12:27:45.110 回答
10

您在应用程序控制台中看到的输出来自底层 Werkzeug 记录器,可以通过 logging.getLogger('werkzeug') 访问该记录器。

通过将处理程序添加到该记录器以及 Flask 记录器,您的日志记录可以在开发和发布中发挥作用。

更多信息和示例代码:将 Flask 请求写入访问日志

于 2014-04-19T18:20:58.743 回答
5

这有效:

if __name__ == '__main__':
    import logging
    logFormatStr = '[%(asctime)s] p%(process)s {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s'
    logging.basicConfig(format = logFormatStr, filename = "global.log", level=logging.DEBUG)
    formatter = logging.Formatter(logFormatStr,'%m-%d %H:%M:%S')
    fileHandler = logging.FileHandler("summary.log")
    fileHandler.setLevel(logging.DEBUG)
    fileHandler.setFormatter(formatter)
    streamHandler = logging.StreamHandler()
    streamHandler.setLevel(logging.DEBUG)
    streamHandler.setFormatter(formatter)
    app.logger.addHandler(fileHandler)
    app.logger.addHandler(streamHandler)
    app.logger.info("Logging is set up.")
    app.run(host='0.0.0.0', port=8000, threaded=True)
于 2015-11-17T13:13:10.933 回答
4

我不喜欢其他答案,所以我坚持下去,似乎我必须在 Flask 完成自己的设置后进行日志记录配置。

@app.before_first_request
def initialize():

    logger = logging.getLogger("your_package_name")
    logger.setLevel(logging.DEBUG)
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    formatter = logging.Formatter(
    """%(levelname)s in %(module)s [%(pathname)s:%(lineno)d]:\n%(message)s"""
    )
    ch.setFormatter(formatter)
    logger.addHandler(ch)

我的应用程序的结构类似于

/package_name
    __main__.py <- where I put my logging configuration
    __init__.py <- conveniance for myself, not necessary
    /tests
    /package_name <- Actual flask app
    __init__.py
    /views
    /static
    /templates
    /lib

按照这些指示http://flask.pocoo.org/docs/0.10/patterns/packages/

于 2016-03-23T21:06:05.343 回答
3

为什么不深入研究代码并查看...

我们登陆的模块是flask.logging.py,它定义了一个名为 的函数create_logger(app)。在使用 Flask 解决日志记录问题时,检查该函数将提供一些潜在罪魁祸首的线索。

编辑:此答案适用于版本 1 之前的 Flask flask.logging.py。从那时起,该模块发生了很大变化。答案仍然有助于解决有关 python 日志记录的一些一般警告和建议,但请注意 Flask 在这方面的一些特性已在版本 1 中得到解决,可能不再适用。

该函数中第一个可能的冲突原因是这一行:

logger = getLogger(app.logger_name)

让我们看看为什么:

该变量app.logger_nameFlask.__init__()方法中设置为 的值import_name,它本身就是 的接收参数Flask(__name__)。这被app.logger_name分配了 的值__name__,这可能是你的主包的名称,让我们在这个例子中称它为'awesomeapp'。

现在,假设您决定手动配置和创建自己的记录器。你认为如果你的项目被命名为“awesomeapp”你也会使用这个名字来配置你的记录器,我认为这很有可能。

my_logger = logging.getLogger('awesomeapp') # doesn't seem like a bad idea
fh = logging.FileHandler('/tmp/my_own_log.log')
my_logger.setLevel(logging.DEBUG)
my_logger.addHandler(fh)

这样做是有道理的……除了一些问题。

Flask.logger第一次调用该属性时,它会依次调用该函数flask.logging.create_logger(),并且会执行以下操作:

logger = getLogger(app.logger_name)

还记得您如何在项目之后命名您的记录器以及如何app.logger_name共享该名称吗?上面的代码行中发生的事情是,该函数logging.getLogger()现在已经检索了您之前创建的记录器,并且以下说明将会以一种让您稍后摸不着头脑的方式来处理它。例如

del logger.handlers[:]

噗,您刚刚丢失了之前在记录器中注册的所有处理程序。

函数内发生的其他事情,无需过多介绍。它创建并注册两个logging.StreamHandler可以吐出到sys.stderr和/或Response对象的对象。一个用于日志级别“调试”,另一个用于“生产”。

class DebugLogger(Logger):
    def getEffectiveLevel(self):
        if self.level == 0 and app.debug:
            return DEBUG
        return Logger.getEffectiveLevel(self)

class DebugHandler(StreamHandler):
    def emit(self, record):
        if app.debug and _should_log_for(app, 'debug'):
            StreamHandler.emit(self, record)

class ProductionHandler(StreamHandler):
    def emit(self, record):
        if not app.debug and _should_log_for(app, 'production'):
            StreamHandler.emit(self, record)

debug_handler = DebugHandler()
debug_handler.setLevel(DEBUG)
debug_handler.setFormatter(Formatter(DEBUG_LOG_FORMAT))

prod_handler = ProductionHandler(_proxy_stream)
prod_handler.setLevel(ERROR)
prod_handler.setFormatter(Formatter(PROD_LOG_FORMAT))

logger.__class__ = DebugLogger
logger.addHandler(debug_handler)
logger.addHandler(prod_handler)

有了上面的细节,我们应该更清楚为什么我们手动配置的记录器和处理程序在涉及 Flask 时行为不端。不过,新信息为我们提供了新的选择。如果您仍想保留单独的处理程序,最简单的方法是将您的记录器命名为与项目不同的名称(例如my_logger = getLogger('awesomeapp_logger'))。如果您想与 Flask 中的日志记录协议保持一致,另一种方法是使用与 Flask 类似的方法注册一个logging.FileHandler对象。Flask.logger

import logging
def set_file_logging_handler(app):

    logging_path = app.config['LOGGING_PATH']

    class DebugFileHandler(logging.FileHandler):
        def emit(self, record):
            # if your app is configured for debugging
            # and the logger has been set to DEBUG level (the lowest)
            # push the message to the file
            if app.debug and app.logger.level==logging.DEBUG:
                super(DebugFileHandler, self).emit(record)

    debug_file_handler = DebugFileHandler('/tmp/my_own_log.log')
    app.logger.addHandler(debug_file_handler)

app = Flask(__name__)
# the config presumably has the debug settings for your app
app.config.from_object(config)
set_file_logging_handler(app)

app.logger.info('show me something')
于 2017-12-14T08:10:46.980 回答
0

记录快速入门

-- 此代码不适用于类/或导入中的多个日志文件

import logging
import os # for Cwd path 
path = os.getcwd()


logFormatStr = '%(asctime)s  %(levelname)s - %(message)s'
logging.basicConfig(filename=path + '\logOne.log', format=logFormatStr, level=logging.DEBUG), logging.info('default message')

用于多个日志记录文件

使用 logging.getLogger() 方法创建一个日志实例---

  1. 每个记录器文件都需要一个记录实例
  2. 我们可以创建多个日志文件,但不能使用相同的实例

使用name 或 Hardcore_String ----preferred ( name )创建新的记录器实例,这将指定它调用的确切类

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

日志记录类型——信息、调试、错误、严重、警告

DEBUG ----详细信息,通常仅在诊断问题时才感兴趣。

INFO ----确认事情按预期工作。

WARNING ---- 表示发生了意外情况,或表示不久的将来会出现一些问题(例如“磁盘空间不足”)。该软件仍按预期工作。

ERROR ----由于更严重的问题,软件无法执行某些功能。

CRITICAL ----严重错误,表示程序本身可能无法继续运行。

创建新格式化程序

format = logging.Formatter('%(asctime)s %(levelname)s - %(message)s')

创建新文件处理程序

file_handel = logging.FileHandler(path + '\logTwo.log')

将格式设置为 FileHandler 并将 file_handler 添加到日志实例 [logger]

file_handel.setFormatter(format)
logger.addHandler(file_handel)

将消息添加到 logOne.log 文件和 logTwo.log 与各自的 setlevel

logger.info("message for logOne")
logging.debug(" message for logTwo")

更多细节

于 2020-07-31T18:56:05.950 回答