考虑一个python模块包含多个函数的情况。每个函数都需要id
。
def f1(id):
log into file f1/{id}.txt
def f2(id):
log into file f2/{id}.txt
假设传递给每个函数的id始终是唯一的。就像1传递给f1
一样,1再次请求f1
。与其他功能相同。
我希望每个功能的记录而不是模块。这样每个函数都会记录到像function_name / id.txt
这样的唯一文件中因此在执行该函数后,无需打开function_name / id.txt进行日志记录,因为下一个请求将包含不同的id。因此,在执行函数后应该关闭该文件的文件处理程序
如何在python中实现每个模块的日志记录,以便每个模块都能正确捕获所有异常?
我正在尝试这种方法:
def setup_logger( name, log_file, level=logging.DEBUG ):
handler = logging.FileHandler(log_file)
handler.setFormatter(logging.Formatter('[%(asctime)s][%(levelname)s]%(message)s'))
logger = logging.getLogger(name)
logger.setLevel(level)
logger.addHandler(handler)
return logger
def f1(id):
logger = setup_logger('f1_id_logger', f'f1/{id}.txt', level=logging.DEBUG)
def f2(id):
logger = setup_logger('f2_id_logger', f'f2/{id}.txt', level=logging.DEBUG)
但我担心的是:
答案 0 :(得分:2)
这是使用装饰器的一个很好的例子。
import logging
from os import mkdir
from os.path import exists
from sys import exc_info # for retrieving the exception
from traceback import format_exception # for formatting the exception
def id_logger_setup(level=logging.DEBUG):
def setup_logger(func):
if not exists(func.__name__): # makes the directory if it doesn't exist
mkdir(func.__name__)
logger = logging.getLogger("{}_id_logger".format(func.__name__))
logger.setLevel(level)
def _setup_logger(id, *args, **kwargs):
handler = logging.FileHandler("{}/{}.txt".format(func.__name__, id)) # a unique handler for each id
handler.setFormatter(logging.Formatter("[%(asctime)s][%(levelname)s]%(message)s"))
logger.addHandler(handler)
try:
rtn = func(id, logger=logger, *args, **kwargs)
except Exception: # if the function breaks, catch the exception and log it
logger.critical("".join(format_exception(*exc_info())))
rtn = None
finally:
logger.removeHandler(handler) # remove ties between the logger and the soon-to-be-closed handler
handler.close() # closes the file handler
return rtn
return _setup_logger
return setup_logger
@id_logger_setup(level=logging.DEBUG) # set the level
def f1(id, *, logger):
logger.debug("In f1 with id {}".format(id))
@id_logger_setup(level=logging.DEBUG)
def f2(id, *, logger):
logger.debug("In f2 with id {}".format(id))
@id_logger_setup(level=logging.DEBUG)
def f3(id, *, logger):
logger.debug("In f3 with id {}".format(id))
logger.debug("Something's going wrong soon...")
int('opps') # raises an error
f1(1234)
f2(5678)
f1(4321)
f2(8765)
f3(345774)
从代码示例中,您可以获得以下内容:
f1 -
|
1234.txt
4321.txt
f2 -
|
5678.txt
8765.txt
f3 -
|
345774.txt
前四个txt文件中的位置如下所示:
[2018-04-26 18:49:29,209][DEBUG]In f1 with id 1234
,在f3 / 345774.txt中,您得到:
[2018-04-26 18:49:29,213][DEBUG]In f3 with id 345774
[2018-04-26 18:49:29,213][DEBUG]Something's going wrong soon...
[2018-04-26 18:49:29,216][CRITICAL]Traceback (most recent call last):
File "/path.py", line 20, in _setup_logger
rtn = func(id, logger=logger, *args, **kwargs)
File "/path.py", line 43, in f3
int('opps')
ValueError: invalid literal for int() with base 10: 'opps'
以下是您的问题的答案:
使用装饰器,您只需创建一个记录器。所以不,一个记录器足以满足每个功能。由于您的记录器的格式为“{func-name} _id_logger”,这意味着每个不同的函数都必须有唯一的记录器。
是的,记录器将捕获作为Exception子类的任何异常。虽然您无论如何都会被捕获,但您仍应尝试捕获+处理函数中的异常。
不,它将被适当关闭。
答案 1 :(得分:0)
您不必分别为每个案例设置记录器。您应该将它们设置一次,以便您有两个记录器,每个输出到另一个文件。然后在两个函数中使用两个不同的记录器。
例如,您可以通过这种方式配置记录器*:
import logging.config
logging.config.dictConfig({
'version': 1,
'formatters': {
'simple_formatter': {
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
}
},
'handlers': {
'first_handler': {
'class' : 'logging.FileHandler',
'formatter': 'simple_formatter',
'filename': 'C:\\Temp\\log1.txt'
},
'second_handler': {
'class' : 'logging.FileHandler',
'formatter': 'simple_formatter',
'filename': 'C:\\Temp\\log2.txt'
}
},
'loggers': {
'first_logger': {
'handlers': ['first_handler']
},
'second_logger': {
'handlers': ['second_handler']
}
}
})
然后,只需使用您需要的一个或另一个记录器:
def f1():
logger = logging.getLogger('first_logger')
logger.warning('Hello from f1')
def f2():
logger = logging.getLogger('second_logger')
logger.warning('Hello from f2')
*配置记录器的方法有多种,有关其他选项,请参阅https://docs.python.org/3.6/library/logging.config.html。