feat(collectors/timex.plugin): add clock status chart (#12501)
Co-authored-by: Suraj Neupane <neupanesuraj@gmail.com>
Ilya Mashchenko committed
Mar 24, 2022 at 13:02 UTC
64efa1122d33d0975694b7ba3808489928a2c4a1
4 files changed
+73
-8
collectors/all.h
+1
@@ -44,6 +44,7 @@
44
#define NETDATA_CHART_PRIO_SYSTEM_ENTROPY 1000
45
#define NETDATA_CHART_PRIO_SYSTEM_UPTIME 1000
46
#define NETDATA_CHART_PRIO_CLOCK_SYNC_STATE 1100
47
+#define NETDATA_CHART_PRIO_CLOCK_STATUS 1105
48
#define NETDATA_CHART_PRIO_CLOCK_SYNC_OFFSET 1110
49
#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_QUEUES 1200 // freebsd only
50
#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_MESSAGES 1201
collectors/timex.plugin/README.md
+5
-6
@@ -8,10 +8,11 @@ custom_edit_url: https://github.com/netdata/netdata/edit/master/collectors/timex
8
9
This plugin monitors the system kernel clock synchronization state.
10
11
-This plugin creates two charts:
11
+This plugin creates the following charts:
12
13
-- System clock synchronization state according to the system kernel
14
-- Computed time offset between local system and reference clock
13
+- System clock synchronization state according to the system kernel
14
+- System clock status which gives the value of the `time_status` variable in the kernel
15
+- Computed time offset between local system and reference clock
16
17
This is obtained from the information provided by the [ntp_adjtime()](https://man7.org/linux/man-pages/man2/adjtimex.2.html) system call.
18
An unsynchronized clock may indicate a hardware clock error, or an issue with UTC synchronization.
@@ -22,11 +23,9 @@ Edit the `netdata.conf` configuration file using [`edit-config`](/docs/configure
23
24
Scroll down to the `[plugin:timex]` section to find the available options:
25
25
-```
26
+```ini
27
[plugin:timex]
28
# update every = 1
29
# clock synchronization state = yes
30
# time offset = yes
31
```
31
-
32
-
collectors/timex.plugin/plugin_timex.c
+56
-2
@@ -7,6 +7,29 @@
7
8
#define CONFIG_SECTION_TIMEX "plugin:timex"
9
10
+struct status_codes {
11
+ char *name;
12
+ int code;
13
+ RRDDIM *rd;
14
+} sta_codes[] = {
15
+ // {"pll", STA_PLL, NULL},
16
+ // {"ppsfreq", STA_PPSFREQ, NULL},
17
+ // {"ppstime", STA_PPSTIME, NULL},
18
+ // {"fll", STA_FLL, NULL},
19
+ // {"ins", STA_INS, NULL},
20
+ // {"del", STA_DEL, NULL},
21
+ {"unsync", STA_UNSYNC, NULL},
22
+ // {"freqhold", STA_FREQHOLD, NULL},
23
+ // {"ppssignal", STA_PPSSIGNAL, NULL},
24
+ // {"ppsjitter", STA_PPSJITTER, NULL},
25
+ // {"ppswander", STA_PPSWANDER, NULL},
26
+ // {"ppserror", STA_PPSERROR, NULL},
27
+ {"clockerr", STA_CLOCKERR, NULL},
28
+ // {"nano", STA_NANO, NULL},
29
+ // {"clk", STA_CLK, NULL},
30
+ {NULL, 0, NULL},
31
+};
32
+
33
static void timex_main_cleanup(void *ptr)
34
{
35
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
@@ -79,6 +102,36 @@ void *timex_main(void *ptr)
102
103
rrddim_set_by_pointer(st_sync_state, rd_sync_state, sync_state != TIME_ERROR ? 1 : 0);
104
rrdset_done(st_sync_state);
105
+
106
+ static RRDSET *st_clock_status = NULL;
107
+
108
+ if (unlikely(!st_clock_status)) {
109
+ st_clock_status = rrdset_create_localhost(
110
+ "system",
111
+ "clock_status",
112
+ NULL,
113
+ "clock synchronization",
114
+ NULL,
115
+ "System Clock Status",
116
+ "status",
117
+ PLUGIN_TIMEX_NAME,
118
+ NULL,
119
+ NETDATA_CHART_PRIO_CLOCK_STATUS,
120
+ update_every,
121
+ RRDSET_TYPE_LINE);
122
+
123
+ for (int i = 0; sta_codes[i].name != NULL; i++) {
124
+ sta_codes[i].rd =
125
+ rrddim_add(st_clock_status, sta_codes[i].name, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
126
+ }
127
+ } else {
128
+ rrdset_next(st_clock_status);
129
+ }
130
+
131
+ for (int i = 0; sta_codes[i].name != NULL; i++) {
132
+ rrddim_set_by_pointer(st_clock_status, sta_codes[i].rd, timex_buf.status & sta_codes[i].code ? 1 : 0);
133
+ }
134
+ rrdset_done(st_clock_status);
135
}
136
137
if (do_offset) {
@@ -133,13 +186,14 @@ void *timex_main(void *ptr)
186
update_every,
187
RRDSET_TYPE_STACKED);
188
136
- rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_INCREMENTAL);
189
+ rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_INCREMENTAL);
190
rd_system = rrddim_add(stcpu_thread, "system", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_INCREMENTAL);
191
} else {
192
rrdset_next(stcpu_thread);
193
}
194
142
- rrddim_set_by_pointer(stcpu_thread, rd_user, thread.ru_utime.tv_sec * USEC_PER_SEC + thread.ru_utime.tv_usec);
195
+ rrddim_set_by_pointer(
196
+ stcpu_thread, rd_user, thread.ru_utime.tv_sec * USEC_PER_SEC + thread.ru_utime.tv_usec);
197
rrddim_set_by_pointer(
198
stcpu_thread, rd_system, thread.ru_stime.tv_sec * USEC_PER_SEC + thread.ru_stime.tv_usec);
199
rrdset_done(stcpu_thread);
web/gui/dashboard_info.js
+11
@@ -1316,6 +1316,17 @@ netdataDashboard.context = {
1316
'<p><b>State map</b>: 0 - not synchronized, 1 - synchronized.</p>'
1317
},
1318
1319
+ 'system.clock_status': {
1320
+ info:'<p>The kernel code can operate in various modes and with various features enabled or disabled, as selected by the '+
1321
+ '<a href="https://man7.org/linux/man-pages/man2/adjtimex.2.html" target="_blank">ntp_adjtime()</a> system call. '+
1322
+ 'The system clock status shows the value of the <b>time_status</b> variable in the kernel. '+
1323
+ 'The bits of the variable are used to control these functions and record error conditions as they exist.</p>'+
1324
+ '<p><b>UNSYNC</b> - set/cleared by the caller to indicate clock unsynchronized (e.g., when no peers are reachable). '+
1325
+ 'This flag is usually controlled by an application program, but the operating system may also set it. '+
1326
+ '<b>CLOCKERR</b> - set/cleared by the external hardware clock driver to indicate hardware fault.</p>'+
1327
+ '<p><b>Status map</b>: 0 - bit unset, 1 - bit set.</p>'
1328
+ },
1329
+
1330
'system.clock_sync_offset': {
1331
info: 'A typical NTP client regularly polls one or more NTP servers. '+
1332
'The client must compute its '+