logging 模块

logging 模块应用模板

模板一

模板代码(log_util.py)
"""
#配置日志文件
"""
# 日志文件不存在,创建
if not os.path.isdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logs')):
  os.mkdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logs'))

class Logger():

  standard_format = '[%(asctime)s:%(levelname)s:task_id:%(name)s in %(filename)s:%(pathname)s:%(lineno)d]' \
                    '>>>:%(message)s'
  simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'

  error_format = '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'

  # log文件的全路径
  logfile_dir = os.path.dirname(os.path.abspath(__file__))  # logs文件的目录
  logfile_path = os.path.join(logfile_dir, 'logs', 'info.log')
  error_logfile_path = os.path.join(logfile_dir, 'logs', 'error.log')

  logging_dic = {
      'version': 1,
      'disable_existing_loggers': False,
      'formatters': {
          'standard': {
              'format': standard_format
          },
          'simple': {
              'format': simple_format
          },
          'error': {
              'format': error_format
          },
      },
      'filters': {},
      # 日志的执行者
      'handlers': {
          # 打印到终端的日志
          'console': {
              'level': 'DEBUG',
              'class': 'logging.StreamHandler',  # 打印到屏幕
              'formatter': 'simple'
          },
          # 打印到文件的日志,收集info及以上的日志
          'default': {
              'level': 'DEBUG',
              'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,日志轮转
              'formatter': 'standard',
              'filename': logfile_path,  # 日志文件
              'maxBytes': 1024 * 1024 * 20,  # 日志大小 5M
              'backupCount': 15,
              'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
          },
          # 只保存出现错误及以上的日志
          'error': {
              'level': 'ERROR',
              'class': 'logging.FileHandler',  # 保存到文件,没有分割文件的功能
              'formatter': 'error',
              'filename': error_logfile_path,
              'encoding': 'utf-8',
          },
      },
      # 日志的生产者
      'loggers': {
          # logging.getLogger(__name__)拿到的logger配置,
          # 空的指定对象,在不指定的情况下,默认使用该对象中的handlers
          '': {
              'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
              'level': 'INFO',  # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
              'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
          },
          'error': {
              'handlers': ['error', ],
              'level': 'DEBUG',
              'propagate': False,
          },
      },
  }

  #调用日志对象
  @classmethod
  def load_logger(cls,logger_name=None):    #传入一个日志的类型,名称为loggers中的,如果没有默认''
      logging.config.dictConfig(cls.logging_dic)  # 导入上面定义的logging配置
      logger = logging.getLogger(logger_name)  # 生成一个log实例变量对应日志配置中的%(name)s
      return logger  #返回一个日志对象,可以直接调用

模板二

模板代码(log_util.py)
import os
import logging
import logging.config

USER_PATH = ''  # 日志文件夹
BASIC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)))

if USER_PATH:
    if not os.path.isdir(USER_PATH):
        raise Exception('USER_PATH 目录不存在')
    if not os.path.isdir(os.path.join(BASIC_PATH, 'logs')):
        os.makedirs(os.path.join(BASIC_PATH, 'logs'))
    PATH = os.path.join(BASIC_PATH, 'logs')
else:
    if not os.path.isdir(os.path.join(USER_PATH, 'logs')):
        os.makedirs(os.path.join(USER_PATH, 'logs'))
    PATH = os.path.join(USER_PATH, 'logs')


class Logger:
    simple = '[%(asctime)s][%(levelname)s][%(filename)s:%(lineno)d]>>>: %(message)s'
    standard = '%(levelname)s [%(asctime)s][%(pathname)s:%(lineno)d][%(process)d][%(processName)s][%(thread)d][%(threadName)s]>>>: %(message)s'
    default_log_path = '{}/{}'.format(PATH, 'log.log')
    app_log_path = '{}/{}'.format(PATH, 'app.log')
    config_dic = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'simple': {
                'format': simple,
                'datefmt': '%H:%M:%S'
            },
            'standard': {
                'format': standard,
                'datefmt': '%Y-%m-%d %H:%M:%S'
            }
        },
        'handlers': {
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
                'formatter': 'simple'
            },
            'default_file': {
                'level': 'DEBUG',
                'class': 'logging.handlers.RotatingFileHandler',
                'formatter': 'standard',
                'filename': default_log_path,
                'maxBytes': 1024 * 1024 * 20,
                'backupCount': 1,
                'encoding': 'utf-8',
            },
            'app_file': {
                'level': 'DEBUG',
                'class': 'logging.handlers.RotatingFileHandler',
                'formatter': 'standard',
                'filename': app_log_path,
                'maxBytes': 1024 * 1024 * 20,
                'backupCount': 1,
                'encoding': 'utf-8',
            }
        },
        'loggers': {
            'default': {
                'handlers': ['console', 'default_file'],
                'level': 'INFO',
                'propagate': False,
            },
            'app': {
                'handlers': ['console', 'app_file'],
                'level': 'INFO',
                'propagate': False,
            }

        },
    }

    @classmethod
    def load_logger(cls, logger_name='default'):
        logging.config.dictConfig(cls.config_dic)
        return logging.getLogger(logger_name)


