日志按照下面四个层次来完成日志的功能 :
1 Logger暴露出来给应用使用的接口
2 Handlers是发送日志记录(由logger创建的)到合适的目的地,包括文件,屏幕,email...
3 Filters 是提供一个过滤的机制,决定哪些日志可以留下
4 Formatters是输出日志的格式
创建格式:
logger = logging.getLogger(‘apps‘) # 创建一个新的apps 的logger logger.setLevel(logging.DEBUG) # 因为它是会默认传播到祖先logger logger.propagate = False # 默认StreamHandler那里, 也就是不会打印在页面上 apps_handler = logging.FileHandler(filename="apps.log") # 添加handler, 决定日志落地到哪里,可以多个 apps_formatter=logging.Formatter(‘%(asctime)s:%(name)s:%(levelname)s:%(message)s‘ # 输出日志的格式 apps_handler.setFormatter(apps_formatter) # 装载上 logger.addHandler(apps_handler) # 装载实例化logger上 # 日志会打印到apps.log, 并且不会输出到屏幕(如果logger.propagate=True就会)
继承;
# 定义一个新的logger child_logger = logging.getLogger(‘apps.owan‘) # 因为这个child_logger 是apps.owan, 它是继承了apps这个logger # 这个child_logger.propagate 默认是True # 所以还是会传到它的祖先logger 也就是apps child_logger.info(‘haha‘) # 所以这个info 是会传播到apps 所以apps.log会出现这个日志。 # 这里充分说明logger的继承关系
定义Log两种方法
第一种:就是实例化logger = logging.logger 然后手动给logger添加addHandler, addFilter, handler.setFormatter 添加格式,这样的形式来获取logger。。。。。
import logging # 没有创建logger, 默认是root logger, 直接打印在屏幕 logging.basicConfig(level=logging.DEBUG,format=‘%(asctime)s:%(name)s:%(levelname)s:%(message)s‘) logger = logging.getLogger(‘apps‘) apps_handler = logging.FileHandler(filename="apps.log") logger.addHandler(apps_handler) logger.setLevel(logging.DEBUG) logger.info(‘shis‘)
第二种:就是使用 logging.config.dictConfig 来从配置文件生成logger
logging.config.dictConfig(log_config.PATTERN) # 没有定义的logger tool_logger = logging.getLogger(‘ToolApi‘) # 由于没有定义,会冒泡到root logger tool_logger.info(‘----------------‘) # 定义过的api logger api_logger = logging.getLogger(‘API‘) # 定义过了,所以api自己的handler会处理,同时会冒泡到root logger处理 api_logger.error(‘fuck !‘)
配置文件:
PATTERN = {
‘version‘: 1,
‘formatters‘: {
‘normal‘: {
‘format‘: ‘%(name)s %(asctime)s %(levelname)s %(message)s‘,
‘datefmt‘: ‘%Y-%m-%d %H:%M:%S‘
},
‘raw‘: {
‘format‘: ‘%(message)s‘,
},
},
‘handlers‘: {
‘console‘: {
‘class‘: ‘logging.StreamHandler‘,
‘stream‘: ‘ext://sys.stdout‘,
‘formatter‘: ‘normal‘,
},
‘root‘: {
‘class‘: ‘logging.handlers.WatchedFileHandler‘,
‘formatter‘: ‘normal‘,
‘filename‘: RUNTIME_HOME + ‘/var/log/root.log‘,
‘mode‘: ‘a‘,
‘level‘: ‘INFO‘,
},
‘extapi‘: {
‘class‘: ‘logging.handlers.WatchedFileHandler‘,
‘formatter‘: ‘normal‘,
‘filename‘: RUNTIME_HOME + ‘/var/log/ext_api.log‘,
‘mode‘: ‘a‘,
‘level‘: ‘DEBUG‘,
},
‘api‘: {
‘class‘: ‘logging.handlers.WatchedFileHandler‘,
‘formatter‘: ‘normal‘,
‘filename‘: RUNTIME_HOME + ‘/var/log/api.log‘,
‘mode‘: ‘a‘,
‘level‘: ‘DEBUG‘,
},
},
‘loggers‘: {
‘API‘: {‘level‘: ‘DEBUG‘,
‘handlers‘: [‘api‘],
},
‘EXTAPI‘: {‘level‘: ‘DEBUG‘,
‘handlers‘: [‘extapi‘],
},
‘requests.packages.urllib3.connectionpool‘: {‘level‘: ‘ERROR‘},
},
‘root‘: {
‘handlers‘: [‘root‘,],
‘level‘: ‘INFO‘,
}
}
例子:
import logging
import os
from douban_scrapy import settings
from logging.handlers import RotatingFileHandler
from logging import StreamHandler
# 直接继承logging.Logger 那么就是说这个类就是一个Logger, 有了Logger所有方法
# 只是在类里面添加一些内部方法,让logger 封装addhandler, setformatter等方法
class LogHandler(logging.Logger):
# 单例模式
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
# 一开始居然用了 cls()来实例化 导致无限次调用
# cls._instance = cls(*args, **kwargs)
cls._instance = object.__new__(cls, *args, **kwargs)
return cls._instance
def __init__(self, name, level=logging.DEBUG, to_stream=True, to_file=True):
self.name = name
self.level = level
self.formatter = logging.Formatter(‘%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s‘)
# 错误的, 继承了logger 本身就是logger 不用再self.logger=xxx 这样变成了一个新的变量
#self.logger = logging.Logger(name=name, level=level)
super(LogHandler, self).__init__(name=name, level=level)
# 写文件
if to_file:
self.__setFileHandler__()
# 写标准输出
if to_stream:
self.__setSteamHandler__()
def __setSteamHandler__(self):
stream_handler = StreamHandler()
stream_handler.setFormatter(self.formatter)
self.addHandler(stream_handler)
def __setFileHandler__(self):
log_path = os.path.join(settings.LOG_DIR, self.name +‘.log‘)
handler = RotatingFileHandler(log_path, maxBytes=1024, backupCount=5)
handler.setFormatter(self.formatter)
self.addHandler(handler)
if __name__ == ‘__main__‘:
logger = LogHandler(‘scrapy‘)
logger2 = LogHandler(‘scrapy‘)
print logger, logger2
logger.info(‘haha‘)
2:-----------------------------------------------------------------------------------------------------------------------2
import os
import logging
from logging.handlers import TimedRotatingFileHandler
# 日志级别
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))
ROOT_PATH = os.path.join(CURRENT_PATH, os.pardir)
LOG_PATH = os.path.join(ROOT_PATH, ‘log‘)
class LogHandler(logging.Logger):
"""
LogHandler
"""
def __init__(self, name, level=DEBUG, stream=True, file=True):
self.name = name
self.level = level
logging.Logger.__init__(self, self.name, level=level)
if stream:
self.__setStreamHandler__()
if file:
self.__setFileHandler__()
def __setFileHandler__(self, level=None):
"""
set file handler
:param level:
:return:
"""
file_name = os.path.join(LOG_PATH, ‘{name}.log‘.format(name=self.name))
# 设置日志回滚, 保存在log目录, 一天保存一个文件, 保留15天
file_handler = TimedRotatingFileHandler(filename=file_name, when=‘D‘, interval=1, backupCount=15)
file_handler.suffix = ‘%Y%m%d.log‘
if not level:
file_handler.setLevel(self.level)
else:
file_handler.setLevel(level)
formatter = logging.Formatter(‘%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s‘)
file_handler.setFormatter(formatter)
self.file_handler = file_handler
self.addHandler(file_handler)
def __setStreamHandler__(self, level=None):
"""
set stream handler
:param level:
:return:
"""
stream_handler = logging.StreamHandler()
formatter = logging.Formatter(‘%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s‘)
stream_handler.setFormatter(formatter)
if not level:
stream_handler.setLevel(self.level)
else:
stream_handler.setLevel(level)
self.addHandler(stream_handler)
def resetName(self, name):
"""
reset name
:param name:
:return:
"""
self.name = name
self.removeHandler(self.file_handler)
self.__setFileHandler__()
if __name__ == ‘__main__‘:
log = LogHandler(‘test‘)
log.info(‘this is a test msg‘)
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did171519