日志记录是一种跟踪某些软件运行时发生的事件的手段。日志记录对于软件开发,调试和运行非常重要。程序崩溃时,如果没有任何日志记录,则很难排查出问题的原因。使用logging来记录日志,以便如果出现问题,可以快速定位问题。
有些人可能会疑问,为什么不使用print打印语句来实现来验证如果语句是否正确执行。它可以解决简单脚本的问题,但对于复杂的脚本不好用。Python具有内置的日志模块logging,允许将状态消息写入文件或任何其他输出流。该文件可以包含执行代码部分的信息以及出现的问题。
日志消息有六个内置级别,每个级别与指示日志严重性的整数相关联:notset=0,debug=10,Info=20,Warn=30,error=40,Critical=50。
Notset:Debug : These are used to give Detailed information, typically of interest only when diagnosing problems.Info : These are used to confirm that things are working as expected.Warning : These are used an indication that something unexpected happened, or is indicative of some problem in the near future.Error : This tells that due to a more serious problem, the software has not been able to perform some function.Critical : This tells serious error, indicating that the program itself may be unable to continue running.
logging模块包含多个功能。它有几个常数,类和方法。大小写的命名是类,以小写字母开头的命名是方法。
模块本身提供了几个记录器对象。
Logger.info(msg) : This will log a message with level INFO on this logger.Logger.warning(msg) : This will log a message with a level WARNING on this logger.Logger.error(msg) : This will log a message with level ERROR on this logger.Logger.critical(msg) : This will log a message with level CRITICAL on this logger.Logger.log(lvl,msg) : This will Logs a message with integer level lvl on this logger.Logger.exception(msg) : This will log a message with level ERROR on this logger.Logger.setLevel(lvl) : This function sets the threshold of this logger to lvl. This means that all the messages below this level will be ignored.Logger.addFilter(filt) : This adds a specific filter filt into this logger.Logger.removeFilter(filt) : This removes a specific filter filt into this logger.Logger.filter(record) : This method applies the logger’s filter to the record provided and returns True if the record is to be processed. Else, it will return False.Logger.addHandler(hdlr) : This adds a specific handler hdlr to this logger.Logger.removeHandler(hdlr) : This removes a specific handler hdlr into this logger.Logger.hasHandlers() : This checks if the logger has any handler configured or not.
logging模块的简单使用
Python日志记录模块提供了许多配置日志记录的方法:
以编程方式创建记录器,处理程序和格式化程序,调用配置方法。创建日志记录配置文件并读取。创建配置信息字典并将其传递给 dictConfig() 函数。
# importing module
import logging
# Create and configure logger
logging.basicConfig(filename="newfile.log",
format='%(asctime)s %(message)s',
filemode='w')
# Creating an object
logger = logging.getLogger()
# Setting the threshold of logger to DEBUG
logger.setLevel(logging.DEBUG)
# Test messages
logger.debug("Harmless debug Message")
logger.info("Just an information")
logger.warning("Its a Warning")
logger.error("Did you try to divide by zero")
logger.critical("Internet is down")
2022-03-27 14:07:45,047 Harmless debug Message 2022-03-27 14:07:45,053 Just an information 2022-03-27 14:07:45,054 Its a Warning 2022-03-27 14:07:45,054 Did you try to divide by zero 2022-03-27 14:07:45,055 Internet is down
logging模块的推荐用法
Python官方文档推荐使用Python字典的方式来进行配置。具体地,使用 logging.config.dictConfig 来配置,其模板包括以下部分:
version:Should be 1 for backwards compatibilitydisable_existing_loggers:Disables the configuration for existing loggers. This is True by default.formatters:Formatter settingshandlers:Handler settingsloggers:Logger settings
配置示例:
import logging.config
MY_LOGGING_ConFIG = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'default_formatter': {
'format': '[%(levelname)s:%(asctime)s] %(message)s'
},
},
'handlers': {
'stream_handler': {
'class': 'logging.StreamHandler',
'formatter': 'default_formatter',
},
},
'loggers': {
'mylogger': {
'handlers': ['stream_handler'],
'level': 'INFO',
'propagate': True
}
}
}
# 日志初始化
logging.config.dictConfig(MY_LOGGING_CONFIG)
logger = logging.getLogger('mylogger')
# 设置日志等级
logger.setLevel(logging.INFO)
# 保存日志文件
file_handler = logging.FileHandler('sample.log')
# 设置日志文件输出格式
formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(message)s')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.info('info log')
完整示例
import logging
from logging import config
class DebugAndInfoOnly(logging.Filter): ### Filters all messages except Info and Debug
def filter(self, record):
if record.levelno < 21:
return True
else:
return False
class WarningsOnly(logging.Filter): ### Filters all messages except Warning
def filter(self, record):
if record.levelno > 20 and record.levelno < 40:
return True
else:
return False
class ErrorsOnly(logging.Filter): ### Filters all messages except Error
def filter(self, record):
if record.levelno > 30 and record.levelno < 50:
return True
else:
return False
log_config = {
"version":1,
"root":{
"handlers" : ["console", "warnings_handler", "errors_handler"],
"level": "DEBUG"
},
"handlers":{
"console":{
"formatter": "std_out",
"filters": ["debug_&_info"],
"class": "logging.StreamHandler",
"level": "DEBUG"
},
"warnings_handler":{
"formatter":"std_out",
"class":"logging.FileHandler",
"filters": ["warnings"],
"level":"DEBUG",
"filename":"warnings_only.log"
},
"errors_handler":{
"formatter":"std_out",
"class":"logging.FileHandler",
"filters": ["errors"],
"level":"DEBUG",
"filename":"errors_only.log"
},
},
"formatters":{
"std_out": {
"format": "%(levelname)s : %(name)s : %(funcName)s : %(message)s",
"datefmt":"%d-%m-%Y %I:%M:%S"
}
},
"filters":{
"debug_&_info":{
"()": DebugAndInfoonly
},
"warnings":{
"()": Warningsonly
},
"errors":{
"()": Errorsonly
}
}
}
config.dictConfig(log_config)
################ Logger #################
logger = logging.getLogger("root")
def addition(a, b):
logger.debug("Inside Addition Function")
if isinstance(a, str) and a.isdigit():
logger.warning("Warning : Parameter A is passed as String. Future versions won't support it.")
if isinstance(b, str) and b.isdigit():
logger.warning("Warning : Parameter B is passed as String. Future versions won't support it.")
try:
result = float(a) + float(b)
logger.info("Addition Function Completed Successfully")
return result
except Exception as e:
logger.error("Error Type : {}, Error Message : {}".format(type(e).__name__, e))
return None
if __name__ == "__main__":
logger.info("Current Log Level : {}n".format(logger.getEffectiveLevel()))
result = addition(10,20)
logger.info("Addition of {} & {} is : {}n".format(10,20, result))
result = addition("20",20)
logger.info("Addition of {} & {} is : {}n".format("'20'",20, result))
result = addition("A",20)
logger.info("Addition of {} & {} is : {}".format("A",20, result))
INFO : root :: Current Log Level : 10 DEBUG : root : addition : Inside Addition Function INFO : root : addition : Addition Function Completed Successfully INFO : root : : Addition of 10 & 20 is : 30.0 DEBUG : root : addition : Inside Addition Function INFO : root : addition : Addition Function Completed Successfully INFO : root : : Addition of '20' & 20 is : 40.0 DEBUG : root : addition : Inside Addition Function INFO : root : : Addition of A & 20 is : None
参考:
https://docs.python.org/3/howto/logging.html
https://www.geeksforgeeks.org/logging-in-python/
https://www.toptal.com/python/in-depth-python-logging
https://coderzcolumn.com/tutorials/python/logging-config-simple-guide-to-configure-loggers-from-dictionary-and-config-files-in-python
https://www.datadoghq.com/blog/python-logging-best-practices/



