master
c 189 lines 6.04 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "database/rrd.h"
4
5 #ifdef OS_MACOS
6 #include <AvailabilityMacros.h>
7 #endif
8
9 #if !defined(OS_MACOS) || (MAC_OS_X_VERSION_MIN_REQUIRED >= 101300)
10
11 #define PLUGIN_TIMEX_NAME "timex.plugin"
12
13 #define CONFIG_SECTION_TIMEX "plugin:timex"
14
15 struct status_codes {
16 char *name;
17 int code;
18 RRDDIM *rd;
19 } sta_codes[] = {
20 // {"pll", STA_PLL, NULL},
21 // {"ppsfreq", STA_PPSFREQ, NULL},
22 // {"ppstime", STA_PPSTIME, NULL},
23 // {"fll", STA_FLL, NULL},
24 // {"ins", STA_INS, NULL},
25 // {"del", STA_DEL, NULL},
26 {"unsync", STA_UNSYNC, NULL},
27 // {"freqhold", STA_FREQHOLD, NULL},
28 // {"ppssignal", STA_PPSSIGNAL, NULL},
29 // {"ppsjitter", STA_PPSJITTER, NULL},
30 // {"ppswander", STA_PPSWANDER, NULL},
31 // {"ppserror", STA_PPSERROR, NULL},
32 {"clockerr", STA_CLOCKERR, NULL},
33 // {"nano", STA_NANO, NULL},
34 // {"clk", STA_CLK, NULL},
35 {NULL, 0, NULL},
36 };
37
38 static void timex_main_cleanup(void *pptr)
39 {
40 struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
41 if(!static_thread) return;
42
43 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
44
45 worker_unregister();
46
47 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
48 }
49
50 void timex_main(void *ptr)
51 {
52 CLEANUP_FUNCTION_REGISTER(timex_main_cleanup) cleanup_ptr = ptr;
53
54 worker_register("TIMEX");
55 worker_register_job_name(0, "clock check");
56
57 int update_every = (int)inicfg_get_duration_seconds(&netdata_config, CONFIG_SECTION_TIMEX, "update every", 10);
58 if (update_every < localhost->rrd_update_every) {
59 update_every = localhost->rrd_update_every;
60 inicfg_set_duration_seconds(&netdata_config, CONFIG_SECTION_TIMEX, "update every", update_every);
61 }
62
63 int do_sync = inicfg_get_boolean(&netdata_config, CONFIG_SECTION_TIMEX, "clock synchronization state", CONFIG_BOOLEAN_YES);
64 int do_offset = inicfg_get_boolean(&netdata_config, CONFIG_SECTION_TIMEX, "time offset", CONFIG_BOOLEAN_YES);
65
66 if (unlikely(do_sync == CONFIG_BOOLEAN_NO && do_offset == CONFIG_BOOLEAN_NO)) {
67 netdata_log_info("No charts to show");
68 return;
69 }
70
71 usec_t step = update_every * USEC_PER_SEC;
72 usec_t real_step = USEC_PER_SEC;
73 heartbeat_t hb;
74 heartbeat_init(&hb, USEC_PER_SEC);
75 while (service_running(SERVICE_COLLECTORS)) {
76 worker_is_idle();
77 heartbeat_next(&hb);
78
79 if (real_step < step) {
80 real_step += USEC_PER_SEC;
81 continue;
82 }
83 real_step = USEC_PER_SEC;
84
85 worker_is_busy(0);
86
87 struct timex timex_buf = {};
88 int sync_state = 0;
89 static int prev_sync_state = 0;
90
91 sync_state = os_adjtimex(&timex_buf);
92
93 int non_seq_failure = (sync_state == -1 && prev_sync_state != -1);
94 prev_sync_state = sync_state;
95
96 if (non_seq_failure) {
97 netdata_log_error("Cannot get clock synchronization state");
98 continue;
99 }
100
101 collected_number divisor = USEC_PER_MS;
102 if (timex_buf.status & STA_NANO)
103 divisor = NSEC_PER_MSEC;
104
105 // ----------------------------------------------------------------
106
107 if (do_sync) {
108 static RRDSET *st_sync_state = NULL;
109 static RRDDIM *rd_sync_state;
110
111 if (unlikely(!st_sync_state)) {
112 st_sync_state = rrdset_create_localhost(
113 "system",
114 "clock_sync_state",
115 NULL,
116 "clock synchronization",
117 NULL,
118 "System Clock Synchronization State",
119 "state",
120 PLUGIN_TIMEX_NAME,
121 NULL,
122 NETDATA_CHART_PRIO_CLOCK_SYNC_STATE,
123 update_every,
124 RRDSET_TYPE_LINE);
125
126 rd_sync_state = rrddim_add(st_sync_state, "state", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
127 }
128
129 rrddim_set_by_pointer(st_sync_state, rd_sync_state, sync_state != TIME_ERROR ? 1 : 0);
130 rrdset_done(st_sync_state);
131
132 static RRDSET *st_clock_status = NULL;
133
134 if (unlikely(!st_clock_status)) {
135 st_clock_status = rrdset_create_localhost(
136 "system",
137 "clock_status",
138 NULL,
139 "clock synchronization",
140 NULL,
141 "System Clock Status",
142 "status",
143 PLUGIN_TIMEX_NAME,
144 NULL,
145 NETDATA_CHART_PRIO_CLOCK_STATUS,
146 update_every,
147 RRDSET_TYPE_LINE);
148
149 for (int i = 0; sta_codes[i].name != NULL; i++) {
150 sta_codes[i].rd =
151 rrddim_add(st_clock_status, sta_codes[i].name, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
152 }
153 }
154
155 for (int i = 0; sta_codes[i].name != NULL; i++)
156 rrddim_set_by_pointer(st_clock_status, sta_codes[i].rd, timex_buf.status & sta_codes[i].code ? 1 : 0);
157
158 rrdset_done(st_clock_status);
159 }
160
161 if (do_offset) {
162 static RRDSET *st_offset = NULL;
163 static RRDDIM *rd_offset;
164
165 if (unlikely(!st_offset)) {
166 st_offset = rrdset_create_localhost(
167 "system",
168 "clock_sync_offset",
169 NULL,
170 "clock synchronization",
171 NULL,
172 "Computed Time Offset Between Local System and Reference Clock",
173 "milliseconds",
174 PLUGIN_TIMEX_NAME,
175 NULL,
176 NETDATA_CHART_PRIO_CLOCK_SYNC_OFFSET,
177 update_every,
178 RRDSET_TYPE_LINE);
179
180 rd_offset = rrddim_add(st_offset, "offset", NULL, 1, divisor, RRD_ALGORITHM_ABSOLUTE);
181 }
182
183 rrddim_set_by_pointer(st_offset, rd_offset, timex_buf.offset);
184 rrdset_done(st_offset);
185 }
186 }
187 }
188
189 #endif // !defined(OS_MACOS) || (MAC_OS_X_VERSION_MIN_REQUIRED >= 101300)