在我的应用程序中,我正在使用python.logging
进行日志记录。
现在我想以交互方式控制loglevel,所以我创建了一个组合框,让用户选择“ ERROR ”,“ WARN ”,“ INFO < / em>的”,...
我真的不喜欢的是目前组合框中的值是硬编码的。
相反,Ii希望列出所有“命名”日志级别(例如系统默认值,但也包括通过logging.addLevelName
添加的那些;但不是像 Level 42 那样的假生成日志级别“)
到目前为止,我提出的最好的方法是使用logging._levelNames
字典。
但是,这似乎是一个私人成员,我不知道感觉直接访问它。
所以我的问题是:在Python中列出所有当前定义的“命名”日志级别的正确方法是什么。
答案 0 :(得分:4)
由于您只是阅读价值观,logging._levelNames
看起来是适合我的解决方案。继续使用logging.addLevelName
来设置新值。
答案 1 :(得分:3)
没有特定的功能可以做你想要的,但你拥有logging._levelNames
所需的一切。
例如,查看addLevelName
定义:
def addLevelName(level, levelName):
"""
Associate 'levelName' with 'level'.
This is used when converting levels to text during message formatting.
"""
_acquireLock()
try: #unlikely to cause an exception, but you never know...
_levelNames[level] = levelName
_levelNames[levelName] = level
finally:
_releaseLock()
所以getLevelNames()
可以像这样实现:
import logging
def getLevelNames():
for k, v in sorted(logging._levelNames.iteritems()):
if isinstance(v, basestring):
yield v, k
import pprint
pprint.pprint(list(getLevelNames()))
示例输出:
[('NOTSET', 0),
('DEBUG', 10),
('INFO', 20),
('WARNING', 30),
('ERROR', 40),
('CRITICAL', 50)]
答案 2 :(得分:0)
在编写接受命令行上日志级别名称的程序的帮助字符串时,我遇到了同样的问题。由于_levelNames
是在Python 3.4中重命名为_levelToName
的私有成员,因此不能/不应该使用,我提出了这个解决方案(简化为SO):
print "Levelnames: {}".format(", ".join(
logging.getLevelName(x)
for x in xrange(1, 101)
if not logging.getLevelName(x).startswith('Level')))
或者,对于Python 3.x:
print("Levelnames: {}".format(", ".join(
logging.getLevelName(x)
for x in range(1, 101)
if not logging.getLevelName(x).startswith('Level'))))
它并不完全漂亮,但它似乎可以在所有Python版本中移植,并且它按升序打印出关卡名称:
Levelnames: DEBUG, INFO, WARNING, ERROR, CRITICAL
答案 3 :(得分:0)
这样的事情怎么样?注意Python 3.4产生的字典与Python 2略有不同,但如果需要,您可以修改函数或结果字典以解决该问题。
import logging
import copy
def get_logging_level_names():
#! find logging's internal dictionary for level names.
#! the internal dict name changed in python 3.4.
try:
level_names = logging._levelToName
except AttributeError:
level_names = logging._levelNames
#! return a copy to prevent modification logging's local dict.
return copy.copy(level_names)
level_names = get_logging_level_names()
print('level_names = {!r}'.format(level_names))
答案 4 :(得分:0)
实际上,这可能比我以前的答案更好。它返回一个排序的级别名称列表。如果您愿意,可以修改以返回字典对{val:name}或{name:val}的排序列表(按值)。
import logging
def get_logging_level_names():
#! find logging's internal dictionary for level names.
#! the internal dict name changed in python 3.4.
try:
level_to_name = logging._levelToName
level_vals = level_to_name.keys()
except AttributeError:
level_to_name = logging._levelNames
level_vals = [ key for key in level_to_name.keys() if isinstance(key,int) ]
level_vals = sorted(level_vals)
level_names = [ level_to_name[val] for val in level_vals ]
return level_names
level_names = get_logging_level_names()
print('level_names = {!r}'.format(level_names))
答案 5 :(得分:0)
我也很沮丧,该模块没有为此提供公开的attr或方法。这是一个简洁的解决方案,适用于Python 2和3:
CFGetRetainCount()
细分:模块名称(import logging
LOG_LEVEL_NAMES = [logging.getLevelName(v) for v in
sorted(getattr(logging, '_levelToName', None)
or logging._levelNames)
if getattr(v, "real", 0)]
)没有改变,因此我们可以通过使用logging
避免try/except
ImportError
围绕getattr(logging, '_levelToName', None)
获得py2 / 3兼容性Python 3的值,如果可能的话。
在Python 2中,我们得到logging._levelNames
,它略有不同 - 它同时包含int-&gt; string和string-&gt; int映射,因此我使用getattr(v, "real", 0)
来确保过滤器处理所有字符串值都为0.我们也以这种方式抛出logging.NOTSET
。
然后我们对值进行排序并映射logging.getLevelName
以返回有序的名称列表。