我没有那么多地使用鲤鱼,因为我一般都是自己动手.但是,本着与Core模块保持一致的精神,我现在正在使用它.然而,似乎它几乎不比警告/死亡好.
此外,咯咯/忏悔/冗长甚至做什么?我已经运行了这个简短的脚本来了解输出的样子(因为Carp文档没有这样做).它在任何运行中看起来都完全相同(除了随机字符串).
#!/usr/bin/perl
package Warning;
sub warning {
warn "warn";
}
package CWarn;
use Carp qw(carp cluck);
sub cwarn {
int(rand(2)) ? carp "carp" : cluck "cluck";
}
package Fatal;
use Carp qw(confess croak);
sub fatal {
int(rand(2)) ? confess "confess" : croak "croak";
}
package Loop;
use v5.10;
sub loop {
say '=' x 80;
Warning::warning();
CWarn::cwarn();
loop() unless ($c++ > 10);
Fatal::fatal();
}
package main;
Warning::warning();
CWarn::cwarn();
Loop::loop();
Run Code Online (Sandbox Code Playgroud)
更新:使用包名更新了脚本,它确实有所作为.但是,就记录信息而言,Carp似乎仍然非常基础,并且它不支持Web输出.我想我会看看其他像CGI :: Carp,Log :: Output和Log :: Log4Perl.
我正在使用大型Perl应用程序,并且每次调用"die"时都希望获得堆栈跟踪.我知道Carp模块,但我不想用'confess'搜索/替换'die'的每个实例.另外,我想要Perl模块或Perl解释器本身的错误的完整堆栈跟踪,显然我不能改变使用Carp的那些.
那么,有没有办法在运行时修改'die'函数,使其表现得像'confess'?或者,是否有一个Perl解释器设置会从'die'中抛出完整的堆栈跟踪?
默认情况下,Raku 的 "die" 报告 "die" 所在的行号,如果你想要调用上下文的行号,ala "carp" with perl 5 怎么办?
在我用C完成的一些项目中,我喜欢使用以下类似于Perl的warn和die子例程的宏:
#include <stdio.h>
#include <stdlib.h>
#define warn(...) \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, " at %s line %d\n", __FILE__, __LINE__)
#define die(...) \
warn(__VA_ARGS__); \
exit(0xFF)
Run Code Online (Sandbox Code Playgroud)
有没有像Perl的鲤鱼,呱呱,咯咯和鲤鱼的忏悔子程序那样存在的东西?我想从用户角度报告错误.
如果没有,我知道glibc中有backtrace()和backtrace_symbols()函数,它们与-rdynamic gcc选项一起可以为我提供函数名和代码地址的回溯.但我想要一些更好的东西; 可以访问调用堆栈中的文件,行和函数名称,如Perl的调用者子例程.我可以编写自己的libcarp用于我的c程序.
编辑:2009-10-19
我正在考虑在basename(argv [0])上创建使用gdb的东西,然后处理堆栈跟踪以生成我想要的不同类型的消息.它应该能够确定我是不是在可调试的可执行文件中,还是没有gdb的系统,在这种情况下,carp和cluck会变成警告并且Craok和confess将会死亡.
我之前从未使用过这样的gdb(我只在开始时使用我的程序运行它,而不是在它已经运行时).但我发现glib中的一些函数(g_on_error_stack_trace和stack_trace)看起来非常接近我想要做的事情:它使用参数basename(argv [0])和进程id分配gdb进程,然后写入其stdin(已被重定向到管道)命令"backtrace"后跟"退出".然后它从结果中读取并按照它喜欢的方式解析它.这几乎就是我需要做的.
我有同样的问题,因为某些原因无法在Carp :: croak()中禁用堆栈跟踪.因为堆栈中的每个调用都被认为是"安全的",所以每次croak()
打印出完整的堆栈跟踪.我想为某些电话禁用它.
这是一个例子:
use Carp;
sub this_may_fail {
# Some code...
croak "This call failed!";
}
sub regular_code {
this_may_fail();
}
regular_code();
Run Code Online (Sandbox Code Playgroud)
两个子程序都在同一个包中,因此this_may_fail
会自动标记为安全.有没有办法告诉Carp this_may_fail
应该被视为不安全?
假设您使用 cpan(或其他外部)模块,就像我们在这里虚构的那样 Stupid::CPAN::Module::OfSatan
package Stupid::CPAN::Module::OfSatan {
BEGIN { $SIG{__DIE__} = sub { print STDERR "ERROR"; exit; }; }
}
Run Code Online (Sandbox Code Playgroud)
现在在你的代码中你有一些非常无辜的东西,
package main {
eval { die 42 };
}
Run Code Online (Sandbox Code Playgroud)
这将触发您的错误信号处理程序。你会想知道那个有问题的信号处理程序是在哪里定义的,所以你会做一些合乎逻辑的事情,比如插入一个Carp::Always
,
package main {
use Carp::Always;
eval { die 42 };
}
Run Code Online (Sandbox Code Playgroud)
Carp::Always
然后将覆盖有问题的信号处理程序,您的代码将神奇地工作。您如何调试引入错误信号处理程序的代码?
我运行了这个测试脚本:
use strict;
use warnings;
use Test::More tests => 3;
use Carp;
ok(1<2);
pass();
fail();
croak "example";
Run Code Online (Sandbox Code Playgroud)
使用命令行prove -MCarp=verbose -v foo.pl
,并得到以下错误:
Subroutine App::Prove::verbose redefined at /opt/ActivePerl-5.12/lib/App/Prove.pm line 407
App::Prove::_load_extension('App::Prove=HASH(0x683718)', 'Carp=verbose') called at /opt/ActivePerl-5.12/lib/App/Prove.pm line 419
App::Prove::_load_extensions('App::Prove=HASH(0x683718)', 'ARRAY(0x683850)') called at /opt/ActivePerl-5.12/lib/App/Prove.pm line 481
App::Prove::run('App::Prove=HASH(0x683718)') called at /opt/ActivePerl-5.12/bin/prove line 11
Undefined subroutine &Carp::verbose called at /opt/ActivePerl-5.12/lib/App/Prove.pm line 484.
Run Code Online (Sandbox Code Playgroud)
如果我使用它运行它perl -MCarp=verbose foo.pl
没有问题.什么导致prove
拒绝啰嗦鲤鱼?如果croak
没有全局替换croak
,我怎样才能从我的测试中获得完整的callstack confess
?
如果BUILD
方法失败,我希望我的班级爆炸.但是,如果我croak
用来处理错误,则会报告错误Class/MOP/Method.pm
,而不是调用者的代码.(也就是说,实例化对象的调用者.)IOW,croak
在调用树上没有吠叫.
看吧:
package Test;
use Moose;
use Carp 'croak';
sub BUILD {
croak 'u r dum';
}
1;
Run Code Online (Sandbox Code Playgroud)
实例化Test
结果:
u r dum at /home/friedo/perl5/lib/perl5/x86_64-linux-gnu-thread-multi/Class/MOP/Method.pm line 125
Run Code Online (Sandbox Code Playgroud)
Carp.pm
应该注意一个名为变量的包变量@CARP_NOT
来知道要避免哪些包,但它似乎只关注列表中的一个项目.例如,如果我将其添加到我的Test.pm
:
our @CARP_NOT = ( 'Class::MOP::Method' );
Run Code Online (Sandbox Code Playgroud)
然后结果是:
u r dum at /home/friedo/perl5/lib/perl5/x86_64-linux-gnu-thread-multi/Moose/Object.pm line 59
Run Code Online (Sandbox Code Playgroud)
所以我也应该将它添加到数组中,对吧?
our @CARP_NOT = ( 'Class::MOP::Method', 'Moose::Object' );
Run Code Online (Sandbox Code Playgroud)
然后结果仍然是:
u r dum at /home/friedo/perl5/lib/perl5/x86_64-linux-gnu-thread-multi/Moose/Object.pm line 59
Run Code Online (Sandbox Code Playgroud)
Moose::Object
似乎没有受到影响.
我现在一直在反对这个问题,现在似乎无法弄清楚是什么弄乱了它.
谢谢.
根据perldoc -f die
, 哪些文件$SIG{__DIE__}
尽管此功能只能在您的程序退出之前运行,但目前并非如此:
$SIG{__DIE__}
当前甚至在 evaled 块/字符串中也调用了钩子!如果希望钩子在这种情况下什么都不做,请将其die @_ if $^S;
作为处理程序的第一行(参见$^S
perlvar)。因为这会促进远距离奇怪的动作,所以这种违反直觉的行为可能会在未来的版本中得到修复。
所以让我们采用一个基本的信号处理程序,它将触发eval { die 42 }
,
package Stupid::Insanity {
BEGIN { $SIG{__DIE__} = sub { print STDERR "ERROR"; exit; }; }
}
Run Code Online (Sandbox Code Playgroud)
我们使这安全
package Stupid::Insanity {
BEGIN { $SIG{__DIE__} = sub { return if $^S; print STDERR "ERROR"; exit; }; }
}
Run Code Online (Sandbox Code Playgroud)
现在这不会用触发eval { die 42 }
,但是当相同的代码位于BEGIN {}
像这样的块中时它会触发
BEGIN { eval { die 42 …
Run Code Online (Sandbox Code Playgroud) 我知道如何覆盖内置的函数perl
,我已经覆盖die
warn
say
,因为print
并且printf
无法覆盖我已将它绑定到我的日志框架的句柄.
覆盖示例warn
:
BEGIN{ *CORE::GLOBAL::warn = sub {
my ($package, $filename, $line, $subroutine) = caller;
untie *STDERR;
my $message;
foreach my $arg (@_) {
$message = $message.$arg;
}
print STDERR $message;
tie *STDERR, __PACKAGE__, (*STDERR);
logmessage("warn",$message,$filename, $line);
return;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我可以croak cluck confess carp
从carp
模块中覆盖Perl
吗?