未找到配置了日志记录的库的处理程序
No handler found for library with logging configured
我配置了日志记录,但我好像少了一步。在此示例中,我使用的是肥皂水,但我在使用此日志方法进行任何库日志记录时遇到了这个问题。
这个有效
host-03:~ # python2.7
Python 2.7.7 (default, Aug 27 2014, 16:51:46)
[GCC 4.3.4 [gcc-4_3-branch revision 152973]] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import logging
>>> logging.basicConfig()
>>> from suds.client import Client
>>> logging.getLogger('suds.client').setLevel(logging.DEBUG)
>>> client = Client('https://10.10.10.10:8443/path/to/wsdl?wsdl')
>>> user = 'User'
>>> password = 'pass'
>>> client.service.checkAuthentication(user, password)
DEBUG:suds.client:sending to (https://10.10.10.10:8443/path/to/wsdl)
message:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns3="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns0="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://DefaultNamespace" xmlns:ns2="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Header/>
<ns2:Body>
<ns1:checkAuthentication>
<username xsi:type="ns3:string">User</username>
<password xsi:type="ns3:string">pass</password>
</ns1:checkAuthentication>
</ns2:Body>
</SOAP-ENV:Envelope>
DEBUG:suds.client:headers = {'SOAPAction': '""', 'Content-Type': 'text/xml; charset=utf-8'}
DEBUG:suds.client:HTTP succeeded:
<?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><ns1:checkAuthenticationResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://DefaultNamespace"><checkAuthenticationReturn xsi:type="xsd:boolean">true</checkAuthenticationReturn></ns1:checkAuthenticationResponse></soapenv:Body></soapenv:Envelope>
True
>>>
但是当我像下面这样配置文件和控制台日志记录时,我发送的任何消息(通过使用 logger.debug 等)都按预期工作,但是,来自库的任何日志总是显示 "No handler found"。
from datetime import datetime
import logging
import logging.handlers
import os
class CustomFormatter(logging.Formatter):
"""used for colored terminal logging"""
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
colors = dict(
CRITICAL='[1;9%dm' % RED,
ERROR='[9%dm' % RED,
WARNING='[9%dm' % YELLOW,
INFO='[1;9%dm' % GREEN,
DEBUG='[9%dm' % BLUE,
NOTSET='[%dm' % BLACK, # reset
)
def __init__(self, fmt=None, datefmt=None, color=False):
fmt = fmt if fmt else ('%(asctime)s %(module)-11s %(levelname)-9s '
'%(threadName)-10s %(message)s')
logging.Formatter.__init__(self, fmt, datefmt)
self.color = color
def formatTime(self, record, datefmt=None):
create_time = datetime.fromtimestamp(record.created)
if datefmt:
s = create_time.strftime(datefmt)
else:
t = create_time.strftime("%Y-%m-%d %H:%M:%S")
s = "%s.%03d" % (t, record.msecs)
return s
def format(self, record):
s = super(CustomFormatter, self).format(record)
if self.color:
s = self.colors[record.levelname] + s + self.colors['NOTSET']
return s
# get logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# configure file handler
path_to_log = '/app/logs/app.log'
filehandler = logging.handlers.RotatingFileHandler(path_to_log, backupCount=5)
filehandler.setLevel(logging.DEBUG)
filehandler.setFormatter(CustomFormatter())
if os.path.isfile(path_to_log):
filehandler.doRollover()
# configure stream handler
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
console.setFormatter(CustomFormatter(color=True))
# add handlers to logger
logger.addHandler(filehandler)
logger.addHandler(console)
# configure client
from suds.client import Client
logging.getLogger('suds.client').setLevel(logging.DEBUG)
client = Client('https://10.10.10.10:8443/path/to/wsdl?wsdl')
user = 'User'
password = 'pass'
client.service.checkAuthentication(user, password)
>>> client.service.checkAuthentication(user, password)
No handlers could be found for logger "suds.client"
True
>>>
当我直接调用它们时,日志记录工作正常
>>> logger.debug('some test message')
2015-01-15 09:10:18.523 <stdin> DEBUG MainThread some test message
>>>
host-03:~ # cat /app/logs/app.log
2015-01-15 09:10:18.523 <stdin> DEBUG MainThread some test message
我的日志记录配置中缺少什么导致库找不到我的日志记录处理程序?
所以我确实设法解决了这个问题。不明显的是……当您使用除 basicConfig、文件或字典配置之外的任何类型的日志配置时,现有的记录器将被禁用。如果图书馆使用
logger = logging.getLogger('your app or module')
那就可以了,但是既然都在抢
logger = logging.getLogger(__name__)
然后滚动您自己的记录器会使 lib 没有配置的处理程序。你有几个选择。
将您的库设置为空处理程序(如上面的 post、suds.client)
logging.getLogger('suds.client').addHandler(logging.NullHandler())
但如果您想查看消息,这不是很有用
或者你可以使用 file 或 dictConfig 并指定 disable_existing_loggers=False
尽管如此,我仍然对结果不满意。如果您将默认日志级别设置为调试,您的库将污染您的输出,但如果您将默认设置为警告,这对您自己的日志记录不是很有用。虽然您可以独立设置库,但这可能会有点麻烦。
我最后做的是将级别设置为 DEBUG,但我添加了一个 lib 过滤器,它将任何日志记录从库发送到它自己的文件。然后在 运行 启动我的应用程序实例后,我查看了日志以确定我认为有用的内容,然后将那些认为不必要的级别降低到 WARN。
logging.getLogger('suds.client').setLevel(logging.DEBUG)
logging.getLogger('suds.transport.http').setLevel(logging.WARN)
我最后留下了 lib 过滤器,因为它对我有一些库的详细跟踪很有用,但它对我的标准日志来说太多了。我还添加了一些初始化,以删除应用程序每个实例的所有先前日志。
以下是与我现在使用的类似的片段。
"""some sample log"""
import os
import logging
import logging.config
import logging.handlers
from datetime import datetime
logger = logging.getLogger(__name__)
class CustomFormatter(logging.Formatter):
"""used for colored terminal logging"""
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
colors = dict(
CRITICAL='[1;9%dm' % RED,
ERROR='[9%dm' % RED,
WARNING='[9%dm' % YELLOW,
INFO='[1;9%dm' % GREEN,
DEBUG='[9%dm' % BLUE,
NOTSET='[%dm' % BLACK, # reset
)
def __init__(self, fmt=None, datefmt=None, color=False):
fmt = fmt if fmt else ('%(asctime)s %(module)-11s %(levelname)-9s '
'%(threadName)-10s %(message)s')
logging.Formatter.__init__(self, fmt, datefmt)
self.color = color
def formatTime(self, record, datefmt=None):
create_time = datetime.fromtimestamp(record.created)
if datefmt:
s = create_time.strftime(datefmt)
else:
t = create_time.strftime("%Y-%m-%d %H:%M:%S")
s = "%s.%03d" % (t, record.msecs)
return s
def format(self, record):
s = super(CustomFormatter, self).format(record)
if self.color:
s = self.colors[record.levelname] + s + self.colors['NOTSET']
return s
class LibFilter(logging.Filter):
"""custom filter to send suds logging to a separate file"""
def filter(self, record):
if [x for x in '__main__', __name__.split('.', 1)[0]
if x in record.name]:
return True
else:
create_time = datetime.fromtimestamp(record.created)
t = create_time.strftime("%Y-%m-%d %H:%M:%S")
s = "%s.%03d" % (t, record.msecs)
with open('logs/%s.log' % record.name, 'a') as f:
f.write(s + '\n')
f.write(record.getMessage() + '\n\n')
return False
def setup_logging():
"""use dictConfig to setup logging"""
log_file = 'logs/app.log'
doRollover = os.path.isfile(log_file)
logging.config.dictConfig(
dict(
version=1,
disable_existing_loggers=False,
filters=dict(libfilter={'()': LibFilter}),
formatters=dict(
colorformatter={'()': CustomFormatter, 'color': True},
fileformatter={'()': CustomFormatter}),
handlers=dict(
console={
'class': 'logging.StreamHandler',
'filters': ['libfilter'],
'formatter': 'colorformatter',
'level': 'DEBUG'},
filehandler={
'class': 'logging.handlers.RotatingFileHandler',
'filename': log_file,
'backupCount': 3,
'filters': ['libfilter'],
'formatter': 'fileformatter',
'level': 'DEBUG'}),
root=dict(level='INFO', handlers=['console', 'filehandler'])
)
)
if doRollover:
for handler in logging.getLogger('').handlers:
if getattr(handler, 'doRollover', None):
handler.doRollover()
还有我的测试应用
"""
test logging configuration
"""
import logging
from mod import log
log.setup_logging()
logger = logging.getLogger(__name__)
logger.debug('debug msg')
logger.info('info msg')
logger.warning('warning msg')
logger.error('error msg')
logger.exception('exception msg')
现在我的控制台和文件日志和以前一样,并且对于我所有的库,我都得到了一个单独的文件。我没有实现翻转逻辑,但在我的应用程序中,我删除了应用程序的每个 运行 之前的库日志。
我配置了日志记录,但我好像少了一步。在此示例中,我使用的是肥皂水,但我在使用此日志方法进行任何库日志记录时遇到了这个问题。
这个有效
host-03:~ # python2.7
Python 2.7.7 (default, Aug 27 2014, 16:51:46)
[GCC 4.3.4 [gcc-4_3-branch revision 152973]] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import logging
>>> logging.basicConfig()
>>> from suds.client import Client
>>> logging.getLogger('suds.client').setLevel(logging.DEBUG)
>>> client = Client('https://10.10.10.10:8443/path/to/wsdl?wsdl')
>>> user = 'User'
>>> password = 'pass'
>>> client.service.checkAuthentication(user, password)
DEBUG:suds.client:sending to (https://10.10.10.10:8443/path/to/wsdl)
message:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns3="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns0="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://DefaultNamespace" xmlns:ns2="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Header/>
<ns2:Body>
<ns1:checkAuthentication>
<username xsi:type="ns3:string">User</username>
<password xsi:type="ns3:string">pass</password>
</ns1:checkAuthentication>
</ns2:Body>
</SOAP-ENV:Envelope>
DEBUG:suds.client:headers = {'SOAPAction': '""', 'Content-Type': 'text/xml; charset=utf-8'}
DEBUG:suds.client:HTTP succeeded:
<?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><ns1:checkAuthenticationResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://DefaultNamespace"><checkAuthenticationReturn xsi:type="xsd:boolean">true</checkAuthenticationReturn></ns1:checkAuthenticationResponse></soapenv:Body></soapenv:Envelope>
True
>>>
但是当我像下面这样配置文件和控制台日志记录时,我发送的任何消息(通过使用 logger.debug 等)都按预期工作,但是,来自库的任何日志总是显示 "No handler found"。
from datetime import datetime
import logging
import logging.handlers
import os
class CustomFormatter(logging.Formatter):
"""used for colored terminal logging"""
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
colors = dict(
CRITICAL='[1;9%dm' % RED,
ERROR='[9%dm' % RED,
WARNING='[9%dm' % YELLOW,
INFO='[1;9%dm' % GREEN,
DEBUG='[9%dm' % BLUE,
NOTSET='[%dm' % BLACK, # reset
)
def __init__(self, fmt=None, datefmt=None, color=False):
fmt = fmt if fmt else ('%(asctime)s %(module)-11s %(levelname)-9s '
'%(threadName)-10s %(message)s')
logging.Formatter.__init__(self, fmt, datefmt)
self.color = color
def formatTime(self, record, datefmt=None):
create_time = datetime.fromtimestamp(record.created)
if datefmt:
s = create_time.strftime(datefmt)
else:
t = create_time.strftime("%Y-%m-%d %H:%M:%S")
s = "%s.%03d" % (t, record.msecs)
return s
def format(self, record):
s = super(CustomFormatter, self).format(record)
if self.color:
s = self.colors[record.levelname] + s + self.colors['NOTSET']
return s
# get logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# configure file handler
path_to_log = '/app/logs/app.log'
filehandler = logging.handlers.RotatingFileHandler(path_to_log, backupCount=5)
filehandler.setLevel(logging.DEBUG)
filehandler.setFormatter(CustomFormatter())
if os.path.isfile(path_to_log):
filehandler.doRollover()
# configure stream handler
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
console.setFormatter(CustomFormatter(color=True))
# add handlers to logger
logger.addHandler(filehandler)
logger.addHandler(console)
# configure client
from suds.client import Client
logging.getLogger('suds.client').setLevel(logging.DEBUG)
client = Client('https://10.10.10.10:8443/path/to/wsdl?wsdl')
user = 'User'
password = 'pass'
client.service.checkAuthentication(user, password)
>>> client.service.checkAuthentication(user, password)
No handlers could be found for logger "suds.client"
True
>>>
当我直接调用它们时,日志记录工作正常
>>> logger.debug('some test message')
2015-01-15 09:10:18.523 <stdin> DEBUG MainThread some test message
>>>
host-03:~ # cat /app/logs/app.log
2015-01-15 09:10:18.523 <stdin> DEBUG MainThread some test message
我的日志记录配置中缺少什么导致库找不到我的日志记录处理程序?
所以我确实设法解决了这个问题。不明显的是……当您使用除 basicConfig、文件或字典配置之外的任何类型的日志配置时,现有的记录器将被禁用。如果图书馆使用
logger = logging.getLogger('your app or module')
那就可以了,但是既然都在抢
logger = logging.getLogger(__name__)
然后滚动您自己的记录器会使 lib 没有配置的处理程序。你有几个选择。
将您的库设置为空处理程序(如上面的 post、suds.client)
logging.getLogger('suds.client').addHandler(logging.NullHandler())
但如果您想查看消息,这不是很有用
或者你可以使用 file 或 dictConfig 并指定 disable_existing_loggers=False
尽管如此,我仍然对结果不满意。如果您将默认日志级别设置为调试,您的库将污染您的输出,但如果您将默认设置为警告,这对您自己的日志记录不是很有用。虽然您可以独立设置库,但这可能会有点麻烦。
我最后做的是将级别设置为 DEBUG,但我添加了一个 lib 过滤器,它将任何日志记录从库发送到它自己的文件。然后在 运行 启动我的应用程序实例后,我查看了日志以确定我认为有用的内容,然后将那些认为不必要的级别降低到 WARN。
logging.getLogger('suds.client').setLevel(logging.DEBUG)
logging.getLogger('suds.transport.http').setLevel(logging.WARN)
我最后留下了 lib 过滤器,因为它对我有一些库的详细跟踪很有用,但它对我的标准日志来说太多了。我还添加了一些初始化,以删除应用程序每个实例的所有先前日志。
以下是与我现在使用的类似的片段。
"""some sample log"""
import os
import logging
import logging.config
import logging.handlers
from datetime import datetime
logger = logging.getLogger(__name__)
class CustomFormatter(logging.Formatter):
"""used for colored terminal logging"""
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
colors = dict(
CRITICAL='[1;9%dm' % RED,
ERROR='[9%dm' % RED,
WARNING='[9%dm' % YELLOW,
INFO='[1;9%dm' % GREEN,
DEBUG='[9%dm' % BLUE,
NOTSET='[%dm' % BLACK, # reset
)
def __init__(self, fmt=None, datefmt=None, color=False):
fmt = fmt if fmt else ('%(asctime)s %(module)-11s %(levelname)-9s '
'%(threadName)-10s %(message)s')
logging.Formatter.__init__(self, fmt, datefmt)
self.color = color
def formatTime(self, record, datefmt=None):
create_time = datetime.fromtimestamp(record.created)
if datefmt:
s = create_time.strftime(datefmt)
else:
t = create_time.strftime("%Y-%m-%d %H:%M:%S")
s = "%s.%03d" % (t, record.msecs)
return s
def format(self, record):
s = super(CustomFormatter, self).format(record)
if self.color:
s = self.colors[record.levelname] + s + self.colors['NOTSET']
return s
class LibFilter(logging.Filter):
"""custom filter to send suds logging to a separate file"""
def filter(self, record):
if [x for x in '__main__', __name__.split('.', 1)[0]
if x in record.name]:
return True
else:
create_time = datetime.fromtimestamp(record.created)
t = create_time.strftime("%Y-%m-%d %H:%M:%S")
s = "%s.%03d" % (t, record.msecs)
with open('logs/%s.log' % record.name, 'a') as f:
f.write(s + '\n')
f.write(record.getMessage() + '\n\n')
return False
def setup_logging():
"""use dictConfig to setup logging"""
log_file = 'logs/app.log'
doRollover = os.path.isfile(log_file)
logging.config.dictConfig(
dict(
version=1,
disable_existing_loggers=False,
filters=dict(libfilter={'()': LibFilter}),
formatters=dict(
colorformatter={'()': CustomFormatter, 'color': True},
fileformatter={'()': CustomFormatter}),
handlers=dict(
console={
'class': 'logging.StreamHandler',
'filters': ['libfilter'],
'formatter': 'colorformatter',
'level': 'DEBUG'},
filehandler={
'class': 'logging.handlers.RotatingFileHandler',
'filename': log_file,
'backupCount': 3,
'filters': ['libfilter'],
'formatter': 'fileformatter',
'level': 'DEBUG'}),
root=dict(level='INFO', handlers=['console', 'filehandler'])
)
)
if doRollover:
for handler in logging.getLogger('').handlers:
if getattr(handler, 'doRollover', None):
handler.doRollover()
还有我的测试应用
"""
test logging configuration
"""
import logging
from mod import log
log.setup_logging()
logger = logging.getLogger(__name__)
logger.debug('debug msg')
logger.info('info msg')
logger.warning('warning msg')
logger.error('error msg')
logger.exception('exception msg')
现在我的控制台和文件日志和以前一样,并且对于我所有的库,我都得到了一个单独的文件。我没有实现翻转逻辑,但在我的应用程序中,我删除了应用程序的每个 运行 之前的库日志。