diff options
Diffstat (limited to 'collectors/timex.plugin')
-rw-r--r-- | collectors/timex.plugin/Makefile.am | 8 | ||||
-rw-r--r-- | collectors/timex.plugin/README.md | 29 | ||||
-rw-r--r-- | collectors/timex.plugin/plugin_timex.c | 176 | ||||
-rw-r--r-- | collectors/timex.plugin/plugin_timex.h | 29 |
4 files changed, 242 insertions, 0 deletions
diff --git a/collectors/timex.plugin/Makefile.am b/collectors/timex.plugin/Makefile.am new file mode 100644 index 00000000..161784b8 --- /dev/null +++ b/collectors/timex.plugin/Makefile.am @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +AUTOMAKE_OPTIONS = subdir-objects +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +dist_noinst_DATA = \ + README.md \ + $(NULL) diff --git a/collectors/timex.plugin/README.md b/collectors/timex.plugin/README.md new file mode 100644 index 00000000..79947441 --- /dev/null +++ b/collectors/timex.plugin/README.md @@ -0,0 +1,29 @@ +<!-- +title: "timex.plugin" +description: "Monitor the system clock synchronization state." +custom_edit_url: https://github.com/netdata/netdata/edit/master/collectors/timex.plugin/README.md +--> + +# timex.plugin + +This plugin monitors the system clock synchronization state on Linux nodes. + +This plugin creates two charts: + +- System clock synchronization state +- Computed time offset between local system and reference clock + +## Configuration + +Edit the `netdata.conf` configuration file using [`edit-config`](/docs/configure/nodes.md#use-edit-config-to-edit-configuration-files) from the [Netdata config directory](/docs/configure/nodes.md#the-netdata-config-directory), which is typically at `/etc/netdata`. + +Scroll down to the `[plugin:timex]` section to find the available options: + +``` +[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 new file mode 100644 index 00000000..b3e722a4 --- /dev/null +++ b/collectors/timex.plugin/plugin_timex.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "plugin_timex.h" +#include "sys/timex.h" + +#define PLUGIN_TIMEX_NAME "timex.plugin" + +#define CONFIG_SECTION_TIMEX "plugin:timex" + +static void timex_main_cleanup(void *ptr) +{ + struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; + static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; + + info("cleaning up..."); + + static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; +} + +void *timex_main(void *ptr) +{ + netdata_thread_cleanup_push(timex_main_cleanup, ptr); + + int vdo_cpu_netdata = config_get_boolean(CONFIG_SECTION_TIMEX, "timex plugin resource charts", CONFIG_BOOLEAN_YES); + + int update_every = (int)config_get_number(CONFIG_SECTION_TIMEX, "update every", 10); + if (update_every < localhost->rrd_update_every) + update_every = localhost->rrd_update_every; + + int do_sync = config_get_boolean(CONFIG_SECTION_TIMEX, "clock synchronization state", CONFIG_BOOLEAN_YES); + int do_offset = config_get_boolean(CONFIG_SECTION_TIMEX, "time offset", CONFIG_BOOLEAN_YES); + + if (unlikely(do_sync == CONFIG_BOOLEAN_NO && do_offset == CONFIG_BOOLEAN_NO)) { + info("No charts to show"); + goto exit; + } + + usec_t step = update_every * USEC_PER_SEC; + heartbeat_t hb; + heartbeat_init(&hb); + while (!netdata_exit) { + usec_t duration = heartbeat_monotonic_dt_to_now_usec(&hb); + heartbeat_next(&hb, step); + + struct timex timex_buf = {}; + int sync_state = 0; + sync_state = adjtimex(&timex_buf); + + collected_number divisor = USEC_PER_MS; + if (timex_buf.status & STA_NANO) + divisor = NSEC_PER_MSEC; + + // ---------------------------------------------------------------- + + if (do_sync) { + static RRDSET *st_sync_state = NULL; + static RRDDIM *rd_sync_state; + + if (unlikely(!st_sync_state)) { + st_sync_state = rrdset_create_localhost( + "system", + "clock_sync_state", + NULL, + "clock synchronization", + NULL, + "System Clock Synchronization State", + "state", + PLUGIN_TIMEX_NAME, + NULL, + NETDATA_CHART_PRIO_CLOCK_SYNC_STATE, + update_every, + RRDSET_TYPE_LINE); + + rd_sync_state = rrddim_add(st_sync_state, "state", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } else { + rrdset_next(st_sync_state); + } + + rrddim_set_by_pointer(st_sync_state, rd_sync_state, sync_state != TIME_ERROR ? 1 : 0); + rrdset_done(st_sync_state); + } + + if (do_sync) { + static RRDSET *st_offset = NULL; + static RRDDIM *rd_offset; + + if (unlikely(!st_offset)) { + st_offset = rrdset_create_localhost( + "system", + "clock_sync_offset", + NULL, + "clock synchronization", + NULL, + "Computed Time Offset Between Local System and Reference Clock", + "milliseconds", + PLUGIN_TIMEX_NAME, + NULL, + NETDATA_CHART_PRIO_CLOCK_SYNC_OFFSET, + update_every, + RRDSET_TYPE_LINE); + + rd_offset = rrddim_add(st_offset, "offset", NULL, 1, divisor, RRD_ALGORITHM_ABSOLUTE); + } else { + rrdset_next(st_offset); + } + + rrddim_set_by_pointer(st_offset, rd_offset, timex_buf.offset); + rrdset_done(st_offset); + } + + if (vdo_cpu_netdata) { + static RRDSET *stcpu_thread = NULL, *st_duration = NULL; + static RRDDIM *rd_user = NULL, *rd_system = NULL, *rd_duration = NULL; + + // ---------------------------------------------------------------- + + struct rusage thread; + getrusage(RUSAGE_THREAD, &thread); + + if (unlikely(!stcpu_thread)) { + stcpu_thread = rrdset_create_localhost( + "netdata", + "plugin_timex", + NULL, + "timex", + NULL, + "Netdata Timex Plugin CPU usage", + "milliseconds/s", + PLUGIN_TIMEX_NAME, + NULL, + NETDATA_CHART_PRIO_NETDATA_TIMEX, + update_every, + RRDSET_TYPE_STACKED); + + 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_system, thread.ru_stime.tv_sec * USEC_PER_SEC + thread.ru_stime.tv_usec); + rrdset_done(stcpu_thread); + + // ---------------------------------------------------------------- + + if (unlikely(!st_duration)) { + st_duration = rrdset_create_localhost( + "netdata", + "plugin_timex_dt", + NULL, + "timex", + NULL, + "Netdata Timex Plugin Duration", + "milliseconds/run", + PLUGIN_TIMEX_NAME, + NULL, + NETDATA_CHART_PRIO_NETDATA_TIMEX + 1, + update_every, + RRDSET_TYPE_AREA); + + rd_duration = rrddim_add(st_duration, "duration", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_ABSOLUTE); + } else { + rrdset_next(st_duration); + } + + rrddim_set_by_pointer(st_duration, rd_duration, duration); + rrdset_done(st_duration); + } + } + +exit: + netdata_thread_cleanup_pop(1); + return NULL; +} diff --git a/collectors/timex.plugin/plugin_timex.h b/collectors/timex.plugin/plugin_timex.h new file mode 100644 index 00000000..6025641a --- /dev/null +++ b/collectors/timex.plugin/plugin_timex.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef NETDATA_PLUGIN_TIMEX_H +#define NETDATA_PLUGIN_TIMEX_H + +#include "../../daemon/common.h" + +#if (TARGET_OS == OS_LINUX) + +#define NETDATA_PLUGIN_HOOK_LINUX_TIMEX \ + { \ + .name = "PLUGIN[timex]", \ + .config_section = CONFIG_SECTION_PLUGINS, \ + .config_name = "timex", \ + .enabled = 1, \ + .thread = NULL, \ + .init_routine = NULL, \ + .start_routine = timex_main \ + }, + +extern void *timex_main(void *ptr); + +#else // (TARGET_OS == OS_LINUX) + +#define NETDATA_PLUGIN_HOOK_LINUX_TIMEX + +#endif // (TARGET_OS == OS_LINUX) + +#endif //NETDATA_PLUGIN_TIMEX_H |