質問

So I want to add logging to a little internal command line utility that I've been maintaining. (Actually I'm converting it's rather ugly manually coded logging to use Python's logging module; and cleaning up some warts along the way).

First, I want to preserve the existing behavior, warts and all, for legacy usage. Any scripts which might be depending on the extraneous warnings that it already emits should not break as a result of what I'm doing. The new functionality should be through -v switches, implemented in OptionParser as a type=count (as per ancient Unix/Linux convention). The wrinkle here is that a single -v sets the verbosity from -1 to 0 (zero) ... ironically squelching at least one warning message from the Paramiko libraries (No handlers could be found for logger "paramiko.transport"). From there I want to support up to four additional -v options and use those with logging.setLevel() to be progressively more verbose, from logging.CRITICAL only down to logging.DEBUG.

There's the rub!

I can easily use something like:

if opts.verbosity == 0: # default is -1 do NOTHING
    # 0 ironically makes it slightly quieter
    logging.getLogger().addHandler(logging.NullHandler())
elif opts.verbosity > 0:
    logging.basicConfig()
    logging.getLogger().setLevel(50 - min(40, 10*opts.verbosity))
    # UGLY BUT IT WORKS.
    # logging.CRITICAL is 50, 
    # each -v reduces log filter by 10 down to 10

In other words I'm converting my count of -v switches into a multiple of ten and subtracting that from the least verbose down towards the most verbose. (This is Python2.7.x by the way).

I've noticed that logging.basicConfig() does away with the "No handles found" warning, and exposes some underlying error messages which have been (harmlessly) occurring for as long as this utility has been in production (years). (So, if I'd started with the default at 0, as one would expect, then I'd've introduced alarming noise to the users.

But my question is: is there a more "proper" way to translate from a numeric verbosity setting into a logging.setLevel()? It seems dirty to use this implementation detail (the numeric values associated with logging.CRITICAL, logging.ERROR, logging.WARN,... etc).

Surely I can't be the only one using -vvv with Python's standard OptionParser and logging modules. But reading the docs and Googling around didn't find any sort of "best practices" on this.

役に立ちましたか?

解決

Cleaner, at least:

level = {
    1: logging.ERROR,
    2: logging.WARNING,
    3: logging.INFO,
    4: logging.DEBUG
}.get(opts.verbosity, logging.DEBUG)

(I'd suggest converting from optparse to argparse too.)

他のヒント

(yay reviving old posts)

I've recently wanted something like this as well but I didn't want to use a dict. Here's my implementation:

def logging_level(verbosity):
    """ Converts a verbosity number to a logging level

    Args:
        verbosity - a number, possibly collected from ``argparse``'s ``count``
        action. If ``verbosity`` is out of the range of possible logging levels
        it will be normalized to the nearest level. Does not take into
        consideration custom levels.
    """
    levels = [
        logging.CRITICAL,
        logging.ERROR,
        logging.WARNING,
        logging.INFO,
        logging.DEBUG
    ]

    return levels[max(min(len(levels) - 1, verbosity), 0)]
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top