3

For my Catalyst project I am using an own Moose based exception type, that is compatible with Catalyst and my command line applications.

To provide clients of my Catalyst REST interface with error messages, I implemented a code subroutine that is providing http status codes as part of my exception class. This way, I want to use Plack::Middleware as described in the pod documentation of Plack::Middleware::HTTPExceptions.

Everything works fine. The exceptions are returned to the client the way I want to them to be returned.

My problem is: whenever I throw an exception, that is caught by the middle ware, my logging (Log::Log4perl) is lost and I can find neither traces nor errors in Catalyst's web server perl script output.

Whenever I throw errors, that are not encapsulated by my exception class, but rare string (like die "BOOM!"), the log output is written and the error is documented (obviously, the error is caught by Catalyst and is not re-thrown).

How can I tell Catalyst to keep logging requests, even though the exception has to be re-thrown to the middle ware?

2 Answers2

0

There sort of seems to be two parts to this question but I think this covers it. It really is more of a question of setting up Log4perl to log the errors, but there are Catalyst and Plack considerations.

First, here would be a typical log4perl config setup I would have:

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

Note the inclusion of the stderr value in there as 1. So this tells log4perl to capture stderr for logging.

On the Catalyst side, I actually have some very custom init code for the context but there are essentially two things being set;

  1. Set the context logger to Log::Log4perl::Catalyst essentially via $c->log

  2. Load the PSGI middleware Plack::Middleware::Log4perl. I actually do this via the psgi_middleware config key when loading catalyst config. So there is nothing more in the config line than "Log4perl" as everything is already in the "Plack::Middleware" context path.

The second part there will "pick-up" the loaded "log4perl" instance and assign to the psgi.logger so that any PSGI components can then access the logger as required.

So then, any later statements that will be "re-throw" in code such as this:

  my $e = HTTP::Exception->new(404);
  $e->status_message("BOOM!!");
  $e->throw;

Will actually be picked up in the "log4perl" output, as well any raw die statements.

At least that is the case on Catalyst 5.90060 and up. There are still some extra niceties that would like to be added regarding HTTP::Exception type classes.

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
  • Hey Neil, somehow that didn't solve my problem. I see, your answer is following the documentation and partly my Catalyst app already worked like yours does when it comes to setting the logger context, but somehow setting Log4perl in the psgi_middleware configuration did not produce further logging. I posted another workaround, that is not including middle ware functionality, but I am still interested in solving the problem by defining middleware or catalyst options. –  May 22 '14 at 11:28
  • @deviolog I'm not sure about "following documentation" so much other than code I actually wrote in contribution. So I would think it actually is correct. – Neil Lunn May 22 '14 at 11:30
0

Even though Neil's answer contains several correct statements, that I applied to my Catalyst application, I didn't get any output. I work around that problem, by sub classing Catalyst::Engine. This subclass is redefining finalize_error only and leaves the rest of its functionality untouched. In case of finding my own exceptions types I set an individual response body and status code to achieve the same result as I do by re-throwing the exception "the ladder up".