File Coverage

blib/lib/Log/Handler/Output/Sendmail.pm
Criterion Covered Total %
statement 62 118 52.5
branch 15 52 28.8
condition 5 15 33.3
subroutine 11 14 78.5
pod 6 6 100.0
total 99 205 48.2


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Log::Handler::Output::Sendmail - Log messages with sendmail.
4              
5             =head1 SYNOPSIS
6              
7             use Log::Handler::Output::Sendmail;
8              
9             my $email = Log::Handler::Output::Sendmail->new(
10             from => 'bar@foo.example',
11             to => 'foo@bar.example',
12             subject => 'your subject',
13             );
14              
15             $email->log(message => $message);
16              
17             =head1 DESCRIPTION
18              
19             With this output module it's possible to log messages via C.
20              
21             =head1 METHODS
22              
23             =head2 new()
24              
25             Call C to create a new Log::Handler::Output::Sendmail object.
26              
27             The following options are possible:
28              
29             =over 4
30              
31             =item B
32              
33             The sender address (From).
34              
35             =item B
36              
37             The receipient address (To).
38              
39             =item B
40              
41             Carbon Copy (Cc).
42              
43             =item B
44              
45             Blind Carbon Copy (Bcc)
46              
47             =item B
48              
49             The subject of the mail.
50              
51             =item B
52              
53             This option is identical with C.
54              
55             =item B
56              
57             With this options it's possible to set your own header.
58              
59             my $email = Log::Handler::Output::Sendmail->new(
60             from => 'bar@foo.example',
61             to => 'foo@bar.example',
62             header => 'Content-Type: text/plain; charset= UTF-8',
63             );
64              
65             Or
66              
67             my $email = Log::Handler::Output::Sendmail->new(
68             header => {
69             From => 'bar@foo.example',
70             To => 'foo@bar.example',
71             Subject => 'my subject',
72             'Content-Type' => text/plain; charset= UTF-8',
73             }
74             );
75              
76             Or
77              
78             my $email = Log::Handler::Output::Sendmail->new(
79             header => [
80             'From: bar@foo.example',
81             'To: foo@bar.example',
82             'Subject: my subject',
83             'Content-Type: text/plain; charset= UTF-8',
84             ]
85             );
86              
87             =item B
88              
89             The default is set to C.
90              
91             =item B
92              
93             Parameters for C.
94              
95             The default is set to C<-t>.
96              
97             =item B
98              
99             Set the maximum size of the buffer in bytes.
100              
101             All messages will be buffered and if C is exceeded
102             the buffer is flushed and the messages will be send as email.
103              
104             The default is set to 1048576 bytes.
105              
106             Set 0 if you want no buffering and send a mail
107             for each log message.
108              
109             =item B
110              
111             Set 1 if you want to enable debugging.
112              
113             The messages can be fetched with $SIG{__WARN__}.
114              
115             =back
116              
117             =head2 log()
118              
119             Call C if you want to log a message as email.
120              
121             $email->log(message => "this message will be mailed");
122              
123             If you pass the level then its placed into the subject:
124              
125             $email->log(message => "foo", level => "INFO");
126             $email->log(message => "bar", level => "ERROR");
127             $email->log(message => "baz", level => "DEBUG");
128              
129             The lowest level is used:
130              
131             Subject: ERROR ...
132              
133             You can pass the level with C by setting
134              
135             message_pattern => '%L'
136              
137             =head2 flush()
138              
139             Call C if you want to flush the buffered messages.
140              
141             =head2 validate()
142              
143             Validate a configuration.
144              
145             =head2 reload()
146              
147             Reload with a new configuration.
148              
149             =head2 errstr()
150              
151             This function returns the last error message.
152              
153             =head1 DESTROY
154              
155             C is defined and called C.
156              
157             =head1 PREREQUISITES
158              
159             Carp
160             Params::Validate
161              
162             =head1 EXPORTS
163              
164             No exports.
165              
166             =head1 REPORT BUGS
167              
168             Please report all bugs to .
169              
170             If you send me a mail then add Log::Handler into the subject.
171              
172             =head1 AUTHOR
173              
174             Jonny Schulz .
175              
176             =head1 COPYRIGHT
177              
178             Copyright (C) 2007-2009 by Jonny Schulz. All rights reserved.
179              
180             This program is free software; you can redistribute it and/or
181             modify it under the same terms as Perl itself.
182              
183             =cut
184              
185             package Log::Handler::Output::Sendmail;
186              
187 1     1   70050 use strict;
  1         13  
  1         31  
