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")

运行时,控制台输出,

logging中可以选择很多消息级别,如debug、info、warning、error以及critical。通过赋予logger或者handler不同的级别,开发者就可以只输出错误信息到特定的记录文件,或者在调试时只记录调试信息。

例如,我们将logger的级别改为DEBUG,再观察一下输出结果,

logging.basicConfig(level = logging.DEBUG,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')

控制台输出,可以发现,输出了debug的信息。

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();

level:设置日志级别,默认为logging.WARNNING;

stream:指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略;

2 将日志写入到文件

2.2.1 将日志写入到文件

设置logging,创建一个FileHandler,并对输出消息的格式进行设置,将其添加到logger,然后将日志写入到指定的文件中,

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)
logger.addHandler(handler) logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.info("Finish")

log.txt中日志数据为,

2.2 将日志同时输出到屏幕和日志文件

logger中添加StreamHandler,可以将日志输出到屏幕上,

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.")
logger.info("Finish")

可以在log.txt文件和控制台中看到,

可以发现,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/IP sockets
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 日志回滚

使用RotatingFileHandler,可以实现日志回滚,

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")
可以在工程目录中看到,备份的日志文件,当日志达到指定1k时,就会做日志切割,将当前日志内容放到log.txt.1的文件里,.1的会放到.2文件里。依此往下存放。而最新日志进行从log.txt文件里面追加写入

最多有三个最近的,时间更久的已经被删除了

2.4 设置消息的等级

可以设置不同的日志等级,用于控制日志的输出,

日志等级:使用范围

FATAL:致命错误
CRITICAL:特别糟糕的事情,如内存耗尽、磁盘空间为空,一般很少使用
ERROR:发生错误时,如IO操作失败或者连接问题
WARNING:发生很重要的事件,但是并不是错误时,如用户登录密码错误
INFO:处理请求或者状态变化等日常事务
DEBUG:调试过程中使用DEBUG等级,如算法中每个循环的中间状态

2.5 捕获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中输出,

也可以使用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中输出,因为没有删除日志,重新运行日志,是在已有的日志文件里面追加的。跟上次相比,区别点在于失败的消息来源不同

2.6 多模块使用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中输出,

我们定义了三个日志对象,主模块中的对象做了配置,两个子模块中并没有配置,是定义子模块的日志对象时使用主模块名字点子模块日志对象名字。我们在子模块中定义了子模块的日志对象,并写了函数或者类方法。然后在主模块中导入,并且在主模块中调用子模块中定义的日志对象做打印日志的行为。因为配置是一样的,主模块和子模块的打印输出都是输出在同一个日志文件中。输出如下,我们需要看清打印的日志对象是哪一个,是主模块中的还是子模块中哪个,根据打印信息(%(name)s输出的是日志对象名字,也就是日志器名字,),我们分清是调用的哪个日志器打印的信息

首先在主模块定义了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,Loader=yaml.FullLoader)
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()
我们将yaml日志的配置文件传入函数,调用设置日志函数之后,就会生成日志器对象,然后在下面的程序中调用日志信息的打印,这里是在函数中调用打印日志信息。
这里除了生成info日志,还生成了errors日志

我们可以设置info信息的日志名字,备份个数,文件最大字节数等等信息。配置级别是INFO。下面还有个错误日志处理,都是要添加日志切割的类

我在程序里输出一个错误信息,执行了三次,三次都将错误信息记录到了错误日志里面,错误日志里面只记录了错误信息,这应该跟级别有关;而info日志里面不知记录了info信息,也记录了错误级别的信息。这应该是info级别的日志输出本来就能打印其它级别的日志输出,所以也是能将这个级别的记录到文件中的,而错误级别的打印就不包含info级别的打印,所以info级别的也不会写入到错误级别的日志中

我们控制台打印这里设置的就是info级别的日志

日志输出格式是引用的上面的

flask中可以使用logging的方式

方式一:

import logging
logger = logging.getLogger('flask.app')
logger.setLevel(level=logging.WARNING)
handler = logging.FileHandler("log2.txt",encoding='utf8')
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
@app.route('/test', methods=['GET', 'POST'])
def test():
logger.error('app下面的视图函数调用')
return 'ok'

我们可以这样做,不过这个是起了个日志器名字falsk.app

方式二:

使用app点的方式在视图函数中使用,通过下面我们看出,logger点会写入到日志文件,不会输出在控制台,app点logger点输出在控制台没有输出在日志文件中

方法三:

有时间验证,可以自己定制一个日志工具类,返回一个日志器对象。然后app配置里面添加一个配置,将日志器对象加进去,看是不是所有蓝图都可以在视图函数中调用,而不需要导入

想多了,如果是这样做不导入是不行的

只要导入了,蓝图下用也是可以的

当我将这里改成app,app点logger就能写入到日志文件中了。不过好像写入了两次。虽然我只调用一次

getLogger我们写入的是app

