File Coverage

lib/Catalyst/Plugin/ErrorCatcher/Email.pm
Criterion Covered Total %
statement 66 73 90.4
branch 16 28 57.1
condition 9 13 69.2
subroutine 16 17 94.1
pod 1 1 100.0
total 108 132 81.8


line stmt bran cond sub pod time code
1             package Catalyst::Plugin::ErrorCatcher::Email;
2             $Catalyst::Plugin::ErrorCatcher::Email::VERSION = '0.0.8.18';
3             {
4             $Catalyst::Plugin::ErrorCatcher::Email::DIST = 'Catalyst-Plugin-ErrorCatcher';
5             }
6             # ABSTRACT: an email emitter for Catalyst::Plugin::ErrorCatcher
7 7     7   78233 use strict;
  7         13  
  7         367  
8 7     7   46 use warnings;
  7         11  
  7         293  
9              
10 7     7   4327 use MIME::Lite;
  7         120179  
  7         315  
11 7     7   522 use Path::Class;
  7         31835  
  7         644  
12 7     7   2143 use Sys::Hostname;
  7         4376  
  7         7341  
13              
14             sub emit {
15 3     3 1 11 my ($class, $c, $output) = @_;
16 3         6 my ($config, $msg);
17              
18             # check and tidy the config
19 3         15 $config = _check_config($c, $config);
20              
21             # build the message
22 3         38 my %msg_config = (
23             From => $config->{from},
24             To => $config->{to},
25             Subject => $config->{subject},
26              
27             Type => 'TEXT',
28             Data => $output,
29             );
30             # add the optional Cc value
31 3 50       21 if (exists $config->{cc}) {
32 0         0 $msg_config{Cc} = $config->{cc};
33             }
34 3         58 $msg = MIME::Lite->new( %msg_config );
35              
36             # send the message
37 3         153150 _send_email($msg, $config);
38              
39 3         63 return;
40             }
41              
42             sub _check_config {
43 13     13   316423 my $c = shift;
44              
45 13         82 my $config = $c->_errorcatcher_c_cfg->{"Plugin::ErrorCatcher::Email"};
46              
47             # no config, no email
48             # we die so we count as a failure
49 13 50       337 if (not defined $config) {
50 0         0 die "Catalyst::Plugin::ErrorCatcher::Email has no configuration\n";
51             }
52              
53             # no To:, no email
54 13 50       65 if (not defined $config->{to}) {
55 0         0 die "Catalyst::Plugin::ErrorCatcher::Email has no To: address\n";
56             }
57              
58             # set a default From address
59 13 100       58 if (not defined $config->{from}) {
60 7         23 $config->{from} = $config->{to};
61             }
62              
63             # allow people to put Magic Tags into the subject line
64             # (nifty idea suggested by pecastro)
65             # only use them if we have a user subject *AND* they've asked us to work
66             # the magic on it
67 13 100 100     133 if (
68             defined $config->{subject}
69             && $config->{use_tags}
70             ) {
71 6         21 $config->{subject} =
72             _parse_tags($c, $config->{subject});
73             }
74              
75             # set a default Subject-Line
76 13 100       58 if (not defined $config->{subject}) {
77 1         8 $config->{subject} =
78             q{Error Report for }
79             . $c->config->{name}
80             ;
81 1         118 my $host = Sys::Hostname::hostname();
82 1 50       18 if (defined $host) {
83 1         5 $config->{subject} .=
84             q{ on }
85             . $host
86             ;
87             }
88             }
89              
90 13         36 return $config;
91             }
92              
93             # supported tags
94             # %h server hostname
95             # %f filename where error occurred
96             # %F filename where error occurred, leading directories trimmed
97             # %l line number where error occurred
98             # %p package where error occurred
99             # %V application version (if set)
100             sub _parse_tags {
101 6     6   9 my $c = shift;
102 6         10 my $subject = shift;
103              
104 6   50     24 my $first_frame = $c->_errorcatcher_first_frame || {};
105              
106 1 50   1   8 my %tag_of = (
107             '%h' => sub{Sys::Hostname::hostname()||'UnknownHost'},
108 0 0   0   0 '%f' => sub{$first_frame->{file}||'UnknownFile'},
109             '%F' => sub{
110 1   50 1   6 my $val=$first_frame->{file}||'UnknownFile';
111             # ideally replace with cross-platform directory separator
112 1         6 return _munge_path($val);
113             },
114 1 50   1   13 '%l' => sub{$first_frame->{line}||'UnknownLine'},
115 1 50   1   9 '%p' => sub{$first_frame->{pkg}||'UnknownPackage'},
116 1 50   1   10 '%V' => sub{$c->config->{version}||'UnknownVersion'},
117 1 50   1   7 '%n' => sub{$c->config->{name}||'UnknownAppName'},
118 6         232 );
119              
120 6         24 foreach my $tag (keys %tag_of) {
121 42         668 $subject =~ s{$tag}{&{$tag_of{$tag}}}eg;
  6         9  
  6         16  
122             }
123              
124 6         89 return $subject;
125             }
126              
127             sub _send_email {
128 3     3   10 my $msg = shift;
129 3         7 my $config = shift;
130              
131             # if there are specific send options, use them
132 3 50 33     31 if (exists $config->{send}{type} and exists $config->{send}{args}) {
133 0         0 $msg->send(
134             $config->{send}{type},
135 0         0 @{ $config->{send}{args} }
136             );
137 0         0 return;
138             }
139              
140             # use default send method
141 3         22 $msg->send;
142              
143 3         1183 return;
144             }
145              
146             sub _munge_path {
147 3     3   2129 my $path_string = shift;
148 3         29 my $path_spec = Path::Class::dir($path_string);
149 3         206 my $path_re = qr{^(?:lib|script)$};
150             #
151             # return $path_string
152             # if not grep { /${path_re}/ } $path_spec->dir_list;
153              
154 3         14 my @dirs = $path_spec->dir_list;
155 3         29 my @new_dirs = ();
156              
157             # work backwards through the path (it should be shorter)
158             # pop of everything until we match or exhaust the list
159             # (which we shouldn't because we already checked for a match)
160 3   100     41 while ( @dirs && $dirs[-1] !~ m/${path_re}/ ) {
161 15         80 unshift @new_dirs, pop @dirs;
162             }
163              
164             # build a path for the list we built up and return it
165 3         12 return Path::Class::dir(@new_dirs)->stringify;
166             }
167              
168             1;
169              
170             =pod
171              
172             =encoding UTF-8
173              
174             =head1 NAME
175              
176             Catalyst::Plugin::ErrorCatcher::Email - an email emitter for Catalyst::Plugin::ErrorCatcher
177              
178             =head1 VERSION
179              
180             version 0.0.8.18
181              
182             =head1 SYNOPSIS
183              
184             In your application:
185              
186             use Catalyst qw/-Debug StackTrace ErrorCatcher/;
187              
188             In your application configuration:
189              
190             <Plugin::ErrorCatcher>
191             # ...
192              
193             emit_module Catalyst::Plugin::ErrorCatcher::Email
194             </Plugin::ErrorCatcher>
195              
196             <Plugin::ErrorCatcher::Email>
197             to address@example.com
198              
199             # defaults to the To: address
200             from another@example.com
201              
202             # defaults to "Error Report For <AppName>"
203             subject Alternative Subject Line
204             </Plugin::ErrorCatcher::Email>
205              
206             SUBJECT LINE TAGS
207              
208             There are some tags which can be used in the subject line which will be
209             replaced with appropriate values. You need to enable tag parsing in your
210             configuration:
211              
212             <Plugin::ErrorCatcher::Email>
213             # ...
214             use_tags 1
215             </Plugin::ErrorCatcher::Email>
216              
217             Available tags are:
218              
219             %f filename where error occurred
220             %F filename where error occurred, leading directories trimmed
221             %h server hostname
222             %l line number where error occurred
223             %n application name
224             %p package where error occurred
225             %V application version
226              
227             Allowing you to set your subject like this:
228              
229             <Plugin::ErrorCatcher::Email>
230             # ...
231              
232             subject Report from: %h; %F, line %l
233             </Plugin::ErrorCatcher::Email>
234              
235             =head2 emit($class, $c, $output)
236              
237             Emit the error report by email.
238              
239             =head1 AUTHOR
240              
241             Chisel <chisel@chizography.net>
242              
243             =head1 COPYRIGHT AND LICENSE
244              
245             This software is copyright (c) 2015 by Chisel Wright.
246              
247             This is free software; you can redistribute it and/or modify it under
248             the same terms as the Perl 5 programming language system itself.
249              
250             =cut
251              
252             __END__
253              
254              
255             # vim: ts=8 sts=4 et sw=4 sr sta