启用详细日志记录的更简单方法


Answers:


87

您需要将Argparse教程的智慧与Python的Logging HOWTO结合起来。这是一个例子

> cat verbose.py 
#!/usr/bin/env python

import argparse
import logging

parser = argparse.ArgumentParser(
    description='A test script for http://stackoverflow.com/q/14097061/78845'
)
parser.add_argument("-v", "--verbose", help="increase output verbosity",
                    action="store_true")

args = parser.parse_args()
if args.verbose:
    logging.basicConfig(level=logging.DEBUG)

logging.debug('Only shown in debug mode')

运行帮助:

> ./verbose.py -h
usage: verbose.py [-h] [-v]

A test script for http://stackoverflow.com/q/14097061/78845

optional arguments:
  -h, --help     show this help message and exit
  -v, --verbose  increase output verbosity

在详细模式下运行:

> ./verbose.py -v
DEBUG:root:Only shown in debug mode

静默运行:

> ./verbose.py   
> 

1
//,我可以确认这可行。但是,“ store_true”的工作方式仍然是个谜。
— 弥敦道(Nathan Basanese)2015年

122

我发现--verbose(对于用户)和--debug(对于开发人员)都很有用。这是我使用logging和的方式argparse:

import argparse
import logging

parser = argparse.ArgumentParser()
parser.add_argument(
    '-d', '--debug',
    help="Print lots of debugging statements",
    action="store_const", dest="loglevel", const=logging.DEBUG,
    default=logging.WARNING,
)
parser.add_argument(
    '-v', '--verbose',
    help="Be verbose",
    action="store_const", dest="loglevel", const=logging.INFO,
)
args = parser.parse_args()    
logging.basicConfig(level=args.loglevel)

因此,如果--debug设置为,则日志记录级别设置为DEBUG。如果是--verbose,则日志记录设置为INFO。如果两者都不是,则缺少--debug设置会将日志记录级别设置为默认值WARNING。


11
我真的很喜欢这种方法...让argparse完成所有工作,if在parse_args之后不做任何事情
— MestreLion 2015年

3
@MestreLion:谢谢。对我来说确实很蟒蛇。
— Matthew Leingang 2015年

有一个陷阱:logging在默认情况下打印一切stderr和你真的想你正常的程序输出(一个来自分离--verbose)的DEV-只(从一方--debug)
— 米哈尔斑羚

1
@MichałGóral:听起来不错。我可以logging.basicConfig用来向info()stdout发送消息,也debug()可以向stderr发送消息吗?
— Matthew Leingang '16

2
@MatthewLeingang:为此,您必须使用多个处理程序。这里的例子:stackoverflow.com/a/16066513/1088577
— 米哈尔斑羚

56

这是一种更简洁的方法,它进行边界检查,并将在帮助中列出有效值:

parser = argparse.ArgumentParser(description='This is a demo.')
parser.add_argument("-l", "--log", dest="logLevel", choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], help="Set the logging level")

args = parser.parse_args()
if args.logLevel:
    logging.basicConfig(level=getattr(logging, args.logLevel))

用法:

demo.py --log DEBUG

18
不需要getattr:level=logging.getLevelName(args.logLevel)
— xmedeko '16

13
更妙的是添加default='INFO'到add_argument()以及(default: %(default)s)到帮助文本,然后将其删除if args.logLevel,并随时调用basicConfig()。然后,用户可以知道默认值将始终是什么。
— jfritz42

30

另一个变体是计算a的数量,-v并将其用作a的索引,list实际水平为logging:

import argparse
import logging

parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', action='count', default=0)
args = parser.parse_args()

levels = [logging.WARNING, logging.INFO, logging.DEBUG]
level = levels[min(len(levels)-1,args.verbose)]  # capped to number of levels

logging.basicConfig(level=level,
                    format="%(asctime)s %(levelname)s %(message)s")

logging.debug("a debug message")
logging.info("a info message")
logging.warning("a warning message")

这适用于-vvvv,-vvv,-vv,-v,-v -v,等,如果没有-v则logging.WARNING选择更多,如果-v提供的话,将会给INFO和DEBUG


4
真好!只要记住将脚本运行为即可python script.py -v [other_args]。如果运行python -v script.py(-v在脚本之前),您将从Python解释器本身(而不是脚本)中获得很多调试输出。(答案不是问题,只是对其他读者的警告)。
— logc

好一个!这是最灵活的(多个日志记录级别),干净的(不会污染参数名称空间)和直观的(由其他几个工具使用)解决方案。
— m000

8

您可以在-v标志后显式指定一个级别为整数:

parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbose", const=1, default=0, type=int, nargs="?",
                    help="increase verbosity: 0 = only warnings, 1 = info, 2 = debug. No number means info. Default is no verbosity.")
args = parser.parse_args()

logger = logging.getLogger()
if args.verbose == 0:
    logger.setLevel(logging.WARN) 
elif args.verbose == 1:
    logger.setLevel(logging.INFO) 
elif args.verbose == 2:
    logger.setLevel(logging.DEBUG) 

2

这是让argparse对-v选项进行计数的另一种方法,以将详细程度从默认的WARNING到INFO(-v)到DEBUG(-vv)增加两个级别。这不会映射到由定义的常量,logging而是直接计算值,从而限制了输入:

print( "Verbosity / loglevel:", args.v )
logging.basicConfig( level=10*(3-max(0,min(args.v,3))) )
logging.debug("debug") # 10
logging.info("info") # 20
logging.warning("warning") # 30 - The default level is WARNING, which means that only events of this level and above will be tracked
logging.error("error") # 40
logging.critical("critical") # 50

请注意argparse参数的需要default=0,否则您将得到TypeError: '<' not supported between instances of 'int' and 'NoneType'。或添加args.v or 0上述...
— 手柄

1

如果要为不想(或无法)编辑的脚本启用logging.DEBUG级别,则可以自定义启动:

jcomeau@aspire:~$ python -c "import site; site._script()"
[snip]...
USER_BASE: '/home/jcomeau/.local' (exists)
USER_SITE: '/home/jcomeau/.local/lib/python2.7/site-packages' (exists)
ENABLE_USER_SITE: True
jcomeau@aspire:~$ mkdir -p ~/.local/lib/python2.7/site-packages
jcomeau@aspire:~$ vi ~/.local/lib/python2.7/site-packages/usercustomize.py

输入以下内容:

import os, logging
if os.getenv('DEBUGGING'):
    logging.basicConfig(level = logging.DEBUG)

那么您可以:

jcomeau@aspire:~$ mkdir -p /tmp/some/random/
jcomeau@aspire:~$ echo 'import logging; logging.debug("test")' >> /tmp/some/random/script.py
jcomeau@aspire:~$ DEBUGGING=1 python /tmp/some/random/script.py 
DEBUG:root:test

来自Paul Ollis,网址为http://nedbatchelder.com/blog/201001/running_code_at_python_startup.html


2017-07-18:此后我改用其他方法:

logging.basicConfig(level=logging.DEBUG if __debug__ else logging.INFO)

它的作用是,如果运行时未进行优化(如所示python script.py),则将获得DEBUG级的内容,而如果不进行优化,则python -OO script.py不会。没有设置环境变量。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.