日志配置 – 通用操作系统服务(Python教程)(参考资料)
logging.config
– 记录配置
源代码: Lib / logging / config.py
本节介绍用于配置记录模块的API .
配置功能
以下功能配置日志记录模块。它们位于logging.config
模块。它们的使用是可选的 – 您可以使用这些函数或通过调用主API来配置日志模块(在中定义)logging
本身)和定义在logging
或logging.handlers
.
logging.config.
dictConfig
(config)中声明的处理程序-
从字典中获取日志记录配置。这本词典的内容在配置字典模式下面
//如果在配置过程中遇到错误,这个函数会输出
ValueError
,TypeError
,AttributeError
或ImportError
用适当的描述性消息。以下是一个(可能不完整的)条件列表,它会引发错误:- A
level
这不是一个字符串,或者是一个与实际日志记录级别无关的字符串. - 一个
propagate
不是boolean的值 - 一个没有的字符相应的目的地.
- 在增量调用期间找到一个不存在的处理程序ID
- 一个无效的记录器名称.
- 无法解析内部或外部对象.
解析由
DictConfigurator
class,其构造函数传递给用于配置的字典,并且有一个configure()
方法。logging.config
模块有一个可调用的属性dictConfigClass
,最初设置为DictConfigurator
你可以用你自己的实施来取代dictConfigClass
的值.dictConfig()
调用dictConfigClass
传递指定的字典,然后调用configure()
返回对象的方法使配置生效:def dictConfig(config): dictConfigClass(config).configure()
例如,
DictConfigurator
的子类可以自己调用DictConfigurator.__init__()
__init__()
,然后设置可在随后的configure()
调用中使用的自定义前缀。dictConfigClass
将绑定到这个新的子类,然后dictConfig()
可以被称为默认的,未定制的状态.版本3.2.
- A
logging.config.
fileConfig
(fname, defaults=None, disable_existing_loggers=True)- 从读取日志配置
configparser
-format文件。文件格式应如配置文件格式。该功能可以从应用程序中多次调用,允许用户从各种预先配置的配置中进行选择(如果开发人员提供了一种机制来呈现选择并加载所选择的配置).参数: - fname – 文件名,类文件对象,或
RawConfigParser
派生的实例。如果传递RawConfigParser
– 派生的实例,则使用asis。否则,Configparser
是实例化的,并且它从对象中读取的配置在fname
中传递。如果它有readline()
方法,则假定它是一个类文件对象并使用read_file()
;否则,它被假定为文件名并传递给read()
. - 默认值 – 可以在此参数中指定要传递给ConfigParser的默认值.
- disable_existing_loggers – 如果指定为
False
,则进行此调用时的记录器是leftenabled。默认值为True
,因为这样可以避免兼容的旧行为。这种行为可以解决任何现有的非根记录器unlessthey或它们的祖先在日志记录配置中被明确命名的情况.
在版本3.4中更改:
RawConfigParser
的子类的实例isnow接受为fname
的值。这有利于:- 使用配置文件,其中日志配置只是整个应用程序配置的一部分.
- 使用从文件读取的配置,然后通过usingapplication修改(例如,基于命令行参数或运行时环境的其他方面)在传递给
fileConfig
.
- fname – 文件名,类文件对象,或
logging.config.
listen
(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None)- 在指定端口上启动套接字服务器,并侦听新配置。如果没有指定端口,则模块默认为
DEFAULT_LOGGING_CONFIG_PORT
用来。记录配置将作为适合由dictConfig()
或fileConfig()
处理的文件发送。返回一个Thread
实例,你可以调用start()
启动服务器,你可以join()
在适当的时候。要停止服务器,请拨打stopListening()
.verify
如果指定的话,参数应该是一个可调用的,它应该验证在套接字上接收的字节是否有效并且应该被处理。这可以通过加密和/或签署在套接字上发送的内容来完成,这样verify
可调用的可以执行签名验证和/或解密。verify
使用单个参数调用callable – 在套接字上接收的字节 – 并且应该返回要处理的字节,或None
表示应该丢弃字节。返回的字节可以与传入的字节相同(例如,仅进行验证时),或者它们可能完全不同(可能是在执行解密时).要将配置发送到套接字,请读入配置文件并将其作为一个字节序列发送到套接字,前面是一个四字节的长度字符串,使用
struct.pack(">L", n)
.二进制打包注意
因为部分配置是通过
eval()
传递的,所以使用这个函数可能会使用户面临安全风险。虽然该函数只能绑定到localhost
,因此不接受来自远程计算机的连接,有些情况下,可以在调用listen()
的进程帐户下运行不受信任的代码。具体来说,如果进程调用listen()
在用户不能互相信任的多用户机器上运行,那么好心的用户可以安排在avictim用户的进程中运行基本上任意的代码,只需连接到受害者的listen()
套接字并发送一个配置,该配置运行攻击者想要在受害者进程中执行的任何代码。如果使用默认端口,这尤其容易,但即使使用了不同的端口也不容易)。为避免发生这种情况的风险,请使用verify
对listen()
防止应用无法识别的配置.版本3.4更改:
verify
争论被添加了注意
如果要将配置发送到不能禁用现有记录器的侦听器,则需要使用配置的JSON格式,这将使用
dictConfig()
配置。这个方法允许你在你发送的配置中指定disable_existing_loggers
为False
.
logging.config.
stopListening
()- 停止通过调用
listen()
。这通常是在调用join()
之前调用来自listen()
.
的返回值//配置字典模式
描述日志记录配置需要列出要创建的各个对象以及它们之间的连接;例如,你可以创建一个名为’console’的处理程序,然后说loggernamed’startup’会将它的消息发送到’console’处理程序。这些对象不仅限于logging
模块提供的对象,因为您可以编写自己的格式化程序或处理程序类。这些类的参数可能还需要包含外部对象,例如sys.stderr
。描述这些对象和连接的语法在对象连接下面定义.
Dictionary Schema Details
字典传递给dictConfig()
必须包含以下键:
- version – 设置为表示schemaversion的整数值。目前唯一有效的值是1,但是这样可以保持模式的发展,同时仍然保持向后兼容性.
所有其他键都是可选的,但如果存在,它们将被解释如下所述。在下面提到“配置字典”的所有情况下,将检查特殊的"()"
键以查看是否需要自定义实例化。如果是这样,中描述的用户定义对象中描述的机制用于创建实例;否则,上下文用于确定要实例化的内容.
-
formatters -相应的值将是一个dict,其中每个键是一个格式化程序ID,每个值都是一个描述如何配置相应的
Formatter
实例的字典搜索配置字典的密钥
format
和datefmt
(默认值为None
)这些用于构造Formatter
instance. -
filters – 相应的值将是一个dict in其中每个键都是一个过滤器ID,每个值都是一个描述如何配置相应过滤器实例的字典.
在配置字典中搜索密钥
name
(默认为空字符串)这用于构造logging.Filter
instance. -
handlers – 相应的值将是一个dict,其中每个键是一个处理程序ID,每个值是一个描述如何的字典配置相应的Handler实例.
在配置字典中搜索以下键:
class
(强制)。这是处理程序类的完全限定名称.level
(可选)。handler.formatter
(可选)的级别。thishandler的格式化程序的idfilters
//(可选)。thishandler的过滤器的id列表
所有other键作为关键字参数传递给handler的构造函数。例如,给定片段:
handlers: console: class : logging.StreamHandler formatter: brief level : INFO filters: [allow_foo] stream : ext://sys.stdout file: class : logging.handlers.RotatingFileHandler formatter: precise filename: logconfig.log maxBytes: 1024 backupCount: 3
将id
console
的处理程序实例化为logging.StreamHandler
,使用sys.stdout
作为基础流。idfile
的处理程序用关键字argumentslogging.handlers.RotatingFileHandler
实例化为filename="logconfig.log", maxBytes=1024, backupCount=3
. -
loggers– 相应的值将是一个dict,其中每个键是一个记录器名称,每个值都是一个描述如何配置相应的Logger实例的字典.
在配置字典中搜索以下键:
level
(可选的)。记录器的级别.propagate
(可选)。记录器的传播设置.filters
(可选)。thislogger.handlers
(可选)的过滤器ID列表。thislogger的处理程序ID列表
指定的记录器将根据指定的级别,传播,过滤器和处理程序配置.
-
root – 这将是根记录器的配置。配置的处理将与任何记录器一样,但
propagate
设置将不适用. -
incremental – 配置是否被解释为对现有配置的增量。此值默认为
False
,这意味着指定的配置将使用与现有fileConfig()
API.如果指定的值为
True
,则按增量配置. -
disable_existing_loggers一节中的描述处理配置 – 是否存在任何非root用户记录器被禁用。此设置镜像
fileConfig()
中相同名称的参数。如果不存在,则此参数默认为True
。如果incremental是True
.
,则忽略此值。增量配置
很难为增量配置提供完全的灵活性。例如,因为诸如filters和formatter之类的对象是匿名的,所以一旦设置了配置,在扩充配置时就不可能引用这样的匿名对象.
此外,一旦配置完成,就没有令人信服的案例来随意改变记录器,处理程序,过滤器,格式化程序的对象图。记录器和处理程序的详细程度可以通过设置级别来控制(在记录器的情况下,传播标志)。在多线程环境中以安全的方式任意改变对象图是有问题的;虽然不可能,但实际上增加的复杂性并不值得实现.
因此,当配置字典的incremental
键存在且是True
时,系统将完全忽略任何formatters
和filters
条目,只处理level
条目中的handlers
设置,以及level
和propagate
loggers
和root
条目中的设置
使用配置dict中的值可以将配置作为pickled dicts发送到线程侦听器。因此,长时间运行的应用程序的loggingverbosity可以随着时间的推移而改变,无需停止和重新启动应用程序.
对象连接
该模式描述了一组日志对象 – 记录器,处理程序,格式化程序,过滤器 – 它们在对象图中相互连接。因此,模式需要表示对象之间的连接。例如,假设一旦配置,特定记录器就会附加一个特定的处理程序。对于本讨论的目的,我们可以说记录器代表两者之间连接的源和目标处理程序。当然,在配置的对象中,这由持有对处理程序的引用的记录器表示。在配置dict中,这是通过为每个目标对象提供一个明确标识的id来完成的,然后使用源对象配置中的id来指示源和具有该id的目标对象之间存在连接。
所以,例如,考虑下面的YAML片段:
formatters:
brief:
# configuration for formatter with id 'brief' goes here
precise:
# configuration for formatter with id 'precise' goes here
handlers:
h1: #This is an id
# configuration of handler with id 'h1' goes here
formatter: brief
h2: #This is another id
# configuration of handler with id 'h2' goes here
formatter: precise
loggers:
foo.bar.baz:
# other configuration for logger 'foo.bar.baz'
handlers: [h1, h2]
(注意:YAML在这里使用是因为它比字典的等效Python源表单更具可读性。)
记录器的ID是以编程方式用于获取对这些记录器的引用的记录器名称,例如foo.bar.baz
。格式化程序和过滤器的ID可以是任何字符串值(例如brief
, precise
以上),它们是瞬态的,因为它们仅对处理配置字典有意义并用于确定对象之间的连接,并且不会在任何地方持久存在配置调用完成.
上面的代码片段表示名为foo.bar.baz
的记录器应该附加两个处理程序,由处理程序h1
和h2
描述。h1
的格式化程序是由id brief
描述的,h2
的格式化程序是由id precise
.
描述的用户定义的对象
该模式支持处理程序,过滤器和格式程序的用户定义对象。(对于不同的实例,记录器不需要具有不同的类型,因此在此配置文件中不支持用户定义的记录器类。)
要配置的对象由字典描述,详细说明了它们的配置。在某些地方,日志记录系统将能够从上下文推断出如何实例化对象,但是当要实例化用户定义的对象时,系统将不知道如何执行此操作。为了为用户定义的对象实例化提供完全灵活性,用户需要提供一个’工厂’ – 一个可调用的,使用配置字典调用并返回实例化的对象。这是通过工厂提供的绝对导入路径来表示的。特殊键"()"
。这是一个具体的例子:
formatters:
brief:
format: '%(message)s'
default:
format: '%(asctime)s %(levelname)-8s %(name)-15s %(message)s'
datefmt: '%Y-%m-%d %H:%M:%S'
custom:
(): my.package.customFormatterFactory
bar: baz
spam: 99.9
answer: 42
上面的YAML片段定义了三个格式化程序。第一个,id brief
,是一个标准logging.Formatter
带有指定格式字符串的实例。第二个,id为default
,具有更长的格式,并且还明确定义了时间格式,并且将在logging.Formatter
中用这两个格式字符串初始化。以//源代码形式显示,brief
和default
格式化程序分别具有配置子字典:
{
"format" : "%(message)s"
}
和:
{
'format' : '%(asctime)s %(levelname)-8s %(name)-15s %(message)s',
'datefmt' : '%Y-%m-%d %H:%M:%S'
}
,因为这些字典不包含特殊键"()"
,从上下文推断实例化:结果,创建了标准的logging.Formatter
实例。第三个格式化程序的配置子字典,id custom
,是:
{
'()' : 'my.package.customFormatterFactory',
'bar' : 'baz',
'spam' : 99.9,
'answer' : 42
}
,它包含特殊键"()"
,这意味着需要用户定义的实例化。在这种情况下,将使用specifiedfactory callable。如果它是一个实际的可调用它将直接使用 – 否则,如果你指定一个字符串(如在例子中),实际的可调用将使用正常的导入机制定位。可调用将调用剩余配置子字典中的项目作为关键字参数。在上面的示例中,将假定id custom
的格式化程序被调用返回:
my.package.customFormatterFactory(bar="baz", spam=99.9, answer=42)
键"()"
已被用作特殊键,因为它不是avalid关键字参数名称,因此不会与调用中使用的关键字参数的名称冲突。"()"
也可以作为助记符,相应的值是可调用的.
访问外部对象
有时候配置需要引用objectsexternal到配置,例如 sys.stderr
。如果配置dict是使用Python代码构造的,那么这是直截了当的,但是当通过文本文件(例如JSON,YAML)提供配置时会出现问题。在文本文件中,没有标准的方法来区分sys.stderr
和文字字符串"sys.stderr"
。为了便于区分,配置系统在字符串值中查找某些特殊前缀并特别对其进行处理。例如,如果文字字符串"ext://sys.stderr"
在配置中作为值提供,然后ext://
将被剥离,并且使用正常的导入机制处理剩余的值.
这种前缀的处理方式是以类似于协议处理的方式完成的:有一种通用机制来查找与正则表达式匹配的前缀^(?P<prefix>[a-z]+)://(?P<suffix>.*)$
,其中,如果prefix
是公认的,suffix
以前缀相关的方式处理,处理结果替换字符串值。如果无法识别前缀,则字符串值将保留为–is.
访问内部对象
除了外部对象之外,有时还需要在配置中引用对象。这将由配置系统隐式地完成它所知道的事情。例如,字符串值"DEBUG"
为一个 level
在记录器或处理程序中,willautomatically将转换为值logging.DEBUG
,并且handlers
, filters
和formatter
条目将采用对象ID并解析为适当的目标对象.
但是,对于logging
模块不知道的用户定义对象,需要更通用的机制。例如,考虑logging.handlers.MemoryHandler
,这需要target
参数,这是另一个委托给它的处理程序。由于系统已经知道了这个类,所以在配置中,给定的target
只需要是相关目标处理程序的对象id,系统将从theid解析为处理程序。但是,如果用户定义my.package.MyHandler
其中有alternate
处理程序,配置系统将不知道alternate
引用了一个处理程序。为了满足这个需要,一个通用的分辨率系统允许用户指定:
handlers:
file:
# configuration of file handler goes here
custom:
(): my.package.MyHandler
alternate: cfg://handlers.file
文字字符串"cfg://handlers.file"
将以无条件的方式解析为ext://
前缀,但查找配置本身而不是导入命名空间。机制允许通过点或索引访问,以类似于str.format
提供的方式。因此,给定以下片段:
handlers:
email:
class: logging.handlers.SMTPHandler
mailhost: localhost
fromaddr: [email protected]
toaddrs:
- [email protected]
- [email protected]
subject: Houston, we have a problem.
在配置中,字符串"cfg://handlers"
将使用键handlers
解析为dict,字符串"cfg://handlers.email
将解析为在email
dict中用键handlers
敲词,依此类推。字符串"cfg://handlers.email.toaddrs[1]
将解析为"dev_team.domain.tld"
并且字符串"cfg://handlers.email.toaddrs[0]"
将解析为值"[email protected]"
。使用subject
或等同于"cfg://handlers.email.subject"
可以访问"cfg://handlers.email[subject]"
值。如果密钥包含空格或非字母数字字符,则只需要使用后一种形式。如果anindex值只包含十进制数字,则会尝试使用相应的整数值进行访问,如果需要则返回stringvalue .
给一个字符串cfg://handlers.myhandler.mykey.123
,这将解析为config_dict["handlers"]["myhandler"]["mykey"]["123"]
。如果字符串指定为cfg://handlers.myhandler.mykey[123]
,系统将尝试从config_dict["handlers"]["myhandler"]["mykey"][123]
中检索值,然后返回到config_dict["handlers"]["myhandler"]["mykey"]["123"]
iffails.
导入解析和自定义导入程序
默认情况下,导入解析使用内置的__import__()
函数进行导入。您可能希望用您自己的importmechanism替换它:如果是这样,您可以替换importer
或其超类DictConfigurator
类的BaseConfigurator
属性。但是,由于从类viadescriptors访问函数的方式,您需要考虑因素。如果您使用Python可调用来执行导入,并且您希望在类级别而不是实例级别定义它,则需要使用staticmethod()
进行换行。例如:
from importlib import import_module
from logging.config import BaseConfigurator
BaseConfigurator.importer = staticmethod(import_module)
如果在配置程序中设置importcallable,则不需要用staticmethod()
包装instance.
配置文件格式
配置fileConfig()
理解的文件格式基于configparser
功能。该文件必须包含名为[loggers]
, [handlers]
和[formatters]
它按名称标识文件中定义的每种类型的实体。对于每个这样的实体,都有一个单独的部分,用于标识该实体的配置方式。因此,fora记录器名为log01
在[loggers]
部分,相关的配置细节保存在[logger_log01]
部分。同样地,在hand01
部分中调用[handlers]
的ahandler将其配置保存在一个名为[handler_hand01]
,在form01
部分中调用[formatters]
的格式化程序将在名为[formatter_form01]
的部分中指定其配置。必须在名为[logger_root]
.
的部分中指定根记录器配置
fileConfig()
API比旧dictConfig()
API并不提供涵盖日志记录某些方面的功能。例如,您无法配置Filter
使用fileConfig()
提供超出简单整数级别的消息过滤的对象。如果在日志配置中需要Filter
的实例,则需要使用dictConfig()
。请注意,配置功能的未来增强功能将添加到dictConfig()
,因此在方便的时候考虑转换到这个新的API是值得的.
下面给出了文件中这些部分的示例.
[loggers]
keys=root,log02,log03,log04,log05,log06,log07
[handlers]
keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09
[formatters]
keys=form01,form02,form03,form04,form05,form06,form07,form08,form09
根记录器必须指定级别和处理程序列表。下面给出了aroot记录器部分的一个例子.
[logger_root]
level=NOTSET
handlers=hand01
level
输入可以是DEBUG, INFO, WARNING, ERROR, CRITICAL
或NOTSET
之一。仅对于根记录器,NOTSET
表示所有消息都会被警告。在eval()
包的命名空间logging
//
的上下文中,级别值是handlers
entry是以逗号分隔的处理程序名称列表,必须出现在[handlers]
部分中。这些名称必须出现在[handlers]
部分,并在配置文件中有相应的部分.
[logger_parser]
level=DEBUG
handlers=hand01
propagate=1
qualname=compiler.parser
level
和handlers
条目被解释为根记录器,除非非root记录器的级别指定为NOTSET
,systemconsults记录器在层次结构的较高位置确定记录器的有效级别。propagate
entry设置为1表示消息必须传播到记录器层次结构中较高的处理程序,或0表示消息是不是传播到层次结构中的处理程序。qualname
条目是记录器的分层通道名称,它是应用程序用来获取记录器的名称.
指定处理程序配置的部分如下所示.
[handler_hand01]
class=StreamHandler
level=NOTSET
formatter=form01
args=(sys.stdout,)
class
条目表示处理程序的类(由eval()
包的命名空间中的logging
确定)。level
被解释为forloggers,而NOTSET
被认为是’记录所有内容’.
formatter
条目表示此处理程序的格式化程序的键名。如果为空,则为默认格式化程序(logging._defaultFormatter
使用。如果指定了名称,它必须出现在[formatters]
部分并且在配置文件中有相应的部分.
args
条目,当eval()
在logging
包的命名空间的上下文中,是处理程序类的构造函数的参数列表。请参阅相关处理程序的构造函数或下面的示例,以了解如何构造典型条目。如果没有提供,则默认为()
.
可选的kwargs
条目,当eval()
包的命名空间的上下文中logging
时,是关键字参数dict to处理程序类的构造函数。如果未提供,则默认为{}
.
[handler_hand02]
class=FileHandler
level=DEBUG
formatter=form02
args=('python.log', 'w')
[handler_hand03]
class=handlers.SocketHandler
level=INFO
formatter=form03
args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)
[handler_hand04]
class=handlers.DatagramHandler
level=WARN
formatter=form04
args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)
[handler_hand05]
class=handlers.SysLogHandler
level=ERROR
formatter=form05
args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)
[handler_hand06]
class=handlers.NTEventLogHandler
level=CRITICAL
formatter=form06
args=('Python Application', '', 'Application')
[handler_hand07]
class=handlers.SMTPHandler
level=WARN
formatter=form07
args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')
kwargs={'timeout': 10.0}
[handler_hand08]
class=handlers.MemoryHandler
level=NOTSET
formatter=form08
target=
args=(10, ERROR)
[handler_hand09]
class=handlers.HTTPHandler
level=NOTSET
formatter=form09
args=('localhost:9022', '/log', 'GET')
kwargs={'secure': True}
指定格式化程序配置的部分以下列为代表.
[formatter_form01]
format=F1 %(asctime)s %(levelname)s %(message)s
datefmt=
class=logging.Formatter
format
条目是整体格式字符串,并且datefmt
条目是strftime()
– 兼容的日期/时间格式字符串。如果为空,则包替换一些几乎相当于指定dateformat字符串的东西"%Y-%m-%d %H:%M:%S"
。此格式还指定使用逗号分隔符附加到使用上述格式字符串的结果的毫秒数。这种格式的示例时间是2003-01-23 00:29:50,411
.
class
条目是可选的。它表示格式化程序类的名称(作为虚线模块和类名。)此选项对于实例化Formatter
子类。 的子类Formatter
可以以扩展或压缩格式呈现异常回溯.
注意
由于使用eval()
如上所述,使用listen()
通过套接字发送和接收配置。风险仅限于没有相互信任的多个用户在同一台机器上运行代码;有关详细信息,请参阅listen()
文档.
评论被关闭。