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   163942 use strict;
  4         35  
  4         117  
6 4     4   20 use warnings;
  4         8  
  4         169  
7              
8             our $VERSION = '0.07';
9              
10 4     4   968 use IO::Socket::INET;
  4         42411  
  4         35  
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 { ## no critic (Subroutines::RequireArgUnpacking)
22 4     4 1 1324 my $classname = shift;
23 4   33     33 my $class = ref($classname) || $classname;
24 4 50       46 my %p = @_ % 2 ? %{$_[0]} : @_;
  0         0  
25              
26 4   50     29 $p{host} ||= '127.0.0.1';
27 4   100     17 $p{port} ||= 8125;
28 4   50     23 $p{namespace} ||= '';
29              
30 4         38 return bless \%p, $class;
31             }
32              
33             sub _socket {
34 57     57   85 my $self = shift;
35 57 100       1239 return $self->{_socket} if $self->{_socket};
36             $self->{_socket} = IO::Socket::INET->new(
37             PeerAddr => $self->{'host'},
38 4         41 PeerPort => $self->{'port'},
39             Proto => 'udp'
40             );
41 4         1853 return $self->{_socket};
42             }
43              
44             sub namespace {
45 2     2 1 2060 my $self = shift;
46 2 50       11 return $self->{'namespace'} unless @_;
47 2         9 $self->{'namespace'} = shift;
48             }
49              
50             sub increment {
51 13     13 1 1620 my $self = shift;
52 13         25 my $stat = shift;
53 13   100     51 my $opts = shift || {};
54 13         40 $self->count($stat, 1, $opts);
55             }
56              
57             sub decrement {
58 9     9 1 3619 my $self = shift;
59 9         20 my $stat = shift;
60 9   100     39 my $opts = shift || {};
61 9         27 $self->count($stat, -1, $opts);
62             }
63              
64             sub count {
65 25     25 1 1090 my $self = shift;
66 25         40 my $stat = shift;
67 25         38 my $count = shift;
68 25   100     69 my $opts = shift || {};
69 25         63 $self->send_stats($stat, $count, 'c', $opts);
70             }
71              
72             sub gauge {
73 9     9 1 3283 my $self = shift;
74 9         19 my $stat = shift;
75 9         15 my $value = shift;
76 9   100     54 my $opts = shift || {};
77 9         29 $self->send_stats($stat, $value, 'g', $opts);
78             }
79              
80             sub histogram {
81 2     2 1 20 my $self = shift;
82 2         5 my $stat = shift;
83 2         4 my $value = shift;
84 2   50     12 my $opts = shift || {};
85 2         14 $self->send_stats($stat, $value, 'h', $opts);
86             }
87              
88             sub timing {
89 12     12 1 3327 my $self = shift;
90 12         31 my $stat = shift;
91 12         24 my $ms = shift;
92 12   100     55 my $opts = shift || {};
93 12         93 $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 10 my $self = shift;
115 1         3 my $stat = shift;
116 1         2 my $value = shift;
117 1   50     14 my $opts = shift || {};
118 1         5 $self->send_stats($stat, $value, 's', $opts);
119             }
120              
121             sub event {
122 8     8 1 4286 my $self = shift;
123 8         15 my $title = shift;
124 8         15 my $text = shift;
125 8   100     34 my $opts = shift || {};
126              
127 8         32 my $event_string = format_event($title, $text, $opts);
128              
129 8         21 $self->send_to_socket($event_string);
130             }
131              
132             sub format_event {
133 8     8 0 15 my $title = shift;
134 8         11 my $text = shift;
135 8   50     23 my $opts = shift || {};
136              
137 8         19 my $tags = delete $opts->{tags};
138              
139 8         21 $title =~ s/\n/\\n/g;
140 8         14 $text =~ s/\n/\\n/g;
141              
142 8         43 my $event_string_data = sprintf "_e{%d,%d}:%s|%s", length($title), length($text), $title, $text;
143              
144 8         31 for my $opt (keys %$opts) {
145 3 50       19 if (my $key = $OPTS_KEYS{$opt}) {
146 3         21 $opts->{$opt} =~ s/|//g;
147 3         14 $event_string_data .= "|$key:$opts->{$opt}";
148             }
149             }
150              
151 8 100       34 if ($tags) {
152 4         11 $event_string_data .= "|#" . join ",", map { s/|//g; $_ } @$tags; ## no critic (ControlStructures::ProhibitMutatingListFunctions)
  8         36  
  8         28  
153             }
154              
155 8         22 return $event_string_data;
156             }
157              
158             sub send_stats {
159 49     49 0 85 my $self = shift;
160 49         73 my $stat = shift;
161 49         84 my $delta = shift;
162 49         88 my $type = shift;
163 49   50     107 my $opts = shift || {};
164              
165 49 100       128 my $sample_rate = defined $opts->{'sample_rate'} ? $opts->{'sample_rate'} : 1;
166 49 50 66     177 if ($sample_rate == 1 || rand() <= $sample_rate) {
167 49         132 $stat =~ s/::/./g;
168 49         120 $stat =~ s/[:|@]/_/g;
169 49         118 my $rate = '';
170 49 100       105 $rate = "|\@${sample_rate}" unless $sample_rate == 1;
171 49         96 my $tags = '';
172 49 100       120 $tags = "|#" . join(',', @{$opts->{'tags'}}) if $opts->{'tags'};
  17         67  
173 49         208 my $message = $self->{'namespace'} . "${stat}:${delta}|${type}${rate}${tags}";
174 49         114 return $self->send_to_socket($message);
175             }
176             }
177              
178             sub send_to_socket {
179 57     57 0 122 my ($self, $message) = @_;
180              
181 57         147 my $r = send($self->_socket(), $message, 0);
182 57 100       306 if (!defined $r) {
    50          
183 9         37 return 0;
184             } elsif ($r != length($message)) {
185 0         0 return 0;
186             }
187              
188 48         238 return 1;
189             }
190              
191             1;
192             __END__