diff options
Diffstat (limited to 'collectors/timex.plugin')
-rw-r--r-- | collectors/timex.plugin/README.md | 16 | ||||
-rw-r--r-- | collectors/timex.plugin/plugin_timex.c | 74 |
2 files changed, 78 insertions, 12 deletions
diff --git a/collectors/timex.plugin/README.md b/collectors/timex.plugin/README.md index 79947441..18665f80 100644 --- a/collectors/timex.plugin/README.md +++ b/collectors/timex.plugin/README.md @@ -6,12 +6,16 @@ custom_edit_url: https://github.com/netdata/netdata/edit/master/collectors/timex # timex.plugin -This plugin monitors the system clock synchronization state on Linux nodes. +This plugin monitors the system kernel clock synchronization state. -This plugin creates two charts: +This plugin creates the following charts: -- System clock synchronization state -- Computed time offset between local system and reference clock +- System clock synchronization state according to the system kernel +- System clock status which gives the value of the `time_status` variable in the kernel +- Computed time offset between local system and reference clock + +This is obtained from the information provided by the [ntp_adjtime()](https://man7.org/linux/man-pages/man2/adjtimex.2.html) system call. +An unsynchronized clock may indicate a hardware clock error, or an issue with UTC synchronization. ## Configuration @@ -19,11 +23,9 @@ Edit the `netdata.conf` configuration file using [`edit-config`](/docs/configure Scroll down to the `[plugin:timex]` section to find the available options: -``` +```ini [plugin:timex] # update every = 1 # clock synchronization state = yes # time offset = yes ``` - -[![analytics](https://www.google-analytics.com/collect?v=1&aip=1&t=pageview&_s=1&ds=github&dr=https%3A%2F%2Fgithub.com%2Fnetdata%2Fnetdata&dl=https%3A%2F%2Fmy-netdata.io%2Fgithub%2Fcollectors%2Ftimex.plugin%2FREADME&_u=MAC~&cid=5792dfd7-8dc4-476b-af31-da2fdb9f93d2&tid=UA-64295674-3)](<>) diff --git a/collectors/timex.plugin/plugin_timex.c b/collectors/timex.plugin/plugin_timex.c index b69f3429..34a3415a 100644 --- a/collectors/timex.plugin/plugin_timex.c +++ b/collectors/timex.plugin/plugin_timex.c @@ -1,12 +1,35 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "daemon/common.h" -#include "sys/timex.h" +#include "libnetdata/os.h" #define PLUGIN_TIMEX_NAME "timex.plugin" #define CONFIG_SECTION_TIMEX "plugin:timex" +struct status_codes { + char *name; + int code; + RRDDIM *rd; +} sta_codes[] = { + // {"pll", STA_PLL, NULL}, + // {"ppsfreq", STA_PPSFREQ, NULL}, + // {"ppstime", STA_PPSTIME, NULL}, + // {"fll", STA_FLL, NULL}, + // {"ins", STA_INS, NULL}, + // {"del", STA_DEL, NULL}, + {"unsync", STA_UNSYNC, NULL}, + // {"freqhold", STA_FREQHOLD, NULL}, + // {"ppssignal", STA_PPSSIGNAL, NULL}, + // {"ppsjitter", STA_PPSJITTER, NULL}, + // {"ppswander", STA_PPSWANDER, NULL}, + // {"ppserror", STA_PPSERROR, NULL}, + {"clockerr", STA_CLOCKERR, NULL}, + // {"nano", STA_NANO, NULL}, + // {"clk", STA_CLK, NULL}, + {NULL, 0, NULL}, +}; + static void timex_main_cleanup(void *ptr) { struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; @@ -44,7 +67,17 @@ void *timex_main(void *ptr) struct timex timex_buf = {}; int sync_state = 0; - sync_state = adjtimex(&timex_buf); + static int prev_sync_state = 0; + + sync_state = ADJUST_TIMEX(&timex_buf); + + int non_seq_failure = (sync_state == -1 && prev_sync_state != -1); + prev_sync_state = sync_state; + + if (non_seq_failure) { + error("Cannot get clock synchronization state"); + continue; + } collected_number divisor = USEC_PER_MS; if (timex_buf.status & STA_NANO) @@ -78,9 +111,39 @@ void *timex_main(void *ptr) rrddim_set_by_pointer(st_sync_state, rd_sync_state, sync_state != TIME_ERROR ? 1 : 0); rrdset_done(st_sync_state); + + static RRDSET *st_clock_status = NULL; + + if (unlikely(!st_clock_status)) { + st_clock_status = rrdset_create_localhost( + "system", + "clock_status", + NULL, + "clock synchronization", + NULL, + "System Clock Status", + "status", + PLUGIN_TIMEX_NAME, + NULL, + NETDATA_CHART_PRIO_CLOCK_STATUS, + update_every, + RRDSET_TYPE_LINE); + + for (int i = 0; sta_codes[i].name != NULL; i++) { + sta_codes[i].rd = + rrddim_add(st_clock_status, sta_codes[i].name, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + } else { + rrdset_next(st_clock_status); + } + + for (int i = 0; sta_codes[i].name != NULL; i++) { + rrddim_set_by_pointer(st_clock_status, sta_codes[i].rd, timex_buf.status & sta_codes[i].code ? 1 : 0); + } + rrdset_done(st_clock_status); } - if (do_sync) { + if (do_offset) { static RRDSET *st_offset = NULL; static RRDDIM *rd_offset; @@ -132,13 +195,14 @@ void *timex_main(void *ptr) update_every, RRDSET_TYPE_STACKED); - rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_INCREMENTAL); + rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_INCREMENTAL); rd_system = rrddim_add(stcpu_thread, "system", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_INCREMENTAL); } else { rrdset_next(stcpu_thread); } - rrddim_set_by_pointer(stcpu_thread, rd_user, thread.ru_utime.tv_sec * USEC_PER_SEC + thread.ru_utime.tv_usec); + rrddim_set_by_pointer( + stcpu_thread, rd_user, thread.ru_utime.tv_sec * USEC_PER_SEC + thread.ru_utime.tv_usec); rrddim_set_by_pointer( stcpu_thread, rd_system, thread.ru_stime.tv_sec * USEC_PER_SEC + thread.ru_stime.tv_usec); rrdset_done(stcpu_thread); |