package Plack::Middleware::ErrorNot; use strict; use warnings; use POSIX qw(strftime); use JSON; use Try::Tiny; use Devel::StackTrace; use AnyEvent::HTTP; use parent qw(Plack::Middleware); use Plack::Util::Accessor qw(api_key api_url); sub call { my ($self, $env) = @_; my($trace, $exception); local $SIG{__DIE__} = sub { $trace = Devel::StackTrace->new; $exception = $_[0]; die @_; }; my $res; try { $res = $self->app->($env) }; if ($trace && (!$res or $res->[0] == 500)) { $self->send_notify($trace, $exception, $env); $res = [500, ['Content-Type' => 'text/html'], [ "Internal Server Error" ]]; } # break $trace here since $SIG{__DIE__} holds the ref to it, and # $trace has refs to Standalone.pm's args ($conn etc.) and # prevents garbage collection to be happening. undef $trace; return $res; } sub send_notify { my ($self, $trace, $exception, $env) = @_; my $req = Plack::Request->new($env); my $raised_at = strftime "%a %b %e %H:%M:%S %Y", gmtime; my @env_infos = ( qw/PATH_INFO SERVER_NAME SERVER_PORT HTTP_ACCEPT HTTP_ACCEPT_CHARSER HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_HOST REQUEST_METHOD REMOTE_ADDR/ ); my $hash_exception = { api_key => $self->api_key, error => { message => $exception, raised_at => $raised_at, backtrace => '', request => { url => $req->uri->as_string, action => $req->uri->path, parameters => map { $_ => $req->parameters->{$_} } keys %{$req->parameters}, session => map { $_ => $req->session->{$_} } keys %{$req->session}, }, } }; foreach my $env_key (@env_infos) { $hash_exception->{environment}->{$env_key} = $env->{$env_key} if exists $env->{$env_key}; } my $cv = AE::cv; AnyEvent::HTTP::http_post $self->api_url, JSON::encode_json($hash_exception), headers => { 'Content-Type' => 'application/json', 'Accept-Type' => 'application/json' }, $cv; $cv->recv unless $env->{'psgi.nonblocking'}; } 1; =head1 NAME Plack::Middleware::ErrorNot - Sends application errors to ErrorNot =head1 SYNOPSIS enable "ErrorNot", api_key => "...", api_url => "..."; =head1 DESCRIPTION This middleware catches exceptions (run-time errors) happening in your application and sends them to L. =head1 AUTHOR franck cuny =head1 LICENSE This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L =cut