Python loggers/handlers 配置错误?
Python loggers/handlers misconfigured?
虽然我已经使用 python/ipython 工作了一段时间,但我认为自己是新手。还有很多东西,特别是关于日志记录支持,我想我从文档中理解了,但显然比我以前希望的更难配置。我正在使用 ipython 5.5.0 / python 2.7.17 on Xubuntu 18.04.04 LTS
和 colorlogs。我的日志记录配置模块如下。
import coloredlogs
import datetime
import logging
import logging.config
import os
import yaml
def setup_logging( default_path='../Config/logging.yaml',
default_level=logging.DEBUG,
env_key='LOG_CFG'):
path = os.path.join(os.path.dirname(os.path.realpath(__file__)), default_path)
value = os.getenv(env_key, None)
# If the envvar is set, use it's value
if value:
path = value
_dt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print("%s Using Logging Configuration: %s" % (_dt, path) )
#
# If the configuration file path is there, read it
#
if os.path.exists(path):
with open(path, 'rt') as f:
try:
config = yaml.safe_load(f.read())
logging.config.dictConfig(config)
coloredlogs.install(level=default_level)
except Exception as err:
print(err)
print('Error in Logging Configuration. Using default configs')
logging.basicConfig(level=default_level)
coloredlogs.install(level=default_level)
# Otherwise, continue without a configuration
else:
logging.basicConfig(level=logging.DEBUG)
coloredlogs.install(level=logging.DEBUG)
print('Failed to load configuration file. Using default configs')
配置保存在具有以下定义的 yaml 文件中。
version: 1
disable_existing_loggers: False
formatters:
basic:
format: "%(name)s - %(message)s"
standard:
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
error:
format: "%(levelname)s <PID %(process)d:%(processName)s> %(name)s.%(funcName)s(): %(message)s"
handlers:
console_basic:
class: logging.StreamHandler
level: DEBUG
formatter: basic
stream: ext://sys.stdout
console_out:
class: logging.StreamHandler
level: DEBUG
formatter: standard
stream: ext://sys.stdout
console_err:
class: logging.StreamHandler
level: DEBUG
formatter: standard
stream: ext://sys.stderr
debug_file_handler:
class: logging.handlers.RotatingFileHandler
level: DEBUG
formatter: standard
filename: /tmp/debug.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
info_file_handler:
class: logging.handlers.RotatingFileHandler
level: INFO
formatter: standard
filename: /tmp/info.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
warn_file_handler:
class: logging.handlers.RotatingFileHandler
level: WARN
formatter: standard
filename: /tmp/warn.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
error_file_handler:
class: logging.handlers.RotatingFileHandler
level: ERROR
formatter: error
filename: /tmp/errors.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
critical_file_handler:
class: logging.handlers.RotatingFileHandler
level: CRITICAL
formatter: standard
filename: /tmp/critical.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
root:
level: CRITICAL
handlers: [console_err]
propogate: no
loggers:
test:
level: DEBUG
handlers: [console_basic]
propogate: no
Utils.paragraph_processing:
level: DEBUG
handlers: [info_file_handler, debug_file_handler, warn_file_handler, error_file_handler, critical_file_handler]
propogate: no
Utils.graphing_functions:
level: DEBUG
handlers: [info_file_handler, debug_file_handler, warn_file_handler, error_file_handler, critical_file_handler]
propogate: no
下面是我的 test.py 模块的片段。
import coloredlogs
from copy import deepcopy
import cv2
import imutils
import logging
import logging.config
import os
import yaml
import matplotlib.pyplot as PLT
import matplotlib.image as MPI
import numpy as np
import Tests.filtering_tests as FT
import Tests.morphology_tests as MT
import Utils.global_defs as GL
import Utils.graphing_functions as GF
import Utils.paragraph_processing as PP
import Utils.logging_functions as LF
.
.
.
def phony_main():
LF.setup_logging()
# create logger
LOG = logging.getLogger(__name__)
LOG.critical("Logging Started...")
# -----------------------------------------------------------------------------
#
# Main
#
img = None
if __name__ == "__main__":
# execute only if run as a script
phony_main()
我的问题是,当我将配置从 [console_out] 更改为 [console_basic] 时,我希望消息符合要求,但事实并非如此。让我相信其他记录器 root(?) 正在处理调用?但是,如果我将其更改为使用 [console_basic],消息仍然相同。也就是说,人们会期望时间和级别名称不再存在,但它们存在!
同样,我并不假装理解发生了什么,但我认为文档显示简单继承的地方我开始怀疑它比那更复杂一点。 我做错了什么?
当我修复拼写错误并删除记录器进行测试时,我仍然遇到相同的行为。打开传播以便控制台日志将到达根记录器,[console_basic] 仍然使用旧格式显示消息。
对我的 yaml 进行以下更改似乎解决了问题,正如@blues 所指出的。
root:
level: NOTSET
handlers: [console_basic]
propagate: no
loggers:
__main__:
level: DEBUG
handlers: [console_basic]
propagate: no
Utils.paragraph_processing:
level: DEBUG
handlers: [info_file_handler, debug_file_handler, warn_file_handler, error_file_handler, critical_file_handler]
propagate: no
Utils.graphing_functions:
level: DEBUG
handlers: [info_file_handler, debug_file_handler, warn_file_handler, error_file_handler, critical_file_handler]
propagate: no
这里发生了两件事。首先,配置中存在 propagate
的拼写错误。它拼错了 propogate:注意 "o" 应该是 "a"。这意味着所有记录器实际上都将他们的日志传播到层次结构中。
第二件事是,当传播打开时,祖先记录器的级别(在本例中为根记录器)将被忽略,只考虑处理程序的级别。由于添加到根的 console_err
处理程序具有级别 DEBUG
并且所有日志传播到根,因此该处理程序将记录每个日志。
相关信息可在 python 文档中找到 here:
Messages are passed directly to the ancestor loggers’ handlers -
neither the level nor filters of the ancestor loggers in question are
considered.
虽然我已经使用 python/ipython 工作了一段时间,但我认为自己是新手。还有很多东西,特别是关于日志记录支持,我想我从文档中理解了,但显然比我以前希望的更难配置。我正在使用 ipython 5.5.0 / python 2.7.17 on Xubuntu 18.04.04 LTS
和 colorlogs。我的日志记录配置模块如下。
import coloredlogs
import datetime
import logging
import logging.config
import os
import yaml
def setup_logging( default_path='../Config/logging.yaml',
default_level=logging.DEBUG,
env_key='LOG_CFG'):
path = os.path.join(os.path.dirname(os.path.realpath(__file__)), default_path)
value = os.getenv(env_key, None)
# If the envvar is set, use it's value
if value:
path = value
_dt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print("%s Using Logging Configuration: %s" % (_dt, path) )
#
# If the configuration file path is there, read it
#
if os.path.exists(path):
with open(path, 'rt') as f:
try:
config = yaml.safe_load(f.read())
logging.config.dictConfig(config)
coloredlogs.install(level=default_level)
except Exception as err:
print(err)
print('Error in Logging Configuration. Using default configs')
logging.basicConfig(level=default_level)
coloredlogs.install(level=default_level)
# Otherwise, continue without a configuration
else:
logging.basicConfig(level=logging.DEBUG)
coloredlogs.install(level=logging.DEBUG)
print('Failed to load configuration file. Using default configs')
配置保存在具有以下定义的 yaml 文件中。
version: 1
disable_existing_loggers: False
formatters:
basic:
format: "%(name)s - %(message)s"
standard:
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
error:
format: "%(levelname)s <PID %(process)d:%(processName)s> %(name)s.%(funcName)s(): %(message)s"
handlers:
console_basic:
class: logging.StreamHandler
level: DEBUG
formatter: basic
stream: ext://sys.stdout
console_out:
class: logging.StreamHandler
level: DEBUG
formatter: standard
stream: ext://sys.stdout
console_err:
class: logging.StreamHandler
level: DEBUG
formatter: standard
stream: ext://sys.stderr
debug_file_handler:
class: logging.handlers.RotatingFileHandler
level: DEBUG
formatter: standard
filename: /tmp/debug.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
info_file_handler:
class: logging.handlers.RotatingFileHandler
level: INFO
formatter: standard
filename: /tmp/info.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
warn_file_handler:
class: logging.handlers.RotatingFileHandler
level: WARN
formatter: standard
filename: /tmp/warn.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
error_file_handler:
class: logging.handlers.RotatingFileHandler
level: ERROR
formatter: error
filename: /tmp/errors.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
critical_file_handler:
class: logging.handlers.RotatingFileHandler
level: CRITICAL
formatter: standard
filename: /tmp/critical.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
root:
level: CRITICAL
handlers: [console_err]
propogate: no
loggers:
test:
level: DEBUG
handlers: [console_basic]
propogate: no
Utils.paragraph_processing:
level: DEBUG
handlers: [info_file_handler, debug_file_handler, warn_file_handler, error_file_handler, critical_file_handler]
propogate: no
Utils.graphing_functions:
level: DEBUG
handlers: [info_file_handler, debug_file_handler, warn_file_handler, error_file_handler, critical_file_handler]
propogate: no
下面是我的 test.py 模块的片段。
import coloredlogs
from copy import deepcopy
import cv2
import imutils
import logging
import logging.config
import os
import yaml
import matplotlib.pyplot as PLT
import matplotlib.image as MPI
import numpy as np
import Tests.filtering_tests as FT
import Tests.morphology_tests as MT
import Utils.global_defs as GL
import Utils.graphing_functions as GF
import Utils.paragraph_processing as PP
import Utils.logging_functions as LF
.
.
.
def phony_main():
LF.setup_logging()
# create logger
LOG = logging.getLogger(__name__)
LOG.critical("Logging Started...")
# -----------------------------------------------------------------------------
#
# Main
#
img = None
if __name__ == "__main__":
# execute only if run as a script
phony_main()
我的问题是,当我将配置从 [console_out] 更改为 [console_basic] 时,我希望消息符合要求,但事实并非如此。让我相信其他记录器 root(?) 正在处理调用?但是,如果我将其更改为使用 [console_basic],消息仍然相同。也就是说,人们会期望时间和级别名称不再存在,但它们存在!
同样,我并不假装理解发生了什么,但我认为文档显示简单继承的地方我开始怀疑它比那更复杂一点。 我做错了什么?
当我修复拼写错误并删除记录器进行测试时,我仍然遇到相同的行为。打开传播以便控制台日志将到达根记录器,[console_basic] 仍然使用旧格式显示消息。
对我的 yaml 进行以下更改似乎解决了问题,正如@blues 所指出的。
root:
level: NOTSET
handlers: [console_basic]
propagate: no
loggers:
__main__:
level: DEBUG
handlers: [console_basic]
propagate: no
Utils.paragraph_processing:
level: DEBUG
handlers: [info_file_handler, debug_file_handler, warn_file_handler, error_file_handler, critical_file_handler]
propagate: no
Utils.graphing_functions:
level: DEBUG
handlers: [info_file_handler, debug_file_handler, warn_file_handler, error_file_handler, critical_file_handler]
propagate: no
这里发生了两件事。首先,配置中存在 propagate
的拼写错误。它拼错了 propogate:注意 "o" 应该是 "a"。这意味着所有记录器实际上都将他们的日志传播到层次结构中。
第二件事是,当传播打开时,祖先记录器的级别(在本例中为根记录器)将被忽略,只考虑处理程序的级别。由于添加到根的 console_err
处理程序具有级别 DEBUG
并且所有日志传播到根,因此该处理程序将记录每个日志。
相关信息可在 python 文档中找到 here:
Messages are passed directly to the ancestor loggers’ handlers - neither the level nor filters of the ancestor loggers in question are considered.