File Coverage

blib/lib/Net/Statsd/Tiny.pm
Criterion Covered Total %
statement 68 75 90.6
branch 15 24 62.5
condition 4 6 66.6
subroutine 15 16 93.7
pod 4 5 80.0
total 106 126 84.1


line stmt bran cond sub pod time code
1             package Net::Statsd::Tiny;
2              
3             # ABSTRACT: A tiny StatsD client that supports multimetric packets
4              
5 24     24   7993464 use v5.12;
  24         72  
6              
7 24     24   96 use warnings;
  24         48  
  24         1944  
8              
9 24     24   96 use parent qw/ Class::Accessor::Fast /;
  24         48  
  24         144  
10              
11 24     24   66840 use Carp ();
  24         48  
  24         432  
12 24     24   72 use IO::Socket 1.18 ();
  24         384  
  24         408  
13 24     24   72 use Socket 2.026 ();
  24         192  
  24         6912  
14              
15             our $VERSION = 'v0.4.0';
16              
17              
18             __PACKAGE__->mk_ro_accessors(
19             qw/ host port proto prefix
20             autoflush max_buffer_size _socket /
21             );
22              
23             sub new {
24 23     23 1 361786457 my ( $class, @args ) = @_;
25              
26 23         1032 my %args;
27 23 50 33     3441 if ( ( @args == 1 ) && ( ref( $args[0] ) eq 'HASH' ) ) {
28 0         0 %args = %{ $args[0] };
  0         0  
29             }
30             else {
31 23         2998 %args = @args;
32             }
33              
34 23         3368 my %DEFAULTS = (
35             host => '127.0.0.1',
36             port => 8125,
37             proto => 'udp',
38             prefix => '',
39             autoflush => 1,
40             max_buffer_size => 512,
41             );
42              
43 23         964 foreach my $attr ( keys %DEFAULTS ) {
44 138 50       1487 next if exists $args{$attr};
45 0         0 $args{$attr} = $DEFAULTS{$attr};
46             }
47              
48 23 50       514 if ( my $socket = delete $args{socket} ) {
49 0         0 $args{_socket} = $socket;
50             }
51             else {
52             $args{_socket} = IO::Socket::INET->new(
53             PeerAddr => $args{host},
54             PeerPort => $args{port},
55             Proto => $args{proto},
56 23 50       1432 ) or die "Failed to initialize socket: $!";
57             }
58              
59 23         22752 my $self = $class->SUPER::new( \%args );
60              
61 23         1901 $self->{_buffer} = '';
62              
63 23         218 return $self;
64             }
65              
66              
67             BEGIN {
68 24     24   72 my $class = __PACKAGE__;
69              
70 24         120 my %PROTOCOL = (
71             set_add => 's',
72             counter => 'c',
73             gauge => 'g',
74             histogram => 'h',
75             meter => 'm',
76             timing => 'ms',
77             );
78              
79 24         72 foreach my $name ( keys %PROTOCOL ) {
80              
81 24     24   120 no strict 'refs'; ## no critic (ProhibitNoStrict)
  24         24  
  24         2808  
82              
83 144         192 my $suffix = '|' . $PROTOCOL{$name};
84              
85 144         360 *{"${class}::${name}"} = sub {
86 27     27   17011453 my ( $self, $metric, $value, $rate ) = @_;
87 27 100 100     766 if ( ( defined $rate ) && ( $rate < 1 ) ) {
88 4 100       473 $self->_record( $suffix . '|@' . $rate, $metric, $value )
89             if rand() < $rate;
90             }
91             else {
92 23         474 $self->_record( $suffix, $metric, $value );
93             }
94 144         552 };
95              
96             }
97              
98             # Alises for other Net::Statsd::Client or Etsy::StatsD
99              
100             {
101 24     24   264 no strict 'refs'; ## no critic (ProhibitNoStrict)
  24         24  
  24         1608  
  24         48  
102              
103 24         48 *{"${class}::update"} = \&counter;
  24         48  
104 24         48 *{"${class}::timing_ms"} = \&timing;
  24         7200  
105              
106             }
107              
108             }
109              
110             sub increment {
111 4     4 1 4001312 my ( $self, $metric, $rate ) = @_;
112 4         30 $self->counter( $metric, 1, $rate );
113             }
114              
115             sub decrement {
116 2     2 1 2000468 my ( $self, $metric, $rate ) = @_;
117 2         91 $self->counter( $metric, -1, $rate );
118             }
119              
120             sub _record {
121 24     24   104 my ( $self, $suffix, $metric, $value ) = @_;
122              
123 24 50       650 Carp::croak "malformed metric" if $metric =~ /[\N{U+00}-\N{U+1f}:|]/;
124 24 50       213 Carp::croak "malformed value" if $value =~ /[\N{U+00}-\N{U+1f}:|]/;
125              
126 24         6113 my $data = $self->prefix . $metric . ':' . $value . $suffix . "\n";
127              
128 24 100       1169 if ( $self->autoflush ) {
129 18         1382 $self->_socket->send( $data, 0 );
130 18         3786 return;
131             }
132              
133 6         178 my $avail = $self->max_buffer_size - length( $self->{_buffer} );
134 6 100       108 $self->flush if length($data) > $avail;
135              
136 6         60 $self->{_buffer} .= $data;
137             }
138              
139              
140              
141             sub flush {
142 2     2 1 11 my ($self) = @_;
143              
144 2 50       29 if ( length($self->{_buffer}) ) {
145 2         67 send( $self->_socket, $self->{_buffer}, 0 );
146 2         109 $self->{_buffer} = '';
147             }
148             }
149              
150             sub DEMOLISH {
151 0     0 0   my ( $self, $is_global ) = @_;
152              
153 0 0         return if $is_global;
154              
155 0           $self->flush;
156             }
157              
158              
159             1;
160              
161             __END__