获取命名日志级别的列表

时间:2013-09-17 09:25:12

标签: python logging

在我的应用程序中,我正在使用python.logging进行日志记录。

现在我想以交互方式控制loglevel,所以我创建了一个组合框,让用户选择“ ERROR ”,“ WARN ”,“ INFO < / em>的”,...

我真的不喜欢的是目前组合框中的值是硬编码的。 相反,Ii希望列出所有“命名”日志级别(例如系统默认值,但也包括通过logging.addLevelName添加的那些;但不是像 Level 42 那样的假生成日志级别“)

到目前为止,我提出的最好的方法是使用logging._levelNames字典。

但是,这似乎是一个私人成员,我不知道感觉直接访问它。

所以我的问题是:在Python中列出所有当前定义的“命名”日志级别的正确方法是什么。

6 个答案:

答案 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以返回有序的名称列表。