logger = Logger.load_logger()
logger_app = Logger.load_logger('app')



"""
配置 DIR_PATH 参数
from ... import logger,logger_app 
logger.info('hello')
logger_app.info('hello app')

"""

模板三

日志处理程序

  • 可用的处理程序类
    StreamHandler 实例将消息发送到流(类似于对象的文件)。
    FileHandler 实例将消息发送到磁盘文件。
    BaseRotatingHandler 是在某一点旋转日志文件的处理程序的基类。它并不打算直接实例化。相反,使用 RotatingFileHandler 或 TimedRotatingFileHandler .
    RotatingFileHandler 实例向磁盘文件发送消息,支持最大日志文件大小和日志文件旋转。
    TimedRotatingFileHandler 实例将消息发送到磁盘文件,以特定的时间间隔旋转日志文件。
    SocketHandler 实例将消息发送到TCP/IP套接字。自3.4以来,还支持Unix域套接字。
    DatagramHandler 实例将消息发送到UDP套接字。自3.4以来,还支持Unix域套接字。
    SMTPHandler 实例将消息发送到指定的电子邮件地址。
    SysLogHandler 实例将消息发送到一个UNIX系统日志守护进程,可能在远程计算机上。
    NTEventLogHandler 实例将消息发送到Windows NT/2000/XP事件日志。
    MemoryHandler 实例将消息发送到内存中的缓冲区,只要满足特定条件,缓冲区就会被刷新。
    HTTPHandler 实例使用以下任一方法向HTTP服务器发送消息 GET 或 POST 语义学。
    WatchedFileHandler 实例监视它们正在登录的文件。如果文件发生更改,将关闭该文件并使用文件名重新打开。此处理程序仅在类Unix系统上有用;Windows不支持所使用的底层机制。
    QueueHandler 实例将消息发送到队列,例如 queue 或 multiprocessing 模块。
    NullHandler 实例不处理错误消息。它们由希望使用日志记录的库开发人员使用,但希望避免出现“找不到日志记录器XXX的处理程序”消息,如果库用户未配置日志记录,则可以显示该消息。见 为库配置日志记录 更多信息。
    

日志输出格式表

  • Formatter 格式器
变量 格式 变量描述
asctime %(asctime)s 将日志的时间构造成可读的形式,默认情况下是精确到毫秒,如 2018-10-13 23:24:57,832,可以额外指定 datefmt 参数来指定该变量的格式
name %(name)s 日志对象的名称
filename %(filename)s 不包含路径的文件名
pathname %(pathname)s 包含路径的文件名
funcName %(funcName)s 日志记录所在的函数名
levelname %(levelname)s 日志的级别名称
message %(message)s 具体的日志信息
lineno %(lineno)d 日志记录所在的行号
pathname %(pathname)s 完整路径
process %(process)d 当前进程ID
processName %(processName)s 当前进程名称
thread %(thread)d 当前线程ID
threadName %(threadName)s 当前线程名称

