欢迎访问我的博客首页。
1. 通过函数调用栈实现
traceback 库记录着 Python 的调用栈。使用 traceback,不仅可以输出日志位置,还可以输出函数调用栈。
import traceback, time, os
def selfLog(*logs, toFile=True):
tracebackinfo = str(traceback.extract_stack()[-2])
begin = tracebackinfo.index('file')
end = tracebackinfo.rindex(' in')
tracebackinfo = tracebackinfo[begin:end]
times = time.strftime('%Y/%m/%d %H:%M:%S', time.localtime())
if toFile:
tracebackinfo = 'file ' + os.path.basename(tracebackinfo)
handle = open('log.txt', 'a')
handle.write('-- log: %s, %s\n' % (tracebackinfo, times))
handle.write(' ')
for log in logs[:-1]:
handle.write('%s ' % log)
handle.write('%s\n' % logs[-1])
handle.close()
return
print('-- log: %s, %s' % (tracebackinfo, times))
print(' ', end='')
for log in logs[:-1]:
print('%s' % log, end=' ')
print(logs[-1])
假如上面的代码在 selfLog.py 中,调用者代码:
from selfLog import selfLog
selfLog('abcd')
selfLog('abc', 'def')
可以看出,我们可以像使用 print 语句一样使用 selfLog:输出单个对象、逗号隔开的多个对象、格式化输出对象。
2. 改变 print 函数输出字体的颜色
python 可以指定 print 字体颜色,代码 selfLog.py:
import config
import time, traceback
from colorama import init
init(autoreset=True)
def getColor(rank):
manner = 1
foreground = 30 # [30, 37]
background = 47 # [40, 47]
foreground += rank % 8
background -= rank % 8
# color = '\033[%d;%d;%dm' % (manner, foreground, background)
color = '\033[%d;%dm' % (manner, foreground)
return color
def selfLog(rank, *logs):
if rank < config.selfLogRank:
return
tracebackinfo = str(traceback.extract_stack()[-2])
begin = tracebackinfo.index('file')
end = tracebackinfo.rindex(' in')
tracebackinfo = tracebackinfo[begin:end]
times = time.strftime('%Y/%m/%d %H:%M:%S', time.localtime())
print('-- %s, %s' % (tracebackinfo, times))
color = getColor(rank)
for log in logs:
print(' %s%s' % (color, log), end=' ')
print()
config.py:
selfLogRank = 0
main.py:
from selfLog import selfLog
if __name__ == '__main__':
selfLog(1, 'Reading image...', 'info_1', 'info_2')
selfLog(3, 'Failed to read image!', 'info_1')
调用时第一个参数 rank 不小于 config.selfLogRank 才会输出。
3. 使用 logging
logging 是 Python 的日志库,可以很方便地把日志输出到控制台或文件中。
使用 logging 库,可以输出单个字符串、数字、变量等对象,但不能输出逗号隔开的多个对象。如果想输出多个对象,需要使用格式化输出。
3.1 自定义名称的句柄
标准库 logging 有一个 logger,该 logger 有一个名称为 root 的默认句柄。句柄负责输出日志,可以通过 logger 添加句柄。
import time
import logging
def init_log():
# 1.变量。
date_fmt = '%Y/%m/%d %H:%M:%S'
masg_fmt = '%(name)s %(pathname)s, line %(lineno)d, %(asctime)s %(levelname)-5.5s: %(message)s'
path_log = time.strftime('%Y%m%d_%H%M%S', time.localtime()) + '.log'
# 2.名称为 root 的默认日志。
logging.basicConfig(filename='root_' + path_log, filemode='w', format=masg_fmt, datefmt=date_fmt,
level=logging.NOTSET)
# 3.自定义名称的日志。
logger = logging.getLogger('阿尔法公司')
# 3.1 控制台。
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.WARNING)
console_handler.setFormatter(fmt=logging.Formatter(fmt=masg_fmt, datefmt=date_fmt))
logger.addHandler(console_handler)
# 3.2 文件。
file_handler = logging.FileHandler(filename=path_log, mode='a', encoding='utf-8')
file_handler.setLevel(logging.ERROR)
file_handler.setFormatter(fmt=logging.Formatter(fmt=masg_fmt, datefmt=date_fmt))
logger.addHandler(file_handler)
return logger
if __name__ == '__main__':
logger = init_log()
logging.info('logging 信息')
logging.debug('logging 调试')
logging.warning('logging 警告')
logging.error('logging 错误')
logging.critical('logging 严重错误')
logger.info('logger 信息')
logger.debug('logger 调试')
logger.warning('logger 警告')
logger.error('logger 错误')
logger.critical('logger 严重错误')
basicConfig 用于配置默认名为 root 的句柄。在这里配置文件名时日志将会被输出到文件,否则输出到控制台。无论使用 logging.info/debug/warning/error/critical 还是 logger.info/debug/warning/error/critical 输出,都会按 basicConfig 的配置输出到文件或控制台。
上面使用 logger 添加的两个自定义句柄,分别把日志输出到控制台和文件。这两个句柄只能响应 logger.info/debug/warning/error/critical,不能响应 logging.info/debug/warning/error/critical。
3.2 使用默认句柄
虽然自定义句柄可以指定名称,但我们必须获取 logger,才能使用它输出。在其它文件中使用 logger,必须先把它 import 进来。使用默认句柄时,只需在项目任意位置配置 logging,在其它文件只需 import logging 就能直接使用。
import time
import logging
def init_log():
# 1.变量。
date_fmt = '%Y/%m/%d %H:%M:%S'
masg_fmt = '%(name)s %(pathname)s, line %(lineno)d, %(asctime)s %(levelname)-5.5s: %(message)s'
path_log = time.strftime('%Y%m%d_%H%M%S', time.localtime()) + '.log'
# 2.名称为 root 的默认日志。
# logging.basicConfig(filename='root_' + path_log, filemode='w', format=masg_fmt, datefmt=date_fmt,
# level=logging.NOTSET)
# 3.自定义名称的日志。
# logger = logging.getLogger('阿尔法公司')
# 3.1 控制台。
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.WARNING)
console_handler.setFormatter(fmt=logging.Formatter(fmt=masg_fmt, datefmt=date_fmt))
logging.getLogger().addHandler(console_handler)
# 3.2 文件。
file_handler = logging.FileHandler(filename=path_log, mode='a', encoding='utf-8')
file_handler.setLevel(logging.ERROR)
file_handler.setFormatter(fmt=logging.Formatter(fmt=masg_fmt, datefmt=date_fmt))
logging.getLogger().addHandler(file_handler)
if __name__ == '__main__':
init_log()
logging.info('logging 信息')
logging.debug('logging 调试')
logging.warning('logging 警告')
logging.error('logging 错误')
logging.critical('logging 严重错误')
4. 参考
- print 颜色
- logging 级别,博客园,2019。