Python argparse errors to file

2019-08-06 02:51发布

I am trying to make a script that takes all errors and logs them to a log file. I want to include any argparse errors to this file. I already use the logging package and a sys.excepthook to drive unexpected exceptions to the log file.

Here's an example code:

import argparse
import logging
import sys
import traceback

def log_uncaught_exceptions(ex_cls, ex, tb):
    logging.critical(''.join(traceback.format_tb(tb)))
    logging.critical('{0}: {1}'.format(ex_cls, ex))

logging.basicConfig(
    level=logging.DEBUG,
    filename='foo.log',
    filemode='w',
    format='%(asctime)s - %(levelname)s - %(message)s')

sys.excepthook = log_uncaught_exceptions

logging.debug('This is a typical debug line')

parser = argparse.ArgumentParser(description='Foo String')
parser.add_argument('foo',type=int)
args = parser.parse_args()
logging.debug('Input was %i'%(args.foo))

When I run it with python logger_argparse.py 1 everything works great. If I run python logger_argparse.py a I get the output in the console and not the log file:

usage: logger_argparse.py [-h] foo
logger_argparse.py: error: argument foo: invalid int value: 'a'

How do I get that information to go to the log file?

2条回答
仙女界的扛把子
2楼-- · 2019-08-06 03:16

I found a workaround that I don't believe is very good. But it seems to be working:

import argparse
import logging
import sys
import traceback

class argparse_logger(argparse.ArgumentParser):
    def _print_message(self, message, file=None):
        if file is sys.stderr:
            logger.error('Arg Parse did something bad...see below:')
            logger.error(message)
        else:
            super()._print_message(message,file=file)

def log_uncaught_exceptions(ex_cls, ex, tb):
    logging.critical(''.join(traceback.format_tb(tb)))
    logging.critical('{0}: {1}'.format(ex_cls, ex))

logging.basicConfig(
    level=logging.DEBUG,
    filename='foo.log',
    filemode='w',
    format='%(asctime)s - %(levelname)s - %(message)s')

# logging.getLogger('root')
logger = logging.getLogger('root')

sys.excepthook = log_uncaught_exceptions

logger.debug('This is a typical debug line')

parser = argparse_logger(description='Foo String')
parser.add_argument('foo',type=int)
args = parser.parse_args()
logger.debug('Input was %i'%(args.foo))
查看更多
淡お忘
3楼-- · 2019-08-06 03:19

Can you use logging.exception in an exception handler? Edit: so how about just logging from ArgumentParser.error()?

import sys
import logging
import argparse

class argparse_logger(argparse.ArgumentParser):
    def error(self, message):
        logging.error(message)
        super().error(message)

logging.basicConfig(
    level=logging.DEBUG,
    filename='foo.log',
    filemode='w',
    format='%(asctime)s - %(levelname)s - %(message)s')

# parser = argparse.ArgumentParser(description="Foo")
parser = argparse_logger(description="Foo")
parser.add_argument('foo',type=int)
logging.debug("Start")

try:
    args = parser.parse_args(sys.argv[1:])
except:
    print("Error handling arguments")
    raise
logging.debug(f"Finish - {args.foo}")
print(f"Exiting! - {args.foo}")

This will show the following:

J:\>python arg_parse_log.py 5
Exiting! - 5

J:\>more foo.log
2018-02-07 11:34:45,647 - DEBUG - Start
2018-02-07 11:34:45,648 - DEBUG - Finish - 5

J:\>python arg_parse_log.py
usage: arg_parse_log.py [-h] foo
arg_parse_log.py: error: the following arguments are required: foo
Error handling arguments

J:\>more foo.log
2018-02-07 11:34:54,577 - DEBUG - Start
2018-02-07 11:34:54,578 - ERROR - the following arguments are required: foo
查看更多
登录 后发表回答