File Coverage

blib/lib/Mojolicious/Plugin/Syslog.pm
Criterion Covered Total %
statement 46 46 100.0
branch 13 18 72.2
condition 13 30 43.3
subroutine 18 18 100.0
pod 1 1 100.0
total 91 113 80.5


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Syslog;
2 2     2   3793 use Mojo::Base 'Mojolicious::Plugin';
  2         6  
  2         17  
3              
4 2     2   1186 use Sys::Syslog qw(:standard :macros);
  2         8657  
  2         1361  
5              
6             our $VERSION = '0.04';
7              
8             my %PRIORITY = (
9             debug => LOG_DEBUG,
10             error => LOG_ERR,
11             fatal => LOG_CRIT,
12             info => LOG_INFO,
13             warn => LOG_WARNING,
14             );
15              
16             sub register {
17 4     4 1 300 my ($self, $app, $config) = @_;
18              
19             $self->_add_syslog($app, %$config)
20             if $config->{enable} // $ENV{MOJO_SYSLOG_ENABLE}
21 4 100 66     39 // $app->mode ne 'development';
      33        
22              
23             $self->_add_access_log($app, %$config)
24 4 50 66     35 if $config->{access_log} // $ENV{MOJO_SYSLOG_ACCESS_LOG};
25             }
26              
27             sub _add_access_log {
28 4     4   13 my ($self, $app, %config) = @_;
29              
30 4   50     16 my $log_format = $config{access_log} || $ENV{MOJO_SYSLOG_ACCESS_LOG} || 'v1';
31 4 100       18 $log_format = '%H "%P" (%I) %C %M (%Ts)' if $log_format =~ /^v?1$/;
32 4 100       14 $log_format = '[%I] %R %H %U %C %M "%F" "%A" (%Ts)' if $log_format =~ /^v?2$/;
33              
34             $app->hook(
35             before_routes => sub {
36 6     6   59108 shift->helpers->timing->begin(__PACKAGE__);
37             }
38 4         33 );
39              
40             my %extractors = (
41 2 50   2   9 A => sub { $_[1]->headers->user_agent || '' },
42 6     6   25 C => sub { $_[2]->code },
43 2 50   2   18 F => sub { $_[1]->headers->referrer || '' },
44 6     6   33 H => sub { $_[1]->method },
45 3     3   12 I => sub { $_[1]->request_id },
46 3 50   3   10 M => sub { $_[2]->message || $_[2]->default_message($_[2]->code) },
47 5     5   51 P => sub { $_[1]->url->path->to_abs_string },
48 2     2   7 R => sub { $_[0]->tx->remote_address },
49 3   50 3   13 T => sub { $_[0]->helpers->timing->elapsed(__PACKAGE__) // 0 },
50 2     2   31 U => sub { $_[1]->url->to_abs->to_string },
51 4         133 );
52              
53 4         39 my $re = join '|', sort keys %extractors;
54 4         83 $re = qr{\%($re)};
55              
56             $app->hook(
57             after_dispatch => sub {
58 6     6   297014 my $c = shift;
59 6         32 my ($req, $res) = ($c->req, $c->res);
60 6 100       310 my $level = $res->is_server_error ? 'warn' : 'info';
61 6         146 my $message = $log_format;
62 6         101 $message =~ s!$re!$extractors{$1}->($c, $req, $res)!ge;
  34         1380  
63 6         1300 $c->app->log->$level($message);
64             }
65 4         25 );
66             }
67              
68             sub _add_syslog {
69 1     1   3 my ($self, $app, %config) = @_;
70              
71 1   33     9 $config{facility} ||= $ENV{MOJO_SYSLOG_FACILITY} || LOG_USER;
      33        
72 1   33     10 $config{ident} ||= $ENV{MOJO_SYSLOG_IDENT} || $app->moniker;
      33        
73 1   50     8 $config{logopt} ||= $ENV{MOJO_SYSLOG_LOGOPT} || 'ndelay,pid';
      33        
74              
75 1         17 openlog @config{qw(ident logopt facility)};
76 1 50       18 $app->log->unsubscribe('message') if $config{only_syslog};
77 1         96 $app->log->unsubscribe(message => \&_syslog);
78 1         26 $app->log->on(message => \&_syslog);
79             }
80              
81             sub _syslog {
82 4     4   3037 my ($log, $level, @msg) = @_;
83 4         78 syslog $PRIORITY{$level}, '%s', join ' ', @msg;
84             }
85              
86             1;
87              
88             =encoding utf8
89              
90             =head1 NAME
91              
92             Mojolicious::Plugin::Syslog - A plugin for enabling a Mojolicious app to log to syslog
93              
94             =head1 SYNOPSIS
95              
96             use Mojolicious::Lite;
97             plugin syslog => {facility => 'local0'};
98              
99             =head1 DESCRIPTION
100              
101             L is a L plugin for making
102             L use L in addition (or instead) of file logging.
103              
104             This can be useful when starting Hypnotoad through Systemd, but want simple
105             logging of error messages to syslog.
106              
107             This plugin can also be used for only access logging, as an alternative to
108             L. This is done by forcing L to
109             "0" and enabling L.
110              
111             =head1 METHODS
112              
113             =head2 register
114              
115             $app->plugin(syslog => \%config);
116             $self->register($app, \%config);
117              
118             Used to register the plugin in your L application. Available
119             config parameters are:
120              
121             =over 2
122              
123             =item * access_log
124              
125             Used to enable logging of access to resources with a route enpoint. This means
126             that static files will not be logged, even if this option is enabled.
127              
128             This can be "v1" or a string. Will use the default format, if "v1" is specified:
129              
130             %H "%P" (%I) %C %M (%Ts)
131             | | | | | \- Time in seconds for this request
132             | | | | \- Response message
133             | | | \- Response code
134             | | \- A unique identified for this request
135             | \- The path requested
136             \- The HTTP method used
137              
138             Default to the "MOJO_SYSLOG_ACCESS_LOG" environment variable or disabled by
139             default.
140              
141             The default format is EXPERIMENTAL.
142              
143             Supported log variables:
144              
145             | Variable | Value |
146             |----------|-----------------------------------------|
147             | %A | User-Agent request header |
148             | %C | Response status code, ex "200" |
149             | %F | Referer request header |
150             | %H | HTTP request method, ex "GET", "POST" |
151             | %I | Mojolicious request ID |
152             | %M | Response message, ex OK |
153             | %P | Request URL path |
154             | %R | Remote address |
155             | %T | Time in seconds for this request |
156             | %U | Absolute request URL, without user info |
157              
158             =item * enable
159              
160             Need to be true to activate this plugin. Will use the "MOJO_SYSLOG_ENABLE"
161             environment variable or default to true if L is something
162             else than "development"
163              
164             =item * facility
165              
166             The syslog facility to use. Default to "MOJO_SYSLOG_FACILITY" environment
167             variable or default to "user".
168              
169             The default is EXPERIMENTAL.
170              
171             =item * ident
172              
173             The syslog ident to use. Default to "MOJO_SYSLOG_IDENT" environment variable or
174             L.
175              
176             =item * only_syslog
177              
178             Set this to true to disabled the default L logging to file/stderr.
179              
180             =back
181              
182             =head1 AUTHOR
183              
184             Jan Henning Thorsen
185              
186             =head1 COPYRIGHT AND LICENSE
187              
188             Copyright (C) 2019, Jan Henning Thorsen.
189              
190             This program is free software, you can redistribute it and/or modify it under
191             the terms of the Artistic License version 2.0.
192              
193             =cut