您是否曾经想过Logz .io或Loggly .com之类的伐木服务如何将日志运到他们的平台上?例如,logz .io有一个opensource记录处理程序,他们用来将日志从您的应用程序运输到其平台,在此对这些日志上进行进一步的分析,以使您能够获得有关应用程序性能的实质性见解。在这篇简短的文章中,我们将简要介绍使用Python standard logging软件包编写用户定义的日志处理程序的基础。
您可能想知道为什么我选择写这个相当“奇怪”的话题,但是良好的记录系统的重要性不能被夸大,无论您的应用程序是Web应用程序,移动设备,甚至是操作系统,登录都可以使您启用。获取有关您的申请表现的有用信息。一个良好的记录系统有助于在发生错误时捕获错误,而不是依靠用户报告这些错误,大多数人只是不知道该怎么做。
logging.streamhandler
Python标准记录程序包提供处理程序类,该类基本上定义了特定日志消息的处理方式,我们可以配置一个简单的处理程序,将日志消息打印到终端:
:
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"stdformatter": {"format": "DateTime=%(asctime)s loglevel=%(levelname)-6s %(funcName)s() L%(lineno)-4d %(message)s call_trace=%(pathname)s L%(lineno)-4d"},
},
"handlers": {
"stdhandler": {
"class": "logging.StreamHandler",
"formatter": "stdformatter",
'stream': 'ext://sys.stdout'
},
},
"loggers" : {
"root": {
"handlers": ["stdhandler"],
"level": "DEBUG",
"propagate": True
}
}
}
我们可以在log.py 中初始化此配置,假设log.py文件是我们要log
的应用程序
import logging
from logging.config import dictConfig
dictConfig(LOGGING)
logger = logging.getLogger()
logger.debug("logger started")
def logToConsole():
logger.info("Application started, succesfully")
logger.info("Logging to the console")
logger.info("Finished logging to console!")
# call the function
logToConsole()
我们运行log.py文件时python3 log.py
;我们可以看到与端子上显示的相似的输出
如您所见,我们已经能够配置直接登录控制台(STDOUT)的处理程序,请记住,您不需要创建任何连接即可登录到终端,因为StreamHandler是该端子的默认处理程序记录包。记录程序包还带有一系列已经制造的处理程序您可以使用Aside the StreamHandler,其中一些列出了:
- fileHandler :将记录输出发送到磁盘文件
- nullhandler :它本质上是图书馆开发人员使用的无用处理程序。我从来没有任何理由使用:)
- BaserotatingHandler :这基本上是特殊用例的另一种fileHandler
- sockethandler :将记录输出发送到网络插座。
- sysloghandler :将记录消息发送到远程或本地unix syslog。
- smtphandler :使用SMTP。 将日志消息发送到电子邮件地址
- httphandler :使用GET或发布语义来支持将记录消息发送到Web服务器。
记录包提供了几个处理程序,可以找到here,其中有些您可能永远不会使用用例,因为它们是为非常特定的用例构建的。
自定义处理程序
假设我们正在建立一个基于云的日志记录,作为像logz.io这样的服务软件,我们想在这里存储,检索和分析我们的日志以获得更好的见解; Python提供了一个低级的“ API”,以使用logging.Handler
类轻松地从Python应用程序传输日志。在下面的示例中,我们将创建一个简单的自定义处理程序,该处理程序写入“ .txt”文件。显然,日志消息没有写入TXT文件,但这是为了说明如何以简单的方式编写自定义日志处理程序。
class SpecialHandler(logging.Handler):
def __init__(self )-> None:
self.sender = LogSender()
logging.Handler.__init__(self=self)
def emit(self, record) -> None:
self.sender.writeLog(record)
在上面的代码中,我们声明了一个名为SpecialHandler
的类,该类从logging.Handler
基类继承,这基本上允许我们扩展基本处理程序,从而使其适合我们的使用。然后,我们声明__init__
方法并启动在检索每个日志记录时处理每个日志记录的类。
class LogSender:
def __init__(self) -> None:
pass
def writeLog(self, msg: logging.LogRecord) -> None:
with open("application.txt",'a',encoding = 'utf-8') as f:
f.write(f"{msg} \n")
LogSender
类充当日志记录的检索,因为它们是从处理程序类的emit
方法发送的; logsender 类声明了writeLog
方法,该方法接受msg: logging.LogRecord
类型的任何参数。在接收记录时,它在附加模式下打开txt文件application.txt
并将日志消息写入文件,在其末尾添加新行。
这基本上是创建自定义Handler所需的全部,我们可以配置我们的LOGGING Dictionary
,以使用几行代码识别此新处理程序,例如:
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"stdformatter": {"format": "DateTime=%(asctime)s loglevel=%(levelname)-6s %(funcName)s() L%(lineno)-4d %(message)s call_trace=%(pathname)s L%(lineno)-4d"},
},
"handlers": {
"stdhandler": {
"class": "logging.StreamHandler",
"formatter": "stdformatter",
'stream': 'ext://sys.stdout'
},
"specialhandler":{
"class" : "writer.SpecialHandler",
"formatter": "stdformatter",
}
},
"loggers" : {
"root": {
"handlers": ["stdhandler", "specialhandler"],
"level": "DEBUG",
"propagate": True
}
}
}
请记住,Writer.specialhandler是我们在Writer.py文件中写的自定义处理程序类。要初始化此更改,我们可以将Writer.py文件导入到我们的log.py文件中,然后再次将记录配置加载到DICTCONFIG中,但是这次使用将写入我们的应用程序的自定义处理程序.txt文件。
import logging
from logging.config import dictConfig
import writer #writer.py contains our SpecialHandler and LogSender class respectively
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"stdformatter": {"format": "DateTime=%(asctime)s loglevel=%(levelname)-6s %(funcName)s() L%(lineno)-4d %(message)s call_trace=%(pathname)s L%(lineno)-4d"},
},
"handlers": {
"stdhandler": {
"class": "logging.StreamHandler",
"formatter": "stdformatter",
'stream': 'ext://sys.stdout'
},
"specialhandler":{
"class" : "writer.SpecialHandler",
"formatter": "stdformatter",
}
},
"loggers" : {
"root": {
"handlers": ["stdhandler", "specialhandler"],
"level": "DEBUG",
"propagate": True
}
}
}
dictConfig(LOGGING)
logger = logging.getLogger()
logger.debug("logger started")
def logToConsole():
logger.info("Application started, succesfully")
logger.info("Logging to the console")
logger.info("Finished logging to console!")
# call the function
logToConsole()
运行python3 log.py
时,我们可以在当前目录中创建一个application.txt文件,其中包含所有日志记录。
结论
记录应用程序可以节省我们在应用程序内调试隐藏错误的时间,并能够获得有关应用程序的性能,可操作性和需求而无需任何麻烦的有用见解。在这篇简短的文章中,我们看到了如何为应用程序编写基本的自定义日志处理程序,以适合我们的特定需求。
让我知道您对本文的看法,以及可以改善其用户体验的任何修正案,感谢您的阅读和度过愉快的时光!
!