SHARE
TWEET

Ganglia::Gmetric::PP + v3.1 support

a guest Apr 14th, 2011 232 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. =head1 NAME
  2.  
  3. Ganglia::Gmetric::PP - Pure Perl emitter/parser of Ganglia gmetric monitoring
  4. packets
  5.  
  6. =head1 SYNOPSIS
  7.  
  8.     my $gmetric = Ganglia::Gmetric::PP->new(host => 'localhost', port => 8649);
  9.     $gmetric->send($type, $name, $value, $units, $slope, $tmax, $dmax);
  10.  
  11. =head1 DESCRIPTION
  12.  
  13. This module constructs Ganglia packets in the manner of the gmetric program and
  14. sends them via UDP to a gmond. Additionally it can receive and/or parse gmetric
  15. packets which is useful for constructing proxies. Though written in pure Perl
  16. with no non-core dependencies, it tries to be fast.
  17.  
  18. =cut
  19.  
  20. package Ganglia::Gmetric::PP;
  21.  
  22. our $VERSION = '1.04';
  23.  
  24. use strict;
  25. use warnings;
  26.  
  27. use base 'Exporter', 'IO::Socket::INET';
  28.  
  29. our @EXPORT_OK = qw(
  30.     GANGLIA_VALUE_STRING
  31.     GANGLIA_VALUE_UNSIGNED_CHAR
  32.     GANGLIA_VALUE_CHAR
  33.     GANGLIA_VALUE_UNSIGNED_SHORT
  34.     GANGLIA_VALUE_SHORT
  35.     GANGLIA_VALUE_UNSIGNED_INT
  36.     GANGLIA_VALUE_INT
  37.     GANGLIA_VALUE_FLOAT
  38.     GANGLIA_VALUE_DOUBLE
  39.     GANGLIA_SLOPE_ZERO
  40.     GANGLIA_SLOPE_POSITIVE
  41.     GANGLIA_SLOPE_NEGATIVE
  42.     GANGLIA_SLOPE_BOTH
  43.     GANGLIA_SLOPE_UNSPECIFIED
  44.     METRIC_INDEX_TYPE
  45.     METRIC_INDEX_NAME
  46.     METRIC_INDEX_VALUE
  47.     METRIC_INDEX_UNITS
  48.     METRIC_INDEX_SLOPE
  49.     METRIC_INDEX_TMAX
  50.     METRIC_INDEX_DMAX
  51. );
  52. our %EXPORT_TAGS = (
  53.     'all' => \@EXPORT_OK,
  54. );
  55.  
  56. our $hostname;
  57.  
  58. =head1 FUNCTIONS
  59.  
  60. =over 4
  61.  
  62. =item * $gmetric = Ganglia::Gmetric::PP->new(host => $host, port => $port)
  63.  
  64. Constructs a new object which sends gmetric packets to the specified C<host>
  65. and UDP C<port>. If omitted, they default to localhost and 8649, respectively.
  66.  
  67. =item * $gmond = Ganglia::Gmetric::PP->new(listen_host => $host, listen_port => $port)
  68.  
  69. Constructs a new object which receives gmetric packets (e.g. in a gmond replacement).
  70. If the $gmetric will be used for receiving packets, C<listen_host> and
  71. C<listen_port> may be specified as well.
  72.  
  73. =cut
  74.  
  75. sub new {
  76.     my $proto = shift;
  77.     my $class = ref($proto) || $proto;
  78.  
  79.     my %p = @_;
  80.  
  81.     my %opts;
  82.  
  83.     $opts{LocalHost} = $p{listen_host} if $p{listen_host};
  84.     $opts{LocalPort} = $p{listen_port} if $p{listen_port};
  85.  
  86.     unless (%opts) {
  87.         $opts{PeerHost} = $p{host} || 'localhost';
  88.         $opts{PeerPort} = $p{port} || 8649;
  89.     }
  90.  
  91.     my $self = IO::Socket::INET->new(
  92.         Proto    => 'udp',
  93.         %opts,
  94.     );
  95.  
  96.     die "failed to create socket: $!" unless $self;
  97.  
  98.     return bless $self, $class;
  99. }
  100.  
  101. =item * $gmetric->send($type, $name, $value, $units, $slope, $tmax, $dmax)
  102.  
  103. Sends a Ganglia message. The parameters are:
  104.  
  105. =over 4
  106.  
  107. =item * $type
  108.  
  109. The type of data being sent. Must be one of these importable constants:
  110.  
  111. =over 4
  112.  
  113. =item * GANGLIA_VALUE_STRING
  114.  
  115. =item * GANGLIA_VALUE_UNSIGNED_CHAR
  116.  
  117. =item * GANGLIA_VALUE_CHAR
  118.  
  119. =item * GANGLIA_VALUE_UNSIGNED_SHORT
  120.  
  121. =item * GANGLIA_VALUE_SHORT
  122.  
  123. =item * GANGLIA_VALUE_UNSIGNED_INT
  124.  
  125. =item * GANGLIA_VALUE_INT
  126.  
  127. =item * GANGLIA_VALUE_FLOAT
  128.  
  129. =item * GANGLIA_VALUE_DOUBLE
  130.  
  131. =back
  132.  
  133. =item * $name
  134.  
  135. The name of the metric.
  136.  
  137. =item * $value
  138.  
  139. The current value of the metric.
  140.  
  141. =item * $units
  142.  
  143. A string describing the units of measure for the metric.
  144.  
  145. =item * $slope
  146.  
  147. A description of how the metric tends to change over time. Must be one of these importable constants:
  148.  
  149. =over 4
  150.  
  151. =item * GANGLIA_SLOPE_ZERO
  152.  
  153. Data is fixed, mostly unchanging.
  154.  
  155. =item * GANGLIA_SLOPE_POSITIVE
  156.  
  157. Value is always increasing (counter).
  158.  
  159. =item * GANGLIA_SLOPE_NEGATIVE
  160.  
  161. Value is always decreasing.
  162.  
  163. =item * GANGLIA_SLOPE_BOTH
  164.  
  165. Value can be anything.
  166.  
  167. =back
  168.  
  169. =item * $tmax
  170.  
  171. The maximum time in seconds between gmetric calls.
  172.  
  173. =item * $dmax
  174.  
  175. The lifetime in seconds of this metric.
  176.  
  177. =back
  178.  
  179. =cut
  180.  
  181. # exported constants. see http://code.google.com/p/embeddedgmetric/wiki/GmetricProtocol
  182. use constant {
  183.     GANGLIA_VALUE_STRING            => 'string',
  184.     GANGLIA_VALUE_UNSIGNED_CHAR     => 'uint8',
  185.     GANGLIA_VALUE_CHAR              => 'int8',
  186.     GANGLIA_VALUE_UNSIGNED_SHORT    => 'uint16',
  187.     GANGLIA_VALUE_SHORT             => 'int16',
  188.     GANGLIA_VALUE_UNSIGNED_INT      => 'uint32',
  189.     GANGLIA_VALUE_INT               => 'int32',
  190.     GANGLIA_VALUE_FLOAT             => 'float',
  191.     GANGLIA_VALUE_DOUBLE            => 'double',
  192.  
  193.     GANGLIA_SLOPE_ZERO              => 0, # data is fixed, mostly unchanging
  194.     GANGLIA_SLOPE_POSITIVE          => 1, # is always increasing (counter)
  195.     GANGLIA_SLOPE_NEGATIVE          => 2, # is always decreasing
  196.     GANGLIA_SLOPE_BOTH              => 3, # can be anything
  197.     GANGLIA_SLOPE_UNSPECIFIED       => 4,
  198.  
  199.     METRIC_INDEX_TYPE               => 0,
  200.     METRIC_INDEX_NAME               => 1,
  201.     METRIC_INDEX_VALUE              => 2,
  202.     METRIC_INDEX_UNITS              => 3,
  203.     METRIC_INDEX_SLOPE              => 4,
  204.     METRIC_INDEX_TMAX               => 5,
  205.     METRIC_INDEX_DMAX               => 6,
  206. };
  207.  
  208. # internal constants
  209. use constant {
  210.     MAGIC_ID_V25                    => 0,
  211.     GMETRIC_FORMAT_V25              => 'N(N/a*x![4])4N3',
  212.     GMETRIC_FORMAT_V31_METADATA     => 'N(N/a*x![4])2N(N/a*x![4])3N3N(N/a*x![4])*',
  213.     GMETRIC_FORMAT_V31_METADATA_U   => 'N(N/a*x![4])2N(N/a*x![4])3N3N/(N/a*x![4])',
  214.     GMETRIC_FORMAT_V31_VALUE_STRING => 'N(N/a*x![4])2N(N/a*x![4])2',
  215.     GMETRIC_FORMAT_V31_VALUE_INT32  => 'N(N/a*x![4])2N(N/a*x![4])l>',
  216.     GMETRIC_FORMAT_V31_VALUE_UINT32 => 'N(N/a*x![4])2N(N/a*x![4])N',
  217.     GMETRIC_FORMAT_V31_VALUE_FLOAT  => 'N(N/a*x![4])2N(N/a*x![4])f>',
  218.     GMETRIC_FORMAT_V31_VALUE_DOUBLE => 'N(N/a*x![4])2N(N/a*x![4])d>',
  219.  
  220.     DEFAULT_UNITS                   => '',
  221.     DEFAULT_SLOPE                   => 3,
  222.     DEFAULT_TMAX                    => 60,
  223.     DEFAULT_DMAX                    => 0,
  224.  
  225.     gmetadata_full                  => 128,
  226.     gmetric_ushort                  => 128 + 1,
  227.     gmetric_short                   => 128 + 2,
  228.     gmetric_int                     => 128 + 3,
  229.     gmetric_uint                    => 128 + 4,
  230.     gmetric_string                  => 128 + 5,
  231.     gmetric_float                   => 128 + 6,
  232.     gmetric_double                  => 128 + 7,
  233.     gmetadata_request               => 128 + 8,
  234. };
  235.  
  236. sub send_v25 {
  237.     my $self = shift;
  238.     my @msg = (MAGIC_ID_V25, @_);
  239.     $msg[4] = DEFAULT_UNITS unless defined $msg[4];
  240.     $msg[5] = DEFAULT_SLOPE unless defined $msg[5];
  241.     $msg[6] = DEFAULT_TMAX  unless defined $msg[6];
  242.     $msg[7] = DEFAULT_DMAX  unless defined $msg[7];
  243.     $self->SUPER::send(pack GMETRIC_FORMAT_V25, @msg);
  244. }
  245.  
  246. sub send_v31 {
  247.     my $self = shift;
  248.  
  249.     my ($type, $name, $value, $units, $slope, $tmax, $dmax, $spoof, $heartbeat) = @_;
  250.     $units = DEFAULT_UNITS unless defined $units;
  251.     $slope = DEFAULT_SLOPE unless defined $slope;
  252.     $tmax  = DEFAULT_TMAX  unless defined $tmax;
  253.     $dmax  = DEFAULT_DMAX  unless defined $dmax;
  254.  
  255.     my $host;
  256.     my @extra_data;
  257.  
  258.     if (defined($spoof)) {
  259.         $host = $spoof;
  260.         push @extra_data, 'SPOOF_HOST', $spoof;
  261.     } else {
  262.         unless (defined($hostname)) {
  263.             require Sys::Hostname;
  264.             $hostname = Sys::Hostname::hostname();
  265.         }
  266.         $host = $hostname;
  267.     }
  268.  
  269.     if ($heartbeat) {
  270.         $name = 'heartbeat';
  271.         $type = 'uint32';
  272.         $units = '';
  273.         $tmax = $dmax = $slope = 0;
  274.         $value = '0';
  275.         push @extra_data, 'SPOOF_HEARTBEAT', 'yes';
  276.     }
  277.  
  278.     $self->SUPER::send(pack GMETRIC_FORMAT_V31_METADATA, gmetadata_full,
  279.         $host, $name, defined($spoof) ? 1 : 0, $type, $name, $units, $slope,
  280.         $tmax, $dmax, @extra_data/2, @extra_data) or return;
  281.  
  282.     $self->SUPER::send(pack GMETRIC_FORMAT_V31_VALUE_STRING, gmetric_string,
  283.         $host, $name, defined($spoof) ? 1 : 0, '%s', $value);
  284.  
  285. }
  286.  
  287. sub send {
  288.     my $self = shift;
  289.     return  ${*$self}{proto_v25} ? $self->send_v25(@_) : $self->send_v31(@_);
  290. }
  291.  
  292. =item * @metric = $gmetric->receive()
  293.  
  294. Waits for a single gmetric packet on the UDP listen port and returns the parsed
  295. metric (see C<parse>).
  296.  
  297. =cut
  298.  
  299. sub receive {
  300.     my $self = shift;
  301.     return() unless $self->recv(my $buf, 1 << 14);
  302.     return $self->parse($buf);
  303. }
  304.  
  305. =item * @metric = Ganglia::Gmetric::PP->parse($packet_data)
  306.  
  307. Parses a gmetric packet, which is typically received by a UDP server.
  308.  
  309. The elements returned match the arguments to C<send>:
  310.  
  311.     ($type, $name, $value, $units, $slope, $tmax, $dmax) = @metric;
  312.  
  313. This function may die if the given data does not resemble a gmetric packet.
  314.  
  315. =cut
  316.  
  317. sub parse_v25 {
  318.     my @res = unpack GMETRIC_FORMAT_V25, $_[1];
  319.     die "bad magic" unless shift(@res) == MAGIC_ID_V25;
  320.     return @res;
  321. }
  322.  
  323. sub parse_v31_metadata {
  324.     my ($id, $host, $name, $spoof, $type, $name2, $units, $slope,
  325.             $tmax, $dmax, @extra_data) =
  326.         unpack GMETRIC_FORMAT_V31_METADATA_U, $_[1];
  327.  
  328.     return unless defined($name);
  329.  
  330.     return {
  331.         'host'          => $host,
  332.         'name'          => $name,
  333.         'spoof'         => $spoof,
  334.         'type'          => $type,
  335.         'units'         => $units,
  336.         'slope'         => $slope,
  337.         'tmax'          => $tmax,
  338.         'dmax'          => $dmax,
  339.         'extra_data'    => { @extra_data },
  340.     };
  341. }
  342.  
  343. sub parse_v31_value_string {
  344.     my @ret = unpack GMETRIC_FORMAT_V31_VALUE_STRING, $_[1];
  345.     shift @ret;
  346.     return @ret;
  347. }
  348.  
  349. sub parse_v31_value_int32 {
  350.     my @ret = unpack GMETRIC_FORMAT_V31_VALUE_INT32, $_[1];
  351.     shift @ret;
  352.     return @ret;
  353. }
  354.  
  355. sub parse_v31_value_uint32 {
  356.     my @ret = unpack GMETRIC_FORMAT_V31_VALUE_UINT32, $_[1];
  357.     shift @ret;
  358.     return @ret;
  359. }
  360.  
  361. sub parse_v31_value_float {
  362.     my @ret = unpack GMETRIC_FORMAT_V31_VALUE_FLOAT, $_[1];
  363.     shift @ret;
  364.     return @ret;
  365. }
  366.  
  367. sub parse_v31_value_double {
  368.     my @ret = unpack GMETRIC_FORMAT_V31_VALUE_DOUBLE, $_[1];
  369.     shift @ret;
  370.     return @ret;
  371. }
  372.  
  373.  
  374. my @parse_v31_value = (
  375.     \&parse_v31_value_uint32,
  376.     \&parse_v31_value_int32,
  377.     \&parse_v31_value_int32,
  378.     \&parse_v31_value_uint32,
  379.     \&parse_v31_value_string,
  380.     \&parse_v31_value_float,
  381.     \&parse_v31_value_double,
  382. );
  383.  
  384. sub parse {
  385.     my $self = shift;
  386.     my ($id) = unpack 'N', $_[0];
  387.  
  388.     if ($id == gmetadata_full) {
  389.         my $ret = $self->parse_v31_metadata(@_);
  390.  
  391.         ${*$self}{metadata_cache}{$ret->{'host'}}{$ret->{'name'}} = $ret
  392.             if $ret;
  393.  
  394.         return ();
  395.     } elsif ($id >= gmetric_ushort && $id <= gmetric_double) {
  396.         my $handler = $parse_v31_value[$id - gmetric_ushort];
  397.         my ($host, $name, $spoof, $fmt, $value) = $handler->($self, @_);
  398.         my $metadata = ${*$self}{metadata_cache}{$host}{$name} or
  399.             return ();
  400.         return ($metadata->{'type'}, $name, $value, $metadata->{'units'},
  401.             $metadata->{'slope'}, $metadata->{'tmax'}, $metadata->{'dmax'},
  402.             $host, $spoof, $metadata->{'extra_data'});
  403.     }
  404.  
  405.     return $self->parse_v25(@_);
  406. }
  407.  
  408. 1;
  409.  
  410. =back
  411.  
  412. =head1 AUTHOR
  413.  
  414. Adam Thomason, E<lt>athomason@cpan.org<gt>
  415.  
  416. =head1 COPYRIGHT AND LICENSE
  417.  
  418. Copyright (C) 2007-2009 by Six Apart, E<lt>cpan@sixapart.comE<gt>
  419.  
  420. This library is free software; you can redistribute it and/or modify
  421. it under the same terms as Perl itself, either Perl version 5.8.6 or,
  422. at your option, any later version of Perl 5 you may have available.
  423.  
  424. =cut
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top