File Coverage

blib/lib/Log/Dispatch/Twilio.pm
Criterion Covered Total %
statement 66 68 97.0
branch 8 10 80.0
condition 6 8 75.0
subroutine 12 12 100.0
pod 2 2 100.0
total 94 100 94.0


line stmt bran cond sub pod time code
1             package Log::Dispatch::Twilio;
2              
3 1     1   387350 use strict;
  1         8  
  1         31  
4 1     1   6 use warnings;
  1         2  
  1         28  
5 1     1   6 use base qw(Log::Dispatch::Output);
  1         1  
  1         529  
6 1     1   35240 use HTTP::Status qw(:is);
  1         4884  
  1         205  
7 1     1   8 use List::Util qw(min);
  1         2  
  1         59  
8 1     1   6 use POSIX qw(ceil);
  1         2  
  1         9  
9 1     1   2072 use WWW::Twilio::API;
  1         38850  
  1         56  
10 1     1   10 use namespace::clean;
  1         3  
  1         10  
11              
12             our $VERSION = '0.03';
13             our $MAX_TWILIO_LENGTH = 160; # max length of SMS message allowed by Twilio
14              
15             sub new {
16 10     10 1 34235 my $proto = shift;
17 10   33     49 my $class = ref($proto) || $proto;
18 10         21 my $self = bless {}, $class;
19 10         68 $self->_basic_init(@_);
20 10         990 $self->_twilio_init(@_);
21 6         17 return $self;
22             }
23              
24             sub _twilio_init {
25 10     10   15 my $self = shift;
26 10         32 my %args = @_;
27              
28             # Grab and store required Twilio specific parameters
29 10         22 foreach my $p (qw( account_sid auth_token from to )) {
30 34 100       83 unless ($args{$p}) {
31 4         39 die __PACKAGE__ . " requires '$p' parameter.\n";
32             }
33 30         71 $self->{$p} = $args{$p};
34             }
35              
36             # Additional parameters
37 6   100     23 my $max = $args{max_messages} || 1;
38 6 50       15 if ($max <= 0) {
39 0         0 die __PACKAGE__ . " requires 'max_messages' to be >= 1.\n";
40             }
41 6         16 $self->{max_messages} = $max;
42             }
43              
44             sub log_message {
45 2     2 1 6315 my $self = shift;
46 2         5 my %msg = @_;
47              
48             my $twilio = WWW::Twilio::API->new(
49             AccountSid => $self->{account_sid},
50             AuthToken => $self->{auth_token},
51 2         12 );
52              
53 2         65 my @to_send = $self->_expand_message($msg{message});
54 2         6 foreach my $entry (@to_send) {
55             my $res = $twilio->POST('SMS/Messages',
56             From => $self->{from},
57             To => $self->{to},
58 2         8 Body => $entry,
59             );
60              
61 2 50       25 unless ($res) {
62 0         0 warn "Unable to send log message via Twilio; $!\n";
63             }
64              
65 2 100       21 unless (is_success($res->{code})) {
66             warn "Failed to send log message via Twilio; "
67 1         18 . $res->{content} . "\n";
68             }
69             }
70             }
71              
72             sub _expand_message {
73 7     7   10884 my $self = shift;
74 7         14 my $msg = shift;
75 7         14 my $max = $self->{max_messages};
76 7         11 my @results;
77              
78             # If its a long message, *and* we're configured for multiple messages,
79             # generate multiple messages.
80 7         14 my $msg_length = length($msg);
81 7 100 100     30 if (($max > 1) && ($msg_length > $MAX_TWILIO_LENGTH)) {
82             # Figure out how many messages we're actually going to generate
83 2         7 my $max_prefix_length = length("$max/$max: ");
84 2         6 my $how_much = $MAX_TWILIO_LENGTH - $max_prefix_length;
85 2         18 my $num_messages = min($max, ceil($msg_length / $how_much));
86              
87             # Create entries w/prefixes
88 2         8 for my $idx (1 .. $num_messages) {
89 5         12 my $prefix = "$idx/$num_messages: ";
90 5         13 my $entry = substr($msg, 0, $how_much, '');
91 5         19 $entry =~ s{^\s+|\s+$}{}g; # trim leading/trailing ws
92 5         15 push @results, $prefix . $entry;
93             }
94             }
95             # Otherwise, its just a single message.
96             else {
97 5         16 my $entry = substr($msg, 0, $MAX_TWILIO_LENGTH, '');
98 5         26 $entry =~ s{^\s+|\s+$}{}g; # trim leading/trailing ws
99 5         13 push @results, $entry;
100             }
101              
102 7         25 return @results;
103             }
104              
105             1;
106              
107             =for stopwords SMS Auth
108              
109             =head1 NAME
110              
111             Log::Dispatch::Twilio - Log output via Twilio SMS Message
112              
113             =head1 SYNOPSIS
114              
115             use Log::Dispatch;
116              
117             my $logger = Log::Dispatch->new(
118             outputs => [
119             [ 'Twilio',
120             min_level => 'emergency',
121             account_sid => '<your-twilio-account-sid>',
122             auth_token => '<your-twilio-auth-token>',
123             from => '<number-to-send-msg-from>',
124             to => '<number-to-send-msg-to>',
125             ],
126             ],
127             );
128              
129             =head1 DESCRIPTION
130              
131             This module provides a C<Log::Dispatch> output that sends log messages via
132             Twilio.
133              
134             While you probably don't want I<every> logged message from your application to
135             go out via Twilio, I find it particularly useful to set it up as part of my
136             C<Log::Dispatch> configuration for critical/emergency errors. In the event
137             that something dire happens, I'll receive an SMS message through Twilio right
138             away.
139              
140             =head2 Required Options
141              
142             When adding Twilio output to your L<Log::Dispatch> configuration, the following
143             options are required:
144              
145             =over
146              
147             =item account_sid
148              
149             Your Twilio "Account Sid".
150              
151             =item auth_token
152              
153             Your Twilio "Auth Token".
154              
155             =item from
156              
157             The telephone number from which the SMS messages will appear to be sent from.
158              
159             This number must be a number attached to your Twilio account.
160              
161             =item to
162              
163             The telephone number to which the SMS messages will be sent to.
164              
165             =back
166              
167             =head2 Additional Options
168              
169             =over
170              
171             =item max_messages (default 1)
172              
173             Maximum number of SMS messages that can be generated from a single logged
174             item. Defaults to 1.
175              
176             =back
177              
178             =head1 METHODS
179              
180             =over
181              
182             =item new
183              
184             Constructor.
185              
186             Implemented as per the L<Log::Dispatch::Output> interface.
187              
188             =item log_message
189              
190             Logs message, by sending it as an SMS message to the configured number via the
191             Twilio API.
192              
193             Implemented as per the L<Log::Dispatch::Output> interface.
194              
195             =back
196              
197             =head1 AUTHOR
198              
199             Graham TerMarsch (cpan@howlingfrog.com)
200              
201             =head1 COPYRIGHT
202              
203             Copyright (C) 2012, Graham TerMarsch. All Rights Reserved.
204              
205             This is free software, you can redistribute it and/or modify it under the
206             Artistic-2.0 license.
207              
208             =head1 SEE ALSO
209              
210             L<Log::Dispatch>,
211             L<http://www.twilio.com/>.
212              
213             =cut