如何使用日志记录 Python 模块写入文件?
Posted
技术标签:
【中文标题】如何使用日志记录 Python 模块写入文件?【英文标题】:How to write to a file, using the logging Python module? 【发布时间】:2011-09-17 05:16:08 【问题描述】:如何使用 Python 中的 logging 模块写入文件?每次我尝试使用它时,它都会打印出消息。
【问题讨论】:
相关,如何在不创建记录器python的情况下记录警告? 【参考方案1】:这里有两个例子,一个打印日志(stdout),另一个将日志写入文件:
import logging
import sys
logger = logging.getLogger()
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s | %(levelname)s | %(message)s')
stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setLevel(logging.DEBUG)
stdout_handler.setFormatter(formatter)
file_handler = logging.FileHandler('logs.log')
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(stdout_handler)
在这个例子中,所有的日志都将被打印出来,并被写入一个名为 logs.log 的文件中
使用示例:
logger.info('This is a log message!')
logger.error('This is an error message.')
所有内置日志处理程序列表https://docs.python.org/3/library/logging.handlers.html
【讨论】:
【参考方案2】:这里有一个更简单的方法。此解决方案不使用 配置字典并使用旋转文件处理程序,如下所示:
import logging
from logging.handlers import RotatingFileHandler
logging.basicConfig(handlers=[RotatingFileHandler(filename=logpath+filename,
mode='w', maxBytes=512000, backupCount=4)], level=debug_level,
format='%(levelname)s %(asctime)s %(message)s',
datefmt='%m/%d/%Y%I:%M:%S %p')
logger = logging.getLogger('my_logger')
或者像这样:
import logging
from logging.handlers import RotatingFileHandler
handlers = [ RotatingFileHandler(filename=logpath+filename,
mode='w',
maxBytes=512000,
backupCount=4)
]
logging.basicConfig(handlers=handlers,
level=debug_level,
format='%(levelname)s %(asctime)s %(message)s',
datefmt='%m/%d/%Y%I:%M:%S %p')
logger = logging.getLogger('my_logger')
handlers 变量必须是可迭代的。 logpath+filename 和 debug_level 只是保存 相应的信息。当然,函数参数的值是向上的 给你。
我第一次使用日志记录模块时犯了以下错误,这会产生操作系统文件锁定错误( 以上是解决方案):
import logging
from logging.handlers import RotatingFileHandler
logging.basicConfig(filename=logpath+filename,
level=debug_level,
format='%(levelname)s %(asctime)s %(message)s',
datefmt='%m/%d/%Y%I:%M:%S %p')
logger = logging.getLogger('my_logger')
logger.addHandler(RotatingFileHandler(
filename=logpath+filename,
mode='w',
maxBytes=512000,
backupCount=4))
【讨论】:
【参考方案3】:这个例子应该可以正常工作。我为控制台添加了流处理程序。安慰 日志和文件处理程序数据应该相似。
# MUTHUKUMAR_TIME_DATE.py #>>>>>>>> file name(module)
import sys
import logging
import logging.config
# ================== Logger ================================
def Logger(file_name):
formatter = logging.Formatter(fmt='%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s',
datefmt='%Y/%m/%d %H:%M:%S') # %I:%M:%S %p AM|PM format
logging.basicConfig(filename = '%s.log' %(file_name),format= '%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s',
datefmt='%Y/%m/%d %H:%M:%S', filemode = 'w', level = logging.INFO)
log_obj = logging.getLogger()
log_obj.setLevel(logging.DEBUG)
# log_obj = logging.getLogger().addHandler(logging.StreamHandler())
# console printer
screen_handler = logging.StreamHandler(stream=sys.stdout) #stream=sys.stdout is similar to normal print
screen_handler.setFormatter(formatter)
logging.getLogger().addHandler(screen_handler)
log_obj.info("Logger object created successfully..")
return log_obj
# =======================================================
MUTHUKUMAR_LOGGING_CHECK.py #>>>>>>>>>>> file name
# calling **Logger** function
file_name = 'muthu'
log_obj =Logger(file_name)
log_obj.info("yes hfghghg ghgfh".format())
log_obj.critical("CRIC".format())
log_obj.error("ERR".format())
log_obj.warning("WARN".format())
log_obj.debug("debug".format())
log_obj.info("qwerty".format())
log_obj.info("asdfghjkl".format())
log_obj.info("zxcvbnm".format())
# closing file
log_obj.handlers.clear()
OUTPUT:
2019/07/13 23:54:40 MUTHUKUMAR_TIME_DATE,line: 17 INFO | Logger object created successfully..
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 8 INFO | yes hfghghg ghgfh
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 9 CRITICAL | CRIC
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 10 ERROR | ERR
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 11 WARNING | WARN
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 12 DEBUG | debug
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 13 INFO | qwerty
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 14 INFO | asdfghjkl
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 15 INFO | zxcvbnm
Thanks,
【讨论】:
【参考方案4】:取自“logging cookbook”:
# create logger with 'spam_application'
logger = logging.getLogger('spam_application')
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
你可以走了。
附:请务必阅读logging HOWTO。
【讨论】:
要回答您的第一个问题,请随意查看我提出的问题的标题。我已经浏览了您提供的链接,这很有帮助。我已经复制了你给我的代码,我错误地认为我可以成功使用 logger.info("message") 和 logger.warning("message") 吗?我能够使用 logger.warning 写入文件,但是 logger.info 似乎没有写入文件。 尝试删除 setLevel 调用。读取处理程序docs 似乎默认处理所有消息。 我只能使用logger.warning("message")
写入文件,不能使用logger.info("message")
或logger.debug("message")
。这有点烦人。
@EliBendersky 编写的代码示例缺少 1 步,如果您想编写信息/调试消息。记录器本身需要配置自己的日志级别以接受该级别的日志消息,例如logger.setLevel(logging.DEBUG)
。记录器可以配置多个处理程序;记录器中配置的级别决定了将哪个严重级别的日志消息发送给每个处理程序,而处理程序中设置的级别决定了处理程序将处理哪些级别。请注意,那些想要打印信息消息的人只需要在记录器和处理程序中将其设置为INFO
。
我已将示例更新为 logger.setLevel(logging.DEBUG)
-- 感谢 cmets【参考方案5】:
使用logging.basicConfig
而不是logging.fileHandler()
的示例
logging.basicConfig(filename=logname,
filemode='a',
format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
datefmt='%H:%M:%S',
level=logging.DEBUG)
logging.info("Running Urban Planning")
self.logger = logging.getLogger('urbanGUI')
五个部分依次执行以下操作:
-
设置输出文件(
filename=logname
)
将其设置为追加而不是覆盖 (filemode='a'
)
确定输出消息的格式 (format=...
)
确定输出时间的格式(datefmt='%H:%M:%S'
)
并确定它将接受的最低消息级别 (level=logging.DEBUG
)。
【讨论】:
文件名可以是hdfs位置吗?如果是,怎么做? 如果在 apache 上运行,请确保它不在if __name__ == '__main__':
下
@RamiAlloush 你能详细说明一下吗?这是为什么? (好奇:))
@notihs,服务器不直接运行脚本文件,所以if __name__ == '__main__':
下面的部分不会被执行。
我想指出的是,默认情况下,这个记录器不是线程安全的,它不会记录未捕获的异常,asctime 不能同时具有时区和毫秒,并且它不会同时记录到文件和打印到控制台。处理这些情况的一个选项是lovely-logger 模块——尽管它们都可以单独使用标准库来克服。【参考方案6】:
import sys
import logging
from util import reducer_logfile
logging.basicConfig(filename=reducer_logfile, format='%(message)s',
level=logging.INFO, filemode='w')
【讨论】:
【参考方案7】:我更喜欢使用配置文件。当我从开发到发布时,它允许我在不更改代码的情况下切换日志记录级别、位置等。我只是用相同的名称打包了一个不同的配置文件,并使用相同的定义记录器。
import logging.config
if __name__ == '__main__':
# Configure the logger
# loggerConfigFileName: The name and path of your configuration file
logging.config.fileConfig(path.normpath(loggerConfigFileName))
# Create the logger
# Admin_Client: The name of a logger defined in the config file
mylogger = logging.getLogger('Admin_Client')
msg='Bite Me'
myLogger.debug(msg)
myLogger.info(msg)
myLogger.warn(msg)
myLogger.error(msg)
myLogger.critical(msg)
# Shut down the logger
logging.shutdown()
这是我的日志配置文件代码
#These are the loggers that are available from the code
#Each logger requires a handler, but can have more than one
[loggers]
keys=root,Admin_Client
#Each handler requires a single formatter
[handlers]
keys=fileHandler, consoleHandler
[formatters]
keys=logFormatter, consoleFormatter
[logger_root]
level=DEBUG
handlers=fileHandler
[logger_Admin_Client]
level=DEBUG
handlers=fileHandler, consoleHandler
qualname=Admin_Client
#propagate=0 Does not pass messages to ancestor loggers(root)
propagate=0
# Do not use a console logger when running scripts from a bat file without a console
# because it hangs!
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=consoleFormatter
args=(sys.stdout,)# The comma is correct, because the parser is looking for args
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=logFormatter
# This causes a new file to be created for each script
# Change time.strftime("%Y%m%d%H%M%S") to time.strftime("%Y%m%d")
# And only one log per day will be created. All messages will be amended to it.
args=("D:\\Logs\\PyLogs\\" + time.strftime("%Y%m%d%H%M%S")+'.log', 'a')
[formatter_logFormatter]
#name is the name of the logger root or Admin_Client
#levelname is the log message level debug, warn, ect
#lineno is the line number from where the call to log is made
#04d is simple formatting to ensure there are four numeric places with leading zeros
#4s would work as well, but would simply pad the string with leading spaces, right justify
#-4s would work as well, but would simply pad the string with trailing spaces, left justify
#filename is the file name from where the call to log is made
#funcName is the method name from where the call to log is made
#format=%(asctime)s | %(lineno)d | %(message)s
#format=%(asctime)s | %(name)s | %(levelname)s | %(message)s
#format=%(asctime)s | %(name)s | %(module)s-%(lineno) | %(levelname)s | %(message)s
#format=%(asctime)s | %(name)s | %(module)s-%(lineno)04d | %(levelname)s | %(message)s
#format=%(asctime)s | %(name)s | %(module)s-%(lineno)4s | %(levelname)-8s | %(message)s
format=%(asctime)s | %(levelname)-8s | %(lineno)04d | %(message)s
#Use a separate formatter for the console if you want
[formatter_consoleFormatter]
format=%(asctime)s | %(levelname)-8s | %(filename)s-%(funcName)s-%(lineno)04d | %(message)s
【讨论】:
用日期命名文件需要在 Python 3 中使用双%%
。例如time.strftime("%%Y%%m%%D")
【参考方案8】:
http://docs.python.org/library/logging.html#logging.basicConfig
logging.basicConfig(filename='/path/to/your/log', level=....)
【讨论】:
这样将日志保存在文件中,很好。如果与此一起,我也希望它在终端上记录输出怎么办? 官方的logging
模块文档允许这样做。您甚至可以选择哪些日志进入终端,哪些日志进入文件,以及更多有趣的应用程序。 docs.python.org/3/howto/…【参考方案9】:
http://docs.python.org/library/logging.handlers.html#filehandler
位于核心
logging
包中的FileHandler
类将日志输出发送到磁盘文件。
【讨论】:
+1 完整示例见“基础教程”:docs.python.org/howto/logging.html#logging-to-a-file 我也喜欢在各种情况下有几种不同类型的FileHandler
s。 (WatchedFileHandler
、RotatingFileHandler
等)以上是关于如何使用日志记录 Python 模块写入文件?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Python 日志记录模块获得非阻塞/实时行为? (输出到 PyQt QTextBrowser)