共计 11385 个字符,预计需要花费 29 分钟才能阅读完成。
1 根本应用
配置 logging 根本的设置,而后在控制台输入日志,
import logging
logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.info("Finish")
运行时,控制台输入,
2016-10-09 19:11:19,434 - __main__ - INFO - Start print log
2016-10-09 19:11:19,434 - __main__ - WARNING - Something maybe fail.
2016-10-09 19:11:19,434 - __main__ - INFO - Finish
logging 中能够抉择很多音讯级别,如 debug、info、warning、error 以及 critical。通过赋予 logger 或者 handler 不同的级别,开发者就能够只输入错误信息到特定的记录文件,或者在调试时只记录调试信息。</pre>
例如,咱们将 logger 的级别改为 DEBUG,再察看一下输入后果,</pre>
logging.basicConfig(level = logging.DEBUG,format = ‘%(asctime)s – %(name)s – %(levelname)s – %(message)s’)</pre>
控制台输入,能够发现,输入了 debug 的信息。
2016-10-09 19:12:08,289 - __main__ - INFO - Start print log
2016-10-09 19:12:08,289 - __main__ - DEBUG - Do something
2016-10-09 19:12:08,289 - __main__ - WARNING - Something maybe fail.
2016-10-09 19:12:08,289 - __main__ - INFO - Finish
logging.basicConfig 函数各参数:
filename:指定日志文件名;
filemode:和 file 函数意义雷同,指定日志文件的关上模式,’w’ 或者 ’a’;
format:指定输入的格局和内容,format 能够输入很多有用的信息,
参数:作用
%(levelno)s:打印日志级别的数值
%(levelname)s:打印日志级别的名称
%(pathname)s:打印以后执行程序的门路,其实就是 sys.argv[0]
%(filename)s:打印以后执行程序名
%(funcName)s:打印日志的以后函数
%(lineno)d:打印日志的以后行号
%(asctime)s:打印日志的工夫
%(thread)d:打印线程 ID%(threadName)s:打印线程名称
%(process)d:打印过程 ID%(message)s:打印日志信息
datefmt:指定工夫格局,同 time.strftime();</pre>
level:设置日志级别,默认为 logging.WARNNING;</pre>
stream:指定将日志的输入流,能够指定输入到 sys.stderr,sys.stdout 或者文件,默认输入到 sys.stderr,当 stream 和 filename 同时指定时,stream 被疏忽;</pre>
2 将日志写入到文件
2.2.1 将日志写入到文件 </pre>
设置 logging,创立一个 FileHandler,并对输入音讯的格局进行设置,将其增加到 logger,而后将日志写入到指定的文件中,
import logginglogger = logging.getLogger(__name__)logger.setLevel(level = logging.INFO)handler = logging.FileHandler("log.txt")handler.setLevel(logging.INFO)formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')handler.setFormatter(formatter)logger.addHandler(handler) logger.info("Start print log")logger.debug("Do something")logger.warning("Something maybe fail.")logger.info("Finish")
log.txt 中日志数据为,
2016-10-09 19:01:13,263 - __main__ - INFO - Start print log2016-10-09 19:01:13,263 - __main__ - WARNING - Something maybe fail.2016-10-09 19:01:13,263 - __main__ - INFO - Finish
2.2 将日志同时输入到屏幕和日志文件 </pre>
logger 中增加 StreamHandler,能够将日志输入到屏幕上,</pre>
import logginglogger = logging.getLogger(__name__)logger.setLevel(level = logging.INFO)handler = logging.FileHandler("log.txt")handler.setLevel(logging.INFO)formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')handler.setFormatter(formatter) console = logging.StreamHandler()console.setLevel(logging.INFO) logger.addHandler(handler)logger.addHandler(console) logger.info("Start print log")logger.debug("Do something")logger.warning("Something maybe fail.")logger.info("Finish")
能够在 log.txt 文件和控制台中看到,
2016-10-09 19:20:46,553 - __main__ - INFO - Start print log2016-10-09 19:20:46,553 - __main__ - WARNING - Something maybe fail.2016-10-09 19:20:46,553 - __main__ - INFO - Finish
能够发现,logging 有一个日志解决的主对象,其余解决形式都是通过 addHandler 增加进去,logging 中蕴含的 handler 次要有如下几种,
handler 名称:地位;作用
StreamHandler:logging.StreamHandler;日志输入到流,能够是 sys.stderr,sys.stdout 或者文件
FileHandler:logging.FileHandler;日志输入到文件
BaseRotatingHandler:logging.handlers.BaseRotatingHandler;根本的日志回滚形式
RotatingHandler:logging.handlers.RotatingHandler;日志回滚形式,反对日志文件最大数量和日志文件回滚
TimeRotatingHandler:logging.handlers.TimeRotatingHandler;日志回滚形式,在肯定工夫区域内回滚日志文件
SocketHandler:logging.handlers.SocketHandler;近程输入日志到 TCP/IPsockets
DatagramHandler:logging.handlers.DatagramHandler;近程输入日志到 UDP sockets
SMTPHandler:logging.handlers.SMTPHandler;近程输入日志到邮件地址
SysLogHandler:logging.handlers.SysLogHandler;日志输入到 syslog
NTEventLogHandler:logging.handlers.NTEventLogHandler;近程输入日志到 Windows NT/2000/XP 的事件日志
MemoryHandler:logging.handlers.MemoryHandler;日志输入到内存中的指定 buffer
HTTPHandler:logging.handlers.HTTPHandler;通过 "GET" 或者 "POST" 近程输入到 HTTP 服务器
2.3 日志回滚 </pre>
应用 RotatingFileHandler,能够实现日志回滚,</pre>
import logging
from logging.handlers import RotatingFileHandler
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
#定义一个 RotatingFileHandler,最多备份 3 个日志文件,每个日志文件最大 1K
rHandler = RotatingFileHandler("log.txt",maxBytes = 1*1024,backupCount = 3)
rHandler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
rHandler.setFormatter(formatter)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter)
logger.addHandler(rHandler)
logger.addHandler(console)
logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.info("Finish")
能够在工程目录中看到,备份的日志文件,
</pre>
2016/10/09 19:36 732 log.txt
2016/10/09 19:36 967 log.txt.1
2016/10/09 19:36 985 log.txt.2
2016/10/09 19:36 976 log.txt.3
2.3 设置音讯的等级
能够设置不同的日志等级,用于管制日志的输入,
</pre>
日志等级:应用范畴
FATAL:致命谬误
CRITICAL:特地蹩脚的事件,如内存耗尽、磁盘空间为空,个别很少应用
ERROR:产生谬误时,如 IO 操作失败或者连贯问题
WARNING:产生很重要的事件,然而并不是谬误时,如用户登录明码谬误
INFO:解决申请或者状态变动等日常事务
DEBUG:调试过程中应用 DEBUG 等级,如算法中每个循环的中间状态
2.4 捕捉 traceback
Python 中的 traceback 模块被用于跟踪异样返回信息,能够在 logging 中记录下 traceback,
代码,
import logging
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler("log.txt")
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
logger.addHandler(handler)
logger.addHandler(console)
logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
try:
open("sklearn.txt","rb")
except (SystemExit,KeyboardInterrupt):
raise
except Exception:
logger.error("Faild to open sklearn.txt from logger.error",exc_info = True)
logger.info("Finish")
控制台和日志文件 log.txt 中输入,
Start print log
Something maybe fail.
Faild to open sklearn.txt from logger.error
Traceback (most recent call last):
File "G:\zhb7627\Code\Eclipse WorkSpace\PythonTest\test.py", line 23, in <module>
open("sklearn.txt","rb")
IOError: [Errno 2] No such file or directory: 'sklearn.txt'
Finish
也能够应用 logger.exception(msg,_args),它等价于 logger.error(msg,exc_info = True,_args),
将
logger.error("Faild to open sklearn.txt from logger.error",exc_info = True)
替换为,
logger.exception("Failed to open sklearn.txt from logger.exception")
控制台和日志文件 log.txt 中输入,
Start print log
Something maybe fail.
Failed to open sklearn.txt from logger.exception
Traceback (most recent call last):
File "G:\zhb7627\Code\Eclipse WorkSpace\PythonTest\test.py", line 23, in <module>
open("sklearn.txt","rb")
IOError: [Errno 2] No such file or directory: 'sklearn.txt'
Finish
2.5 多模块应用 logging
主模块 mainModule.py,
import logging
import subModule
logger = logging.getLogger("mainModule")
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler("log.txt")
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter)
logger.addHandler(handler)
logger.addHandler(console)
logger.info("creating an instance of subModule.subModuleClass")
a = subModule.SubModuleClass()
logger.info("calling subModule.subModuleClass.doSomething")
a.doSomething()
logger.info("done with subModule.subModuleClass.doSomething")
logger.info("calling subModule.some_function")
subModule.som_function()
logger.info("done with subModule.some_function")
子模块 subModule.py,
import logging
module_logger = logging.getLogger("mainModule.sub")
class SubModuleClass(object):
def __init__(self):
self.logger = logging.getLogger("mainModule.sub.module")
self.logger.info("creating an instance in SubModuleClass")
def doSomething(self):
self.logger.info("do something in SubModule")
a = []
a.append(1)
self.logger.debug("list a =" + str(a))
self.logger.info("finish something in SubModuleClass")
def som_function():
module_logger.info("call function some_function")
执行之后,在管制和日志文件 log.txt 中输入,
2016-10-09 20:25:42,276 - mainModule - INFO - creating an instance of subModule.subModuleClass
2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - creating an instance in SubModuleClass
2016-10-09 20:25:42,279 - mainModule - INFO - calling subModule.subModuleClass.doSomething
2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - do something in SubModule
2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - finish something in SubModuleClass
2016-10-09 20:25:42,279 - mainModule - INFO - done with subModule.subModuleClass.doSomething
2016-10-09 20:25:42,279 - mainModule - INFO - calling subModule.some_function
2016-10-09 20:25:42,279 - mainModule.sub - INFO - call function some_function
2016-10-09 20:25:42,279 - mainModule - INFO - done with subModule.some_function
首先在主模块定义了 logger’mainModule’,并对它进行了配置,就能够在解释器过程外面的其余中央通过 getLogger(‘mainModule’) 失去的对象都是一样的,不须要重新配置,能够间接应用。定义的该 logger 的子 logger,都能够共享父 logger 的定义和配置,所谓的父子 logger 是通过命名来辨认,任意以 ’mainModule’ 结尾的 logger 都是它的子 logger,例如 ’mainModule.sub’。
理论开发一个 application,首先能够通过 logging 配置文件编写好这个 application 所对应的配置,能够生成一个根 logger,如 ’PythonAPP’,而后在主函数中通过 fileConfig 加载 logging 配置,接着在 application 的其余中央、不同的模块中,能够应用根 logger 的子 logger,如 ’PythonAPP.Core’,’PythonAPP.Web’ 来进行 log,而不须要重复的定义和配置各个模块的 logger。
3 通过 JSON 或者 YAML 文件配置 logging 模块
只管能够在 Python 代码中配置 logging,然而这样并不够灵便,最好的办法是应用一个配置文件来配置。在 Python 2.7 及当前的版本中,能够从字典中加载 logging 配置,也就意味着能够通过 JSON 或者 YAML 文件加载日志的配置。
3.1 通过 JSON 文件配置
JSON 配置文件,
{
"version":1,
"disable_existing_loggers":false,
"formatters":{
"simple":{"format":"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
}
},
"handlers":{
"console":{
"class":"logging.StreamHandler",
"level":"DEBUG",
"formatter":"simple",
"stream":"ext://sys.stdout"
},
"info_file_handler":{
"class":"logging.handlers.RotatingFileHandler",
"level":"INFO",
"formatter":"simple",
"filename":"info.log",
"maxBytes":"10485760",
"backupCount":20,
"encoding":"utf8"
},
"error_file_handler":{
"class":"logging.handlers.RotatingFileHandler",
"level":"ERROR",
"formatter":"simple",
"filename":"errors.log",
"maxBytes":10485760,
"backupCount":20,
"encoding":"utf8"
}
},
"loggers":{
"my_module":{
"level":"ERROR",
"handlers":["info_file_handler"],
"propagate":"no"
}
},
"root":{
"level":"INFO",
"handlers":["console","info_file_handler","error_file_handler"]
}
}
通过 JSON 加载配置文件,而后通过 logging.dictConfig 配置 logging,
import json
import logging.config
import os
def setup_logging(default_path = "logging.json",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 = json.load(f)
logging.config.dictConfig(config)
else:
logging.basicConfig(level = default_level)
def func():
logging.info("start func")
logging.info("exec func")
logging.info("end func")
if __name__ == "__main__":
setup_logging(default_path = "logging.json")
func()
3.2 通过 YAML 文件配置
通过 YAML 文件进行配置,比 JSON 看起来更加简介明了,
version: 1
disable_existing_loggers: False
formatters:
simple:
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
handlers:
console:
class: logging.StreamHandler
level: DEBUG
formatter: simple
stream: ext://sys.stdout
info_file_handler:
class: logging.handlers.RotatingFileHandler
level: INFO
formatter: simple
filename: info.log
maxBytes: 10485760
backupCount: 20
encoding: utf8
error_file_handler:
class: logging.handlers.RotatingFileHandler
level: ERROR
formatter: simple
filename: errors.log
maxBytes: 10485760
backupCount: 20
encoding: utf8
loggers:
my_module:
level: ERROR
handlers: [info_file_handler]
propagate: no
root:
level: INFO
handlers: [console,info_file_handler,error_file_handler]
通过 YAML 加载配置文件,而后通过 logging.dictConfig 配置 logging
import yaml
import logging.config
import os
def setup_logging(default_path = "logging.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)
def func():
logging.info("start func")
logging.info("exec func")
logging.info("end func")
if __name__ == "__main__":
setup_logging(default_path = "logging.yaml")
func()
文末福利
点击支付 2020Python 材料合集,视频 & 电子书