Python
中有好用的 logging
模块,方便我们为程序添加 log
输出,我一直希望能够写个小程序,现在的现在有个小的关于数据提取的小程序,我希望能够提取相关数据,但是用 print
的方式来观察输出实在是忧伤,所以我试着配置了 log
,问题出现了,我希望同时输出到控制台和文件中保存,恩,怎么配置呢?
问题描述
根据 logconfig.yaml
文件,配置 log
,测试模块文件。
问题背景
此处引用输出级别描述:
作者:好吃的野菜
链接:http://www.jianshu.com/p/feb86c06c4f4
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
输出级别 |
描述 |
级别 |
何时使用 |
DEBUG |
详细信息,典型地调试问题时会感兴趣。 |
INFO |
证明事情按预期工作。 |
WARNING |
表明发生了一些意外,或者不久的将来会发生问题(如‘磁盘满了’)。软件还是在正常工作。 |
ERROR |
由于更严重的问题,软件已不能执行一些功能了。 |
CRITICAL |
严重错误,表明软件已不能继续运行了。 |
从上往下,信息级别依次升高!
可采用的 format
格式关键词:
关键词 |
描述 |
%(levelno)s |
打印日志级别的数值 |
%(levelname)s |
打印日志级别名称 |
%(pathname)s |
打印当前执行程序的路径 |
%(filename)s |
打印当前执行程序名称 |
%(funcName)s |
打印日志的当前函数 |
%(lineno)d |
打印日志的当前行号 |
%(asctime)s |
打印日志的时间 |
%(thread)d |
打印线程 id |
%(threadName)s |
打印线程名称 |
%(process)d |
打印进程 ID |
%(message)s |
打印日志信息 |
配置文件
version
键值为 1
,表示启用这个配置。
1
2
3
|
formatters:
simple:
format: '%(asctime)s - %(filename)s - %(lineno)d - [%(levelname)s] %(message)s'
|
formatters
键值中需要有对应的 format
设置,可自定义 format
。
datefmt
格式采用 time.strftime
标准模式,此处不设置,自动启用默认。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
handlers:
console:
class: logging.StreamHandler
level: WARNING
formatter: simple
stream: ext://sys.stdout
logfile:
class: logging.handlers.RotatingFileHandler
level: DEBUG
formatter: simple
filename: log.log
maxBytes: 10485760
backupCount: 3
|
Handlers
是处理 log
的处理器,主要配置输出模式,这里我设置两种模式,控制台( console
)和日志文件( logfile
)。
class
设定 log 采用的输出模式,不同的 class
有着不同的参数, lever
指定处理器处理的最小级别。
-
StreamHandler
是流输出模式,此处特殊设置流的去处 stream
为 ext://sys.stdout
, sys.stdout
是控制台输出位,加上 ext://
是为了让 Yaml
识别。
-
RotatingFileHandler
是循环文件模式,此处特殊设置 filename
、 maxBytes
、 backupCount
的参数。其中 filename
指定保存文件的名称, maxBytes
指定文件大小的最大值, backupCount
指定文件保存数目的最大值,以序号标注,如果超过次数目,默认删掉最早的,更新文件名。
1
2
3
4
5
6
7
8
|
loggers:
logger:
level: INFO
handlers: [logfile]
propagate: yes
root:
level: WARNING
handlers: [console]
|
loggers
指定自定义的 log
名称,此处设置名称为 logger
,propagate
指定是否将信息传到其他 loggers
,这里设置为 yes
,这样 logger 接收到的错误信息可以传到 root
那里, 以供显示输出。
完整配置文件( logconfig.yaml
)如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
version: 1
formatters:
simple:
format: '%(asctime)s - %(filename)s - %(lineno)d - [%(levelname)s] %(message)s'
handlers:
console:
class: logging.StreamHandler
level: WARNING
formatter: simple
stream: ext://sys.stdout
logfile:
class: logging.handlers.RotatingFileHandler
level: DEBUG
formatter: simple
filename: log.log
maxBytes: 10485760
backupCount: 3
loggers:
logger:
level: INFO
handlers: [logfile]
propagate: yes
root:
level: WARNING
handlers: [console]
|
main.py
文件中导入配置文件
main.py
中使用函数导入文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import logging
import logging.config
import yaml
def setup_logging(default_path = "./logconfig.yaml",default_level = logging.INFO,env_key = "LOG_CFG"):
path = default_path
value = os.getenv(env_key,None)
if value:
path = value
if os.path.exists(path):
with open(path,"r") as f:
config = yaml.load(f)
logging.config.dictConfig(config)
else:
logging.basicConfig(level = default_level)
if __name__ == '__main__':
setup_logging(default_path = "./logconfig.yaml")
logger = logging.getLogger("logger")
#测试
logger.debug("测试debug")
logger.info("测试info")
logger.warn("测试warn")
logger.error("测试error")
logger.critical("测试critical")
|
控制台输出如下:
1
2
3
|
2017-08-17 20:32:11,723 - main.py - 39 - [WARNING] 测试warn
2017-08-17 20:32:11,724 - main.py - 40 - [ERROR] 测试error
2017-08-17 20:32:11,724 - main.py - 41 - [CRITICAL] 测试critical
|
log.log
文件输出如下:
1
2
3
4
|
2017-08-17 20:32:11,723 - main.py - 38 - [INFO] 测试info
2017-08-17 20:32:11,723 - main.py - 39 - [WARNING] 测试warn
2017-08-17 20:32:11,724 - main.py - 40 - [ERROR] 测试error
2017-08-17 20:32:11,724 - main.py - 41 - [CRITICAL] 测试critical
|
模块引入配置
如果模块文件需要引入 log
配置,
如下使用:
test.py
内容如下:
1
2
3
4
5
6
7
8
9
|
import logging
logger = logging.getLogger("logger")
def test()
logger.debug("测试debug")
logger.info("测试info")
logger.warn("测试warn")
logger.error("测试error")
logger.critical("测试critical")
|
main.py
内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
import test
import logging
import logging.config
import yaml
def setup_logging(default_path = "./logconfig.yaml",default_level = logging.INFO,env_key = "LOG_CFG"):
path = default_path
value = os.getenv(env_key,None)
if value:
path = value
if os.path.exists(path):
with open(path,"r") as f:
config = yaml.load(f)
logging.config.dictConfig(config)
else:
logging.basicConfig(level = default_level)
if __name__ == '__main__':
setup_logging(default_path = "./logconfig.yaml")
logger = logging.getLogger("logger")
#测试
logger.debug("测试debug")
logger.info("测试info")
logger.warn("测试warn")
logger.error("测试error")
logger.critical("测试critical")
test.test()
|
控制台输出如下:
1
2
3
4
5
6
|
2017-08-17 20:45:40,586 - main.py - 40 - [WARNING] 测试warn
2017-08-17 20:45:40,586 - main.py - 41 - [ERROR] 测试error
2017-08-17 20:45:40,587 - main.py - 42 - [CRITICAL] 测试critical
2017-08-17 20:45:40,587 - test.py - 17 - [WARNING] 测试warn
2017-08-17 20:45:40,587 - test.py - 18 - [ERROR] 测试error
2017-08-17 20:45:40,587 - test.py - 19 - [CRITICAL] 测试critical
|
log.log
输出如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
2017-08-17 20:45:14,225 - main.py - 39 - [INFO] 测试info
2017-08-17 20:45:14,225 - main.py - 40 - [WARNING] 测试warn
2017-08-17 20:45:14,225 - main.py - 41 - [ERROR] 测试error
2017-08-17 20:45:14,225 - main.py - 42 - [CRITICAL] 测试critical
2017-08-17 20:45:40,586 - main.py - 39 - [INFO] 测试info
2017-08-17 20:45:40,586 - main.py - 40 - [WARNING] 测试warn
2017-08-17 20:45:40,586 - main.py - 41 - [ERROR] 测试error
2017-08-17 20:45:40,587 - main.py - 42 - [CRITICAL] 测试critical
2017-08-17 20:45:40,587 - test.py - 16 - [INFO] 测试info
2017-08-17 20:45:40,587 - test.py - 17 - [WARNING] 测试warn
2017-08-17 20:45:40,587 - test.py - 18 - [ERROR] 测试error
2017-08-17 20:45:40,587 - test.py - 19 - [CRITICAL] 测试critical
|
解决模块引入配置的问题
模块引入 log
后,log.log
的信息有重复。
修复方法:
logconfig.yaml
文件添加一条配置
1
|
disable_existing_loggers: False
|
log.log
输出如下:
1
2
3
4
5
6
7
8
|
2017-08-17 20:57:32,535 - main.py - 39 - [INFO] 测试info
2017-08-17 20:57:32,535 - main.py - 40 - [WARNING] 测试warn
2017-08-17 20:57:32,536 - main.py - 41 - [ERROR] 测试error
2017-08-17 20:57:32,536 - main.py - 42 - [CRITICAL] 测试critical
2017-08-17 20:57:32,536 - test.py - 16 - [INFO] 测试info
2017-08-17 20:57:32,536 - test.py - 17 - [WARNING] 测试warn
2017-08-17 20:57:32,536 - test.py - 18 - [ERROR] 测试error
2017-08-17 20:57:32,536 - test.py - 19 - [CRITICAL] 测试critical
|
问题解决,控制台输出同上。
其他补充
-
logconfig.yaml
配置文件对大小写敏感。
-
logconfig.yaml
配置文件使用缩进确认键值包含关系。
-
logconfig.yaml
配置文件中同样的缩进表示同一级别键值。
-
logconfig.yaml
配置文件键值冒号后需要一个空格!
-
本文仅提供配置文件的部分参数介绍,需要了解详情,建议参考 Python 3.5.2
标准库 logging
模块文档(中文) 。