From 26314b8c3fb08e1f0017ee9a6277b7fe370bf2a0 Mon Sep 17 00:00:00 2001 From: Nicolas JOURDEN Date: Tue, 10 Nov 2015 15:59:08 +0100 Subject: [PATCH] Initial support of GPSd in collectd. --- configure.ac | 62 ++++++++++++++++ src/Makefile.am | 9 +++ src/gps.c | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/gps.pod | 71 ++++++++++++++++++ src/types.db | 3 + 5 files changed, 368 insertions(+) create mode 100644 src/gps.c create mode 100644 src/gps.pod diff --git a/configure.ac b/configure.ac index 7b2296d0..7a811456 100644 --- a/configure.ac +++ b/configure.ac @@ -2082,6 +2082,59 @@ AC_SUBST(GCRYPT_LIBS) AM_CONDITIONAL(BUILD_WITH_LIBGCRYPT, test "x$with_libgcrypt" = "xyes") # }}} + +### +# --with-libgps {{{ +with_libgps_cflags="" +with_libgps_ldflags="" +AC_ARG_WITH(libgps, [AS_HELP_STRING([--with-libgps@<:@=PREFIX@:>@], [Path to libgps.])], +[ + if test "x$withval" != "xno" && test "x$withval" != "xyes" + then + with_libgps_cflags="-I$withval/include" + with_libgps_ldflags="-L$withval/lib" + with_libgps="yes" + else + with_libgps="$withval" + fi +], +[ + with_libgps="yes" +]) +if test "x$with_libgps" = "xyes" +then + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $with_libgps_cflags" + + AC_CHECK_HEADERS(gps.h, [with_libgps="yes"], [with_libgps="no (gps.h not found)"]) + + CFLAGS="$SAVE_CFLAGS" +fi +if test "x$with_libgps" = "xyes" +then + SAVE_CFLAGS="$CFLAGS" + SAVE_LDFLAGS="$LDFLAGS" + CFLAGS="$CFLAGS $with_libgps_cflags" + LDFLAGS="$LDFLAGS $with_libgps_ldflags" + + AC_CHECK_LIB(gps, gps_open, [with_libgps="yes"], [with_libgps="no (symbol gps_open not found)"]) + + CFLAGS="$SAVE_CFLAGS" + LDFLAGS="$SAVE_LDFLAGS" +fi +if test "x$with_libgps" = "xyes" +then + BUILD_WITH_LIBGPS_CFLAGS="$with_libgps_cflags" + BUILD_WITH_LIBGPS_LDFLAGS="$with_libgps_ldflags" + BUILD_WITH_LIBGPS_LIBS="-lgps" + AC_SUBST(BUILD_WITH_LIBGPS_CFLAGS) + AC_SUBST(BUILD_WITH_LIBGPS_LDFLAGS) + AC_SUBST(BUILD_WITH_LIBGPS_LIBS) +fi +AM_CONDITIONAL(BUILD_WITH_LIBGPS, test "x$with_libgps" = "xyes") +# }}} + + # --with-libiptc {{{ AC_ARG_WITH(libiptc, [AS_HELP_STRING([--with-libiptc@<:@=PREFIX@:>@], [Path to libiptc.])], [ @@ -5227,6 +5280,7 @@ plugin_entropy="no" plugin_ethstat="no" plugin_fhcount="no" plugin_fscache="no" +plugin_gps="no" plugin_interface="no" plugin_ipmi="no" plugin_ipvs="no" @@ -5488,6 +5542,11 @@ then plugin_interface="yes" fi +if test "x$with_libgps" = "xyes" && test "x$with_libpthread" = "xyes" +then + plugin_gps="yes" +fi + if test "x$have_getloadavg" = "xyes" then plugin_load="yes" @@ -5616,6 +5675,7 @@ AC_PLUGIN([fhcount], [$plugin_fhcount], [File handles statistics]) AC_PLUGIN([filecount], [yes], [Count files in directories]) AC_PLUGIN([fscache], [$plugin_fscache], [fscache statistics]) AC_PLUGIN([gmond], [$with_libganglia], [Ganglia plugin]) +AC_PLUGIN([gps], [$plugin_gps], [GPS plugin]) AC_PLUGIN([hddtemp], [yes], [Query hddtempd]) AC_PLUGIN([interface], [$plugin_interface], [Interface traffic statistics]) AC_PLUGIN([ipc], [$plugin_ipc], [IPC statistics]) @@ -5907,6 +5967,7 @@ Configuration: libesmtp . . . . . . $with_libesmtp libganglia . . . . . $with_libganglia libgcrypt . . . . . . $with_libgcrypt + libgps . . . . . . . $with_libgps libhal . . . . . . . $with_libhal libhiredis . . . . . $with_libhiredis libi2c-dev . . . . . $with_libi2c @@ -5994,6 +6055,7 @@ Configuration: filecount . . . . . . $enable_filecount fscache . . . . . . . $enable_fscache gmond . . . . . . . . $enable_gmond + gps . . . . . . . . . $enable_gps hddtemp . . . . . . . $enable_hddtemp interface . . . . . . $enable_interface ipc . . . . . . . . . $enable_ipc diff --git a/src/Makefile.am b/src/Makefile.am index 07ffdda9..2848ebdb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -387,6 +387,14 @@ gmond_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(GANGLIA_LDFLAGS) gmond_la_LIBADD = $(GANGLIA_LIBS) endif +if BUILD_PLUGIN_GPS +pkglib_LTLIBRARIES += gps.la +gps_la_SOURCES = gps.c +gps_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBGPS_CFLAGS) +gps_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBGPS_LDFLAGS) +gps_la_LIBADD = -lpthread $(BUILD_WITH_LIBGPS_LIBS) +endif + if BUILD_PLUGIN_HDDTEMP pkglib_LTLIBRARIES += hddtemp.la hddtemp_la_SOURCES = hddtemp.c @@ -1324,6 +1332,7 @@ EXTRA_DIST += collectd.conf.pod \ collectd-threshold.pod \ collectd-unixsock.pod \ postgresql_default.conf \ + gps.pod \ types.db.pod .pod.1: diff --git a/src/gps.c b/src/gps.c new file mode 100644 index 00000000..1136f50b --- /dev/null +++ b/src/gps.c @@ -0,0 +1,223 @@ +/** + * This plug-in helps to monitor the GPS connected to a system. + * It reads the data comming from GPSd. + It look for the following parameters. + */ + +#include "collectd.h" +#include "common.h" +#include "plugin.h" + +#if HAVE_GPS_H +#include +#endif + +#if HAVE_LIBPTHREAD +#include +#endif + +typedef struct +{ + char *host; + char *port; + int timeout; +} gps_definition_t; +static gps_definition_t gps_data_config; + +typedef struct { + int satellites; + double vdop; + double hdop; +} gpsDATA_t; +static gpsDATA_t gps_data_read; + + +static const char *config_keys[] = +{ + "Host", + "Port", + "Timeout" +}; +static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); + + +// Thread items: +static pthread_t connector = (pthread_t) 0; +static pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER; + + +/** + * Thread reading from GPSd. + */ +static void * gps_collectd_thread (void * pData) +{ + struct gps_data_t gps_data; + + while (1) + { + if (gps_open(gps_data_config.host, gps_data_config.port, &gps_data) < 0) + { + printf ("cannot connect to: %s:%s", gps_data_config.host, gps_data_config.port); + sleep(60); + continue; + } + + gps_stream(&gps_data, WATCH_ENABLE | WATCH_JSON, NULL); + + while (1) + { + if (gps_waiting (&gps_data, gps_data_config.timeout)) + { + if (gps_read (&gps_data) == -1) + { + WARNING ("incorrect data.\n"); + } + else { + pthread_mutex_lock (&data_mutex); + + // Dop data: + if (isnan(gps_data.dop.vdop) == 0) + { + gps_data_read.vdop = gps_data.dop.vdop; + } + if (isnan(gps_data.dop.hdop) == 0) + { + gps_data_read.hdop = gps_data.dop.hdop; + } + + // Sat in view: + if ((gps_data.set & LATLON_SET)) + { + gps_data_read.satellites = gps_data.satellites_used; + } + + pthread_mutex_unlock (&data_mutex); + } + } + } + } + + gps_stream(&gps_data, WATCH_DISABLE, NULL); + gps_close(&gps_data); + + pthread_exit ((void *)0); +} + + +/** + * Submit the data. + */ +static void gps_collectd_submit (const char *type, gauge_t value) +{ + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + values[0].gauge = value; + + vl.values = values; + vl.values_len = 1; + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, "gps", sizeof (vl.plugin)); + sstrncpy (vl.type, type, sizeof (vl.type)); + sstrncpy (vl.type_instance, "gps", sizeof (vl.type_instance)); + + plugin_dispatch_values (&vl); +} + + +/** + * Read the data and submit. + */ +static int gps_collectd_read () +{ + pthread_mutex_lock (&data_mutex); + gps_collectd_submit("gps_hdop", (gauge_t) gps_data_read.hdop); + gps_collectd_submit("gps_vdop", (gauge_t) gps_data_read.vdop); + gps_collectd_submit("gps_sat", (gauge_t) gps_data_read.satellites); + printf ("gps: hdop=%1.3f, vdop=%1.3f, sat=%02d.\n", + gps_data_read.hdop, + gps_data_read.vdop, + gps_data_read.satellites + ); + pthread_mutex_unlock (&data_mutex); + return (0); +} + + +/** + * Read configuration. + */ +static int gps_collectd_config (const char *key, const char *value) +{ + if (strcasecmp (key, "Host") == 0) { + if (gps_data_config.host != NULL) free (gps_data_config.host); + gps_data_config.host = sstrdup (value); + } + if (strcasecmp (key, "Port") == 0) { + if (gps_data_config.port != NULL) free (gps_data_config.port); + gps_data_config.port = sstrdup (value); + } + if (strcasecmp (key, "Timeout") == 0) { + gps_data_config.timeout = (int) strtol (value, NULL, 1000); + } + return (0); +} + + +/** + * Init. + */ +static int gps_collectd_init (void) +{ + int err = 0; + + printf ("gps: will use %s:%s with timeout %d.\n", gps_data_config.host, gps_data_config.port, gps_data_config.timeout); + + err = plugin_thread_create (&connector, NULL, gps_collectd_thread, NULL); + + if (err != 0) { + WARNING ("pthread_create() failed."); + return (-1); + } + + return (0); +} + + +/** + * Shutdown. + */ +static int gps_collectd_shutdown (void) +{ + if (connector != ((pthread_t) 0)) { + pthread_kill (connector, SIGTERM); + connector = (pthread_t) 0; + } + + sfree (gps_data_config.port); + sfree (gps_data_config.host); + + return (0); +} + +/** + * Register the module. + */ +void module_register (void) +{ + gps_data_config.host = sstrdup ("localhost"); + gps_data_config.port = sstrdup ("2947"); + gps_data_read.hdop = 0; + gps_data_read.vdop = 0; + gps_data_read.satellites = 0; + + // Read the config params: + plugin_register_config ("gps", gps_collectd_config, config_keys, config_keys_num); + // Create the thread: + plugin_register_init ("gps", gps_collectd_init); + // Kill the thread and stop. + plugin_register_shutdown ("gps", gps_collectd_shutdown); + // Read plugin: + plugin_register_read ("gps", gps_collectd_read); +} + diff --git a/src/gps.pod b/src/gps.pod new file mode 100644 index 00000000..e9d50146 --- /dev/null +++ b/src/gps.pod @@ -0,0 +1,71 @@ +=encoding UTF-8 + +=head1 NAME + +gps - Documentation of collectd's C + +=head1 SYNOPSIS + + # See collectd.conf(5) + LoadPlugin gps + + Host "localhost" + Port "2947" + Timeout 1000 + + +=head1 DESCRIPTION + +The C connects to gpsd on the host machine. +The port and the timeout are configurable. + + +=head1 OPTIONS + +=over 4 + +=item B + +The host on which gpsd runs. + +=item B + +Port to connect to gpsd on the host machine. + +=item B + +Timeout in ms. + +=back + +=head1 NOTIFICATION DATA FORMAT + +=over 4 + +=item B + +Number of satelites in view. +0 means no GPS are visible. + +=item B + +Horizontal dilution. +It should be between 0 and 3. +Look at the documentaiton of your GPS. + +=item B + +Vertical dilution. +Same as above. + +=head1 SEE ALSO + +L, +L, +gpsd + +=head1 AUTHOR + +Nicolas Jourden Enicolas.jourden@laposte.netE + +=cut diff --git a/src/types.db b/src/types.db index 38fb546c..bfe660e0 100644 --- a/src/types.db +++ b/src/types.db @@ -77,6 +77,9 @@ frequency_offset value:GAUGE:-1000000:1000000 frequency value:GAUGE:0:U fscache_stat value:DERIVE:0:U gauge value:GAUGE:U:U +gps_sat value:GAUGE:0:25 +gps_hdop value:GAUGE:0:100 +gps_vdop value:GAUGE:0:100 hash_collisions value:DERIVE:0:U http_request_methods value:DERIVE:0:U http_requests value:DERIVE:0:U -- 2.11.0