File Coverage

blib/lib/DataDog/DogStatsd.pm
Criterion Covered Total %
statement 99 101 98.0
branch 17 22 77.2
condition 23 32 71.8
subroutine 17 17 100.0
pod 10 13 76.9
total 166 185 89.7


line stmt bran cond sub pod time code
1             package DataDog::DogStatsd;
2              
3             # ABSTRACT: A Perl client for DogStatsd
4              
5 4     4   165197 use strict;
  4         19  
  4         119  
6 4     4   20 use warnings;
  4         7  
  4         154  
7              
8             our $VERSION = '0.06';
9              
10 4     4   1046 use IO::Socket::INET;
  4         43246  
  4         30  
11              
12             my %OPTS_KEYS = (
13             date_happened => 'd',
14             hostname => 'h',
15             aggregation_key => 'k',
16             priority => 'p',
17             source_type_name => 's',
18             alert_type => 't'
19             );
20              
21             sub new {
22 4     4 1 1468 my $classname = shift;
23 4   33     33 my $class = ref( $classname ) || $classname;
24 4 50       58 my %p = @_ % 2 ? %{$_[0]} : @_;
  0         0  
25              
26 4   50     32 $p{host} ||= '127.0.0.1';
27 4   100     20 $p{port} ||= 8125;
28 4   50     24 $p{namespace} ||= '';
29              
30 4         35 return bless \%p, $class;
31             }
32              
33             sub _socket {
34 57     57   88 my $self = shift;
35 57 100       1463 return $self->{_socket} if $self->{_socket};
36             $self->{_socket} = IO::Socket::INET->new(
37             PeerAddr => $self->{'host'},
38 4         40 PeerPort => $self->{'port'},
39             Proto => 'udp'
40             );
41 4         1875 return $self->{_socket};
42             }
43              
44             sub namespace {
45 2     2 1 2233 my $self = shift;
46 2 50       12 return $self->{'namespace'} unless @_;
47 2         7 $self->{'namespace'} = shift;
48             }
49              
50             sub increment {
51 13     13 1 1622 my $self = shift;
52 13         22 my $stat = shift;
53 13   100     48 my $opts = shift || {};
54 13         39 $self->count( $stat, 1, $opts );
55             }
56              
57             sub decrement {
58 9     9 1 3606 my $self = shift;
59 9         19 my $stat = shift;
60 9   100     39 my $opts = shift || {};
61 9         25 $self->count( $stat, -1, $opts );
62             }
63              
64             sub count {
65 25     25 1 1124 my $self = shift;
66 25         42 my $stat = shift;
67 25         35 my $count = shift;
68 25   100     71 my $opts = shift || {};
69 25         63 $self->send_stats( $stat, $count, 'c', $opts );
70             }
71              
72             sub gauge {
73 9     9 1 3314 my $self = shift;
74 9         47 my $stat = shift;
75 9         19 my $value = shift;
76 9   100     49 my $opts = shift || {};
77 9         34 $self->send_stats( $stat, $value, 'g', $opts );
78             }
79              
80             sub histogram {
81 2     2 1 9 my $self = shift;
82 2         5 my $stat = shift;
83 2         5 my $value = shift;
84 2   50     10 my $opts = shift || {};
85 2         8 $self->send_stats( $stat, $value, 'h', $opts );
86             }
87              
88             sub timing {
89 12     12 1 3413 my $self = shift;
90 12         26 my $stat = shift;
91 12         22 my $ms = shift;
92 12   100     46 my $opts = shift || {};
93 12         95 $self->send_stats( $stat, sprintf("%d", $ms), 'ms', $opts );
94             }
95              
96             # Reports execution time of the provided block using {#timing}.
97             #
98             # @param [String] stat stat name
99             # @param [Hash] opts the options to create the metric with
100             # @option opts [Numeric] :sample_rate sample rate, 1 for always
101             # @option opts [Array] :tags An array of tags
102             # @yield The operation to be timed
103             # @see #timing
104             # @example Report the time (in ms) taken to activate an account
105             # $statsd.time('account.activate') { @account.activate! }
106             ##def time(stat, opts={})
107             ## start = Time.now
108             ## result = yield
109             ## timing(stat, ((Time.now - start) * 1000).round, opts)
110             ## result
111             ##end
112              
113             sub set {
114 1     1 1 7 my $self = shift;
115 1         3 my $stat = shift;
116 1         2 my $value = shift;
117 1   50     5 my $opts = shift || {};
118 1         3 $self->send_stats( $stat, $value, 's', $opts );
119             }
120              
121             sub event {
122 8     8 1 4335 my $self = shift;
123 8         17 my $title = shift;
124 8         14 my $text = shift;
125 8   100     49 my $opts = shift || {};
126              
127 8         26 my $event_string = format_event( $title, $text, $opts );
128              
129 8         23 $self->send_to_socket($event_string);
130             }
131              
132             sub format_event {
133 8     8 0 15 my $title = shift;
134 8         14 my $text = shift;
135 8   50     32 my $opts = shift || {};
136              
137 8         18 my $tags = delete $opts->{tags};
138              
139 8         23 $title =~ s/\n/\\n/g;
140 8         16 $text =~ s/\n/\\n/g;
141              
142 8         46 my $event_string_data = sprintf "_e{%d,%d}:%s|%s",
143             length($title), length($text), $title, $text;
144              
145 8         30 for my $opt ( keys %$opts ) {
146 3 50       13 if ( my $key = $OPTS_KEYS{$opt} ) {
147 3         22 $opts->{$opt} =~ s/|//g;
148 3         15 $event_string_data .= "|$key:$opts->{$opt}";
149             }
150             }
151              
152 8 100       25 if ($tags) {
153 4         10 $event_string_data .= "|#" . join ",", map { s/|//g; $_ } @$tags;
  8         37  
  8         27  
154             }
155              
156 8         19 return $event_string_data;
157             }
158              
159             sub send_stats {
160 49     49 0 80 my $self = shift;
161 49         76 my $stat = shift;
162 49         73 my $delta = shift;
163 49         69 my $type = shift;
164 49   50     102 my $opts = shift || {};
165              
166 49 100       124 my $sample_rate = defined $opts->{'sample_rate'} ? $opts->{'sample_rate'} : 1;
167 49 50 66     180 if( $sample_rate == 1 || rand() <= $sample_rate ) {
168 49         125 $stat =~ s/::/./g;
169 49         122 $stat =~ s/[:|@]/_/g;
170 49         111 my $rate = '';
171 49 100       127 $rate = "|\@${sample_rate}" unless $sample_rate == 1;
172 49         75 my $tags = '';
173 49 100       110 $tags = "|#".join(',',@{$opts->{'tags'}}) if $opts->{'tags'};
  17         61  
174 49         167 my $message = $self->{'namespace'}."${stat}:${delta}|${type}${rate}${tags}";
175 49         107 return $self->send_to_socket( $message );
176             }
177             }
178              
179             sub send_to_socket {
180 57     57 0 116 my ($self, $message) = @_;
181              
182 57         129 my $r = send($self->_socket(), $message, 0);
183 57 100       302 if (! defined $r) {
    50          
184 9         37 return 0;
185             } elsif ($r != length($message)) {
186 0         0 return 0;
187             }
188              
189 48         232 return 1;
190             }
191              
192             1;
193             __END__