如何收集、更新和组织Python日志
Python在标准库中自带了一个日志模块,为从Python程序中发射日志信息提供了一个灵活的框架。这篇文章解释了如何使用Python中的日志模块来记录所有需要的数据。
我们可以使用一个外部配置文件来设置Python日志子系统。我们可以在Python标准库中找到日志设置设计的细节。
日志库包括四个类。 loggers, handlers,filters, 和formatters.
修改日志配置
日志模块中的basicConfig() 方法是设置日志配置的最快捷方式。然而,[Python文档]建议为你的应用程序中的每一个模块制作一个日志器。单独利用basicConfig() 可能会很困难。
basicConfig() 方法的三个重要配置是。
- 等级:决定了你的应用程序中的日志等级。常见的日志等级是
DEBUG,INFO,WARNING,ERROR, 和CRITICAL。默认级别是WARNING。 - handler: 决定了应用程序将在哪里处理你的日志。
- 设计:消息是以这种格式记录的:
LEVEL>:LOGGER NAME>: MESSAGE>。
你可能会失去真正的低级日志,这些日志可以帮助你更轻松地工作,基于日志模块提供WARNING 和更基本的级别日志作为替代。使用FileHandler 来记录文件系统中的单个或额外的文件。使用StreamHandler 或SocketHandler 来路由日志可能有助于日志的组织。
日志的好处
- 当网络连接中断时,我们不会丢失日志,因为日志是存储在文件系统中的。
- 日志使我们更容易监控应用程序,并在得到错误日志时修复bug。
basicConfig()方法的表述
日志遵循一个特定的设计,包括以下内容。
%(asctime)s:它产生了日志的日期和季节,以[当地时间]表示。%(levelname)s:信息的记录等级。%(message)s:日志的内容。
设置日志模块
应用程序越是扩展,我们就越是需要利用可靠的方式来设计每个记录器,将日志名称纳入日志部分。以下是设置日志模块的步骤。
- 排列各种日志,并记录它们的属性,以自作主张地设置日志标题,以适应我们模块的属性。利用日志库纳入的[getLogger()方法]。
logger = logging.getLogger(__name__)
getLogger()将日志字符设置为身份,这与确定策略的模块的生产ID相吻合。这可以指导我们实现我们的应用程序的哪一部分带来了每个消息。然后,在这一点上,我们可以解释我们的日志。因此,当我们改变日志设计并包括日志身份时,描述将显示在每个日志消息中。
# lessermodule.py
import logging.config
import traceback
logging.config.fileConfig('logging.ini', disable_existing_loggers=False)
logger = logging.getLogger(__name__)
def word_count(myid):
try:
# count the number of words in a file, myid, and log the result
with open(myfile, 'r+') as f:
file_data = f.read()
words = file_data.split(" ")
final_word_count = len(words)
logger.info("this file has %d words", final_word_count)
f.write("this file has %d words", final_word_count)
return final_word_count
except OSError as e:
logger.error(e, exc_info=True)
except:
logger.error("uncaught exception: %s", traceback.format_exc())
return False
if __name__ == '__main__':
word_count('myid.txt')
运行higher_module.py ,日志将产生以下结果。
2021-11-02 23:45:23,567 __main__INFO:starting the capacity
2021-11-02 23:45:23,567 lessermodude INFO:this record has 27 words
2021-11-02 23:45:23,567 __main__DEBUG:the work is finished the record myid.text
2021-11-02 23:45:23,567 __main__INFO:starting the capacity
2021-11-02 23:45:23,567 lessermodule ERROR:[errno 2] No such document or index
2021-11-02 23:45:23,567 __main__DEBUG:the work is ruined the document nonexistent
日志标签肯定设置在时间戳之后,通过这种方式,你可以关注到每条消息是由哪个部分产生的。然而,如果没有用getLogger() ,每个日志标签都会以根的形式出现,这样就更难看出哪些消息是由父模块而不是子模块产生的。
从higher_module.py 创建的消息将主 模块算作日志标签,因为higher_module.py 是在高层脚本执行的。记住,我们正在有力地融合日志的生活方式,作为日志设计的一个部分,这两个日志都是用等价的basicConfig() 。
- 利用
fileConfig(),向多个站点发送日志。利用基于记录(indexConfig())或基于字典(dictConfig())的配置,可以为你的应用程序中的每个日志提供更多的定制安排和指导选择。
一个日志设置记录需要包含最极端的三个部分。
[loggers]:你要设计的日志的身份。[handlers]:打算利用这些日志的控制器。[formatters]:你需要每个日志遵循的结构。
键指导你将需要设计的不同部分的标签,安排为[<SECTION_NAME>_<KEY_NAME>] ,通过该部分的名称是记录器、控制器或格式器。
下面是一个日志设置文件的基本纲要。
[loggers]
keys=root
[handlers]
keys=fileHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=fileHandler
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=simpleFormatter
args=("/path/to/log/file.log",)
[formatter_simpleFormatter]
format=%(asctime)s %(name)s - %(levelname)s:%(message)s
Python库规定,我们在一个日志中只能包含一个处理程序。看一下大纲 '( 父模块和子模块)',两个日志将在排列'(formatter_simpleFormatter)'中给出DEBUG产量和高需求的标志,并将它们纳入一个日志记录(file.log)。这将消除在你的章节中包含logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)s %(levelname)s:%(message)s') 的需要。
在包含了前面所说的格式后,你可以添加logging.config.fileConfig() 。
import logging.config
logging.config.fileConfig('/way/to/logging.ini', disable_existing_loggers=False)
lumberjack = logging.getLogger(__name__)
另外,你可以使用Django应用程序来记录你的文件,因为它利用了Python模块。在利用Django日志时应遵守以下步骤。
- 为各种记录器、处理程序、过滤器和格式化器配置
location.py。 - 在视图或任何其他适用的模块中包括记录器的代码。
- 配置
location.py。为了在Django中启用日志,我们必须配置其locale。
Django中使用的方法是dictConfig ,因为它在不同的模块下工作。下面是一个示例说明。
# Logging Information
LOGGING = {
'variant': 1,
# Version of logging
'disable_existing_loggers': False,
# disable logging
# Handlers contained
'overseers': {
'record': {
'level': 'Investigate',
'class': 'logging.FileHandler',
'filename': 'dataflair-debug.log',
},
'console': {
'class': 'logging.StreamHandler',
},
},
# Loggers appended
'loggers': {
'django': {
'overseers': ['file', 'console'
],
'level': 'Investigate',
'proliferate': True,
'level': os.getenv('DJANGO_LOG_LEVEL', 'Investigate')
},
},
}
在Django中,有一个内置的变量包含在库中。此外,在日志字典中还有一些键值;版本、disable-existing-loggers 、处理程序和记录器。版本键显示映射形式,默认值为1。
disable-existing-logger 键告诉 Django 不要禁用记录器。这个键,按照惯例,是真的。然而,在处理数据库查询和函数时,不要将其设置为真,这一点很重要。
处理程序处理消息并将其传递给支持记录等。实际的控制器是一个词的引用。那些单词引用的键名将是控制器的名称。有各种类型,但更强调的是。
FileHandler:将日志存储在一个文件中。StreamHandler:在控制台中流传日志。
日志器记录服务器或软件的细节。Django提供了几个记录器,例如:django.request 。你应该用$python manage.py runserver 来启动你的服务器,以实现日志记录。之后,点击回车,应用程序将在控制台显示日志信息,因为默认级别被设置为调试。
样式化和合并JSON日志
当你的框架在一个给定的术语中产生大量的日志时,就很难识别那些在故障排除时可以帮助你的日志。一般来说,这些日志分散在不同的服务器或文件中。
当你需要查看和组织你的日志时,把你的日志集中在一起有助于你。此外,JSON设计/风格的意义在于它可以有效地适应。例如,如果你想在每个日志设计中添加属性,你就不必每次在日志设计中添加或取消积分时刷新你的日志处理途径。
最初的步骤是在你目前的日志中引入:'
pip introduce python-json-logger
建立后,你需要刷新设计记录,使当前的格式化器或添加一个新的格式化器,将日志样式化为JSON。JSON格式器利用了pythonjsonlogger.jsonlogger.JsonFormater类。我们可以确定我们需要记住每条日志记录的特征。
[loggers]
keys=root,lowermodule
[handlers]
keys=consoleHandler,fileHandler
[formatters]
keys=simpleFormatter,json
[logger_root]
level=DEBUG
handlers=consoleHandler
[logger_lowermodule]
level=DEBUG
handlers=fileHandler
qualname=lowermodule
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=json
args=("/home/molly/myid.log",)
[formatter_json]
class=pythonjsonlogger.jsonlogger.JsonFormatter
format=%(asctime)s %(name)s %(levelname)s %(message)s
[formatter_simpleFormatter]
format=%(asctime)s %(name) s-%(levelname)s: %(message)s
从命令提示符(with consoleHandler) 运送的日志遵循simpleFormatter 的风格,以提高可读性。在你的配置文件中包含pythonjsonlogger.jsonlogger.JsonFormatter 类后,如果代码运行在可以导入pythonjsonlogger 的环境中,fileConfig() 函数将创建JsonFormatter。
例如,假设你没有利用基于记录的设置,你应该在你的函数代码中包含python-json-logger 种类,并描述一个控制器和格式器的特征,如库中所描述的那样。
在JSON中签名的另一个好处是添加属性,外部日志管理服务可以解析并随之调查。例如,之前,我们安排的格式包含了标准的属性,如%(asctime)s,%(name)s,%(levelname)s, 和%(message)s 。
# lessermodule.py
import logging.config
import traceback
import time
def word_count(myid):
logger = logging.getLogger(__name__)
logging.fileConfig('logging.ini', disable_existing_loggers=False)
try:
starttime = time.time()
with open(myfile, 'r') as f:
file_data = f.read()
words = file_data.split(" ")
final_word_count = len(words)
endtime = time.time()
duration = endtime - starttime
logger.info("this file has %d words", final_word_count, extra={"run_duration":duration})
return final_word_count
except OSError as e:
[...]
在上面的程序中,run_duration 代表了对行动的跨度的估计,马上。
输出
{"asctime": "2021-11-05 16:45:35,861", "name": "lesser_module", "levelname": "Data", "message": "this record has 89 words", "run_duration": 6.675498706528215e-05}
结论
记录模块简化了一切,缓解了复杂的压力。它被认为是多功能的。它的安排是合理的,应该满足你开箱即用的情况。
如果你还没有在你的应用程序中使用日志,这是一个很好的开始机会。如果做得好,日志无疑会提高你的生产力。