- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详解Python logging调用Logger.info方法的处理过程由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
本次分析一下logger.info的流程 。
1. logger.info源码
1
2
3
4
5
6
7
8
9
10
11
|
def
info(
self
, msg,
*
args,
*
*
kwargs):
"""
log 'msg % args' with severity 'info'.
to pass exception information, use the keyword argument exc_info with
a true value, e.g.
logger.info("houston, we have a %s", "interesting problem", exc_info=1)
"""
if
self
.isenabledfor(info):
self
._log(info, msg, args,
*
*
kwargs)
|
注释中反应了可以通过 msg和不定参数args来进行日志的格式化。 真实的调用为:_log方法:
2. logger._log方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
def
_log(
self
, level, msg, args, exc_info
=
none, extra
=
none, stack_info
=
false):
"""
low-level logging routine which creates a logrecord and then calls
all the handlers of this logger to handle the record.
"""
sinfo
=
none
if
_srcfile:
#ironpython doesn't track python frames, so findcaller raises an
#exception on some versions of ironpython. we trap it here so that
#ironpython can use logging.
try
:
fn, lno, func, sinfo
=
self
.findcaller(stack_info)
except
valueerror:
# pragma: no cover
fn, lno, func
=
"(unknown file)"
,
0
,
"(unknown function)"
else
:
# pragma: no cover
fn, lno, func
=
"(unknown file)"
,
0
,
"(unknown function)"
if
exc_info:
if
isinstance
(exc_info, baseexception):
exc_info
=
(
type
(exc_info), exc_info, exc_info.__traceback__)
elif
not
isinstance
(exc_info,
tuple
):
exc_info
=
sys.exc_info()
record
=
self
.makerecord(
self
.name, level, fn, lno, msg, args,
exc_info, func, extra, sinfo)
self
.handle(record)
|
最后两行:
生成日志记录:
1
|
record
=
self
.makerecord(
self
.name, level, fn, lno, msg, args, exc_info, func, extra, sinfo)
|
处理日志记录 。
1
|
self
.handle(record)
|
2 生成日志记录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
def
makerecord(
self
, name, level, fn, lno, msg, args, exc_info,
func
=
none, extra
=
none, sinfo
=
none):
"""
a factory method which can be overridden in subclasses to create
specialized logrecords.
"""
rv
=
_logrecordfactory(name, level, fn, lno, msg, args, exc_info, func,
sinfo)
if
extra
is
not
none:
for
key
in
extra:
if
(key
in
[
"message"
,
"asctime"
])
or
(key
in
rv.__dict__):
raise
keyerror(
"attempt to overwrite %r in logrecord"
%
key)
rv.__dict__[key]
=
extra[key]
return
rv
|
调用_logrecordfactory初始化一个日志记录实例,_logrecordfactory 其实就是logrecord类,初始化时,可能包含logger的name, level、调用的函数、行号、日志字符串、模板参数、堆栈信息等.
再看extra信息,extra到底有何用?现在从代码中可以看到,只是更新到生成的日志记录实例的__dict__中去.猜测:肯定会在生成最终的日志字符串的时候会用到。继续往下看.
3 处理日志记录self.handle(record)
logger继承自filterer.
1
2
3
4
5
6
7
8
9
|
def
handle(
self
, record):
"""
call the handlers for the specified record.
this method is used for unpickled records received from a socket, as
well as those created locally. logger-level filtering is applied.
"""
if
(
not
self
.disabled)
and
self
.
filter
(record):
self
.callhandlers(record)
|
3.1 if语句中有一self.filter(record)的判断,看函数名,是来筛选是否要继续处理消息的,其核心源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
def
filter
(
self
, record):
"""
determine if a record is loggable by consulting all the filters.
the default is to allow the record to be logged; any filter can veto
this and the record is then dropped. returns a zero value if a record
is to be dropped, else non-zero.
.. versionchanged:: 3.2
allow filters to be just callables.
"""
rv
=
true
for
f
in
self
.filters:
if
hasattr
(f,
'filter'
):
result
=
f.
filter
(record)
else
:
result
=
f(record)
# assume callable - will raise if not
if
not
result:
rv
=
false
break
return
rv
|
可以看到, 如果在handler中的filter中如果有返回为false或空,则会屏蔽对应的record,返回true或部位空的值,则会将record放行。那么我们就可以自定义自己的filter.
3.2 让logger中所有的handles去处理record
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
28
29
|
def
callhandlers(
self
, record):
"""
pass a record to all relevant handlers.
loop through all handlers for this logger and its parents in the
logger hierarchy. if no handler was found, output a one-off error
message to sys.stderr. stop searching up the hierarchy whenever a
logger with the "propagate" attribute set to zero is found - that
will be the last logger whose handlers are called.
"""
c
=
self
found
=
0
while
c:
for
hdlr
in
c.handlers:
found
=
found
+
1
if
record.levelno >
=
hdlr.level:
hdlr.handle(record)
if
not
c.propagate:
c
=
none
#break out
else
:
c
=
c.parent
if
(found
=
=
0
):
if
lastresort:
if
record.levelno >
=
lastresort.level:
lastresort.handle(record)
elif
raiseexceptions
and
not
self
.manager.emittednohandlerwarning:
sys.stderr.write(
"no handlers could be found for logger"
" \"%s\"\n"
%
self
.name)
self
.manager.emittednohandlerwarning
=
true
|
代码中会去循环调用当前logger的所有handlers去处理record,for循环部分,之后,如果当前的logger的propagate的值为false或空,则不向logger的父logger传递,即向上传递.
4. handler 中的 handler(record) 部分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
def
handle(
self
, record):
"""
conditionally emit the specified logging record.
emission depends on filters which may have been added to the handler.
wrap the actual emission of the record with acquisition/release of
the i/o thread lock. returns whether the filter passed the record for
emission.
"""
rv
=
self
.
filter
(record)
if
rv:
self
.acquire()
try
:
self
.emit(record)
finally
:
self
.release()
return
rv
|
可以看到, handler在处理record时, 会去加锁,然后调用self.emit(record)方法去处理.
4.1 emit(record) 。
1
2
3
4
5
6
7
8
9
|
def
emit(
self
, record):
"""
do whatever it takes to actually log the specified logging record.
this version is intended to be implemented by subclasses and so
raises a notimplementederror.
"""
raise
notimplementederror(
'emit must be implemented '
'by handler subclasses'
)
|
看到需要由子类去实现,以streamhandler为例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
def
emit(
self
, record):
"""
emit a record.
if a formatter is specified, it is used to format the record.
the record is then written to the stream with a trailing newline. if
exception information is present, it is formatted using
traceback.print_exception and appended to the stream. if the stream
has an 'encoding' attribute, it is used to determine how to do the
output to the stream.
"""
try
:
msg
=
self
.
format
(record)
stream
=
self
.stream
stream.write(msg)
stream.write(
self
.terminator)
self
.flush()
except
exception:
self
.handleerror(record)
|
4.2 handler.format(record)
1
2
3
4
5
6
7
8
9
10
11
12
|
def
format
(
self
, record):
"""
format the specified record.
if a formatter is set, use it. otherwise, use the default formatter
for the module.
"""
if
self
.formatter:
fmt
=
self
.formatter
else
:
fmt
=
_defaultformatter
return
fmt.
format
(record)
|
如果handler有自定义的formatter就用自定义的,如果没有则用默认的formatter的实例, 初始化元源码为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
def
__init__(
self
, fmt
=
none, datefmt
=
none, style
=
'%'
):
"""
initialize the formatter with specified format strings.
initialize the formatter either with the specified format string, or a
default as described above. allow for specialized date formatting with
the optional datefmt argument (if omitted, you get the iso8601 format).
use a style parameter of '%', '{' or '$' to specify that you want to
use one of %-formatting, :meth:`str.format` (``{}``) formatting or
:class:`string.template` formatting in your format string.
.. versionchanged:: 3.2
added the ``style`` parameter.
"""
if
style
not
in
_styles:
raise
valueerror(
'style must be one of: %s'
%
','
.join(
_styles.keys()))
self
._style
=
_styles[style][
0
](fmt)
self
._fmt
=
self
._style._fmt
self
.datefmt
=
datefmt
|
有三个参数:
style有三种:
1
2
3
4
|
_styles
=
{
'%'
: (percentstyle, basic_format),
'{'
: (strformatstyle,
'{levelname}:{name}:{message}'
),
'$'
: (stringtemplatestyle,
'${levelname}:${name}:${message}'
),
|
可以看出对应到:% 操作符的格式化, format方法的格式化以及template的格式化.
formatter的format方法源码为:
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
28
29
|
def
format
(
self
, record):
"""
format the specified record as text.
the record's attribute dictionary is used as the operand to a
string formatting operation which yields the returned string.
before formatting the dictionary, a couple of preparatory steps
are carried out. the message attribute of the record is computed
using logrecord.getmessage(). if the formatting string uses the
time (as determined by a call to usestime(), formattime() is
called to format the event time. if there is exception information,
it is formatted using formatexception() and appended to the message.
"""
record.message
=
record.getmessage()
if
self
.usestime():
record.asctime
=
self
.formattime(record,
self
.datefmt)
s
=
self
.formatmessage(record)
if
record.exc_info:
# cache the traceback text to avoid converting it multiple times
# (it's constant anyway)
if
not
record.exc_text:
record.exc_text
=
self
.formatexception(record.exc_info)
if
record.exc_text:
if
s[
-
1
:] !
=
"\n"
:
s
=
s
+
"\n"
s
=
s
+
record.exc_text
if
record.stack_info:
if
s[
-
1
:] !
=
"\n"
:
s
=
s
+
"\n"
s
=
s
+
self
.formatstack(record.stack_info)
|
看到会调用record.getmessage(),这里仅仅是获取我们需要的日志信息.
之后会调用s = self.formatmessage(record)
1
2
|
def
formatmessage(
self
, record):
return
self
._style.
format
(record)
|
其实是调用了当前style的format方法,以%这一类型为例percentstyle:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class
percentstyle(
object
):
default_format
=
'%(message)s'
asctime_format
=
'%(asctime)s'
asctime_search
=
'%(asctime)'
def
__init__(
self
, fmt):
self
._fmt
=
fmt
or
self
.default_format
def
usestime(
self
):
return
self
._fmt.find(
self
.asctime_search) >
=
0
def
format
(
self
, record):
return
self
._fmt
%
record.__dict__
|
从其中的format方法可以看出,是针对record的__dict__属性中的所有参数进行格式化,这下,就清楚了之前的extra参数是干嘛用的了:可以在formatter中加入自己自定义的一些参数,如固定的用户信息等等.
之后,将最终的message flush到对应的stream里面去就行了,就是整个流程
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:https://segmentfault.com/a/1190000018119406 。
最后此篇关于详解Python logging调用Logger.info方法的处理过程的文章就讲到这里了,如果你想了解更多关于详解Python logging调用Logger.info方法的处理过程的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
为了让我的代码几乎完全用 Jquery 编写,我想用 Jquery 重写 AJAX 调用。 这是从网页到 Tomcat servlet 的调用。 我目前情况的类似代码: var http = new
我想使用 JNI 从 Java 调用 C 函数。在 C 函数中,我想创建一个 JVM 并调用一些 Java 对象。当我尝试创建 JVM 时,JNI_CreateJavaVM 返回 -1。 所以,我想知
环顾四周,我发现从 HTML 调用 Javascript 函数的最佳方法是将函数本身放在 HTML 中,而不是外部 Javascript 文件。所以我一直在网上四处寻找,找到了一些简短的教程,我可以根
我有这个组件: import {Component} from 'angular2/core'; import {UserServices} from '../services/UserService
我正在尝试用 C 实现一个简单的 OpenSSL 客户端/服务器模型,并且对 BIO_* 调用的使用感到好奇,与原始 SSL_* 调用相比,它允许一些不错的功能。 我对此比较陌生,所以我可能会完全错误
我正在处理有关异步调用的难题: 一个 JQuery 函数在用户点击时执行,然后调用一个 php 文件来检查用户输入是否与数据库中已有的信息重叠。如果是这样,则应提示用户确认是否要继续或取消,如果他单击
我有以下类(class)。 public Task { public static Task getInstance(String taskName) { return new
嘿,我正在构建一个小游戏,我正在通过制作一个数字 vector 来创建关卡,该数字 vector 通过枚举与 1-4 种颜色相关联。问题是循环(在 Simon::loadChallenge 中)我将颜
我有一个java spring boot api(数据接收器),客户端调用它来保存一些数据。一旦我完成了数据的持久化,我想进行另一个 api 调用(应该处理持久化的数据 - 数据聚合器),它应该自行异
首先,这涉及桌面应用程序而不是 ASP .Net 应用程序。 我已经为我的项目添加了一个 Web 引用,并构建了各种数据对象,例如 PayerInfo、Address 和 CreditCard。但问题
我如何告诉 FAKE 编译 .fs文件使用 fsc ? 解释如何传递参数的奖励积分,如 -a和 -target:dll . 编辑:我应该澄清一下,我正在尝试在没有 MSBuild/xbuild/.sl
我使用下划线模板配置了一个简单的主干模型和 View 。两个单独的 API 使用完全相同的配置。 API 1 按预期工作。 要重现该问题,请注释掉 API 1 的 URL,并取消注释 API 2 的
我不确定什么是更好的做法或更现实的做法。我希望从头开始创建目录系统,但不确定最佳方法是什么。 我想我在需要显示信息时使用对象,例如 info.php?id=100。有这样的代码用于显示 Game.cl
from datetime import timedelta class A: def __abs__(self): return -self class B1(A):
我在操作此生命游戏示例代码中的数组时遇到问题。 情况: “生命游戏”是约翰·康威发明的一种细胞自动化技术。它由一个细胞网格组成,这些细胞可以根据数学规则生存/死亡/繁殖。该网格中的活细胞和死细胞通过
如果我像这样调用 read() 来读取文件: unsigned char buf[512]; memset(buf, 0, sizeof(unsigned char) * 512); int fd;
我用 C 编写了一个简单的服务器,并希望调用它的功能与调用其他 C 守护程序的功能相同(例如使用 ./ftpd start 调用它并使用 ./ftpd stop 关闭该实例)。显然我遇到的问题是我不知
在 dos 中,当我粘贴此命令时它会起作用: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://google.
在 dos 中,当我粘贴此命令时它会起作用: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://google.
我希望能够从 cmd 在我的 Windows 10 计算机上调用 python3。 我已重新安装 Python3.7 以确保选择“添加到路径”选项,但仍无法调用 python3 并使 CMD 启动 P
我是一名优秀的程序员,十分优秀!