File Coverage

blib/lib/Collectd/Plugin/Write/Message/Passing.pm
Criterion Covered Total %
statement 58 80 72.5
branch 4 14 28.5
condition 2 11 18.1
subroutine 15 16 93.7
pod 3 3 100.0
total 82 124 66.1


line stmt bran cond sub pod time code
1             package Collectd::Plugin::Write::Message::Passing;
2 3     3   6605 use strict;
  3         9  
  3         129  
3 3     3   18 use warnings;
  3         6  
  3         102  
4 3     3   138 use Collectd ();
  3         16  
  3         54  
5 3     3   19 use JSON;
  3         8  
  3         24  
6 3     3   6217 use Module::Runtime qw/ require_module /;
  3         5847  
  3         19  
7 3     3   2633 use String::RewritePrefix ();
  3         47521  
  3         88  
8 3     3   3508 use Try::Tiny;
  3         11128  
  3         218  
9 3     3   3013 use namespace::clean;
  3         69319  
  3         26  
10              
11             our $OUTPUT;
12             our %CONFIG;
13              
14             sub _clean_value {
15 3     3   3 my $val = shift;
16 3 50       22 scalar(@$val) > 1 ? $val : $val->[0];
17             }
18              
19             sub _flatten_item {
20 3     3   5 my $item = shift;
21 3         2 my $val;
22 3 100       4 if (scalar(@{$item->{children}})) {
  3         11  
23 1         2 $val = [ map { my $i = $_; _flatten_item($i) } @{$item->{children}} ];
  1         1  
  1         4  
  1         3  
24             }
25             else {
26 2         2 $val = $item->{values};
27             }
28             return {
29 3         8 $item->{key} => _clean_value($val)
30             }
31             }
32              
33             sub config {
34 1     1 1 970 my @items = @{ $_[0]->{children} };
  1         4  
35 1         3 foreach my $item (@items) {
36 2         4 %CONFIG = ( %{_flatten_item($item)} , %CONFIG );
  2         5  
37             }
38             }
39              
40             sub _output {
41 1 50   1   4 if (!$OUTPUT) {
42             try {
43 1         33 my $out = $CONFIG{outputclass}->new(
44 1     1   70 %{ $CONFIG{outputoptions} }
45             );
46 0         0 $OUTPUT = $CONFIG{encoderclass}->new(
47 0         0 %{ $CONFIG{encoderoptions} },
48             output_to => $out,
49             );
50             }
51             catch {
52 1     1   25 Collectd::plugin_log(Collectd::LOG_WARNING, "Got exception building outputs: $_ - DISABLING");
53 1         152 undef $OUTPUT;
54             }
55 1         18 }
56 1         20 return $OUTPUT;
57             }
58              
59             sub init {
60 0 0   0 1 0 if (!$CONFIG{outputclass}) {
61 0         0 Collectd::plugin_log(Collectd::LOG_WARNING, "No outputclass config for Message::Passing plugin - disabling");
62 0         0 return 0;
63             }
64 0         0 $CONFIG{outputclass} = String::RewritePrefix->rewrite(
65             { '' => 'Message::Passing::Output::', '+' => '' },
66             $CONFIG{outputclass}
67             );
68 0 0       0 if (!eval { require_module($CONFIG{outputclass}) }) {
  0         0  
69 0         0 Collectd::plugin_log(Collectd::LOG_WARNING, "Could not load outputclass=" . $CONFIG{OutputClass} . " error: $@");
70 0         0 return 0;
71             }
72 0   0     0 $CONFIG{encoderclass} ||= '+Message::Passing::Filter::Encoder::JSON';
73 0         0 $CONFIG{encoderclass} = String::RewritePrefix->rewrite(
74             { '' => 'Message::Passing::Filter::Encoder::', '+' => '' },
75             $CONFIG{encoderclass}
76             );
77 0 0       0 if (!eval { require_module($CONFIG{encoderclass}) }) {
  0         0  
78 0         0 Collectd::plugin_log(Collectd::LOG_WARNING, "Could not load encoderclass=" . $CONFIG{EncoderClass} . " error: $@");
79 0         0 return 0;
80             }
81 0   0     0 $CONFIG{outputoptions} ||= {};
82 0   0     0 $CONFIG{encoderoptions} ||= {};
83 0 0       0 _output() || return 0;
84 0         0 return 1;
85             }
86              
87             my %_TYPE_LOOKUP = (
88             0 => 'COUNTER',
89             1 => 'GAUGE',
90             );
91             sub write {
92 1     1 1 13466 my ($name, $types, $data) = @_;
93             # ["load",[{"min":0,"max":100,"name":"shortterm","type":1},{"min":0,"max":100,"name":"midterm","type":1},{"min":0,"max":100,"name":"longterm","type":1}],{"plugin":"load","time":1341655869.22588,"type":"load","values":[0.41,0.13,0.08],"interval":10,"host":"ldn-dev-tdoran.youdevise.com"}]
94             # "transport.tx.size",[{"min":0,"max":0,"name":"transport.tx.size","type":0}],{"plugin":"ElasticSearch","time":1341655799.77979,"type":"transport.tx.size","values":[9725948078],"interval":10,"host":"ldn-dev-tdoran.youdevise.com"}
95 1         3 my @values;
96 1         3 foreach my $val (@{ $data->{values} }) {
  1         6  
97 1         4 my $meta = shift(@$types);
98 1         3 $meta->{value} = $val;
99 1         4 push(@values, $meta);
100 1   33     18 $meta->{type} = $_TYPE_LOOKUP{$meta->{type}} || $meta->{type};
101             }
102 1         6 $data->{values} = \@values;
103 1   50     6 my $output = _output() || return 0;
104 0           $output->consume($data);
105 0           return 1;
106             }
107              
108             Collectd::plugin_register(
109             Collectd::TYPE_INIT, 'Write::Message::Passing', 'Collectd::Plugin::Write::Message::Passing::init'
110             );
111             Collectd::plugin_register(
112             Collectd::TYPE_CONFIG, 'Write::Message::Passing', 'Collectd::Plugin::Write::Message::Passing::config'
113             );
114             Collectd::plugin_register(
115             Collectd::TYPE_WRITE, 'Write::Message::Passing', 'Collectd::Plugin::Write::Message::Passing::write'
116             );
117              
118             1;
119              
120             =head1 NAME
121              
122             Collectd::Plugin::Write::Message::Passing - Write collectd metrics via Message::Passing
123              
124             =head1 SYNOPSIS
125              
126            
127             Globals true
128            
129            
130             BaseName "Collectd::Plugin"
131             LoadPlugin "Write::Message::Passing"
132            
133             # MANDATORY - You MUST configure an output class
134             outputclass "ZeroMQ"
135            
136             connect "tcp://192.168.0.1:5552"
137            
138             # OPTIONAL - Defaults to JSON
139             #encoderclass "JSON"
140             #
141             # pretty "0"
142             #
143            
144            
145              
146             Will emit metrics like this:
147              
148             {
149             "plugin":"ElasticSearch",
150             "time":1341656031.18621,
151             "values":[
152             {
153             "value":0,
154             "min":0,
155             "name":"indices.get.time",
156             "max":0,
157             "type":0
158             }
159             ],
160             "type":"indices.get.time",
161             "interval":10,
162             "host":"t0m.local"
163             }
164              
165             or, for multi-value metrics:
166              
167             {
168             "plugin":"load",
169             "time":1341655869.22588,
170             "type":"load",
171             "values":[
172             {
173             "value":0.41,
174             "min":0,
175             "max":100,
176             "name":"shortterm",
177             "type":"GAUGE"
178             },
179             {
180             "value":0.13,
181             "min":0,
182             "max":100,
183             "name":"midterm",
184             "type":"GAUGE"
185             },
186             {
187             "value":0.08
188             "min":0,
189             "max":100,
190             "name":"longterm",
191             "type":"GAUGE"
192             }
193             ],
194             "interval":10,
195             "host":"t0m.local"
196             }
197              
198             =head1 DESCRIPTION
199              
200             A collectd plugin to emit metrics from L into L.
201              
202             =head1 PACKAGE VARIABLES
203              
204             =head2 %CONFIG
205              
206             A hash containing the following:
207              
208             =head3 outputclass
209              
210             The name of the class which will act as the Message::Passing output. Will be used as-is if prefixed with C<+>,
211             otherwise C will be prepended. Required.
212              
213             =head3 outputoptions
214              
215             The hash of options for the output class. Not required, but almost certainly needed.
216              
217             =head3 encoderclass
218              
219             The name of the class which will act the Message::Passing encoder. Will be used as-is if prefixed with C<+>,
220             otherwise C will be prepended. Optional, defaults to L.
221              
222             =head3 encoderoptions
223              
224             The hash of options for the encoder class.
225              
226             =head1 FUNCTIONS
227              
228             =head2 config
229              
230             Called first with configuration in the config file, munges it into the format expected
231             and places it into the C<%CONFIG> hash.
232              
233             =head2 init
234              
235             Validates the config, and initializes the C<$OUTPUT>
236              
237             =head2 write
238              
239             Writes a metric to the output in C<$OUTPUT>.
240              
241             =head1 BUGS
242              
243             Never enters the L event loop, and therefore may only work reliably with
244             (and is only tested with) L.
245              
246             =head1 AUTHOR, COPYRIGHT & LICENSE
247              
248             See L.
249              
250             =cut
251