这是请求test,发现视图函数里面调用一次但是写入了日志两次,控制台未打印。

flask中配置日志思路

我们可以通过yaml方式配置,生成主模块的日志器,然后每个蓝图中定义子日志器,这样打印日志信息是不是就能很容易定位问题呢,是否可以实现呢。有时间研究。是否可以把日志对象存储到某处呢,然后所有蓝图中能够使用?存储到g对象应该是可以的,是否能存储成一个flask app点配置呢,回头研究视图函数中如何获取flask app点配置信息,

python 日志 logging模块详解的更多相关文章

  1. Python的logging模块详解

          Python的logging模块详解 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.日志级别 日志级别指的是产生的日志的事件的严重程度. 设置一个级别后,严重程度 ...

  2. python之OS模块详解

    python之OS模块详解 ^_^,步入第二个模块世界----->OS 常见函数列表 os.sep:取代操作系统特定的路径分隔符 os.name:指示你正在使用的工作平台.比如对于Windows ...

  3. python之sys模块详解

    python之sys模块详解 sys模块功能多,我们这里介绍一些比较实用的功能,相信你会喜欢的,和我一起走进python的模块吧! sys模块的常见函数列表 sys.argv: 实现从程序外部向程序传 ...

  4. python中threading模块详解(一)

    python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...

  5. Python中time模块详解

    Python中time模块详解 在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. ...

  6. python logging模块详解[转]

    一.简单将日志打印到屏幕: import logging logging.debug('debug message') logging.info('info message') logging.war ...

  7. Python logging模块详解

    简单将日志打印到屏幕: import logging logging.debug('debug message') logging.info('info message') logging.warni ...

  8. Python自学笔记-logging模块详解

    简单将日志打印到屏幕: import logging logging.debug('debug message') logging.info('info message') logging.warni ...

  9. [转载]Python logging模块详解

    原文地址: http://blog.csdn.net/zyz511919766/article/details/25136485 简单将日志打印到屏幕: import logging logging. ...

  10. python中常用模块详解二

    log模块的讲解 Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适: logger提供了应用程序可以直接使用的接口API: handler将(logger创建的 ...

随机推荐

  1. unknow or unsupported command install

    错误原因: 今天使用pip下载labelimg时,出现了"unknow or unsupported command install"的错误,这是由于电脑有多个pip文件路径所导致 ...

  2. DS-Net:可落地的动态网络,实际加速1.62倍,快改造起来 | CVPR 2021 Oral

    论文提出能够适配硬件加速的动态网络DS-Net,通过提出的double-headed动态门控来实现动态路由.基于论文提出的高性能网络设计和IEB.SGS训练策略,仅用1/2-1/4的计算量就能达到静态 ...

  3. 开始学习web-sql注入

    web内容多且杂,不知道怎么下手开始学,那就先从sql注入开始学吧 目前只在b站上找了一些课程,还有ctfwiki作为参考 链接贴在下面: ctfwiki https://www.bilibili.c ...

  4. PMF源解析技术在大气颗粒物与VOCs研究中的创新应用

    目前,大气颗粒物和臭氧污染成为我国亟待解决的环境问题.颗粒物和臭氧污染不仅对气候和环境有重要影响,而且对人体健康有严重损害.而臭氧的前体物之一为挥发性有机物(VOCs).为了高效.精准地治理区域大气颗 ...

  5. K8S 性能优化 - K8S APIServer 调优

    前言 K8S 性能优化系列文章,本文为第二篇:Kubernetes API Server 性能优化参数最佳实践. 系列文章: <K8S 性能优化 - OS sysctl 调优> 参数一览 ...

  6. 日志分析qsnctfwp

    使用工具:http Logs Viewer 使用 http Logs Viewer 载入 access.log 按照 Status 排序 其中大量 Status 为404的日志不难推断出,这是在进行目 ...

  7. spring boot 学习前提

    前言 总结spring boot的学习前提. 正文 1.spring 程度(可以基本使用,我在学习spring boot的时候,感觉到需要一些spring的基础) 2.maven (这个是包管理,一定 ...

  8. swing 聊天窗体,支持图文模式

    package com.*.test; import java.awt.EventQueue; import java.awt.HeadlessException; import java.awt.T ...

  9. java操作xml超简单的方法

    用dom4j?SAX?no,no,no,光看api和帮助文档就烦,有没有更简单的方法呢?答案是有的. 那就是默默无名的:JAXB jaxb是啥? 摘抄一段度娘百科的介绍: JAXB能够使用Jackso ...

  10. 07cj031,07CJ03-1图集免费下载

    简介 07CJ03-1轻钢龙骨石膏板隔墙.吊顶图集是中国建筑标准设计研究院组织编写的一部针对轻钢龙骨.石膏板材料用于非承重隔墙.室内吊顶装修的装修.建造参考资料,为用户提供专业的建造参考 下载 有需要 ...