239 lines
7.1 KiB
Perl
239 lines
7.1 KiB
Perl
package steffen::MojoPlug::Syslog;
|
|
use Mojo::Base 'Mojolicious::Plugin';
|
|
use Sys::Syslog qw(:standard :macros);
|
|
|
|
our $VERSION = '__VERSION__';
|
|
|
|
my %PRIORITY = (
|
|
debug => LOG_DEBUG,
|
|
error => LOG_ERR,
|
|
fatal => LOG_CRIT,
|
|
info => LOG_INFO,
|
|
warn => LOG_WARNING,
|
|
);
|
|
|
|
sub register {
|
|
my ($self, $app, $config) = @_;
|
|
my $log_warn = $config->{log_warn} || '1';
|
|
my $log_level = $config->{level} || 'info';
|
|
my $log_color = $config->{color} && $config->{color} eq 1 ? 1 : 0;
|
|
my $only_syslog = $config->{only_syslog} && $config->{only_syslog} eq 1 ? 1 : 0;
|
|
|
|
if ( $Mojolicious::VERSION < 9.20 ) {
|
|
if ( $config->{access_log} && $config->{access_log} ne '' ) {
|
|
$config->{access_log} = undef;
|
|
$app->log->warn('Mojo access_log geht erst ab Version 9.20, wird deaktiviert');
|
|
}
|
|
|
|
if ( $log_level =~ /trace/ ) {
|
|
$log_level = 'debug';
|
|
$app->log->warn('Mojo Trace geht erst ab Version 9.20, setze auf debug');
|
|
}
|
|
}
|
|
|
|
if ( $Mojolicious::VERSION > 9.00 ) {
|
|
$app->log->color( $log_color )
|
|
} elsif ( $log_color == 1 ) {
|
|
$app->log->warn('Mojo Log Color geht erst ab Version 9.01');
|
|
}
|
|
|
|
if ( $log_level =~ /trace|debug|info|warn|error|fatal/ ) {
|
|
$app->log->level( lc $log_level);
|
|
} else {
|
|
return $app->log->error(sprintf('REGISTERED failed: %s V%s, loglevel: %s is unknown', __PACKAGE__, $VERSION, $log_level));
|
|
}
|
|
|
|
$self->_add_syslog($app, %$config)
|
|
if $config->{enable} // $ENV{MOJO_SYSLOG_ENABLE}
|
|
// $app->mode ne 'development';
|
|
|
|
$self->_add_access_log($app, %$config)
|
|
if $config->{access_log} // $ENV{MOJO_SYSLOG_ACCESS_LOG};
|
|
|
|
if ($log_warn eq '1') {
|
|
$SIG{__WARN__} = sub {
|
|
|
|
my $msg = join ' ', @_;
|
|
chomp $msg;
|
|
|
|
$app->log->warn($msg)
|
|
if $app->mode eq 'development' && $only_syslog == 0; # wenn syslog aus ist dann auch im Developermode kein errorlog
|
|
syslog $PRIORITY{warn}, '%s [MOJO] %s', 'WARN', $msg;
|
|
};
|
|
}
|
|
$app->log->info(sprintf('REGISTERED: %s V%s', __PACKAGE__, $VERSION)) if $config->{verbose};
|
|
}
|
|
|
|
sub _add_access_log {
|
|
my ($self, $app, %config) = @_;
|
|
|
|
my $log_format = $config{access_log} || $ENV{MOJO_SYSLOG_ACCESS_LOG} || 'v1';
|
|
$log_format = '%H "%P" (%I) %C %M (%Ts)' if $log_format =~ /^v?1$/;
|
|
$log_format = '%R %H %U %C "%F" "%A" (%Ts)' if $log_format =~ /^v?2$/;
|
|
|
|
$app->hook(
|
|
before_routes => sub {
|
|
shift->helpers->timing->begin(__PACKAGE__);
|
|
}
|
|
);
|
|
|
|
my %extractors = (
|
|
A => sub { $_[1]->headers->user_agent || '' },
|
|
C => sub { $_[2]->code },
|
|
F => sub { $_[1]->headers->referrer || '' },
|
|
H => sub { $_[1]->method },
|
|
I => sub { $_[1]->request_id },
|
|
M => sub { $_[2]->message || $_[2]->default_message($_[2]->code) },
|
|
P => sub { $_[1]->url->path->to_abs_string },
|
|
R => sub { $_[0]->tx->remote_address },
|
|
T => sub { $_[0]->helpers->timing->elapsed(__PACKAGE__) // 0 },
|
|
U => sub { $_[1]->url->to_abs->to_string },
|
|
);
|
|
|
|
my $app_log = $log_format =~ m!\%I\b! && $app->log;
|
|
|
|
my $re = join '|', sort keys %extractors;
|
|
$re = qr{\%($re)};
|
|
|
|
$app->hook(
|
|
after_dispatch => sub {
|
|
my $c = shift;
|
|
my $log = $app_log || $c->log;
|
|
my ($req, $res) = ($c->req, $c->res);
|
|
my $level = $res->is_server_error ? 'warn' : 'trace';
|
|
my $message = $log_format;
|
|
$message =~ s!$re!$extractors{$1}->($c, $req, $res)!ge;
|
|
$log->$level($message);
|
|
}
|
|
);
|
|
}
|
|
|
|
sub _add_syslog {
|
|
my ($self, $app, %config) = @_;
|
|
|
|
$config{facility} ||= $ENV{MOJO_SYSLOG_FACILITY} || LOG_USER;
|
|
$config{ident} ||= $ENV{MOJO_SYSLOG_IDENT} || $app->moniker;
|
|
$config{logopt} ||= $ENV{MOJO_SYSLOG_LOGOPT} || 'ndelay';
|
|
|
|
openlog @config{qw(ident logopt facility)};
|
|
$app->log->unsubscribe('message') if $config{only_syslog};
|
|
$app->log->unsubscribe(message => \&_syslog);
|
|
$app->log->on(message => \&_syslog);
|
|
}
|
|
|
|
sub _syslog {
|
|
my ($log, $level, @msg) = @_;
|
|
my $loglevel = $level eq 'trace' ? 'debug': $level;
|
|
|
|
syslog $PRIORITY{$loglevel}, '%s [MOJO] %s', uc $level, join ' ', @msg if $PRIORITY{$loglevel};
|
|
}
|
|
|
|
1;
|
|
|
|
=encoding utf8
|
|
|
|
=head1 NAME
|
|
|
|
steffen::MojoPlugin::Syslog - A plugin for enabling a Mojolicious app to log to syslog
|
|
original Mojolicious::Plugin::Syslog modified for mlands
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use Mojolicious::Lite;
|
|
plugin syslog => {facility => 'local0'};
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
L<steffen::MojoPlug::Syslog> is a L<Mojolicious> plugin for making
|
|
L<Mojo::Log> use L<Sys::Syslog> in addition (or instead) of file logging.
|
|
|
|
This can be useful when starting Hypnotoad through Systemd, but want simple
|
|
logging of error messages to syslog.
|
|
|
|
This plugin can also be used for only access logging, as an alternative to
|
|
L<Mojolicious::Plugin::AccessLog>. This is done by forcing L</enable> to
|
|
"0" and enabling L</access_log>.
|
|
|
|
=head1 METHODS
|
|
|
|
=head2 register
|
|
|
|
$app->plugin(steffen::MojoPlugin::Syslog => \%config);
|
|
$self->register($app, \%config);
|
|
|
|
Used to register the plugin in your L<Mojolicious> application. Available
|
|
config parameters are:
|
|
|
|
=over 2
|
|
|
|
=item * access_log
|
|
|
|
Used to enable logging of access to resources with a route enpoint. This means
|
|
that static files will not be logged, even if this option is enabled. It is
|
|
also possible to set the default value using the C<MOJO_SYSLOG_ACCESS_LOG>
|
|
environment variable.
|
|
|
|
This can be "v1", "v2" or a custom format. The default is currently "v1", but
|
|
that might change in the future.
|
|
|
|
.---------------------------------------.
|
|
| Version | Format |
|
|
|---------|-----------------------------|
|
|
| v1 | %H "%P" (%I) %C %M (%Ts) |
|
|
| v2 | %R %H %U %C "%F" "%A" (%Ts) |
|
|
'---------------------------------------'
|
|
|
|
Supported log variables:
|
|
|
|
.----------------------------------------------------.
|
|
| Variable | Value |
|
|
|----------|-----------------------------------------|
|
|
| %A | User-Agent request header |
|
|
| %C | Response status code, ex "200" |
|
|
| %F | Referer request header |
|
|
| %H | HTTP request method, ex "GET", "POST" |
|
|
| %I | Mojolicious request ID |
|
|
| %M | Response message, ex OK |
|
|
| %P | Request URL path |
|
|
| %R | Remote address |
|
|
| %T | Time in seconds for this request |
|
|
| %U | Absolute request URL, without user info |
|
|
'----------------------------------------------------'
|
|
|
|
=item * enable
|
|
|
|
Need to be true to activate this plugin. Will use the "MOJO_SYSLOG_ENABLE"
|
|
environment variable or default to true if L<Mojolicious/mode> is something
|
|
else than "development"
|
|
|
|
=item * facility
|
|
|
|
The syslog facility to use. Default to "MOJO_SYSLOG_FACILITY" environment
|
|
variable or default to "user".
|
|
|
|
The default is EXPERIMENTAL.
|
|
|
|
=item * ident
|
|
|
|
The syslog ident to use. Default to "MOJO_SYSLOG_IDENT" environment variable or
|
|
L<Mojolicious/moniker>.
|
|
|
|
=item * only_syslog
|
|
|
|
Set this to true to disabled the default L<Mojo::Log> logging to file/stderr.
|
|
|
|
=back
|
|
|
|
=head1 AUTHOR
|
|
|
|
Jan Henning Thorsen
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
|
|
|
Copyright (C) 2019, Jan Henning Thorsen.
|
|
|
|
This program is free software, you can redistribute it and/or modify it under
|
|
the terms of the Artistic License version 2.0.
|
|
|
|
=cut
|