188 1     1   6 use warnings;
  1         1  
  1         25  
189 1     1   5 use Carp;
  1         2  
  1         68  
190 1     1   575 use Params::Validate qw();
  1         9334  
  1         1917  
191              
192             our $VERSION = "0.07";
193             our $ERRSTR = "";
194             our $TEST = 0; # is needed to disable flush() for tests
195              
196             my %LEVEL_BY_STRING = (
197             DEBUG => 7,
198             INFO => 6,
199             NOTICE => 5,
200             WARNING => 4,
201             ERROR => 3,
202             CRITICAL => 2,
203             ALERT => 1,
204             EMERGENCY => 0,
205             FATAL => 0,
206             );
207              
208             sub new {
209 1     1 1 597 my $class = shift;
210 1         5 my $opts = $class->_validate(@_);
211 1         3 my $self = bless $opts, $class;
212              
213 1         5 $self->{message} = "";
214 1         4 $self->{length} = 0;
215              
216 1         3 return $self;
217             }
218              
219             sub log {
220 3     3 1 25 my $self = shift;
221 3         7 my $class = ref($self);
222 3 50       11 my $message = @_ > 1 ? {@_} : shift;
223 3         6 my $length = length($message->{message});
224              
225 3 50       8 if (!$self->{maxsize}) {
226 0 0       0 if ($self->{debug}) {
227 0         0 warn "$class: maxsize disabled, no buffering";
228             }
229              
230 0 0       0 if ($message->{level}) {
231 0         0 $self->{level} = $message->{level};
232             }
233              
234 0         0 $self->{message} = $message->{message};
235 0         0 return $self->_sendmail;
236             }
237              
238 3 50       9 if ($length + $self->{length} > $self->{maxsize}) {
239 0 0       0 if ($self->{debug}) {
240 0         0 warn "$class: maxsize of $self->{maxsize} reached";
241             }
242 0         0 $self->flush;
243             }
244              
245 3 50 33     14 if ($message->{level} && !$self->{level}) {
    50 33        
246 0         0 $self->{level} = $message->{level};
247             } elsif ($self->{level} && $message->{level}) {
248 0         0 my $slevel = $self->{level};
249 0         0 my $mlevel = $message->{level};
250              
251 0 0       0 if ($LEVEL_BY_STRING{$slevel} > $LEVEL_BY_STRING{$mlevel}) {
252 0         0 $self->{level} = $message->{level};
253             }
254             }
255              
256 3         5 $self->{message} .= $message->{message};
257 3         7 $self->{length} += $length;
258              
259 3 50       17 if ($self->{debug}) {
260 0         0 warn "$class: buffer new message, length $length";
261 0         0 warn "$class: buffer length: $self->{length}";
262             }
263              
264 3         9 return 1;
265             }
266              
267             sub flush {
268 2     2 1 5 my $self = shift;
269              
270 2 50 33     7 if ($TEST || !$self->{message}) {
271 2         132 return 1;
272             }
273              
274 0         0 return $self->_sendmail;
275             }
276              
277             sub validate {
278 1     1 1 2 my $self = shift;
279 1         2 my $opts = ();
280              
281 1         2 eval { $opts = $self->_validate(@_) };
  1         4  
282              
283 1 50       5 if ($@) {
284 0         0 return $self->_raise_error($@);
285             }
286              
287 1         3 return $opts;
288             }
289              
290             sub reload {
291 1     1 1 946 my $self = shift;
292 1         4 my $opts = $self->validate(@_);
293              
294 1         6 $self->flush;
295              
296 1         4 foreach my $key (keys %$opts) {
297 8         14 $self->{$key} = $opts->{$key};
298             }
299              
300 1         3 $self->{message} = "";
301 1         3 $self->{length} = 0;
302              
303 1         4 return 1;
304             }
305              
306             sub errstr {
307 0     0 1 0 return $ERRSTR;
308             }
309              
310             sub DESTROY {
311 1     1   413 my $self = shift;
312 1         3 $self->flush;
313             }
314              
315             #
316             # private stuff
317             #
318              
319             sub _sendmail {
320 0     0   0 my $self = shift;
321 0         0 my $class = ref($self);
322 0         0 my $header = $self->{header};
323 0         0 my $sendmail = $self->{sendmail};
324              
325 0 0       0 if ($self->{params}) {
326 0         0 $sendmail .= " $self->{params}";
327             }
328              
329 0 0       0 if ($self->{debug}) {
330 0         0 warn "$class: call <$sendmail>";
331 0         0 warn "$class: header <$header>";
332 0         0 warn "$class: message $self->{length} bytes";
333             }
334              
335 0 0       0 if ($self->{level}) {
336 0         0 $header =~ s/Subject:(.)/Subject: $self->{level}:$1/;
337 0         0 $self->{level} = "";
338             }
339              
340 0 0       0 open my $fh, "|$sendmail"
341             or return $self->_raise_error("unable to execute '$self->{sendmail}' - $!");
342              
343 0         0 my $ret = print $fh $header, "\n", $self->{message};
344              
345 0         0 close $fh;
346              
347 0         0 $self->{message} = "";
348 0         0 $self->{length} = 0;
349              
350 0 0       0 if (!$ret) {
351 0         0 return $self->_raise_error("unable to write to stdin - $!");
352             }
353              
354 0         0 return 1;
355             }
356              
357             sub _validate {
358 2     2   4 my $class = shift;
359              
360 2         119 my %options = Params::Validate::validate(@_, {
361             sender => {
362             type => Params::Validate::SCALAR,
363             optional => 1,
364             },
365             from => {
366             type => Params::Validate::SCALAR,
367             optional => 1,
368             },
369             to => {
370             type => Params::Validate::SCALAR,
371             optional => 1,
372             },
373             cc => {
374             type => Params::Validate::SCALAR,
375             optional => 1,
376             },
377             bcc => {
378             type => Params::Validate::SCALAR,
379             optional => 1,
380             },
381             subject => {
382             type => Params::Validate::SCALAR,
383             optional => 1,
384             },
385             header => {
386             type => Params::Validate::SCALAR
387             | Params::Validate::ARRAYREF
388             | Params::Validate::HASHREF,
389             optional => 1,
390             },
391             maxsize => {
392             type => Params::Validate::SCALAR,
393             regex => qr/^\d+\z/,
394             default => 1048576,
395             },
396             sendmail => {
397             type => Params::Validate::SCALAR,
398             default => "/usr/sbin/sendmail",
399             },
400             params => {
401             type => Params::Validate::SCALAR,
402             default => "-t",
403             },
404             debug => {
405             type => Params::Validate::SCALAR,
406             regex => qr/^[01]\z/,
407             default => 0,
408             },
409             });
410              
411 2 0 33     23 if (!$TEST && !-x $options{sendmail}) {
412 0         0 Carp::croak "'$options{sendmail}' is not executable";
413             }
414              
415 2 50       6 if ($options{subject}) {
416 2         7 $options{subject} =~ s/\n/ /g;
417 2         4 $options{subject} =~ s/(.{78})/$1\n /;
418              
419 2 50       7 if (length($options{subject}) > 998) {
420 0         0 warn "Subject to long for email!";
421 0         0 $options{subject} = substr($options{subject}, 0, 998);
422             }
423             }
424              
425 2 50       6 if (ref($options{header})) {
426 0         0 my $header = ();
427              
428 0 0       0 if (ref($options{header}) eq "HASH") {
    0          
429 0         0 foreach my $n (keys %{ $options{header} }) {
  0         0  
430 0         0 $header .= "$n: $options{header}{$n}\n";
431             }
432             } elsif (ref($options{header}) eq "ARRAY") {
433 0         0 foreach my $h (@{ $options{header} }) {
  0         0  
434 0         0 $header .= "$h\n";
435             }
436             }
437              
438 0         0 $options{header} = $header;
439             }
440              
441 2 50 33     6 if ($options{header} && $options{header} !~ /(?:\015|\012)\z/) {
442 0         0 $options{header} .= "\n";
443             }
444              
445 2         5 foreach my $opt (qw/from to cc bcc subject/) {
446 10 100       21 if ($options{$opt}) {
447 6         23 $options{header} .= ucfirst($opt).": $options{$opt}\n";
448             }
449             }
450              
451 2 50       6 if ($options{sender}) {
452 0         0 $options{sendmail} .= " -f $options{sender}";
453             }
454              
455 2         5 return \%options;
456             }
457              
458             sub _raise_error {
459 0     0     $ERRSTR = $_[1];
460 0           return undef;
461             }
462              
463             1;