File Coverage

blib/lib/Log/Fine/Handle/Email.pm
Criterion Covered Total %
statement 53 73 72.6
branch 13 42 30.9
condition 11 53 20.7
subroutine 12 14 85.7
pod 1 1 100.0
total 90 183 49.1


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Log::Fine::Handle::Email - Email log messages to one or more addresses
5              
6             =head1 SYNOPSIS
7              
8             Provides messaging to one or more email addresses.
9              
10             use Email::Sender::Simple qw(sendmail);
11             use Email::Sender::Transport::SMTP qw();
12             use Log::Fine;
13             use Log::Fine::Handle::Email;
14             use Log::Fine::Levels::Syslog;
15              
16             # Get a new logger
17             my $log = Log::Fine->logger("foo");
18              
19             # Create a formatter object for subject line
20             my $subjfmt = Log::Fine::Formatter::Template
21             ->new( name => 'template1',
22             template => "%%LEVEL%% : The angels have my blue box" );
23              
24             # Create a formatted msg template
25             my $msgtmpl = <
26             The program, $0, has encountered the following error condition:
27              
28             %%MSG%% at %%TIME%%
29              
30             Contact Operations at 1-800-555-5555 immediately!
31             EOF
32              
33             my $bodyfmt = Log::Fine::Formatter::Template
34             ->new( name => 'template2',
35             template => $msgtmpl );
36              
37             # Create an Email Handle
38             my $handle = Log::Fine::Handle::Email
39             ->new( name => 'email0',
40             mask => LOGMASK_EMERG | LOGMASK_ALERT | LOGMASK_CRIT,
41             subject_formatter => $subjfmt,
42             body_formatter => $bodyfmt,
43             header_from => "alerts@example.com",
44             header_to => [ "critical_alerts@example.com" ],
45             envelope =>
46             { to => [ "critical_alerts@example.com" ],
47             from => "alerts@example.com",
48             transport =>
49             Email::Sender::Transport::SMTP->new({ host => 'smtp.example.com' }),
50             }
51             );
52              
53             # Register the handle
54             $log->registerHandle($handle);
55              
56             # Log something
57             $log->log(CRIT, "Beware the weeping angels");
58              
59             =head1 DESCRIPTION
60              
61             Log::Fine::Handle::Email provides formatted message delivery to one or
62             more email addresses. The intended use is for programs that need to
63             alert a user in the event of a critical condition. Conceivably, the
64             destination address could be a pager or cell phone.
65              
66             =head2 Implementation Details
67              
68             Log::Fine::Handle::Email uses the L framework for
69             delivery of emails. Users who wish to use Log::Fine::Handle::Email
70             are I encouraged to read the following documentation:
71              
72             =over
73              
74             =item * L
75              
76             =item * L
77              
78             =item * L
79              
80             =back
81              
82             Be especially mindful of the following environment variables as they
83             will take precedence when defining a transport:
84              
85             =over
86              
87             =item * C
88              
89             =item * C
90              
91             =item * C
92              
93             =back
94              
95             See L for further details.
96              
97             =head2 Constructor Parameters
98              
99             The following parameters can be passed to
100             Log::Fine::Handle::Email->new();
101              
102             =over
103              
104             =item * name
105              
106             [optional] Name of this object (see L). Will be auto-set if
107             not specified.
108              
109             =item * mask
110              
111             Mask to set the handle to (see L)
112              
113             =item * subject_formatter
114              
115             A Log::Fine::Formatter object. Will be used to format the Email
116             Subject Line.
117              
118             =item * body_formatter
119              
120             A Log::Fine::Formatter object. Will be used to format the body of the
121             message.
122              
123             =item * header_from
124              
125             String containing text to be placed in "From" header of generated
126             email.
127              
128             =item * header_to
129              
130             String containing text to be placed in "To" header of generated email.
131             Optionally, this can be an array ref containing multiple addresses
132              
133             =item * envelope
134              
135             [optional] hash ref containing envelope information for email:
136              
137             =over 8
138              
139             =item + to
140              
141             array ref containing one or more destination addresses
142              
143             =item + from
144              
145             String containing email sender
146              
147             =item + transport
148              
149             An L object. See L
150             for further details.
151              
152             =back
153              
154             =back
155              
156             =cut
157              
158 2     2   132182 use strict;
  2         9  
  2         103  
159 2     2   16 use warnings;
  2         5  
  2         100  
160              
161             package Log::Fine::Handle::Email;
162              
163 2     2   84 use 5.008_003; # Email::Sender requires Moose which requires 5.8.3
  2         9  
  2         108  
