File Coverage

blib/lib/Net/Statsd/Lite.pm
Criterion Covered Total %
statement 111 111 100.0
branch 14 16 87.5
condition n/a
subroutine 21 21 100.0
pod 4 6 66.6
total 150 154 97.4


line stmt bran cond sub pod time code
1             package Net::Statsd::Lite;
2              
3             # ABSTRACT: A lightweight StatsD client that supports multimetric packets
4              
5 27     27   1158790939 use v5.20;
  27         686  
6              
7 27     27   945 use Moo 1.000000;
  27         3230  
  27         1763  
8              
9 27     27   41448 use Devel::StrictMode;
  27         362  
  27         11911  
10 27     27   495 use IO::Socket 1.18 ();
  27         2121  
  27         1710  
11 27     27   20252 use MooX::TypeTiny;
  27         16120  
  27         568  
12 27     27   43831 use Ref::Util qw/ is_plain_hashref /;
  27         196  
  27         4682  
13 27     27   402 use Scalar::Util qw/ refaddr /;
  27         227  
  27         5071  
14 27     27   555 use Sub::Quote qw/ quote_sub /;
  27         152  
  27         5420  
15 27     27   280 use Sub::Util 1.40 qw/ set_subname /;
  27         1333  
  27         5857  
16 27         403 use Types::Common 2.000000 qw/ Bool Enum InstanceOf Int IntRange NonEmptySimpleStr
17             NumRange PositiveInt PositiveOrZeroInt PositiveOrZeroNum SimpleStr StrMatch
18 27     27   17109 /;
  27         7804489  
19              
20 27     27   172504 use namespace::autoclean;
  27         73  
  27         3333  
21              
22 27     27   24941 use experimental qw/ signatures /;
  27         61033  
  27         228  
