42

Python logging levels can be registered using logging.addLevelName. Is there a method to obtain the Python logging number from a level name?

1
  • 4
    Just to make sure: You did notice that the documentation on this function says "Defining your own levels is possible, but should not be necessary, as the existing levels have been chosen on the basis of practical experience. However, if you are convinced that you need custom levels, great care should be exercised when doing this…" Commented Aug 23, 2013 at 0:23

3 Answers 3

56

After you call addLevelName, the resulting level is treated exactly the same as all of the standard ones:

>>> import logging
>>> logging.getLevelName(10)
'DEBUG'
>>> logging.getLevelName('DEBUG')
10
>>> logging.addLevelName(15, 'DEBUGGISH')
>>> logging.getLevelName(15)
'DEBUGGISH'
>>> logging.getLevelName('DEBUGGISH')
15

The fact that getLevelName can map names to numbers as well as numbers to names is not actually documented in Python 2.x, nor does the name give any hint that it should… but a quick look at the source shows why it works.

Sign up to request clarification or add additional context in comments.

10 Comments

Looks documented to me. "If a numeric value corresponding to one of the defined levels is passed in, the corresponding string representation is returned."
@user2357112: It's the other way around that isn't documented, where you pass in a string and get back the corresponding number.
It would be nice if the logging module officially exported a table of names. [k for k in logging._levelNames if isinstance(k, basestring)] works, but, bleh. :-)
@torek: I think it would be cleaner if it kept separate dicts for names-for-numbers and numbers-to-names, and had a getLevelNumber(name) function alongside the getLevelName(number) function. IIRC, the clever hack that motivated this single-dict design in the pre-stdlib module isn't even there anymore.
Update: the current / 3.6 documentation notes: In Python versions earlier than 3.4, this function could also be passed a text level, and would return the corresponding numeric value of the level. This undocumented behaviour was considered a mistake, and was removed in Python 3.4, but reinstated in 3.4.2 due to retain backward compatibility.
|
0

If you can deal with a default level, checking the type of the result is a decent workaround.

int_level = logging.getLevelName(string_level)
  if type(int_level) != int:
    int_level = 20 # default to INFO

Comments

0

Surprisingly late, since Python 3.11 you can and maybe should start using: logging.getLevelNamesMapping

import logging
assert logging.INFO == logging.getLevelNamesMapping()["INFO"]

logging.addLevelName(logging.INFO + 5, "IMPORTANT")
assert logging.INFO + 5 == logging.getLevelNamesMapping()["IMPORTANT"]

Why, >maybe< should.

  • The double mapping of getLevelName was a (nice?) mistake back in Python 2. Shortly removed in 3.4.0..1. pyright therefore also reports the getLevelName("some_string") usage as deprecated. So you end up with warnings if you use it (reportDeprecated option active), but also the opinion of pyright.
  • Semantically it is not intuitive, why should getLevelName return an integer? The new function is more intuitive, but slightly more expensive as it copies the underlying dict.
  • logging.getLevelNamesMapping()["invalid"] will raise a KeyError if input a wrong level name, with getLevelName("invalid") -> "Level invalid". Of course that is both an advantage and disadvantage at the same time.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.