diff --git a/Build.PL b/Build.PL
index 4c7c31a97f..a92de0cffb 100644
--- a/Build.PL
+++ b/Build.PL
@@ -32,9 +32,12 @@ my $builder = Local::Module::Build->new(
'Catalyst::View::JSON' => 0,
'Catalyst::View::TT' => 0,
'Config::General' => 0,
+ 'Convert::Ascii85' => 0,
+ 'Data::Dumper' => 0,
'Data::Validate::IP' => 0,
'DateTime' => 0,
'DateTime::Format::ISO8601' => 0,
+ 'DateTime::Format::RFC3339' => 0,
'DBIx::Class::ResultSet::RecursiveUpdate' => '0.30',
'Email::Valid' => 0,
'File::ShareDir' => 0,
@@ -49,6 +52,7 @@ my $builder = Local::Module::Build->new(
'HTML::FormHandler::Moose' => 0,
'HTML::FormHandler::Widget::Block::Bootstrap' => 0,
'HTTP::Status' => 0,
+ 'IO::Compress::Xz' => 0,
'IPC::System::Simple' => 0,
'Log::Log4perl::Catalyst' => 0,
'Module::Runtime' => 0,
@@ -65,6 +69,7 @@ my $builder = Local::Module::Build->new(
'strict' => 0,
'Template' => 0,
'Text::CSV_XS' => 0,
+ 'Time::HiRes' => 0,
'URI::Encode' => 0,
'URI::Escape' => 0,
'UUID' => 0,
@@ -95,6 +100,9 @@ my $builder = Local::Module::Build->new(
# for the testcover target
'Devel::Cover' => 0,
'sigtrap' => 0,
+ # for development
+ 'Convert::Ascii85' => 0,
+ 'IO::Uncompress::UnXz' => 0,
},
add_to_cleanup => [ 'NGCP-Panel-*' ],
);
diff --git a/lib/NGCP/Panel/Controller/Root.pm b/lib/NGCP/Panel/Controller/Root.pm
index 4e54139888..7b00f826a6 100644
--- a/lib/NGCP/Panel/Controller/Root.pm
+++ b/lib/NGCP/Panel/Controller/Root.pm
@@ -1,11 +1,15 @@
package NGCP::Panel::Controller::Root;
use Sipwise::Base;
-
-
BEGIN { extends 'Catalyst::Controller' }
-
+use Carp qw(longmess);
+use Convert::Ascii85 qw();
+use Data::Dumper qw(Dumper);
+use DateTime qw();
+use DateTime::Format::RFC3339 qw();
+use IO::Compress::Xz qw(xz);
use NGCP::Panel::Widget;
use Scalar::Util qw(blessed);
+use Time::HiRes qw();
#
# Sets the actions in this controller to be registered with no prefix
@@ -111,7 +115,41 @@ sub default :Path {
$c->detach( '/error_page' );
}
-sub end : ActionClass('RenderView') {}
+sub render :ActionClass('RenderView') { }
+
+sub end :Private {
+ my ($self, $c) = @_;
+ $c->forward('render');
+ if (@{ $c->error }) {
+ my $incident = DateTime->from_epoch(epoch => Time::HiRes::time);
+ my $incident_id = sprintf '%X', $incident->strftime('%s%N');
+ my $incident_timestamp = DateTime::Format::RFC3339->new->format_datetime($incident);
+ my $crash_state;
+ if ($c->config->{log_crash_state}) {
+ local $Data::Dumper::Indent = 1;
+ local $Data::Dumper::Useqq = 1;
+ local $Data::Dumper::Deparse = 1;
+ local $Data::Dumper::Quotekeys = 0;
+ local $Data::Dumper::Sortkeys = 1;
+ my $buffer;
+ xz(\(join(q(), @{ $c->error }) . longmess . Dumper($c) . Dumper($c->config)), \$buffer);
+ $crash_state = Convert::Ascii85::encode($buffer);
+ $crash_state =~ s/(.{80})/$1\n/g;
+ }
+ $c->log->error(
+ "Exception id $incident_id at $incident_timestamp crash_state:" .
+ ($crash_state ? ("\n" . $crash_state) : ' disabled')
+ );
+ $c->clear_errors;
+ $c->stash(
+ exception_incident => $incident_id,
+ exception_timestamp => $incident_timestamp,
+ template => 'error_page.tt'
+ );
+ $c->response->status(500);
+ $c->detach($c->view);
+ }
+}
sub _prune_row {
my ($columns, %row) = @_;
@@ -129,8 +167,7 @@ sub error_page :Private {
my ($self,$c) = @_;
$c->log->error( 'Failed to find path ' . $c->request->path );
- $c->stash(template => 'error_page.tt');
- #$c->response->body( 'Page not found' );
+ $c->stash(template => 'notfound_page.tt');
$c->response->status(404);
}
diff --git a/ngcp_panel.conf b/ngcp_panel.conf
index 6975164a04..7b86c9f0b7 100644
--- a/ngcp_panel.conf
+++ b/ngcp_panel.conf
@@ -10,6 +10,9 @@ log4perl.appender.Default.layout=PatternLayout
log4perl.appender.Default.layout.ConversionPattern=%d{ISO8601} [%p] [%F +%L] %m{chomp}%n
# perhaps also add: host=%H pid=%P
+# each crash state is <50 KiB
+log_crash_state 1
+
Sorry, an exceptional error has occured:
+Details have been logged on the server. If you want to report the error, + describe what you were doing or attempting to do just before.