对于我的Catalyst
项目,我使用自己的基于Moose
的异常类型,这与Catalyst
和我的命令行应用程序兼容。
为了向Catalyst REST接口的客户端提供错误消息,我实现了一个code
子例程,它将http状态码作为异常类的一部分提供。这样,我想使用Plack::Middleware::HTTPExceptions
的pod文档中所描述的Plack::Middleware
。
一切正常。异常以我想要的方式返回给客户端。
我的问题是:每当我抛出一个异常,这是由中间件捕获的,我的日志(Log::Log4perl
)丢失了,我既找不到Catalyst
的web服务器perl脚本输出的痕迹也找不到错误。
每当我抛出错误时,没有被我的异常类封装,而是罕见的字符串(如die "BOOM!"
),将写入日志输出并记录错误(显然,错误被Catalyst
捕获并且不会重新抛出)。
我怎么能告诉Catalyst
保持日志请求,即使异常必须被重新抛出到中间件?
这个问题似乎有两个部分,但我认为这涵盖了它。它实际上更多的是设置Log4perl来记录错误的问题,但是有Catalyst和Plack的考虑。
首先,下面是典型的log4perl配置设置:
log4perl.logger = DEBUG, FileAppndr, Screen, DebugPanel
log4perl.appender.FileAppndr = Log::Log4perl::Appender::File
log4perl.appender.FileAppndr.filename = log/server.log
log4perl.appender.FileAppndr.autoflush = 1
log4perl.appender.FileAppndr.stderr = 1
log4perl.appender.FileAppndr.layout = PatternLayout
log4perl.appender.FileAppndr.layout.ConversionPattern=%d [%p] - %m%n
log4perl.appender.Screen = Log::Log4perl::Appender::Screen
log4perl.appender.Screen.stderr = 1
log4perl.appender.Screen.autoflush = 1
log4perl.appender.Screen.layout = PatternLayout
log4perl.appender.Screen.layout.ConversionPattern=%d [%p] - %m%n
请注意,这里将stderr
值包含为1
。这告诉log4perl捕获stderr
进行日志记录。
在Catalyst端,我实际上有一些非常自定义的上下文初始化代码,但基本上有两个东西要设置;
通过
$c->log
设置上下文记录器为Log::Log4perl::Catalyst加载PSGI中间件Plack:: middleware::Log4perl。实际上,在加载催化剂配置时,我通过
psgi_middleware
配置键来做到这一点。所以在配置行中没有什么比"Log4perl"更多的了,因为一切都已经在"Plack::Middleware"上下文路径中。
第二部分将"拾取"加载的"log4perl"实例并将其分配给psgi.logger
,以便任何PSGI组件都可以根据需要访问日志记录器。
那么,任何将在代码中被"重新抛出"的后续语句,例如:
my $e = HTTP::Exception->new(404);
$e->status_message("BOOM!!");
$e->throw;
实际上将在"log4perl"输出中拾取,以及任何原始的die
语句。
至少在Catalyst 5.90060及以上版本是这样的。对于HTTP::Exception类型的类,还有一些额外的细节需要添加。
尽管Neil的答案包含了几个正确的语句,我将它们应用到我的Catalyst应用程序中,但我没有得到任何输出。我通过子类化Catalyst::Engine
来解决这个问题。这个子类只重新定义finalize_error
,其余的功能保持不变。在找到自己的异常类型的情况下,我设置了一个单独的响应体和状态代码,以获得与重新抛出异常"the ladder up"相同的结果。