23              
24             # RECOMMEND PREREQ: Ref::Util::XS
25             # RECOMMEND PREREQ: Type::Tiny::XS
26              
27             our $VERSION = 'v0.8.0';
28              
29              
30             has host => (
31             is => 'ro',
32             isa => NonEmptySimpleStr,
33             default => '127.0.0.1',
34             );
35              
36              
37             has port => (
38             is => 'ro',
39             isa => IntRange[ 0, 65535 ],
40             default => 8125,
41             );
42              
43              
44             has proto => (
45             is => 'ro',
46             isa => Enum [qw/ tcp udp /],
47             default => 'udp',
48             );
49              
50              
51             has prefix => (
52             is => 'ro',
53             isa => SimpleStr,
54             default => '',
55             );
56              
57              
58             has autoflush => (
59             is => 'ro',
60             isa => Bool,
61             default => 1,
62             );
63              
64             my %Buffers;
65              
66              
67             has max_buffer_size => (
68             is => 'ro',
69             isa => PositiveInt,
70             default => 512,
71             );
72              
73 23         96 has _socket => (
74             is => 'lazy',
75             isa => InstanceOf ['IO::Socket::INET'],
76 23     23   511 builder => sub($self) {
  23         76  
77 23 50       1134 my $sock = IO::Socket::INET->new(
78             PeerAddr => $self->host,
79             PeerPort => $self->port,
80             Proto => $self->proto,
81             ) or die "Failed to initialize socket: $!";
82 23         17899 return $sock;
83             },
84             handles => { _send => 'send' },
85             );
86              
87              
88             BEGIN {
89 27     27   444 my $class = __PACKAGE__;
90              
91 27         278 my %PROTOCOL = (
92             set_add => [ '|s', SimpleStr, ],
93             counter => [ '|c', Int, 1 ],
94             gauge => [ '|g', StrMatch[ qr{\A[\-\+]?[0-9]+\z} ] ],
95             histogram => [ '|h', PositiveOrZeroNum, 1 ],
96             meter => [ '|m', PositiveOrZeroNum ],
97             timing => [ '|ms', PositiveOrZeroNum, 1 ],
98             );
99              
100 27         266191 foreach my $name ( keys %PROTOCOL ) {
101              
102 162         230492 my $type = $PROTOCOL{$name}[1];
103 162         449 my $rate = $PROTOCOL{$name}[2];
104              
105 162         22136 my $code = q{ my ($self, $metric, $value, $opts) = @_; };
106              
107 162 100       15825 if (defined $rate) {
108 81         28334 $code .= q[ $opts = { rate => $opts } unless is_plain_hashref($opts); ] .
109             q[ my $rate = $opts->{rate} // 1; ]
110             }
111             else {
112 81         271 $code .= q[ $opts //= {}; ];
113             }
114              
115 162         428 if (STRICT) {
116              
117 162         817 $code .= $type->inline_assert('$value');
118              
119 162 100       56950 if (defined $rate) {
120 81         42319 my $range = NumRange[0,1];
121 81         176112 $code .= $range->inline_assert('$rate') . ';';
122             }
123             }
124              
125 162         31195 my $tmpl = $PROTOCOL{$name}[0];
126              
127 162 100       22480 if ( defined $rate ) {
128              
129 81         246 $code .= q/ if ($rate<1) {
130             $self->record_metric( $tmpl . '|@' . $rate, $metric, $value, $opts )
131             if rand() <= $rate;
132             } else {
133             $self->record_metric( $tmpl, $metric, $value, $opts ); } /;
134             }
135             else {
136              
137 81         217 $code .= q{$self->record_metric( $tmpl, $metric, $value, $opts );};
138              
139             }
140              
141 162         1298 quote_sub "${class}::${name}", $code,
142             { '$tmpl' => \$tmpl },
143             { no_defer => 1 };
144              
145             }
146              
147             # Alises for other Net::Statsd::Client or Etsy::StatsD
148              
149             {
150 27     27   40740 no strict 'refs'; ## no critic (ProhibitNoStrict)
  27         758  
  27         5958  
  27         54742  
151              
152 27         46308 *{"${class}::update"} = set_subname "update" => \&counter;
  27         22045  
153 27         40303 *{"${class}::timing_ms"} = set_subname "timing_ms" => \&timing;
  27         406  
154              
155             }
156              
157             }
158              
159 5     5 1 5002563 sub increment( $self, $metric, $opts = undef ) {
  5         26  
  5         19  
  5         39  
  5         44  
160 5         3005 $self->counter( $metric, 1, $opts );
161             }
162              
163 2     2 1 2004075 sub decrement( $self, $metric, $opts = undef ) {
  2         12  
  2         9  
  2         9  
  2         5  
164 2         147 $self->counter( $metric, -1, $opts );
165             }
166              
167              
168 27     27 1 18019408 sub record_metric( $self, $suffix, $metric, $value, $ ) {
  27         85  
  27         186  
  27         106  
  27         99  
  27         112  
169              
170 27         236 my $data = $self->prefix . $metric . ':' . $value . $suffix . "\n";
171              
172 27 100       228 if ( $self->autoflush ) {
173 21         1091 send( $self->_socket, $data, 0 );
174 21         2377 return;
175             }
176              
177 6         9 my $index = refaddr $self;
178 6         21 my $avail = $self->max_buffer_size - length( $Buffers{$index} );
179              
180 6 100       17 $self->flush if length($data) > $avail;
181              
182 6         38 $Buffers{$index} .= $data;
183              
184             }
185              
186              
187 29     29 1 82 sub flush($self) {
  29         81  
  29         58  
188 29         137 my $index = refaddr $self;
189 29 100       208 if ( $Buffers{$index} ne '' ) {
190 3         55 send( $self->_socket, $Buffers{$index}, 0 );
191 3         335 $Buffers{$index} = '';
192             }
193             }
194              
195 27     27 0 264055 sub BUILD($self, $) {
  27         103  
  27         64  
196 27         343 $Buffers{ refaddr $self } = '';
197             }
198              
199 27     27 0 2056740 sub DEMOLISH( $self, $is_global ) {
  27         83  
  27         97  
  27         92  
200              
201 27 50       142 return if $is_global;
202              
203 27         194 $self->flush;
204              
205 27         740 delete $Buffers{ refaddr $self };
206             }
207              
208              
209             1;
210              
211             __END__