Perl:在不死的情况下捕获错误

Posted

技术标签:

【中文标题】Perl:在不死的情况下捕获错误【英文标题】:Perl: catch error without die 【发布时间】:2011-02-07 09:07:10 【问题描述】:

我正在玩错误处理并遇到了一个小问题。 我使用 DBI 模块连接数据库。

我使用调用错误的子例程进行自己的错误处理。

我可以抓住自己的模具并很好地处理它们,但是当我的数据库连接失败时,DBI 模块显然会打印出它自己的模具:

DBI 连接(...)失败:ORA-12154:TNS:无法解析 在...处指定连接标识符(DBD 错误:OCIServerAttach)

我要怎么抓到这个?

我尝试像这样使用$SIG__DIE__

local $SIG__DIE__ = sub 
  my $e = shift;
  print "Error: " .$e;
;

这是在我的主文件的底部,在这个文件中我还调用了我自己的模块中可用的连接子例程。我也尝试将这段代码放在我的模块底部,但它仍然打印没有

的错误

错误:

在它前面。

【问题讨论】:

【参考方案1】:

DBI 连接(...)失败:ORA-12154: TNS:无法解析连接 指定的标识符(DBD 错误: OCIServerAttach) 在 ...

我要怎么抓到这个?

要捕获并处理这种级别的错误,请以块形式使用 eval,“eval ... ”。这将捕获子代码中发生的任何死亡。如果 eval 块中的代码死亡,它将设置 $@ 并且该块将返回 false。如果代码没有死,$@ 将被设置为 ''。

通过 SIGWARN 和 SIGDIE 使用信号处理很麻烦,因为它们是全局的,还需要考虑竞争条件(如果我在处理不同的信号时收到信号会发生什么?等等。基于信号的计算的传统问题)。您可能正在编写单线程代码,因此您不必担心调用 die 的多个事物的并发问题,但是需要考虑用户(也许他会在您尝试打开 DBI 连接时发送 SIGKILL )

在这种特定情况下,您使用的是 DBI。使用 DBI,您可以控制发生错误时发生的情况,是否应该死机、警告或静默失败,并等待您检查返回状态。

这是一个使用 eval ... 的基本示例。

my $dbh = eval  DBI->connect( @args) ;
if ( $@ )

    #DBI->connect threw an error via die
    if ($@ =~ m/ORA-12154/i )
    
        #handle this error, so I can clean up and continue
    
    elsif ( $@ =~ m/SOME \s* other \s* ERROR \s+ string/ix )
    
       #I can't handle this error, but I can translate it
        die "our internal error code #7";
    
    else 
    
      die $@; #re-throw the die
    

以这种方式使用 eval 存在一些小问题,与 $@ 的全局范围有关。 Try::Tiny cpan 页面有很好的解释。 Try::Tiny 处理最小的 Try/catch 块设置并处理 $@ 本地化和处理其他边缘情况。

【讨论】:

这是我一开始的方式,但是 eval 没有捕获我也想报告的警告。因此我必须使用 SIGWARN。【参考方案2】:

好的,找到了解决方案,显然我需要 __WARN__ 而不是 __DIE__ 并且这段代码需要在文件顶部,在引发错误之前,与我阅读的示例不同:)

【讨论】:

没错,这是警告而不是死亡,必须先安装处理程序。如果将其包装在 BEGIN 中,则可以将其安装在任何模块中。【参考方案3】:

将此包含在您的 SIG__DIE__ 块中:

### Check if exceptions being caught.
return if $^S;

这将防止您的处理程序被用于在 eval 块中生成 die 的基于异常的代码。

【讨论】:

【参考方案4】:

DBI 中有很多开关,例如 PrintError、RaiseError 等,您可以调整它们。 见http://search.cpan.org/perldoc?DBI

【讨论】:

嗯没有更通用的解决方案吗?这样我就可以用 1 个函数捕获所有其他错误。我可能会使用很多有很多方法输出错误的模块,我想独立于这个.. DBI 也有一个 HandleError 方法。或者,如果您将 PrintError 设置为 false,RaiseError 设置为 true,则应该调用您的(Pmarcoen 的)错误处理。【参考方案5】:

这不像一个整体的捕鼠器那样通用,但专门用于 DBI 错误处理,我们实际上有自己的模块提供数据库调用的包装器;该模块的功能之一是将eval(取决于标志)包装在每个 DBI 调用周围。

这使我们能够在数据访问级别上进行自定义错误处理,例如查询重试、统计信息、自动故障转移等 - 所有这些对其余代码都是透明的。

【讨论】:

以上是关于Perl:在不死的情况下捕获错误的主要内容,如果未能解决你的问题,请参考以下文章

34 年了,“杀”不死的 Perl!

组合:如何在不完成原始发布者的情况下替换/捕获错误?

我可以在不使用 await 的情况下从异步中捕获错误吗?

如何在不发送错误的情况下使按钮转到另一个视图控制器?

十字叉病毒,杀不死的小强,一次云服务器沦陷实录

一个杀不死的小强,kill进程无效的原因 记录故障排查过程中kill进程无效的分析过程