【问题标题】:Properly handling IOError thrown by logging.config.fileConfig?正确处理 logging.config.fileConfig 抛出的 IOError?
【发布时间】:2011-11-14 21:04:28
【问题描述】:

这可能是一个开放式或尴尬的问题,但我发现自己遇到了越来越多的异常处理问题,我不知道处理它们的“最佳”方法。

如果您尝试使用不存在的文件配置 FileHandler,Python 的日志记录模块会引发 IOError。该模块不处理此异常,而只是引发它。很多时候,文件的路径不存在(因此文件不存在),所以如果我们想处理异常并继续,我们必须沿着路径创建目录。

我希望我的应用程序能够正确处理此错误,因为每个用户都问我们为什么不为他们创建正确的目录。

我决定处理此问题的方式如下所示。

done = False
while not done:
    try:
        # Configure logging based on a config file
        # if a filehandler's full path to file does not exist, it raises an IOError
        logging.config.fileConfig(filename)

    except IOError as e:
        if e.args[0] == 2 and e.filename:
            # If we catch the IOError, we can see if it is a "does not exist" error
            # and try to recover by making the directories

            print "Most likely the full path to the file does not exist, so we can try and make it"
            fp = e.filename[:e.rfind("/")]

            # See http://stackoverflow.com/questions/273192/python-best-way-to-create-directory-if-it-doesnt-exist-for-file-write#273208 for why I don't just leap
            if not os.path.exists(fp):
                os.makedirs(fp)

        else:
            print "Most likely some other error...let's just reraise for now"
            raise
    else:
        done = True

我需要循环(或者我想是递归),因为需要配置 N 个 FileHandler,因此需要针对这种情况提出和纠正 N 个 IOErrors。

这是正确的方法吗?有没有更好、更 Pythonic 的方式,我不知道或可能不理解?

【问题讨论】:

  • 我很困惑不存在的文件是配置文件(传递给fileConfig,如您的源代码)还是日志文件的名称(根据文本您的问题 - “尝试使用不存在的文件配置 FileHandler”)。我的答案是后者。通常,在指定文件(无论是配置文件还是日志文件)时,您需要确保很多事情 - 例如,文件可能已经存在但由于权限问题而无法读取或写入。没有万能的解决方案,这就是为什么您有时需要自己动手。
  • 我指的是日志文件的名称,我需要从日志配置文件中获取它以检查它是否存在。在代码中此时必须获取该信息是不方便的。我同意您的观点,在启动时进行此检查将是理想的。也许我真正的问题是为什么日志模块不为用户处理这些类型的异常?
  • 因为日志模块期望日志文件名是一个可写的文件,并且在一个存在的目录中。这种行为符合最小意外原则。典型的文本编辑器(例如,Windows 上的记事本或 Linux 上的 gedit)在使用不存在的目录中的文件名调用时,不会自动为您创建文件。记事本给出错误信息; gedit 不会以该名称保存文件,但会在您单击“保存”时提示您输入位置。

标签: python exception logging exception-handling ioerror


【解决方案1】:

这不是特定于日志记录模块的东西:通常,Python 代码不会自动为您自动创建中间目录;您需要使用os.makedirs() 明确地执行此操作,通常如下所示:

if not os.path.exists(dirname):
    os.makedirs(dirname)

您可以将日志记录提供的标准FileHandler 替换为执行所需检查的子类,并在必要时使用os.makedirs() 创建日志记录文件的目录。然后你可以在配置文件中指定这个处理程序而不是标准处理程序。

【讨论】:

  • 那么为了正确处理日志模块中的异常,我需要子类化模块吗?虽然我同意这个设计是合理的,但它似乎是一种处理异常(或一组)的复杂方法。
【解决方案2】:

假设它只需要在您的应用程序开始执行时执行一次,我将只 os.makedirs() 所有需要的目录而不首先检查它们的存在,甚至等待日志模块引发错误。如果您在尝试启动记录器时遇到错误,您可以按照您可能已经做过的方式处理它:打印错误,禁用记录器。您只是通过尝试创建目录来超越。如果用户向您提供虚假信息,您的情况不会比现在更糟,而且在绝大多数情况下您会更好。

【讨论】:

  • 这种方法让我担心的是我需要解析,然后遍历日志配置文件,检查 args 变量是否是文件处理程序,然后采取行动。虽然这不是一个挑战,但它似乎是一个漫长的问题解决方案。为什么我需要这样做?为什么日志记录模块不为我执行此操作?
  • 嗯,是的,起初我没有注意到您传递给日志文件的文件名是日志配置文件而不是日志文件的文件名。看起来 Vinay 建议使用自定义 FileHandler 执行此操作,这可能是更好的方法。
  • 虽然 Vinay 的解决方案确实是个好主意,但您是否觉得对于这个问题来说它是矫枉过正?
  • 不,在我看来,这是处理此类问题的方式。文件处理程序似乎是引发您在示例代码中捕获的异常的类,因此如果您可以根据需要替换创建目录的自己的文件处理程序,这对我来说似乎很手术。
  • 外科手术,是的,但是想想一个新手开发人员只是尝试使用日志记录模块。这对于新手来说有点牵强。阿尔比特,这可能就是我要走的路。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-20
  • 2023-01-10
  • 1970-01-01
  • 2012-11-28
  • 2013-11-23
  • 1970-01-01
  • 2015-08-11
相关资源
最近更新 更多