summaryrefslogtreecommitdiffstats
path: root/collectors/timex.plugin
diff options
context:
space:
mode:
Diffstat (limited to 'collectors/timex.plugin')
-rw-r--r--collectors/timex.plugin/README.md16
-rw-r--r--collectors/timex.plugin/plugin_timex.c74
2 files changed, 78 insertions, 12 deletions
diff --git a/collectors/timex.plugin/README.md b/collectors/timex.plugin/README.md
index 79947441f..18665f807 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 b69f34292..34a3415a0 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);