diff options
Diffstat (limited to 'src/pmdas/gpsd/pmdagpsd.pl')
-rw-r--r-- | src/pmdas/gpsd/pmdagpsd.pl | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/src/pmdas/gpsd/pmdagpsd.pl b/src/pmdas/gpsd/pmdagpsd.pl new file mode 100644 index 0000000..c924d04 --- /dev/null +++ b/src/pmdas/gpsd/pmdagpsd.pl @@ -0,0 +1,310 @@ +# +# Copyright (c) 2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# + +use strict; +use warnings; +use PCP::PMDA; +use JSON; +use Time::HiRes qw ( time ); + +use vars qw( $pmda ); +use vars qw( %devdata %satdata ); + +my $gpspipe = "gpspipe -w"; + +my $json; + +my $gpsd_release = "?"; +my $gpsd_rev = "?"; +my $gpsd_proto_maj = -1; +my $gpsd_proto_min = -1; + +# FIXME: the following will need changing to support multiple devices +my $gpsd_device = undef; +my %devdata = ( + "time" => -1, + "ept" => -1, + "lat" => -1, + "lon" => -1, + "alt" => -1, + "track" => -1, + "speed" => -1, + "climb" => -1, + "mode" => 0, # 0 = no fix + "xdop" => -1, + "ydop" => -1, + "vdop" => -1, + "tdop" => -1, + "hdop" => -1, + "gdop" => -1, + "pdop" => -1, + "num_satellites" => 0, +); +my $gpsd_sat_indom = 0; +my @gpsd_sat_dom = (); + +sub gpsd_pipe_callback +{ + (undef, $_) = @_; + + # $pmda->log("pipe got: $_"); + + my $jtxt = $json->decode($_); + + if ($jtxt->{"class"} eq "VERSION") { + $gpsd_release = $jtxt->{"release"}; + $gpsd_rev = $jtxt->{"rev"}; + $gpsd_proto_maj = $jtxt->{"proto_major"}; + $gpsd_proto_min = $jtxt->{"proto_minor"}; + } elsif ($jtxt->{"class"} eq "DEVICES") { + foreach my $dev (@{$jtxt->{"devices"}}) { + if ($dev->{"class"} eq "DEVICE") { + $pmda->log("gpsd_pipe_callback: oops! multiple " . + "devices detected, only using the first " . + "($gpsd_device)") if (defined($gpsd_device) and + $dev->{"path"} ne $gpsd_device); + + $gpsd_device = $dev->{"path"}; + } else { + $pmda->log("gpsd_pipe_callback: unknown class '" . + $dev->{"class"} . "'"); + } + } + } elsif ($jtxt->{"class"} eq "DEVICE") { + # nothing to do + } elsif ($jtxt->{"class"} eq "WATCH") { + # nothing to do + } elsif ($jtxt->{"class"} eq "TPV") { + return if ($jtxt->{"device"} ne $gpsd_device); + + $devdata{"time"} = $jtxt->{"time"}; + $devdata{"ept"} = $jtxt->{"ept"}; + $devdata{"lat"} = $jtxt->{"lat"}; + $devdata{"lon"} = $jtxt->{"lon"}; + $devdata{"alt"} = $jtxt->{"alt"}; + $devdata{"track"} = $jtxt->{"track"}; + $devdata{"speed"} = $jtxt->{"speed"}; + $devdata{"climb"} = $jtxt->{"climb"}; + $devdata{"mode"} = $jtxt->{"mode"}; + } elsif ($jtxt->{"class"} eq "SKY") { + return if ($jtxt->{"device"} ne $gpsd_device); + + $devdata{"xdop"} = $jtxt->{"xdop"}; + $devdata{"ydop"} = $jtxt->{"ydop"}; + $devdata{"vdop"} = $jtxt->{"vdop"}; + $devdata{"tdop"} = $jtxt->{"tdop"}; + $devdata{"hdop"} = $jtxt->{"hdop"}; + $devdata{"gdop"} = $jtxt->{"gdop"}; + $devdata{"pdop"} = $jtxt->{"pdop"}; + + my %sats = {}; + my @dom = (); + foreach my $sat (@{$jtxt->{"satellites"}}) { + push(@dom, $sat->{"PRN"} => "$sat->{'PRN'}"); + + $sats{"el"}{$sat->{"PRN"}} = $sat->{"el"}; + $sats{"az"}{$sat->{"PRN"}} = $sat->{"az"}; + $sats{"ss"}{$sat->{"PRN"}} = $sat->{"ss"}; + $sats{"used"}{$sat->{"PRN"}} = $sat->{"used"}; + } + %satdata = %sats; + $pmda->replace_indom($gpsd_sat_indom, \@dom); + + $devdata{"num_satellites"} = scalar(@dom) / 2; + } else { + $pmda->log("gpsd_pipe_callback: unknown class '" . $jtxt->{"class"} . "'"); + } +} + +sub gpsd_fetch_callback +{ + my ($cluster, $item, $inst) = @_; + my $metric_name = pmda_pmid_name($cluster, $item); + + # $pmda->log("gpsd_fetch_callback $metric_name $cluster:$item ($inst)\n"); + + return (PM_ERR_PMID, 0) if (!defined($metric_name)); + + if ($cluster == 0) { + return (PM_ERR_INST, 0) if ($inst != PM_IN_NULL); + + if ($metric_name eq "gpsd.release") { + return ($gpsd_release, 1); + } elsif ($metric_name eq "gpsd.rev") { + return ($gpsd_rev, 1); + } elsif ($metric_name eq "gpsd.proto.major") { + return ($gpsd_proto_maj, 1); + } elsif ($metric_name eq "gpsd.proto.minor") { + return ($gpsd_proto_min, 1); + } + } + + $metric_name =~ s/^gpsd\.devices\.dev0\.//; + + if ($metric_name =~ m/^satellites\./) { + # satellite info + $metric_name =~ s/^satellites\.//; + + # $pmda->log("gpsd_fetch_callbac2 $metric_name $cluster:$item ($inst): ${satdata{$metric_name}}\n"); + # $pmda->log("gpsd_fetch_callbac2 $metric_name $cluster:$item ($inst): ${satdata{$metric_name}{$inst}}\n"); + return (PM_ERR_INST, 0) if ($inst == PM_IN_NULL); + return (PM_ERR_PMID, 0) if (!defined($satdata{$metric_name}{$inst})); + return ($satdata{$metric_name}{$inst}, 1); + } + + return (PM_ERR_INST, 0) if ($inst != PM_IN_NULL); + return (PM_ERR_PMID, 0) if (!defined($devdata{$metric_name})); + return ($devdata{$metric_name}, 1); +} + +$json = new JSON; + +$pmda = PCP::PMDA->new('gpsd', 105); + +$pmda->add_metric(pmda_pmid(0,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.release", '', ''); +$pmda->add_metric(pmda_pmid(0,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.rev", '', ''); +$pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.proto.major", '', ''); +$pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.proto.minor", '', ''); + +$pmda->add_metric(pmda_pmid(1,0), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.time", '', ''); +$pmda->add_metric(pmda_pmid(1,1), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.ept", '', ''); +$pmda->add_metric(pmda_pmid(1,2), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.lat", '', ''); +$pmda->add_metric(pmda_pmid(1,3), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.lon", '', ''); +$pmda->add_metric(pmda_pmid(1,4), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.alt", '', ''); +$pmda->add_metric(pmda_pmid(1,5), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.track", '', ''); +$pmda->add_metric(pmda_pmid(1,6), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.speed", '', ''); +$pmda->add_metric(pmda_pmid(1,7), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.climb", '', ''); +$pmda->add_metric(pmda_pmid(1,8), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.mode", '', ''); + +$pmda->add_metric(pmda_pmid(1,9), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.xdop", '', ''); +$pmda->add_metric(pmda_pmid(1,10), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.ydop", '', ''); +$pmda->add_metric(pmda_pmid(1,11), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.vdop", '', ''); +$pmda->add_metric(pmda_pmid(1,12), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.tdop", '', ''); +$pmda->add_metric(pmda_pmid(1,13), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.hdop", '', ''); +$pmda->add_metric(pmda_pmid(1,14), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.gdop", '', ''); +$pmda->add_metric(pmda_pmid(1,15), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.pdop", '', ''); + +$pmda->add_metric(pmda_pmid(1,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.num_satellites", '', ''); + +$pmda->add_metric(pmda_pmid(1,100), PM_TYPE_U32, $gpsd_sat_indom, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.satellites.el", '', ''); +$pmda->add_metric(pmda_pmid(1,101), PM_TYPE_U32, $gpsd_sat_indom, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.satellites.az", '', ''); +$pmda->add_metric(pmda_pmid(1,102), PM_TYPE_U32, $gpsd_sat_indom, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.satellites.ss", '', ''); +$pmda->add_metric(pmda_pmid(1,103), PM_TYPE_U32, $gpsd_sat_indom, PM_SEM_INSTANT, + pmda_units(0,0,0,0,0,0), + "gpsd.devices.dev0.satellites.used", '', ''); + +$pmda->add_indom($gpsd_sat_indom, \@gpsd_sat_dom, '', ''); +$pmda->add_pipe($gpspipe, \&gpsd_pipe_callback, 0); + +$pmda->set_fetch_callback(\&gpsd_fetch_callback); +$pmda->set_user('pcp'); +$pmda->run; + +=pod + +=head1 NAME + +pmdagpsd - gpsd performance metrics domain agent (PMDA) + +=head1 DESCRIPTION + +B<pmdagpsd> is a Performance Metrics Domain Agent (PMDA) which exports +values from the gpsd daemon. + +=head1 INSTALLATION + +If you want access to the names and values for gpsd, do the following as +root: + + # cd $PCP_PMDAS_DIR/gpsd + # ./Install + +If you want to undo the installation, do the following as root: + + # cd $PCP_PMDAS_DIR/gpsd + # ./Remove + +B<pmdagpsd> is launched by pmcd(1) and should never be executed +directly. The Install and Remove scripts notify pmcd(1) when +the agent is installed or removed. + +=head1 FILES + +=over + +=item $PCP_PMDAS_DIR/gpsd/Install + +installation script for the B<pmdagpsd> agent + +=item $PCP_PMDAS_DIR/gpsd/Remove + +undo installation script for the B<pmdagpsd> agent + +=item $PCP_LOG_DIR/pmcd/gpsd.log + +default log file for error messages from B<pmdagpsd> + +=back + +=head1 SEE ALSO + +pmcd(1). |