164              
165 2     2   21 use base qw( Log::Fine::Handle );
  2         5  
  2         1004  
166              
167             #use Data::Dumper;
168 2     2   2234 use Email::Sender::Simple qw(try_to_sendmail);
  2         513690  
  2         21  
169 2     2   667 use Email::Simple;
  2         7  
  2         64  
170 2     2   14 use Mail::RFC822::Address qw(valid validlist);
  2         4  
  2         176  
171 2     2   13 use Log::Fine;
  2         5  
  2         47  
172 2     2   12 use Log::Fine::Formatter;
  2         5  
  2         55  
173 2     2   12 use Sys::Hostname;
  2         5  
  2         2286  
174              
175             our $VERSION = $Log::Fine::Handle::VERSION;
176              
177             =head1 METHODS
178              
179             =head2 msgWrite
180              
181             Sends given message via Email::Sender module. Note that
182             L will be called should there be a failure of
183             delivery.
184              
185             See L
186              
187             =cut
188              
189             sub msgWrite
190             {
191              
192 1     1 1 3 my $self = shift;
193 1         3 my $lvl = shift;
194 1         4 my $msg = shift;
195 1         2 my $skip = shift;
196              
197 1         11 my $email =
198             Email::Simple->create(
199             header => [
200             To => $self->{header_to},
201             From => $self->{header_from},
202             Subject =>
203             $self->{subject_formatter}->format($lvl, "", $skip),
204             ],
205             body => $self->{body_formatter}->format($lvl, $msg, $skip),
206             );
207              
208             # Set X-Mailer
209 1         6311 $email->header_set("X-Mailer",
210             sprintf("%s ver %s", ref $self, $VERSION));
211              
212 1 50       54 $self->_error("Unable to deliver email: $_")
213             unless (try_to_sendmail($email, $self->{envelope}));
214              
215             } # msgWrite()
216              
217             # --------------------------------------------------------------------
218              
219             ##
220             # Initializes our object
221              
222             sub _init
223             {
224              
225 1     1   3 my $self = shift;
226              
227             # Perform any necessary upper class initializations
228 1         12 $self->SUPER::_init();
229              
230             # Make sure envelope is defined
231 1   50     9 $self->{envelope} ||= {};
232              
233             # Validate From address
234 1 50 33     17 if (not defined $self->{header_from}) {
    50          
235 0         0 $self->{header_from} =
236             printf("%s@%s", $self->_userName(), $self->_hostName());
237             } elsif (defined $self->{header_from}
238             and not valid($self->{header_from})) {
239 0         0 $self->_fatal(
240             "{header_from} must be a valid RFC 822 Email Address");
241             }
242              
243             # Validate To address
244 1 50       2924 $self->_fatal( "{header_to} must be either an array ref containing "
245             . "valid email addresses or a string representing a "
246             . "valid email address")
247             unless (defined $self->{header_to});
248              
249             # Check for array ref
250 1 50       8 if (ref $self->{header_to} eq "ARRAY") {
    50          
251              
252 0 0       0 if (validlist($self->{header_to})) {
253 0         0 $self->{header_to} = join(",", @{ $self->{header_to} });
  0         0  
254             } else {
255 0         0 $self->_fatal( "{header_to} must contain valid "
256             . "RFC 822 email addresses");
257             }
258              
259             } elsif (not valid($self->{header_to})) {
260 0         0 $self->_fatal( "{header_to} must contain a valid "
261             . "RFC 822 email address");
262             }
263              
264             # Validate subject formatter
265 1 50 33     187 $self->_fatal( "{subject_formatter} must be a valid "
      33        
      33        
266             . "Log::Fine::Formatter object")
267             unless ( defined $self->{subject_formatter}
268             and ref $self->{subject_formatter}
269             and UNIVERSAL::can($self->{subject_formatter}, 'isa')
270             and $self->{subject_formatter}->isa("Log::Fine::Formatter"));
271              
272             # Validate body formatter
273 1 50 0     25 $self->_fatal( "{body_formatter} must be a valid "
      33        
      33        
      33        
274             . "Log::Fine::Formatter object : "
275             . ref $self->{body_formatter} || "{undef}")
276             unless ( defined $self->{body_formatter}
277             and ref $self->{body_formatter}
278             and UNIVERSAL::can($self->{body_formatter}, 'isa')
279             and $self->{body_formatter}->isa("Log::Fine::Formatter"));
280              
281             # Grab a ref to envelope
282 1         4 my $envelope = $self->{envelope};
283              
284             # Check Envelope Transport
285 1 50       5 if (defined $envelope->{transport}) {
286 0         0 my $transtype = ref $envelope->{transport};
287 0 0       0 $self->_fatal( "{envelope}->{transport} must be a valid "
288             . "Email::Sender::Transport object : $transtype")
289             unless ($transtype =~ /^Email\:\:Sender\:\:Transport/);
290             }
291              
292             # Check Envelope To
293 1 50       5 if (defined $envelope->{to}) {
294 0 0 0     0 $self->_fatal( "{envelope}->{to} must be an "
295             . "array ref containing one or more valid "
296             . "RFC 822 email addresses")
297             unless (ref $envelope->{to} eq "ARRAY"
298             and validlist($envelope->{to}));
299             }
300              
301             # Check envelope from
302 1 50 33     7 if (defined $envelope->{from} and $envelope->{from} =~ /\w/) {
303 0 0       0 $self->_fatal( "{envelope}->{from} must be a "
304             . "valid RFC 822 Email Address")
305             unless valid($envelope->{from});
306             } else {
307 1         6 $envelope->{from} = $self->{header_from};
308             }
309              
310             # Validate subject formatter
311 1 50 33     12 $self->_fatal( "{subject_formatter} must be a valid "
312             . "Log::Fine::Formatter object")
313             unless (defined $self->{subject_formatter}
314             and $self->{subject_formatter}->isa("Log::Fine::Formatter"));
315              
316             # Validate body formatter
317 1 50 0     11 $self->_fatal( "{body_formatter} must be a valid "
      33        
318             . "Log::Fine::Formatter object : "
319             . ref $self->{body_formatter} || "{undef}")
320             unless (defined $self->{body_formatter}
321             and $self->{body_formatter}->isa("Log::Fine::Formatter"));
322              
323 1         5 return $self;
324              
325             } # _init()
326              
327             ##
328             # Getter/Setter for hostname
329              
330             sub _hostName
331             {
332              
333 0     0     my $self = shift;
334              
335             # Should {_fullHost} be already cached, then return it,
336             # otherwise get hostname, cache it, and return
337 0 0 0       $self->{_fullHost} = hostname() || "{undef}"
      0        
338             unless (defined $self->{_fullHost} and $self->{_fullHost} =~ /\w/);
339              
340 0           return $self->{_fullHost};
341              
342             } # _hostName()
343              
344             ##
345             # Getter/Setter for user name
346              
347             sub _userName
348             {
349              
350 0     0     my $self = shift;
351              
352             # Should {_userName} be already cached, then return it,
353             # otherwise get the user name, cache it, and return
354 0 0 0       if (defined $self->{_userName} and $self->{_userName} =~ /\w/) {
    0          
355 0           return $self->{_userName};
356             } elsif ($self->{use_effective_id}) {
357 0 0 0       $self->{_userName} =
      0        
358             ($^O eq "MSWin32")
359             ? $ENV{EUID} || 0
360             : getpwuid($>) || "nobody";
361             } else {
362 0   0       $self->{_userName} = getlogin() || getpwuid($<) || "nobody";
363             }
364              
365 0           return $self->{_userName};
366              
367             } # _userName()
368              
369             =head1 BUGS
370              
371             Please report any bugs or feature requests to
372             C, or through the web interface at
373             L.
374             I will be notified, and then you'll automatically be notified of progress on
375             your bug as I make changes.
376              
377             =head1 SUPPORT
378              
379             You can find documentation for this module with the perldoc command.
380              
381             perldoc Log::Fine
382              
383             You can also look for information at:
384              
385             =over 4
386              
387             =item * AnnoCPAN: Annotated CPAN documentation
388              
389             L
390              
391             =item * CPAN Ratings
392              
393             L
394              
395             =item * RT: CPAN's request tracker
396              
397             L
398              
399             =item * Search CPAN
400              
401             L
402              
403             =back
404              
405             =head1 AUTHOR
406              
407             Christopher M. Fuhrman, C<< >>
408              
409             =head1 SEE ALSO
410              
411             L, L, L
412              
413             =head1 COPYRIGHT & LICENSE
414              
415             Copyright (c) 2011-2013 Christopher M. Fuhrman,
416             All rights reserved.
417              
418             This program is free software licensed under the...
419              
420             The BSD License
421              
422             The full text of the license can be found in the
423             LICENSE file included with this module.
424              
425             =cut
426              
427             1; # End of Log::Fine::Handle::Email