提问人:squarespiral 提问时间:2/18/2023 最后编辑:vvvvvsquarespiral 更新时间:4/3/2023 访问量:90
python:在程序执行过程中处理模块的日志输出
python: Handling log output of module during program execution
问:
我正在我的脚本中设置一个记录器,如底部所示。这适用于我的目的,并记录我的日志消息以及我用于 stdout 和日志文件的任何模块的日志消息。__main__
在程序执行期间,我使用的模块调用在某些情况下会引发错误,并生成以下日志输出:xarray.open_dataset(file, engine="cfgrib")
2023-02-18 10:02:06,731 cfgrib.dataset ERROR skipping variable: paramId==228029 shortName='i10fg'
Traceback (most recent call last):
...
如何在程序执行期间访问此输出?
cfgrib 模块中引发的错误在那里得到优雅处理,程序可以继续执行,但我的程序逻辑要求我访问错误消息,特别是为了详尽地处理错误而说的部分。shortName='i10fg'
以下是我的记录器的设置方式:
def init_log():
"""initialize logging
returns logger using log settings from the config file (settings.toml)
"""
# all settings from a settings file with reasonable defaults
lg.basicConfig(
level=settings.logging.log_level,
format=settings.logging.format,
filemode=settings.logging.logfile_mode,
filename=settings.logging.filename,
)
mylogger = lg.getLogger(__name__)
stream = lg.StreamHandler()
mylogger.addHandler(stream)
clg.install(
level=settings.logging.log_level,
logger=mylogger,
fmt="%(asctime)s %(levelname)s:\t%(message)s",
)
return mylogger
# main
log = init_log()
log.info('...reading files...')
我浏览了 python 日志记录文档和食谱。虽然这包含大量关于如何出于各种目的修改日志记录的示例,但我找不到在程序执行期间访问和响应日志消息的示例。
我的日志中的异常如下所示:
2023-02-20 12:22:37,209 cfgrib.dataset ERROR skipping variable: paramId==228029 shortName='i10fg'
Traceback (most recent call last):
File "/home/foo/projects/windgrabber/.venv/lib/python3.10/site-packages/cfgrib/dataset.py", line 660, in build_dataset_components
dict_merge(variables, coord_vars)
File "/home/foo/projects/windgrabber/.venv/lib/python3.10/site-packages/cfgrib/dataset.py", line 591, in dict_merge
raise DatasetBuildError(
cfgrib.dataset.DatasetBuildError: key present and new value is different: key='time' value=Variable(dimensions=('time',), data=array([1640995200, 1640998800, 1641002400, ..., 1672520400, 1672524000,
1672527600])) new_value=Variable(dimensions=('time',), data=array([1640973600, 1641016800, 1641060000, 1641103200, 1641146400,
1641189600, 1641232800, 1641276000, 1641319200, 1641362400,
由于某种原因,我无法直接捕获异常:
...
import sys
from cfgrib.dataset import DatasetBuildError
...
try:
df = xr.open_dataset(file, engine="cfgrib").to_dataframe()
# triggering error manually like with the two lines below works as expected
# raise Exception()
# raise DatasetBuildError()
except Exception as e:
print('got an Exception')
print(e)
print(e.args)
except BaseException as e:
print('got a BaseException')
print(e.args)
except DatasetBuildError as e:
print(e)
except:
print('got any and all exception')
type, value, traceback = sys.exc_info()
print(type)
print(value)
print(traceback)
除非我取消注释手动引发异常的两行,否则永远不会触发子句,尽管我可以在日志中看到事件。except
DatabaseBuildError
不确定这是否有任何影响,但是虽然我可以在我的文件日志中看到上面引用的异常,但它没有打印到 stdout。
编辑:
正如@dskrypa在评论中建议的那样,传递给函数调用确实允许我处理异常。不幸的是,这让我陷入了困境:电话非常昂贵(需要很长时间)。它返回一堆变量的时间序列。当异常发生时,调用会返回它所能返回的任何内容,我必须在单独的调用中获取其余变量。errors='raise'
xr.open_dataset()
现在,当我提出错误并且调用失败时,它不会返回任何时间序列,我必须再进行 2 次调用才能恢复(一次用于获取第一组变量,同时忽略异常,第二次用于获取其余部分)。
相反,当我没有提出错误时(记录了异常,但调用已完成部分 = 原始问题),我必须在另一个语句中重复每个调用,并假设它可能没有获得所有变量/时间序列。不幸的是,这种例外发生在大约一半的情况下。try
我需要的是一种在运行时确定是否记录了异常的方法,同时仍然允许调用继续并传递 var 的前半部分(如果没有异常,则提供所有 var)。只有当有异常日志时,我才会再次调用以获取其余变量。这基本上又是原来的问题陈述。
看起来我可能不得不重构整个事情,将 grib 转换为 netcdf(据报道更快),然后从那里读取。希望即使我遇到同样的异常,它在时间上的影响也会较小。
答: 暂无答案
评论
traceback.format_exc(),
它提供与日志中相同的回溯输出。xarray.open_dataset(file, engine="cfgrib")
try:
except ... as e:
raise DatasetBuildError
name
cfgrib.dataset
errors='raise'
open_dataset
param_id
shortName
errors='raise'
有效,感谢您找到它!但不幸的是,让我处于第 1 个方块:提出错误意味着,我必须对函数进行 2 次额外的调用 - 我将在问题中添加详细信息。