plugin_timex.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "daemon/common.h"
  3. #include "libnetdata/os.h"
  4. #define PLUGIN_TIMEX_NAME "timex.plugin"
  5. #define CONFIG_SECTION_TIMEX "plugin:timex"
  6. static void timex_main_cleanup(void *ptr)
  7. {
  8. struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
  9. static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
  10. info("cleaning up...");
  11. static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
  12. }
  13. void *timex_main(void *ptr)
  14. {
  15. netdata_thread_cleanup_push(timex_main_cleanup, ptr);
  16. int vdo_cpu_netdata = config_get_boolean(CONFIG_SECTION_TIMEX, "timex plugin resource charts", CONFIG_BOOLEAN_YES);
  17. int update_every = (int)config_get_number(CONFIG_SECTION_TIMEX, "update every", 10);
  18. if (update_every < localhost->rrd_update_every)
  19. update_every = localhost->rrd_update_every;
  20. int do_sync = config_get_boolean(CONFIG_SECTION_TIMEX, "clock synchronization state", CONFIG_BOOLEAN_YES);
  21. int do_offset = config_get_boolean(CONFIG_SECTION_TIMEX, "time offset", CONFIG_BOOLEAN_YES);
  22. if (unlikely(do_sync == CONFIG_BOOLEAN_NO && do_offset == CONFIG_BOOLEAN_NO)) {
  23. info("No charts to show");
  24. goto exit;
  25. }
  26. usec_t step = update_every * USEC_PER_SEC;
  27. heartbeat_t hb;
  28. heartbeat_init(&hb);
  29. while (!netdata_exit) {
  30. usec_t duration = heartbeat_monotonic_dt_to_now_usec(&hb);
  31. heartbeat_next(&hb, step);
  32. struct timex timex_buf = {};
  33. int sync_state = 0;
  34. sync_state = ADJUST_TIMEX(&timex_buf);
  35. collected_number divisor = USEC_PER_MS;
  36. if (timex_buf.status & STA_NANO)
  37. divisor = NSEC_PER_MSEC;
  38. // ----------------------------------------------------------------
  39. if (do_sync) {
  40. static RRDSET *st_sync_state = NULL;
  41. static RRDDIM *rd_sync_state;
  42. if (unlikely(!st_sync_state)) {
  43. st_sync_state = rrdset_create_localhost(
  44. "system",
  45. "clock_sync_state",
  46. NULL,
  47. "clock synchronization",
  48. NULL,
  49. "System Clock Synchronization State",
  50. "state",
  51. PLUGIN_TIMEX_NAME,
  52. NULL,
  53. NETDATA_CHART_PRIO_CLOCK_SYNC_STATE,
  54. update_every,
  55. RRDSET_TYPE_LINE);
  56. rd_sync_state = rrddim_add(st_sync_state, "state", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  57. } else {
  58. rrdset_next(st_sync_state);
  59. }
  60. rrddim_set_by_pointer(st_sync_state, rd_sync_state, sync_state != TIME_ERROR ? 1 : 0);
  61. rrdset_done(st_sync_state);
  62. }
  63. if (do_offset) {
  64. static RRDSET *st_offset = NULL;
  65. static RRDDIM *rd_offset;
  66. if (unlikely(!st_offset)) {
  67. st_offset = rrdset_create_localhost(
  68. "system",
  69. "clock_sync_offset",
  70. NULL,
  71. "clock synchronization",
  72. NULL,
  73. "Computed Time Offset Between Local System and Reference Clock",
  74. "milliseconds",
  75. PLUGIN_TIMEX_NAME,
  76. NULL,
  77. NETDATA_CHART_PRIO_CLOCK_SYNC_OFFSET,
  78. update_every,
  79. RRDSET_TYPE_LINE);
  80. rd_offset = rrddim_add(st_offset, "offset", NULL, 1, divisor, RRD_ALGORITHM_ABSOLUTE);
  81. } else {
  82. rrdset_next(st_offset);
  83. }
  84. rrddim_set_by_pointer(st_offset, rd_offset, timex_buf.offset);
  85. rrdset_done(st_offset);
  86. }
  87. if (vdo_cpu_netdata) {
  88. static RRDSET *stcpu_thread = NULL, *st_duration = NULL;
  89. static RRDDIM *rd_user = NULL, *rd_system = NULL, *rd_duration = NULL;
  90. // ----------------------------------------------------------------
  91. struct rusage thread;
  92. getrusage(RUSAGE_THREAD, &thread);
  93. if (unlikely(!stcpu_thread)) {
  94. stcpu_thread = rrdset_create_localhost(
  95. "netdata",
  96. "plugin_timex",
  97. NULL,
  98. "timex",
  99. NULL,
  100. "Netdata Timex Plugin CPU usage",
  101. "milliseconds/s",
  102. PLUGIN_TIMEX_NAME,
  103. NULL,
  104. NETDATA_CHART_PRIO_NETDATA_TIMEX,
  105. update_every,
  106. RRDSET_TYPE_STACKED);
  107. rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_INCREMENTAL);
  108. rd_system = rrddim_add(stcpu_thread, "system", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_INCREMENTAL);
  109. } else {
  110. rrdset_next(stcpu_thread);
  111. }
  112. rrddim_set_by_pointer(stcpu_thread, rd_user, thread.ru_utime.tv_sec * USEC_PER_SEC + thread.ru_utime.tv_usec);
  113. rrddim_set_by_pointer(
  114. stcpu_thread, rd_system, thread.ru_stime.tv_sec * USEC_PER_SEC + thread.ru_stime.tv_usec);
  115. rrdset_done(stcpu_thread);
  116. // ----------------------------------------------------------------
  117. if (unlikely(!st_duration)) {
  118. st_duration = rrdset_create_localhost(
  119. "netdata",
  120. "plugin_timex_dt",
  121. NULL,
  122. "timex",
  123. NULL,
  124. "Netdata Timex Plugin Duration",
  125. "milliseconds/run",
  126. PLUGIN_TIMEX_NAME,
  127. NULL,
  128. NETDATA_CHART_PRIO_NETDATA_TIMEX + 1,
  129. update_every,
  130. RRDSET_TYPE_AREA);
  131. rd_duration = rrddim_add(st_duration, "duration", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_ABSOLUTE);
  132. } else {
  133. rrdset_next(st_duration);
  134. }
  135. rrddim_set_by_pointer(st_duration, rd_duration, duration);
  136. rrdset_done(st_duration);
  137. }
  138. }
  139. exit:
  140. netdata_thread_cleanup_pop(1);
  141. return NULL;
  142. }