logsmanagement.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. /** @file logsmanagement.c
  3. * @brief This is the main file of the Netdata logs management project
  4. *
  5. * The aim of the project is to add the capability to collect, parse and
  6. * query logs in the Netdata agent. For more information please refer
  7. * to the project's [README](README.md) file.
  8. */
  9. #include <uv.h>
  10. #include "daemon/common.h"
  11. #include "db_api.h"
  12. #include "file_info.h"
  13. #include "flb_plugin.h"
  14. #include "functions.h"
  15. #include "helper.h"
  16. #include "libnetdata/required_dummies.h"
  17. #include "logsmanag_config.h"
  18. #include "rrd_api/rrd_api_stats.h"
  19. #if defined(ENABLE_LOGSMANAGEMENT_TESTS)
  20. #include "logsmanagement/unit_test/unit_test.h"
  21. #endif
  22. netdata_mutex_t stdout_mut = NETDATA_MUTEX_INITIALIZER;
  23. bool logsmanagement_should_exit = false;
  24. struct File_infos_arr *p_file_infos_arr = NULL;
  25. static uv_loop_t *main_loop;
  26. static struct {
  27. uv_signal_t sig;
  28. const int signum;
  29. } signals[] = {
  30. // Add here signals that will terminate the plugin
  31. {.signum = SIGINT},
  32. {.signum = SIGQUIT},
  33. {.signum = SIGPIPE},
  34. {.signum = SIGTERM}
  35. };
  36. static void signal_handler(uv_signal_t *handle, int signum __maybe_unused) {
  37. UNUSED(handle);
  38. debug_log("Signal received: %d\n", signum);
  39. __atomic_store_n(&logsmanagement_should_exit, true, __ATOMIC_RELAXED);
  40. }
  41. static void on_walk_cleanup(uv_handle_t* handle, void* data){
  42. UNUSED(data);
  43. if (!uv_is_closing(handle))
  44. uv_close(handle, NULL);
  45. }
  46. /**
  47. * @brief The main function of the logs management plugin.
  48. * @details Any static asserts are most likely going to be inluded here. After
  49. * any initialisation routines, the default uv_loop_t is executed indefinitely.
  50. */
  51. int main(int argc, char **argv) {
  52. /* Static asserts */
  53. #pragma GCC diagnostic push
  54. #pragma GCC diagnostic ignored "-Wunused-local-typedefs"
  55. COMPILE_TIME_ASSERT(SAVE_BLOB_TO_DB_MIN <= SAVE_BLOB_TO_DB_MAX);
  56. COMPILE_TIME_ASSERT(CIRCULAR_BUFF_DEFAULT_MAX_SIZE >= CIRCULAR_BUFF_MAX_SIZE_RANGE_MIN);
  57. COMPILE_TIME_ASSERT(CIRCULAR_BUFF_DEFAULT_MAX_SIZE <= CIRCULAR_BUFF_MAX_SIZE_RANGE_MAX);
  58. #pragma GCC diagnostic pop
  59. clocks_init();
  60. program_name = LOGS_MANAGEMENT_PLUGIN_STR;
  61. nd_log_initialize_for_external_plugins(program_name);
  62. // netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
  63. // if(verify_netdata_host_prefix() == -1) exit(1);
  64. int g_update_every = 0;
  65. for(int i = 1; i < argc ; i++) {
  66. if(isdigit(*argv[i]) && !g_update_every && str2i(argv[i]) > 0 && str2i(argv[i]) < 86400) {
  67. g_update_every = str2i(argv[i]);
  68. debug_log("new update_every received: %d", g_update_every);
  69. }
  70. else if(!strcmp("--unittest", argv[i])) {
  71. #if defined(ENABLE_LOGSMANAGEMENT_TESTS)
  72. exit(logs_management_unittest());
  73. #else
  74. collector_error("%s was not built with unit test support.", program_name);
  75. #endif
  76. }
  77. else if(!strcmp("version", argv[i]) ||
  78. !strcmp("-version", argv[i]) ||
  79. !strcmp("--version", argv[i]) ||
  80. !strcmp("-v", argv[i]) ||
  81. !strcmp("-V", argv[i])) {
  82. printf(VERSION"\n");
  83. exit(0);
  84. }
  85. else if(!strcmp("-h", argv[i]) ||
  86. !strcmp("--help", argv[i])) {
  87. fprintf(stderr,
  88. "\n"
  89. " netdata %s %s\n"
  90. " Copyright (C) 2023 Netdata Inc.\n"
  91. " Released under GNU General Public License v3 or later.\n"
  92. " All rights reserved.\n"
  93. "\n"
  94. " This program is the logs management plugin for netdata.\n"
  95. "\n"
  96. " Available command line options:\n"
  97. "\n"
  98. " --unittest run unit tests and exit\n"
  99. "\n"
  100. " -v\n"
  101. " -V\n"
  102. " --version print version and exit\n"
  103. "\n"
  104. " -h\n"
  105. " --help print this message and exit\n"
  106. "\n"
  107. " For more information:\n"
  108. " https://github.com/netdata/netdata/tree/master/collectors/logs-management.plugin\n"
  109. "\n",
  110. program_name,
  111. VERSION
  112. );
  113. exit(1);
  114. }
  115. else
  116. collector_error("%s(): ignoring parameter '%s'", __FUNCTION__, argv[i]);
  117. }
  118. Flb_socket_config_t *p_forward_in_config = NULL;
  119. main_loop = mallocz(sizeof(uv_loop_t));
  120. fatal_assert(uv_loop_init(main_loop) == 0);
  121. flb_srvc_config_t flb_srvc_config = {
  122. .flush = FLB_FLUSH_DEFAULT,
  123. .http_listen = FLB_HTTP_LISTEN_DEFAULT,
  124. .http_port = FLB_HTTP_PORT_DEFAULT,
  125. .http_server = FLB_HTTP_SERVER_DEFAULT,
  126. .log_path = "NULL",
  127. .log_level = FLB_LOG_LEVEL_DEFAULT,
  128. .coro_stack_size = FLB_CORO_STACK_SIZE_DEFAULT
  129. };
  130. p_file_infos_arr = callocz(1, sizeof(struct File_infos_arr));
  131. if(logs_manag_config_load(&flb_srvc_config, &p_forward_in_config, g_update_every))
  132. exit(1);
  133. if(flb_init(flb_srvc_config, get_stock_config_dir(), g_logs_manag_config.sd_journal_field_prefix)){
  134. collector_error("flb_init() failed - logs management will be disabled");
  135. exit(1);
  136. }
  137. if(flb_add_fwd_input(p_forward_in_config))
  138. collector_error("flb_add_fwd_input() failed - logs management forward input will be disabled");
  139. /* Initialize logs management for each configuration section */
  140. config_file_load(main_loop, p_forward_in_config, &flb_srvc_config, &stdout_mut);
  141. if(p_file_infos_arr->count == 0){
  142. collector_info("No valid configuration could be found for any log source - logs management will be disabled");
  143. exit(1);
  144. }
  145. /* Run Fluent Bit engine
  146. * NOTE: flb_run() ideally would be executed after db_init(), but in case of
  147. * a db_init() failure, it is easier to call flb_stop_and_cleanup() rather
  148. * than the other way round (i.e. cleaning up after db_init(), if flb_run()
  149. * fails). */
  150. if(flb_run()){
  151. collector_error("flb_run() failed - logs management will be disabled");
  152. exit(1);
  153. }
  154. if(db_init()){
  155. collector_error("db_init() failed - logs management will be disabled");
  156. exit(1);
  157. }
  158. uv_thread_t *p_stats_charts_thread_id = NULL;
  159. const char *const netdata_internals_monitoring = getenv("NETDATA_INTERNALS_MONITORING");
  160. if( netdata_internals_monitoring &&
  161. *netdata_internals_monitoring &&
  162. strcmp(netdata_internals_monitoring, "YES") == 0){
  163. p_stats_charts_thread_id = mallocz(sizeof(uv_thread_t));
  164. fatal_assert(0 == uv_thread_create(p_stats_charts_thread_id, stats_charts_init, &stdout_mut));
  165. }
  166. #if defined(__STDC_VERSION__)
  167. debug_log( "__STDC_VERSION__: %ld", __STDC_VERSION__);
  168. #else
  169. debug_log( "__STDC_VERSION__ undefined");
  170. #endif // defined(__STDC_VERSION__)
  171. debug_log( "libuv version: %s", uv_version_string());
  172. debug_log( "LZ4 version: %s", LZ4_versionString());
  173. debug_log( "SQLITE version: " SQLITE_VERSION);
  174. for(int i = 0; i < (int) (sizeof(signals) / sizeof(signals[0])); i++){
  175. uv_signal_init(main_loop, &signals[i].sig);
  176. uv_signal_start(&signals[i].sig, signal_handler, signals[i].signum);
  177. }
  178. struct functions_evloop_globals *wg = logsmanagement_func_facets_init(&logsmanagement_should_exit);
  179. collector_info("%s setup completed successfully", program_name);
  180. /* Run uvlib loop. */
  181. while(!__atomic_load_n(&logsmanagement_should_exit, __ATOMIC_RELAXED))
  182. uv_run(main_loop, UV_RUN_ONCE);
  183. /* If there are valid log sources, there should always be valid handles */
  184. collector_info("uv_run(main_loop, ...); no handles or requests - cleaning up...");
  185. nd_log_limits_unlimited();
  186. // TODO: Clean up stats charts memory
  187. if(p_stats_charts_thread_id){
  188. uv_thread_join(p_stats_charts_thread_id);
  189. freez(p_stats_charts_thread_id);
  190. }
  191. uv_stop(main_loop);
  192. flb_terminate();
  193. flb_free_fwd_input_out_cb();
  194. p_file_info_destroy_all();
  195. uv_walk(main_loop, on_walk_cleanup, NULL);
  196. while(0 != uv_run(main_loop, UV_RUN_ONCE));
  197. if(uv_loop_close(main_loop))
  198. m_assert(0, "uv_loop_close() result not 0");
  199. freez(main_loop);
  200. functions_evloop_cancel_threads(wg);
  201. collector_info("logs management clean up done - exiting");
  202. exit(0);
  203. }