日志级别等级排序:critical > error > warning > info > debug
级别越高打印的日志越少,反之亦然,即
通过 logging.basicConfig() 可以设置 root 的日志级别,和日志输出格式。
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p',level=logging.DEBUG)
日志器(logger)需要通过处理器(handler)将日志信息输出到目标位置,不同的处理器(handler)可以将日志输出到不同的位置;
日志器(logger)可以设置多个处理器(handler)将同一条日志记录输出到不同的位置;
每个处理器(handler)都可以设置自己的过滤器(filter)实现日志过滤,从而只保留感兴趣的日志;
每个处理器(handler)都可以设置自己的格式器(formatter)实现同一条日志以不同的格式输出到不同的地方。
日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。
Logger 可以包含一个或多个 Handler 和 Filter
Logger 与 Handler 或 Fitler 是一对多的关系
一个 Logger 实例可以新增多 个 Handler,一个 Handler 可以新增多个格式化器或多个过滤器,而且日志级别将会继承。
logging标准模块支持三种配置方式: dictConfig,fileConfig,listen。字典配置、文件配置、显式配置
一、
logging.conf
[loggers]
keys=root,simpleExample
[handlers]
keys=consoleHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler
[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=
import logging
import logging.config
logging.config.fileConfig('logging.conf')
# create logger
logger = logging.getLogger('simpleExample')
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
二、
import logging
from logging.handlers import TimedRotatingFileHandler
class MylogHandler(logging.Logger):
def __init__(self,name,level="DEBUG",stream=True,files=True):
self.name = name
self.level = level
logging.Logger.__init__(self,self.name,level=self.level)
if stream:
self.__streamHandler__(self.level)
if files:
self.__filesHandler__(self.level)
def __streamHandler__(self,level=None):
handler = TimedRotatingFileHandler(filename=self.name+".log", when='D', interval=1, backupCount=15)
handler.suffix = '%Y%m%d.log'
handler.setLevel(level)
formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
handler.setFormatter(formatter)
self.addHandler(handler) #将hander添加到logger上
def __filesHandler__(self,level=None):
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
handler.setFormatter(formatter)
handler.setLevel(level)
self.addHandler(handler)
if __name__ == '__main__':
log = MylogHandler('test')
log.info('this is a my log handler')
三、
import os
import sys
import re
import logging
from logging import handlers
__all__ = ['Logger']
class Logger(object):
# 日志级别关系映射
DEFAULT_FMT = '%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'
LEVEL_DICT = {
'debug': logging.DEBUG,
'info': logging.INFO,
'warning': logging.WARNING,
'error': logging.ERROR,
'critical': logging.CRITICAL
}
def __init__(
self,
log_obj,
filename,
level='info',
when='s',
backupCount=3,
fmt=DEFAULT_FMT
):
self.logger = logging.getLogger(log_obj)
self.fmt = logging.Formatter(fmt)
self.setLogDir(filename)
self.logger.setLevel(self.LEVEL_DICT.get(level)) # level
# self.logger.addHandler(self.setStream(self.fmt))
self.logger.addHandler(self.setTimeRotator(
filename=filename,
when=when,
backupCount=backupCount
))
# self.logger.addHandler(self.setEmailHandler())
def setLogDir(self, filename):
_dir, _ = os.path.split(filename)
if not os.path.exists(_dir):
os.makedirs(_dir)
# System standard output
def setStream(self, fmt=None):
handler = logging.StreamHandler(sys.stdout)
if not fmt:
handler.setFormatter(fmt)
else:
handler.setFormatter(self.fmt)
return handler
# Log record settings, include writing file, backup, etc.
@classmethod
def setTimeRotator(cls, filename, when, backupCount, encoding='utf-8', level=None, **kwargs):
handler = handlers.TimedRotatingFileHandler(
filename=filename,
when=when,
backupCount=backupCount,
encoding=encoding,
**kwargs
)
# Warnings: suffix issue is a `logging` package bug.
# Must add `.log` string to `suffix` attribute format,
# Or `TimedRotatingFileHandler` can't backup log files.
# Specific formatting can be read in `logging.TimedRotatingFileHandler`
if level is None:
handler.setLevel(cls.LEVEL_DICT.get('info'))
else:
handler.setLevel(level)
handler.suffix = "%Y-%m-%d_%H-%M-%S.log"
handler.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}(\.\w+)?$")
handler.setFormatter(logging.Formatter(cls.DEFAULT_FMT)) # 设置文件里写入的格式
return handler
# TODO: email handler.
def setEmailHandler(self, mailhost, fromaddr, toaddrs, subject,
credentials=None, secure=None, timeout=5.0, level='info'):
email = handlers.SMTPHandler(
mailhost,
fromaddr,
toaddrs,
subject,
credentials=None,
secure=None,
timeout=5.0
)
email.setLevel(self.LEVEL_DICT.get('error'))
email.setFormatter(logging.Formatter(
'[%(asctime)s] %(levelname)s in %(module)s: %(message)s'))
return email
四、
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '[%(asctime)s] [%(levelname)s] %(message)s'
},
},
'handlers': {
# 输出日志的控制台
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'verbose'
},
# 输出日志到文件,按日期滚动
'file': {
'level': 'DEBUG',
'class': 'logging.handlers.TimedRotatingFileHandler',
# TimedRotatingFileHandler的参数
# 参照https://docs.python.org/3/library/logging.handlers.html#timedrotatingfilehandler
# 目前设定每天一个日志文件
'filename': 'logs/all_info.log',
'when': 'midnight',
'interval': 1,
'backupCount': 100,
'formatter': 'verbose'
},
# 发送邮件,目前腾讯云、阿里云的服务器对外发送邮件都有限制,暂时不使用
'email': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'include_html': True,
}
},
'loggers': {
# 不同的logger
'django': {
'handlers': ['console', 'file'],
'level': 'INFO',
'propagate': True,
},
},
}
logger = logging.getLogger('django') # 日志捕捉方法
logging.config.dictConfig(settings.LOGGING)
logger.error(e.__class__.__name__)
logger.error('视图报错,报错详情如下:\n%s' % traceback.format_exc()) # todo 显示报错第几行
from loguru import logger
logger.add('file_{time}.log', format="{name} {level} {message}", level="INFO", rotation='5 MB', encoding='utf-8', , rotation="1 week", compression="zip"))
# 根据时间为日志命名,每5MB新建一个, 一周清理一次,压缩节省空间
logger.add('out.log', backtrace=True, diagnose=True, encoding='utf-8')
完整描述异常:包括内存地址,可能泄露敏感数据
logger.add('json.log', serialize=True, encoding='utf-8') #保存为json格式日志
# 装饰器
from loguru import logger
@logger.catch
def func(x, y, z):
return 1 / (x + y + z)
# 上下文
with logger.catch():
func(0, 1, -1)
from loguru import logger
from utils.path_config import ConfigFilePath
class DWLog(object):
def __init__(self, module):
self.module = module
self.log_obj = logger
self.log_obj.add(ConfigFilePath().log_file(self.module), format="{time} | {message}",
rotation="20 MB", encoding='utf-8', retention="30 days",
enqueue=True)
# self.log_obj.add(ConfigFilePath().log_file("error"), format="{time} | {message}",
# rotation="20 MB", encoding='utf-8', retention="30 days", level='ERROR', enqueue=True)
def log(self, msg):
self.log_obj.info("[%s]--%s" % (self.module, msg))
_ = DWLog('hot')
log, logger = _.log, _.log_obj # 打印和保存log,catch 异常
log("hot_word_trend ok")