日志的重要性

如果程序在生产中挂掉, 第一时间要看的不是代码而是日志,这样才能更准确地定位到
错误的位置和原因,话说回来如果运行一个重要的程序,没有日志并且代码很多很复杂,运行报错,结果没有日志记录运行情况,这样就会导致我们要花时间是调试代码,重现错误! 这样的代价就是时间跟精力!因此日志记录是日常开发所必须的。

python的logging模块

python的logging模块很强大能够让我们根据自己的需求,将我们想要的信息输入到日志文件和
工作台,可以设置日志输出的级别(debug, info, warning, error, critical)

相关用法

  1. 使用logging模块的优点
  • 根据不同需求,场景,环境, 设置不同级别的输出等级;
  • 输出更为灵活, 可以是任意位置(文件, 远程服务器),或不同文本格式(文本,json)
  • 可以输出更详细的运行信息(执行文件,运行时间,第几行输出), 而只需简单的设置
    基本用法如下:
import logging

# 设置日志级别
logging.basicConfig(level=logging.DEBUG)

logging.debug('debug log info ')
logging.info('info log info')
logging.warning('warning log info')
logging.error('error log info')
logging.critical('critical log info')
  1. 日志输出设置
    通过修改logging.basicConfig()的参数来调整logging模块默认行为
filename  Specifies that a FileHandler be created, using the specified filename,
          rather than a StreamHandler. # 指定日志文件的名称
              
filemode  Specifies the mode to open the file, if filename is specified
          (if filemode is unspecified, it defaults to 'a'). # 文件打开的方式。 默认是 a 追加模式。
          
format    Use the specified format string for the handler. # 指定日志的显示格式

datefmt   Use the specified date/time format. # 指定日期时间的显示格式。

level     Set the root logger level to the specified level. # 指定日志级别。
stream    Use the specified stream to initialize the StreamHandler. Note
          that this argument is incompatible with 'filename' - if both
          are present, 'stream' is ignored. # 指定输出到标准输出或标准错误等

format 常用的参数

%(name)s            Name of the logger (logging channel) # Logger的名字
%(levelno)s         Numeric logging level for the message (DEBUG, INFO,
                    WARNING, ERROR, CRITICAL) # 数字形式的日志级别
%(levelname)s       Text logging level for the message ("DEBUG", "INFO",
                    "WARNING", "ERROR", "CRITICAL") #文本形式日志级别 
%(pathname)s        Full pathname of the source file where the logging
                    call was issued (if available) # 调用日志输出函数的完整路径名
%(filename)s        Filename portion of pathname # 调用日志输出函数的文件名
%(module)s          Module (name portion of filename) # 调用日志输出模块名
%(lineno)d          Source line number where the logging call was issued
                    (if available) # 调用日志输出函数的语句所在的代码行
%(funcName)s        Function name # 调用日志输出函数的函数名
%(created)f         Time when the LogRecord was created (time.time()
                    return value) # 当前时间,用UNIX标准的表示时间的浮 点数表示
%(asctime)s         Textual time when the LogRecord was created
%(msecs)d           Millisecond portion of the creation time
%(thread)d          Thread ID (if available) # 线程ID
%(threadName)s      Thread name (if available) # 线程名
%(process)d         Process ID (if available) # 进程ID
%(message)s         The result of record.getMessage(), computed just as
                    the record is emitted 用户输出信息

使用logger对象对日志输出

直接上代码

# encoding=utf-8
import logging
import logging.handlers
import time
import os,sys

# log_path是存放日志的路径
cur_path = os.path.dirname(os.path.realpath(__file__))
# 此处是将每天的日志一个由时间生成的目录里
log_path = os.path.join(os.path.dirname(cur_path), 'logs/%s'%time.strftime('%Y_%m_%d'))
# 如果不存在这个logs文件夹,就自动创建一个
if not os.path.exists(log_path): os.mkdir(log_path)


logger = logging.getLogger()
logname = os.path.join(log_path, 'debug.log')
# 本地日志文件
fp = logging.FileHandler(logname, mode='a', encoding='utf-8')
logger.addHandler(fp)

# 标准输出流
std = logging.StreamHandler(sys.stdout)
logger.addHandler(std)

# 定制标准输出和本地文件日志格式
formatter = logging.Formatter("[%(asctime)s] [%(levelname)s] [%(filename)s] [%(lineno)d] - %(message)s")
fp.setFormatter(formatter)
std.setFormatter(formatter)

logger.setLevel(logging.NOTSET)
logger.setLevel(logging.NOTSET)

if __name__ == '__main__':
    logger.debug("I'm spider man")
    logger.warning("I'm iron man")
[2019-12-17 20:48:56,477] [DEBUG] [log.py] [39] - I'm spider man
[2019-12-17 20:48:56,477] [WARNING] [log.py] [40] - I'm iron man