NAME

Exception::Reporter - a generic exception-reporting object

VERSION

version 0.014

SYNOPSIS

Achtung! This is an experimental refactoring of some long-standing internal code. It might get even more refactored. Once I've sent a few hundred thousand exceptions through it, I'll remove this warning...

First, you create a reporter. Probably you stick it someplace globally accessible, like MyApp->reporter.

my $reporter = Exception::Reporter->new({
  always_dump => { env => sub { \%ENV } },
  senders     => [
    Exception::Reporter::Sender::Email->new({
      from => 'root',
      to   => 'SysAdmins <sysadmins@example.com>',
    }),
  ],
  summarizers => [
    Exception::Reporter::Summarizer::Email->new,
    Exception::Reporter::Summarizer::File->new,
    Exception::Reporter::Summarizer::ExceptionClass->new,
    Exception::Reporter::Summarizer::Fallback->new,
  ],
});

Later, some exception has been thrown! Maybe it's an Exception::Class-based exception, or a string, or a Throwable object or who knows what.

try {
  ...
} catch {
  MyApp->reporter->report_exception(
    [
      [ exception => $_ ],
      [ request   => $current_request ],
      [ uploading => Exception::Reporter::Dumpable::File->new($filename) ],
    ],
  );
};

The sysadmins will get a nice email report with all the dumped data, and reports will thread. Awesome, right?

OVERVIEW

Exception::Reporter takes a bunch of input (the dumpables) and tries to figure out how to summarize them and build them into a report to send to somebody. Probably a human being.

It does this with two kinds of plugins: summarizers and senders.

The summarizers' job is to convert each dumpable into a simple hashref describing it. The senders' job is to take those hashrefs and send them to somebody who cares.

METHODS

new

my $reporter = Exception::Reporter->new(\%arg);

This returns a new reporter. Valid arguments are:

summarizers  - an arrayref of summarizer objects; required
senders      - an arrayref of sender objects; required
dumper       - a Exception::Reporter::Dumper used for dumping data
always_dump  - a hashref of coderefs used to generate extra dumpables
caller_level - if given, the reporter will look n frames up; see below

The always_dump hashref bears a bit more explanation. When "report_exception" is called, each entry in always_dump will be evaluated and appended to the list of given dumpables. This lets you make your reporter always include some more useful information.

...but remember! The reporter is probably doing its job in a catch block, which means that anything that might have been changed local-ly in your try block will not be the same when evaluated as part of the always_dump code. This might not matter often, but keep it in mind when setting up your reporter.

In real code, you're likely to create one Exception::Reporter object and make it globally accessible through some method. That method adds a call frame, and Exception::Reporter sometimes looks at caller to get a default. If you want to skip those intermedite call frames, pass caller_level. It will be used as the number of frames up the stack to look. It defaults to zero.

report_exception

$reporter->report_exception(\@dumpables, \%arg);

This method makes the reporter do its job: summarize dumpables and send a report.

Useful options in %arg are:

reporter    - the program or authority doing the reporting; defaults to
              the calling package

handled     - this indicates that this exception has been handled and that
              the user has not seen a terrible crash; senders might use
              this to decide who needs to get woken up

extra_rcpts - this can be an arrayref of email addresses to be used as
              extra envelope recipients by the Email sender

Each entry in @dumpables is expected to look like this:

[ $short_name, $value, \%arg ]

The short name is used for a few things, including identifying the dumps inside the report produced. It's okay to have duplicated short names.

The value can, in theory, be anything. It can be undef, any kind of object, or whatever you want to stick in a scalar. It's possible that extremely exotic values could confuse the "fallback" summarizer of last resort, but for the most part, anything goes.

The %arg entry isn't used for anything by the core libraries that ship with Exception::Reporter, but you might want to use it for your own purposes. Feel free.

The reporter will try to summarize each dumpable by asking each summarizer, in order, whether it can_summarize the dumpable. If it can, it will be asked to summarize the dumpable. The summaries are collected into a structure that looks like this:

[
  [ dumpable_short_name => \@summaries ],
  ...
]

If a given dumpable can't be dumped by any summarizer, a not-very-useful placeholder is put in its place.

The arrayref constructed is passed to the send_report method of each sender, in turn.

collect_summaries

$reporter->report_exception(\@dumpables);

This method is used by "report_exception" to convert dumpables into summaries. It may be called directly by summarizers through $self->reporter->collect_summaries(\@dumpables); if your summarizers receive dumpables that may be handled by another summarizer. Be wary though, because you could possibly create an endless loop...

AUTHOR

Ricardo Signes <rjbs@cpan.org>

CONTRIBUTORS

  • Matthew Horsfall <wolfsage@gmail.com>

  • Tomohiro Hosaka <bokutin@bokut.in>

COPYRIGHT AND LICENSE

This software is copyright (c) 2010 by Ricardo Signes.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.