日志基础模式

  • 基础模式构成代码
    import logging
    
    # 创建基础程序
    logging.basicConfig(
        filename='log.log',
        filemode='w',
        format='%(levelname)s--%(asctime)s -- %(message)s ',
        datefmt='%m/%d/%Y %I:%M:%S %p',
        style='%',
        level=logging.DEBUG,
    )
    logging.debug('debug')
    logging.info('info')
    logging.warning('warning')
    logging.error('error')
    logging.critical('critical')
    logging.exception('exception')    # 仅从异常处理程序调用此方法。
    
    
    # 创建高级日志记录器
    # 格式化程序
    formatter = logging.Formatter(fmt='%(levelname)s == %(asctime)s == %(message)s == %(filename)s == %(pathname)s',datefmt='%m/%d/%Y %I:%M:%S %p', style='%')
    
    # 处理程序
    stream_handler = logging.StreamHandler()  # 标准系统输出
    stream_handler.setLevel(logging.DEBUG)
    stream_handler.setFormatter(formatter)
    file_handler = logging.FileHandler('log.log', mode='a', encoding='utf-8', delay=False)  # 文件输出
    file_handler.setLevel(logging.DEBUG)  # 设置输出等级
    file_handler.setFormatter(formatter)  # 设置输出格式
    
    # 创建记录器
    logger = logging.getLogger('mylogger')
    logger.setLevel(logging.DEBUG)  # 设置日志过滤等级
    logger.addHandler(stream_handler)  # 添加流处理程序
    logger.addHandler(file_handler)  # 添加文件处理程序
    
    logger.debug('DEBUG')
    logger.info('INFO')
    logger.warning('WARNING')
    logger.error('ERROR')
    logger.critical('CRITICAL')
    logger.exception('EXCEPTION')    # 仅从异常处理程序调用此方法。
    
    
    • 控制台输出(高级)
      ERROR [01/04/2023 10:57:07 AM]: msg=error  -test.py 
      CRITICAL [01/04/2023 10:57:07 AM]: msg=critical  -test.py 
      ERROR [01/04/2023 10:57:07 AM]: msg=exception  -test.py 
      NoneType: None
      
      
    • 文件输出(高级)
      DEBUG [01/04/2023 10:57:07 AM]: msg=debug  -test.py 
      INFO [01/04/2023 10:57:07 AM]: msg=info  -test.py 
      WARNING [01/04/2023 10:57:07 AM]: msg=warning  -test.py 
      ERROR [01/04/2023 10:57:07 AM]: msg=error  -test.py 
      CRITICAL [01/04/2023 10:57:07 AM]: msg=critical  -test.py 
      ERROR [01/04/2023 10:57:07 AM]: msg=exception  -test.py 
      NoneType: None
      
      

日志特别说明

  • 等级说明
  • logger.setLevel(),对象可以设置等级 ,handler.setLevel()也可以设置等级
    • logger 中设置的等级指的是,记录器传递给处理程序的日志等级,而hander 中的日志等级是,拿到记录器给的日志再根据等级判断哪些日志输出来。
  • 记录器说明
    • 一个记录器可以挂载 多个处理器,logger可以对应多个handler
  • 日志记录程序说明
    • 日志记录程序,可以多个记录器配置。
    • 记录器是单例模式构成。

logging 日志对象加载配置

方式一: dict模式

查看代码
import logging
import logging.config

config = {
    'version': 1,
    'formatters': {
        'simple': {
            'format': '[%(asctime)s][%(name)s][%(levelname)s] - %(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S',
            'style': '%'
        },
        # 其他格式处理器
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'formatter': 'simple'
        },
        'file': {
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': 'log.log',
            'level': 'DEBUG',
            'formatter': 'simple',
            'maxBytes': 1024 * 1024,
            'backupCount': 1,
        },
        # 其他处理程序
    },
    'loggers': {
        'StreamLogger': {
            'handlers': ['console'],
            'level': 'DEBUG',
        },
        'FileLogger': {
            'handlers': ['console', 'file'],
            'level': 'INFO',
        },
        # 其他记录器
    }
}
logging.config.dictConfig(config)
logger = logging.getLogger("FileLogger")
logger.debug(' debug ')
logger.info('info ')
logger.warning(' warning ')
logger.error(' error ')
logger.critical('critical ')

方式二:yaml模式

查看代码
import logging
import logging.config
import yaml

with open('log.yaml', 'r') as f:
    config = yaml.safe_load(f.read())
    logging.config.dictConfig(config)

logger = logging.getLogger("simpleExample")
logger.debug(' debug ')
logger.info('info ')
logger.warning(' warning ')
logger.error(' error ')
logger.critical('123')

yaml 配置文件

查看代码
# 文件名为 log.yaml
version: 1
formatters:
  simple:
    format: '[%(asctime)s][%(name)s][%(levelname)s] - %(message)s'
    datefmt: '%Y-%m-%d %H:%M:%S'
    style: '%'
handlers:
  console:
      class: logging.StreamHandler
      level: DEBUG
      formatter: simple
  file:
      class: logging.handlers.RotatingFileHandler
      filename: log.log
      level: DEBUG
      formatter: simple
      maxBytes: 1048576
      backupCount: 1
loggers:
  simpleExample:
    level: DEBUG
    handlers: [ console,file ]
    propagate: no
root:
  level: DEBUG
  handlers: [ console ]

参考文献

posted @ 2023-01-04 12:21  空白的时间  阅读(21)  评论(0编辑  收藏  举报