File Coverage

blib/lib/Mojo/Log/Role/AttachLogger.pm
Criterion Covered Total %
statement 38 75 50.6
branch 13 50 26.0
condition 5 13 38.4
subroutine 8 13 61.5
pod 1 1 100.0
total 65 152 42.7


line stmt bran cond sub pod time code
1             package Mojo::Log::Role::AttachLogger;
2              
3 3     3   2009 use Role::Tiny;
  3         8  
  3         21  
4 3     3   464 use Carp ();
  3         6  
  3         43  
5 3     3   1523 use Import::Into ();
  3         7959  
  3         65  
6 3     3   21 use Module::Runtime ();
  3         8  
  3         39  
7 3     3   14 use Scalar::Util ();
  3         6  
  3         2548  
8              
9             our $VERSION = 'v1.0.2';
10              
11             our @CARP_NOT = 'Mojolicious::Plugin::Log::Any';
12              
13             requires 'on';
14              
15             sub attach_logger {
16 4     4 1 1784 my ($self, $logger, $opt) = @_;
17 4 50       16 Carp::croak 'No logger passed' unless defined $logger;
18 4         8 my ($category, $prepend);
19 4 100       14 if (ref $opt) {
20 3         11 ($category, $prepend) = @$opt{'category','prepend_level'};
21             } else {
22 1         3 $category = $opt;
23             }
24 4   100     14 $category //= 'Mojo::Log';
25 4   100     19 $prepend //= 1;
26            
27 4         5 my $do_log;
28 4 100 0     41 if (Scalar::Util::blessed($logger)) {
    50          
    0          
    0          
29 3 50 33     113 if ($logger->isa('Log::Any::Proxy')) {
    50          
    50          
    50          
30             $do_log = sub {
31 0     0   0 my ($self, $level, @msg) = @_;
32 0 0       0 my $msg = @msg > 1 ? join("\n", @msg) : $msg[0];
33 0 0       0 $msg = "[$level] $msg" if $prepend;
34 0         0 $logger->$level($msg);
35 0         0 };
36             } elsif ($logger->isa('Log::Dispatch')) {
37             $do_log = sub {
38 0     0   0 my ($self, $level, @msg) = @_;
39 0 0       0 my $msg = @msg > 1 ? join("\n", @msg) : $msg[0];
40 0 0       0 $msg = "[$level] $msg" if $prepend;
41 0 0       0 $level = 'critical' if $level eq 'fatal';
42 0         0 $logger->log(level => $level, message => $msg);
43 0         0 };
44             } elsif ($logger->isa('Log::Dispatchouli') or $logger->isa('Log::Dispatchouli::Proxy')) {
45             $do_log = sub {
46 0     0   0 my ($self, $level, @msg) = @_;
47 0 0       0 my $msg = @msg > 1 ? join("\n", @msg) : $msg[0];
48 0 0       0 $msg = "[$level] $msg" if $prepend;
49 0 0       0 return $logger->log_debug($msg) if $level eq 'debug';
50             # hacky but we don't want to use log_fatal because it throws an
51             # exception, we want to allow real exceptions to propagate, and we
52             # can't localize a call to set_muted
53 0 0 0     0 local $logger->{muted} = 0 if $level eq 'fatal' and $logger->get_muted;
54 0         0 $logger->log($msg);
55 0         0 };
56             } elsif ($logger->isa('Mojo::Log')) {
57             $do_log = sub {
58 45     45   111650 my ($self, $level, @msg) = @_;
59 45         175 $logger->$level(@msg);
60 3         16 };
61             } else {
62 0         0 Carp::croak "Unsupported logger object class " . ref($logger);
63             }
64             } elsif ($logger eq 'Log::Any') {
65 1         6 require Log::Any;
66 1         7 $logger = Log::Any->get_logger(category => $category);
67             $do_log = sub {
68 10     10   4256 my ($self, $level, @msg) = @_;
69 10 100       32 my $msg = @msg > 1 ? join("\n", @msg) : $msg[0];
70 10 50       27 $msg = "[$level] $msg" if $prepend;
71 10         47 $logger->$level($msg);
72 1         4918 };
73             } elsif ($logger eq 'Log::Log4perl') {
74 0         0 require Log::Log4perl;
75 0         0 $logger = Log::Log4perl->get_logger($category);
76             $do_log = sub {
77 0     0   0 my ($self, $level, @msg) = @_;
78 0 0       0 my $msg = @msg > 1 ? join("\n", @msg) : $msg[0];
79 0 0       0 $msg = "[$level] $msg" if $prepend;
80 0         0 $logger->$level($msg);
81 0         0 };
82             } elsif ($logger eq 'Log::Contextual' or "$logger"->isa('Log::Contextual')) {
83 0         0 Module::Runtime::require_module("$logger");
84 0         0 Log::Contextual->VERSION('0.008001');
85 0         0 my %functions = map { ($_ => "slog_$_") } qw(debug info warn error fatal);
  0         0  
86 0         0 "$logger"->import::into(ref($self), values %functions);
87             $do_log = sub {
88 0     0   0 my ($self, $level, @msg) = @_;
89 0 0       0 my $msg = @msg > 1 ? join("\n", @msg) : $msg[0];
90 0 0       0 $msg = "[$level] $msg" if $prepend;
91 0         0 $self->can($functions{$level})->($msg);
92 0         0 };
93             } else {
94 0         0 Carp::croak "Unsupported logger class $logger";
95             }
96            
97 4         25 $self->on(message => $do_log);
98            
99 4         36 return $self;
100             }
101              
102             1;
103              
104             =head1 NAME
105              
106             Mojo::Log::Role::AttachLogger - Use other loggers for Mojo::Log
107              
108             =head1 SYNOPSIS
109              
110             use Mojo::Log;
111             my $log = Mojo::Log->with_roles('+AttachLogger')->new->unsubscribe('message');
112            
113             # Log::Any
114             use Log::Any::Adapter {category => 'Mojo::Log'}, 'Syslog';
115             $log->attach_logger('Log::Any', 'Some::Category');
116            
117             # Log::Contextual
118             use Log::Contextual::WarnLogger;
119             use Log::Contextual -logger => Log::Contextual::WarnLogger->new({env_prefix => 'MYAPP'});
120             $log->attach_logger('Log::Contextual');
121            
122             # Log::Dispatch
123             use Log::Dispatch;
124             my $logger = Log::Dispatch->new(outputs => ['File::Locked',
125             min_level => 'warning',
126             filename => '/path/to/file.log',
127             mode => 'append',
128             newline => 1,
129             callbacks => sub { my %p = @_; '[' . localtime() . '] ' . $p{message} },
130             ]);
131             $log->attach_logger($logger);
132            
133             # Log::Dispatchouli
134             use Log::Dispatchouli;
135             my $logger = Log::Dispatchouli->new({ident => 'MyApp', facility => 'daemon', to_file => 1});
136             $log->attach_logger($logger);
137            
138             # Log::Log4perl
139             use Log::Log4perl;
140             Log::Log4perl->init('/path/to/log.conf');
141             $log->attach_logger('Log::Log4perl', 'Some::Category');
142            
143             =head1 DESCRIPTION
144              
145             L is a L role for L that
146             redirects log messages to an external logging framework. L
147             currently recognizes the strings C, C,
148             C, and objects of the classes C,
149             C, C, and C.
150              
151             The default L event handler is not suppressed by
152             L, so if you want to suppress the default behavior, you
153             should unsubscribe from the message event first. Unsubscribing from the message
154             event will also remove any loggers attached by L.
155              
156             Since L 8.06, the L event will not be sent
157             for messages below the log level set in the L object, so the
158             attached logger will only receive log messages exceeding the configured level.
159              
160             L can be used to attach a logger to the
161             L application logger and suppress the default message event
162             handler.
163              
164             =head1 METHODS
165              
166             L composes the following methods.
167              
168             =head2 attach_logger
169              
170             $log = $log->attach_logger($logger, $options);
171              
172             Subscribes to L and passes log messages to the given
173             logging framework or object. The second argument is optionally a category
174             (default C) or hashref of options. The log level will be prepended
175             to the message in square brackets (except when passing to another L
176             object, or L is false).
177              
178             The following loggers are recognized:
179              
180             =over
181              
182             =item Log::Any
183              
184             The string C will use a global L logger with the specified
185             category (defaults to C).
186              
187             =item Log::Any::Proxy
188              
189             A L object can be passed directly and will be used for logging
190             in the standard manner, using the object's existing category.
191              
192             =item Log::Contextual
193              
194             The string C will use the global L logger.
195             Package loggers are not supported. Note that L
196             may be difficult to use with L logging due to the asynchronous
197             nature of the dispatch cycle.
198              
199             =item Log::Dispatch
200              
201             A L object can be passed to be used for logging. The C
202             log level will be mapped to C.
203              
204             =item Log::Dispatchouli
205              
206             A L object can be passed to be used for logging. The
207             C log level will log messages even if the object is C, but an
208             exception will not be thrown as L normally does.
209              
210             =item Log::Log4perl
211              
212             The string C will use a global L logger with the
213             specified category (defaults to C).
214              
215             =item Mojo::Log
216              
217             Another L object can be passed to be used for logging.
218              
219             =back
220              
221             The following options are supported:
222              
223             =over
224              
225             =item category
226              
227             Category name (defaults to Mojo::Log).
228              
229             =item prepend_level
230              
231             Prepend the log level to messages in the form C<[$level]> (default for
232             non-L loggers). Set false to disable.
233              
234             =back
235              
236             =head1 BUGS
237              
238             Report any issues on the public bugtracker.
239              
240             =head1 AUTHOR
241              
242             Dan Book
243              
244             =head1 COPYRIGHT AND LICENSE
245              
246             This software is Copyright (c) 2017 by Dan Book.
247              
248             This is free software, licensed under:
249              
250             The Artistic License 2.0 (GPL Compatible)
251              
252             =head1 SEE ALSO
253              
254             L, L, L, L,
255             L, L