Skip to content

Latest commit

 

History

History
198 lines (148 loc) · 7.05 KB

logging.md

File metadata and controls

198 lines (148 loc) · 7.05 KB

logging

标准的输出日志库,比每次用 print 输出不知道高到哪里去了。

#coding=utf-8

import logging
import sys

LEVELS = {'debug': logging.DEBUG,
          'info': logging.INFO,
          'warning': logging.WARNING,
          'error': logging.ERROR,
          'critical': logging.CRITICAL}

if len(sys.argv) > 1:
    level_name = sys.argv[1]
    level = LEVELS.get(level_name, logging.NOTSET)
    logging.basicConfig(level=level)

logging.debug('This is a debug message')
logging.info('This is an info message')
logging.warning('This is a warning message')
logging.error('This is an error message')
logging.critical('This is a critical error message')

logging 共分五个 log 等级,默认输出的 Level 为 warning 等级,可以设定为其他等级就可以将代码中的每一个等级大于等于 Level 的问题都输出。

#coding=utf-8

import sys
import logging
    
logger = logging.getLogger("Test Logging")
formatter = logging.Formatter('%(name)-12s %(asctime)s %(levelname)-8s %(lineno)-4d %(message)s', '%Y%b%d %a %H:%M:%S')
file_handler = logging.FileHandler("test.log")
file_handler.setFormatter(formatter)
file_handler.setLevel(logging.DEBUG)

stream_handler = logging.StreamHandler(sys.stderr)
stream_handler.setFormatter(formatter)
stream_handler.setLevel(logging.WARNING)

logger.addHandler(file_handler)
logger.addHandler(stream_handler)
logger.setLevel(logging.DEBUG)

logger.debug('This is a debug message')
logger.info('This is an info message')
logger.warning('This is a warning message')
logger.error('This is an error message')

logger.removeHandler(stream_handler)
logger.critical('This is a critical error message')

设定 log 的的格式,和 log 的输出位置,可以在屏幕上,也可以输出到文件中,可以将不同地方的 log 输出等级设为不同。

关于输出的 log 格式

格式 用处
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是“2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s 用户输出的消息

一般常用的 logging

import sys
import logging

logger = logging.getLogger("Socket Logging")
formatter = logging.Formatter('%(name)-12s %(asctime)s %(levelname)-8s %(lineno)-4d %(message)s', '%Y %b %d %a %H:%M:%S',)

file_handler = logging.FileHandler("SocketServer.log")
file_handler.setFormatter(formatter)

logger.addHandler(file_handler)

stream_handler = logging.StreamHandler(sys.stderr)
stream_handler.setFormatter(formatter)

logger.addHandler(stream_handler)

logger.setLevel(logging.DEBUG)

也可以这样配置日志

# coding=utf-8
import logging

def main():
    # Configure the logging system
    logging.basicConfig(
        filename='app.log',
        level=logging.ERROR,
        format='%(levelname)s:%(asctime)s:%(message)s'
    )

    # Variables (to make the calls that follow work)
    hostname = 'www.python.org'
    item = 'spam'
    filename = 'data.csv'
    mode = 'r'

    # Example logging calls (insert into your program)
    logging.critical('Host %s unknown', hostname)
    logging.error("Couldn't find %r", item)
    logging.warning('Feature is deprecated')
    logging.info('Opening file %r, mode=%r', filename, mode)
    logging.debug('Got here')

if __name__ == '__main__':
    main()

关于 logger 输出异常堆栈,无论使用 logger.info 或者 logger.error 输出格式都是一样的,只是日志等级不一样,但是有时在输出异常的时候,我们不只是需要知道异常名称,还需要知道异常的上下文,堆栈信息等,特别是在多线程中,子线程的异常不会被主线程捕获输出,只能通过日志打印出来。

所以可以使用 logger.exception 代替 logger.error ,日志等级也是 error, 但是会打印出异常的堆栈信息。

logging 如果不配置是没有数据输出的,但是如果不想写这么长的配置怎么办呢?直接使用 logging.basicConfig() 进行一个简单的基础配置。

logging.basicConfig(
    level=logging.INFO,
    format='%(name)-25s %(asctime)s %(levelname)-8s %(lineno)-4d %(message)s',
    datefmt='[%Y-%m-%d %H:%M:%S]'
)

示例代码

# coding=utf-8

import sys
import logging

logger = logging.getLogger(__name__)
formatter = logging.Formatter('%(name)-12s %(asctime)s %(levelname)-8s %(lineno)-4d %(message)s', '%Y %b %d %a %H:%M:%S',)

stream_handler = logging.StreamHandler(sys.stderr)
stream_handler.setFormatter(formatter)

logger.addHandler(stream_handler)
logger.setLevel(logging.DEBUG)

if __name__ == '__main__':
    logger.info("main start...")
    try:
        1 / 0
    except Exception as e:
        logger.exception("error %s", e)
    logger.info("main end.")

对比一下输出的日志即可看出。

使用 logger.error 的效果

__main__     2019 May 25 Sat 22:23:36 INFO     16   main start...
__main__     2019 May 25 Sat 22:23:36 ERROR    20   error integer division or modulo by zero
__main__     2019 May 25 Sat 22:23:36 INFO     21   main end.

使用 logger.exception 的效果

__main__     2019 May 25 Sat 22:23:52 INFO     16   main start...
__main__     2019 May 25 Sat 22:23:52 ERROR    20   error integer division or modulo by zero
Traceback (most recent call last):
  File "code/logging_exception.py", line 18, in <module>
    1 / 0
ZeroDivisionError: integer division or modulo by zero
__main__     2019 May 25 Sat 22:23:52 INFO     21   main end.