logsmanag_config.c 70 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. /** @file logsmanag_config.c
  3. * @brief This file includes functions to manage
  4. * the logs management configuration.
  5. */
  6. #include "logsmanag_config.h"
  7. #include "db_api.h"
  8. #include "rrd_api/rrd_api.h"
  9. #include "helper.h"
  10. g_logs_manag_config_t g_logs_manag_config = {
  11. .update_every = UPDATE_EVERY,
  12. .update_timeout = UPDATE_TIMEOUT_DEFAULT,
  13. .use_log_timestamp = CONFIG_BOOLEAN_AUTO,
  14. .circ_buff_max_size_in_mib = CIRCULAR_BUFF_DEFAULT_MAX_SIZE / (1 MiB),
  15. .circ_buff_drop_logs = CIRCULAR_BUFF_DEFAULT_DROP_LOGS,
  16. .compression_acceleration = COMPRESSION_ACCELERATION_DEFAULT,
  17. .db_mode = GLOBAL_DB_MODE_DEFAULT,
  18. .disk_space_limit_in_mib = DISK_SPACE_LIMIT_DEFAULT,
  19. .buff_flush_to_db_interval = SAVE_BLOB_TO_DB_DEFAULT,
  20. .enable_collected_logs_total = ENABLE_COLLECTED_LOGS_TOTAL_DEFAULT,
  21. .enable_collected_logs_rate = ENABLE_COLLECTED_LOGS_RATE_DEFAULT,
  22. .sd_journal_field_prefix = SD_JOURNAL_FIELD_PREFIX,
  23. .do_sd_journal_send = SD_JOURNAL_SEND_DEFAULT
  24. };
  25. static logs_manag_db_mode_t db_mode_str_to_db_mode(const char *const db_mode_str){
  26. if(!db_mode_str || !*db_mode_str) return g_logs_manag_config.db_mode;
  27. else if(!strcasecmp(db_mode_str, "full")) return LOGS_MANAG_DB_MODE_FULL;
  28. else if(!strcasecmp(db_mode_str, "none")) return LOGS_MANAG_DB_MODE_NONE;
  29. else return g_logs_manag_config.db_mode;
  30. }
  31. static struct config log_management_config = {
  32. .first_section = NULL,
  33. .last_section = NULL,
  34. .mutex = NETDATA_MUTEX_INITIALIZER,
  35. .index = {
  36. .avl_tree = {
  37. .root = NULL,
  38. .compar = appconfig_section_compare
  39. },
  40. .rwlock = AVL_LOCK_INITIALIZER
  41. }
  42. };
  43. static struct Chart_meta chart_types[] = {
  44. {.type = FLB_TAIL, .init = generic_chart_init, .update = generic_chart_update},
  45. {.type = FLB_WEB_LOG, .init = web_log_chart_init, .update = web_log_chart_update},
  46. {.type = FLB_KMSG, .init = kernel_chart_init, .update = kernel_chart_update},
  47. {.type = FLB_SYSTEMD, .init = systemd_chart_init, .update = systemd_chart_update},
  48. {.type = FLB_DOCKER_EV, .init = docker_ev_chart_init, .update = docker_ev_chart_update},
  49. {.type = FLB_SYSLOG, .init = generic_chart_init, .update = generic_chart_update},
  50. {.type = FLB_SERIAL, .init = generic_chart_init, .update = generic_chart_update},
  51. {.type = FLB_MQTT, .init = mqtt_chart_init, .update = mqtt_chart_update}
  52. };
  53. char *get_user_config_dir(void){
  54. char *dir = getenv("NETDATA_USER_CONFIG_DIR");
  55. return dir ? dir : CONFIG_DIR;
  56. }
  57. char *get_stock_config_dir(void){
  58. char *dir = getenv("NETDATA_STOCK_CONFIG_DIR");
  59. return dir ? dir : LIBCONFIG_DIR;
  60. }
  61. char *get_log_dir(void){
  62. char *dir = getenv("NETDATA_LOG_DIR");
  63. return dir ? dir : LOG_DIR;
  64. }
  65. char *get_cache_dir(void){
  66. char *dir = getenv("NETDATA_CACHE_DIR");
  67. return dir ? dir : CACHE_DIR;
  68. }
  69. /**
  70. * @brief Cleanup p_file_info struct
  71. * @param p_file_info The struct of File_info type to be cleaned up.
  72. * @todo Pass p_file_info by reference, so that it can be set to NULL. */
  73. static void p_file_info_destroy(void *arg){
  74. struct File_info *p_file_info = (struct File_info *) arg;
  75. // TODO: Clean up rrd / chart stuff.
  76. // p_file_info->chart_meta
  77. if(unlikely(!p_file_info)){
  78. collector_info("p_file_info_destroy() called but p_file_info == NULL - already destroyed?");
  79. return;
  80. }
  81. char chartname[100];
  82. snprintfz(chartname, 100, "%s", p_file_info->chartname ? p_file_info->chartname : "Unknown");
  83. collector_info("[%s]: p_file_info_destroy() cleanup...", chartname);
  84. __atomic_store_n(&p_file_info->state, LOG_SRC_EXITING, __ATOMIC_RELAXED);
  85. if(uv_is_active((uv_handle_t *) &p_file_info->flb_tmp_buff_cpy_timer)){
  86. uv_timer_stop(&p_file_info->flb_tmp_buff_cpy_timer);
  87. if (!uv_is_closing((uv_handle_t *) &p_file_info->flb_tmp_buff_cpy_timer))
  88. uv_close((uv_handle_t *) &p_file_info->flb_tmp_buff_cpy_timer, NULL);
  89. }
  90. // TODO: Need to do proper termination of DB threads and allocated memory.
  91. if(p_file_info->db_writer_thread){
  92. uv_thread_join(p_file_info->db_writer_thread);
  93. sqlite3_finalize(p_file_info->stmt_get_log_msg_metadata_asc);
  94. sqlite3_finalize(p_file_info->stmt_get_log_msg_metadata_desc);
  95. if(sqlite3_close(p_file_info->db) != SQLITE_OK)
  96. collector_error("[%s]: Failed to close database", chartname);
  97. freez(p_file_info->db_mut);
  98. freez((void *) p_file_info->db_metadata);
  99. freez((void *) p_file_info->db_dir);
  100. freez(p_file_info->db_writer_thread);
  101. }
  102. freez((void *) p_file_info->chartname);
  103. freez(p_file_info->filename);
  104. freez((void *) p_file_info->file_basename);
  105. freez((void *) p_file_info->stream_guid);
  106. for(int i = 1; i <= BLOB_MAX_FILES; i++){
  107. if(p_file_info->blob_handles[i]){
  108. uv_fs_close(NULL, NULL, p_file_info->blob_handles[i], NULL);
  109. p_file_info->blob_handles[i] = 0;
  110. }
  111. }
  112. if(p_file_info->circ_buff)
  113. circ_buff_destroy(p_file_info->circ_buff);
  114. if(p_file_info->parser_metrics){
  115. switch(p_file_info->log_type){
  116. case FLB_WEB_LOG: {
  117. if(p_file_info->parser_metrics->web_log)
  118. freez(p_file_info->parser_metrics->web_log);
  119. break;
  120. }
  121. case FLB_KMSG: {
  122. if(p_file_info->parser_metrics->kernel){
  123. dictionary_destroy(p_file_info->parser_metrics->kernel->subsystem);
  124. dictionary_destroy(p_file_info->parser_metrics->kernel->device);
  125. freez(p_file_info->parser_metrics->kernel);
  126. }
  127. break;
  128. }
  129. case FLB_SYSTEMD:
  130. case FLB_SYSLOG: {
  131. if(p_file_info->parser_metrics->systemd)
  132. freez(p_file_info->parser_metrics->systemd);
  133. break;
  134. }
  135. case FLB_DOCKER_EV: {
  136. if(p_file_info->parser_metrics->docker_ev)
  137. freez(p_file_info->parser_metrics->docker_ev);
  138. break;
  139. }
  140. case FLB_MQTT: {
  141. if(p_file_info->parser_metrics->mqtt){
  142. dictionary_destroy(p_file_info->parser_metrics->mqtt->topic);
  143. freez(p_file_info->parser_metrics->mqtt);
  144. }
  145. break;
  146. }
  147. default:
  148. break;
  149. }
  150. for(int i = 0; p_file_info->parser_cus_config &&
  151. p_file_info->parser_metrics->parser_cus &&
  152. p_file_info->parser_cus_config[i]; i++){
  153. freez(p_file_info->parser_cus_config[i]->chartname);
  154. freez(p_file_info->parser_cus_config[i]->regex_str);
  155. freez(p_file_info->parser_cus_config[i]->regex_name);
  156. regfree(&p_file_info->parser_cus_config[i]->regex);
  157. freez(p_file_info->parser_cus_config[i]);
  158. freez(p_file_info->parser_metrics->parser_cus[i]);
  159. }
  160. freez(p_file_info->parser_cus_config);
  161. freez(p_file_info->parser_metrics->parser_cus);
  162. freez(p_file_info->parser_metrics);
  163. }
  164. if(p_file_info->parser_config){
  165. freez(p_file_info->parser_config->gen_config);
  166. freez(p_file_info->parser_config);
  167. }
  168. Flb_output_config_t *output_next = p_file_info->flb_outputs;
  169. while(output_next){
  170. Flb_output_config_t *output = output_next;
  171. output_next = output_next->next;
  172. struct flb_output_config_param *param_next = output->param;
  173. while(param_next){
  174. struct flb_output_config_param *param = param_next;
  175. param_next = param->next;
  176. freez(param->key);
  177. freez(param->val);
  178. freez(param);
  179. }
  180. freez(output->plugin);
  181. freez(output);
  182. }
  183. freez(p_file_info->flb_config);
  184. freez(p_file_info);
  185. collector_info("[%s]: p_file_info_destroy() cleanup done", chartname);
  186. }
  187. void p_file_info_destroy_all(void){
  188. if(p_file_infos_arr){
  189. uv_thread_t thread_id[p_file_infos_arr->count];
  190. for(int i = 0; i < p_file_infos_arr->count; i++){
  191. fatal_assert(0 == uv_thread_create(&thread_id[i], p_file_info_destroy, p_file_infos_arr->data[i]));
  192. }
  193. for(int i = 0; i < p_file_infos_arr->count; i++){
  194. uv_thread_join(&thread_id[i]);
  195. }
  196. freez(p_file_infos_arr);
  197. p_file_infos_arr = NULL;
  198. }
  199. }
  200. /**
  201. * @brief Load logs management configuration.
  202. * @returns 0 if success,
  203. * -1 if config file not found
  204. * -2 if p_flb_srvc_config if is NULL (no flb_srvc_config_t provided)
  205. */
  206. int logs_manag_config_load( flb_srvc_config_t *p_flb_srvc_config,
  207. Flb_socket_config_t **forward_in_config_p,
  208. int g_update_every){
  209. int rc = LOGS_MANAG_CONFIG_LOAD_ERROR_OK;
  210. char section[100];
  211. char temp_path[FILENAME_MAX + 1];
  212. struct config logsmanagement_d_conf = {
  213. .first_section = NULL,
  214. .last_section = NULL,
  215. .mutex = NETDATA_MUTEX_INITIALIZER,
  216. .index = {
  217. .avl_tree = {
  218. .root = NULL,
  219. .compar = appconfig_section_compare
  220. },
  221. .rwlock = AVL_LOCK_INITIALIZER
  222. }
  223. };
  224. char *filename = strdupz_path_subpath(get_user_config_dir(), "logsmanagement.d.conf");
  225. if(!appconfig_load(&logsmanagement_d_conf, filename, 0, NULL)) {
  226. collector_info("CONFIG: cannot load user config '%s'. Will try stock config.", filename);
  227. freez(filename);
  228. filename = strdupz_path_subpath(get_stock_config_dir(), "logsmanagement.d.conf");
  229. if(!appconfig_load(&logsmanagement_d_conf, filename, 0, NULL)){
  230. collector_error("CONFIG: cannot load stock config '%s'. Logs management will be disabled.", filename);
  231. rc = LOGS_MANAG_CONFIG_LOAD_ERROR_NO_STOCK_CONFIG;
  232. }
  233. }
  234. freez(filename);
  235. /* [global] section */
  236. snprintfz(section, 100, "global");
  237. g_logs_manag_config.update_every = appconfig_get_number(
  238. &logsmanagement_d_conf,
  239. section,
  240. "update every",
  241. g_logs_manag_config.update_every);
  242. g_logs_manag_config.update_every =
  243. g_update_every && g_update_every > g_logs_manag_config.update_every ?
  244. g_update_every : g_logs_manag_config.update_every;
  245. g_logs_manag_config.update_timeout = appconfig_get_number(
  246. &logsmanagement_d_conf,
  247. section,
  248. "update timeout",
  249. UPDATE_TIMEOUT_DEFAULT);
  250. if(g_logs_manag_config.update_timeout < g_logs_manag_config.update_every)
  251. g_logs_manag_config.update_timeout = g_logs_manag_config.update_every;
  252. g_logs_manag_config.use_log_timestamp = appconfig_get_boolean_ondemand(
  253. &logsmanagement_d_conf,
  254. section,
  255. "use log timestamp",
  256. g_logs_manag_config.use_log_timestamp);
  257. g_logs_manag_config.circ_buff_max_size_in_mib = appconfig_get_number(
  258. &logsmanagement_d_conf,
  259. section,
  260. "circular buffer max size MiB",
  261. g_logs_manag_config.circ_buff_max_size_in_mib);
  262. g_logs_manag_config.circ_buff_drop_logs = appconfig_get_boolean(
  263. &logsmanagement_d_conf,
  264. section,
  265. "circular buffer drop logs if full",
  266. g_logs_manag_config.circ_buff_drop_logs);
  267. g_logs_manag_config.compression_acceleration = appconfig_get_number(
  268. &logsmanagement_d_conf,
  269. section,
  270. "compression acceleration",
  271. g_logs_manag_config.compression_acceleration);
  272. g_logs_manag_config.enable_collected_logs_total = appconfig_get_boolean(
  273. &logsmanagement_d_conf,
  274. section,
  275. "collected logs total chart enable",
  276. g_logs_manag_config.enable_collected_logs_total);
  277. g_logs_manag_config.enable_collected_logs_rate = appconfig_get_boolean(
  278. &logsmanagement_d_conf,
  279. section,
  280. "collected logs rate chart enable",
  281. g_logs_manag_config.enable_collected_logs_rate);
  282. g_logs_manag_config.do_sd_journal_send = appconfig_get_boolean(
  283. &logsmanagement_d_conf,
  284. section,
  285. "submit logs to system journal",
  286. g_logs_manag_config.do_sd_journal_send);
  287. g_logs_manag_config.sd_journal_field_prefix = appconfig_get(
  288. &logsmanagement_d_conf,
  289. section,
  290. "systemd journal fields prefix",
  291. g_logs_manag_config.sd_journal_field_prefix);
  292. if(!rc){
  293. collector_info("CONFIG: [%s] update every: %d", section, g_logs_manag_config.update_every);
  294. collector_info("CONFIG: [%s] update timeout: %d", section, g_logs_manag_config.update_timeout);
  295. collector_info("CONFIG: [%s] use log timestamp: %d", section, g_logs_manag_config.use_log_timestamp);
  296. collector_info("CONFIG: [%s] circular buffer max size MiB: %d", section, g_logs_manag_config.circ_buff_max_size_in_mib);
  297. collector_info("CONFIG: [%s] circular buffer drop logs if full: %d", section, g_logs_manag_config.circ_buff_drop_logs);
  298. collector_info("CONFIG: [%s] compression acceleration: %d", section, g_logs_manag_config.compression_acceleration);
  299. collector_info("CONFIG: [%s] collected logs total chart enable: %d", section, g_logs_manag_config.enable_collected_logs_total);
  300. collector_info("CONFIG: [%s] collected logs rate chart enable: %d", section, g_logs_manag_config.enable_collected_logs_rate);
  301. collector_info("CONFIG: [%s] submit logs to system journal: %d", section, g_logs_manag_config.do_sd_journal_send);
  302. collector_info("CONFIG: [%s] systemd journal fields prefix: %s", section, g_logs_manag_config.sd_journal_field_prefix);
  303. }
  304. /* [db] section */
  305. snprintfz(section, 100, "db");
  306. const char *const db_mode_str = appconfig_get(
  307. &logsmanagement_d_conf,
  308. section,
  309. "db mode",
  310. GLOBAL_DB_MODE_DEFAULT_STR);
  311. g_logs_manag_config.db_mode = db_mode_str_to_db_mode(db_mode_str);
  312. snprintfz(temp_path, FILENAME_MAX, "%s" LOGS_MANAG_DB_SUBPATH, get_cache_dir());
  313. db_set_main_dir(appconfig_get(&logsmanagement_d_conf, section, "db dir", temp_path));
  314. g_logs_manag_config.buff_flush_to_db_interval = appconfig_get_number(
  315. &logsmanagement_d_conf,
  316. section,
  317. "circular buffer flush to db",
  318. g_logs_manag_config.buff_flush_to_db_interval);
  319. g_logs_manag_config.disk_space_limit_in_mib = appconfig_get_number(
  320. &logsmanagement_d_conf,
  321. section,
  322. "disk space limit MiB",
  323. g_logs_manag_config.disk_space_limit_in_mib);
  324. if(!rc){
  325. collector_info("CONFIG: [%s] db mode: %s [%d]", section, db_mode_str, (int) g_logs_manag_config.db_mode);
  326. collector_info("CONFIG: [%s] db dir: %s", section, temp_path);
  327. collector_info("CONFIG: [%s] circular buffer flush to db: %d", section, g_logs_manag_config.buff_flush_to_db_interval);
  328. collector_info("CONFIG: [%s] disk space limit MiB: %d", section, g_logs_manag_config.disk_space_limit_in_mib);
  329. }
  330. /* [forward input] section */
  331. snprintfz(section, 100, "forward input");
  332. const int fwd_enable = appconfig_get_boolean(
  333. &logsmanagement_d_conf,
  334. section,
  335. "enabled",
  336. CONFIG_BOOLEAN_NO);
  337. *forward_in_config_p = (Flb_socket_config_t *) callocz(1, sizeof(Flb_socket_config_t));
  338. (*forward_in_config_p)->unix_path = appconfig_get(
  339. &logsmanagement_d_conf,
  340. section,
  341. "unix path",
  342. FLB_FORWARD_UNIX_PATH_DEFAULT);
  343. (*forward_in_config_p)->unix_perm = appconfig_get(
  344. &logsmanagement_d_conf,
  345. section,
  346. "unix perm",
  347. FLB_FORWARD_UNIX_PERM_DEFAULT);
  348. // TODO: Check if listen is in valid format
  349. (*forward_in_config_p)->listen = appconfig_get(
  350. &logsmanagement_d_conf,
  351. section,
  352. "listen",
  353. FLB_FORWARD_ADDR_DEFAULT);
  354. (*forward_in_config_p)->port = appconfig_get(
  355. &logsmanagement_d_conf,
  356. section,
  357. "port",
  358. FLB_FORWARD_PORT_DEFAULT);
  359. if(!rc){
  360. collector_info("CONFIG: [%s] enabled: %s", section, fwd_enable ? "yes" : "no");
  361. collector_info("CONFIG: [%s] unix path: %s", section, (*forward_in_config_p)->unix_path);
  362. collector_info("CONFIG: [%s] unix perm: %s", section, (*forward_in_config_p)->unix_perm);
  363. collector_info("CONFIG: [%s] listen: %s", section, (*forward_in_config_p)->listen);
  364. collector_info("CONFIG: [%s] port: %s", section, (*forward_in_config_p)->port);
  365. }
  366. if(!fwd_enable) {
  367. freez(*forward_in_config_p);
  368. *forward_in_config_p = NULL;
  369. }
  370. /* [fluent bit] section */
  371. snprintfz(section, 100, "fluent bit");
  372. snprintfz(temp_path, FILENAME_MAX, "%s/%s", get_log_dir(), FLB_LOG_FILENAME_DEFAULT);
  373. if(p_flb_srvc_config){
  374. p_flb_srvc_config->flush = appconfig_get(
  375. &logsmanagement_d_conf,
  376. section,
  377. "flush",
  378. p_flb_srvc_config->flush);
  379. p_flb_srvc_config->http_listen = appconfig_get(
  380. &logsmanagement_d_conf,
  381. section,
  382. "http listen",
  383. p_flb_srvc_config->http_listen);
  384. p_flb_srvc_config->http_port = appconfig_get(
  385. &logsmanagement_d_conf,
  386. section,
  387. "http port",
  388. p_flb_srvc_config->http_port);
  389. p_flb_srvc_config->http_server = appconfig_get(
  390. &logsmanagement_d_conf,
  391. section,
  392. "http server",
  393. p_flb_srvc_config->http_server);
  394. p_flb_srvc_config->log_path = appconfig_get(
  395. &logsmanagement_d_conf,
  396. section,
  397. "log file",
  398. temp_path);
  399. p_flb_srvc_config->log_level = appconfig_get(
  400. &logsmanagement_d_conf,
  401. section,
  402. "log level",
  403. p_flb_srvc_config->log_level);
  404. p_flb_srvc_config->coro_stack_size = appconfig_get(
  405. &logsmanagement_d_conf,
  406. section,
  407. "coro stack size",
  408. p_flb_srvc_config->coro_stack_size);
  409. }
  410. else
  411. rc = LOGS_MANAG_CONFIG_LOAD_ERROR_P_FLB_SRVC_NULL;
  412. if(!rc){
  413. collector_info("CONFIG: [%s] flush: %s", section, p_flb_srvc_config->flush);
  414. collector_info("CONFIG: [%s] http listen: %s", section, p_flb_srvc_config->http_listen);
  415. collector_info("CONFIG: [%s] http port: %s", section, p_flb_srvc_config->http_port);
  416. collector_info("CONFIG: [%s] http server: %s", section, p_flb_srvc_config->http_server);
  417. collector_info("CONFIG: [%s] log file: %s", section, p_flb_srvc_config->log_path);
  418. collector_info("CONFIG: [%s] log level: %s", section, p_flb_srvc_config->log_level);
  419. collector_info("CONFIG: [%s] coro stack size: %s", section, p_flb_srvc_config->coro_stack_size);
  420. }
  421. return rc;
  422. }
  423. static bool metrics_dict_conflict_cb(const DICTIONARY_ITEM *item __maybe_unused, void *old_value, void *new_value, void *data __maybe_unused){
  424. ((metrics_dict_item_t *)old_value)->num_new += ((metrics_dict_item_t *)new_value)->num_new;
  425. return true;
  426. }
  427. #define FLB_OUTPUT_PLUGIN_NAME_KEY "name"
  428. static int flb_output_param_get_cb(void *entry, void *data){
  429. struct config_option *option = (struct config_option *) entry;
  430. Flb_output_config_t *flb_output = (Flb_output_config_t *) data;
  431. char *param_prefix = callocz(1, snprintf(NULL, 0, "output %d", MAX_OUTPUTS_PER_SOURCE) + 1);
  432. sprintf(param_prefix, "output %d", flb_output->id);
  433. size_t param_prefix_len = strlen(param_prefix);
  434. if(!strncasecmp(option->name, param_prefix, param_prefix_len)){ // param->name looks like "output 1 host"
  435. char *param_key = &option->name[param_prefix_len]; // param_key should look like " host"
  436. while(*param_key == ' ') param_key++; // remove whitespace so it looks like "host"
  437. if(*param_key && strcasecmp(param_key, FLB_OUTPUT_PLUGIN_NAME_KEY)){ // ignore param_key "name"
  438. // debug_log( "config_option: name[%s], value[%s]", option->name, option->value);
  439. // debug_log( "config option kv:[%s][%s]", param_key, option->value);
  440. struct flb_output_config_param **p = &flb_output->param;
  441. while((*p) != NULL) p = &((*p)->next); // Go to last param of linked list
  442. (*p) = callocz(1, sizeof(struct flb_output_config_param));
  443. (*p)->key = strdupz(param_key);
  444. (*p)->val = strdupz(option->value);
  445. }
  446. }
  447. freez(param_prefix);
  448. return 0;
  449. }
  450. /**
  451. * @brief Initialize logs management based on a section configuration.
  452. * @note On error, calls p_file_info_destroy() to clean up before returning.
  453. * @param config_section Section to read configuration from.
  454. * @todo How to handle duplicate entries?
  455. */
  456. static void config_section_init(uv_loop_t *main_loop,
  457. struct section *config_section,
  458. Flb_socket_config_t *forward_in_config,
  459. flb_srvc_config_t *p_flb_srvc_config,
  460. netdata_mutex_t *stdout_mut){
  461. struct File_info *p_file_info = callocz(1, sizeof(struct File_info));
  462. /* -------------------------------------------------------------------------
  463. * Check if config_section->name is valid and if so, use it as chartname.
  464. * ------------------------------------------------------------------------- */
  465. if(config_section->name && *config_section->name){
  466. char tmp[LOGS_MANAG_CHARTNAME_SIZE] = {0};
  467. snprintfz(tmp, sizeof(tmp), "%s%s", LOGS_MANAG_CHARTNAME_PREFIX, config_section->name);
  468. netdata_fix_chart_id(tmp);
  469. for(char *ch = (char *) tmp; *ch; ch++)
  470. *ch = *ch == '.' ? '_' : *ch; // Convert dots to underscores
  471. p_file_info->chartname = strdupz(tmp);
  472. collector_info("[%s]: Initializing config loading", p_file_info->chartname);
  473. } else {
  474. collector_error("Invalid logs management config section.");
  475. return p_file_info_destroy(p_file_info);
  476. }
  477. /* -------------------------------------------------------------------------
  478. * Check if this log source is enabled.
  479. * ------------------------------------------------------------------------- */
  480. if(appconfig_get_boolean(&log_management_config, config_section->name, "enabled", CONFIG_BOOLEAN_NO)){
  481. collector_info("[%s]: enabled = yes", p_file_info->chartname);
  482. } else {
  483. collector_info("[%s]: enabled = no", p_file_info->chartname);
  484. return p_file_info_destroy(p_file_info);
  485. }
  486. /* -------------------------------------------------------------------------
  487. * Check log type.
  488. * ------------------------------------------------------------------------- */
  489. char *type = appconfig_get(&log_management_config, config_section->name, "log type", "flb_tail");
  490. if(!type || !*type) p_file_info->log_type = FLB_TAIL; // Default
  491. else{
  492. if(!strcasecmp(type, "flb_tail")) p_file_info->log_type = FLB_TAIL;
  493. else if (!strcasecmp(type, "flb_web_log")) p_file_info->log_type = FLB_WEB_LOG;
  494. else if (!strcasecmp(type, "flb_kmsg")) p_file_info->log_type = FLB_KMSG;
  495. else if (!strcasecmp(type, "flb_systemd")) p_file_info->log_type = FLB_SYSTEMD;
  496. else if (!strcasecmp(type, "flb_docker_events")) p_file_info->log_type = FLB_DOCKER_EV;
  497. else if (!strcasecmp(type, "flb_syslog")) p_file_info->log_type = FLB_SYSLOG;
  498. else if (!strcasecmp(type, "flb_serial")) p_file_info->log_type = FLB_SERIAL;
  499. else if (!strcasecmp(type, "flb_mqtt")) p_file_info->log_type = FLB_MQTT;
  500. else p_file_info->log_type = FLB_TAIL;
  501. }
  502. freez(type);
  503. collector_info("[%s]: log type = %s", p_file_info->chartname, log_src_type_t_str[p_file_info->log_type]);
  504. /* -------------------------------------------------------------------------
  505. * Read log source.
  506. * ------------------------------------------------------------------------- */
  507. char *source = appconfig_get(&log_management_config, config_section->name, "log source", "local");
  508. if(!source || !*source) p_file_info->log_source = LOG_SOURCE_LOCAL; // Default
  509. else if(!strcasecmp(source, "forward")) p_file_info->log_source = LOG_SOURCE_FORWARD;
  510. else p_file_info->log_source = LOG_SOURCE_LOCAL;
  511. freez(source);
  512. collector_info("[%s]: log source = %s", p_file_info->chartname, log_src_t_str[p_file_info->log_source]);
  513. if(p_file_info->log_source == LOG_SOURCE_FORWARD && !forward_in_config){
  514. collector_info("[%s]: forward_in_config == NULL - this log source will be disabled", p_file_info->chartname);
  515. return p_file_info_destroy(p_file_info);
  516. }
  517. /* -------------------------------------------------------------------------
  518. * Read stream uuid.
  519. * ------------------------------------------------------------------------- */
  520. p_file_info->stream_guid = appconfig_get(&log_management_config, config_section->name, "stream guid", "");
  521. collector_info("[%s]: stream guid = %s", p_file_info->chartname, p_file_info->stream_guid);
  522. /* -------------------------------------------------------------------------
  523. * Read log path configuration and check if it is valid.
  524. * ------------------------------------------------------------------------- */
  525. p_file_info->filename = appconfig_get(&log_management_config, config_section->name, "log path", LOG_PATH_AUTO);
  526. if( /* path doesn't matter when log source is not local */
  527. (p_file_info->log_source == LOG_SOURCE_LOCAL) &&
  528. /* FLB_SYSLOG is special case, may or may not require a path */
  529. (p_file_info->log_type != FLB_SYSLOG) &&
  530. /* FLB_MQTT is special case, does not require a path */
  531. (p_file_info->log_type != FLB_MQTT) &&
  532. (!p_file_info->filename /* Sanity check */ ||
  533. !*p_file_info->filename ||
  534. !strcmp(p_file_info->filename, LOG_PATH_AUTO) ||
  535. access(p_file_info->filename, R_OK)
  536. )){
  537. freez(p_file_info->filename);
  538. p_file_info->filename = NULL;
  539. switch(p_file_info->log_type){
  540. case FLB_TAIL:
  541. if(!strcasecmp(p_file_info->chartname, LOGS_MANAG_CHARTNAME_PREFIX "netdata_daemon_log")){
  542. char path[FILENAME_MAX + 1];
  543. snprintfz(path, FILENAME_MAX, "%s/daemon.log", get_log_dir());
  544. if(access(path, R_OK)) {
  545. collector_error("[%s]: 'Netdata daemon.log' path (%s) invalid, unknown or needs permissions",
  546. p_file_info->chartname, path);
  547. return p_file_info_destroy(p_file_info);
  548. } else p_file_info->filename = strdupz(path);
  549. } else if(!strcasecmp(p_file_info->chartname, LOGS_MANAG_CHARTNAME_PREFIX "fluentbit_log")){
  550. if(access(p_flb_srvc_config->log_path, R_OK)){
  551. collector_error("[%s]: Netdata fluentbit.log path (%s) invalid, unknown or needs permissions",
  552. p_file_info->chartname, p_flb_srvc_config->log_path);
  553. return p_file_info_destroy(p_file_info);
  554. } else p_file_info->filename = strdupz(p_flb_srvc_config->log_path);
  555. } else if(!strcasecmp(p_file_info->chartname, LOGS_MANAG_CHARTNAME_PREFIX "auth_log_tail")){
  556. const char * const auth_path_default[] = {
  557. "/var/log/auth.log",
  558. NULL
  559. };
  560. int i = 0;
  561. while(auth_path_default[i] && access(auth_path_default[i], R_OK)) i++;
  562. if(!auth_path_default[i]){
  563. collector_error("[%s]: auth.log path invalid, unknown or needs permissions", p_file_info->chartname);
  564. return p_file_info_destroy(p_file_info);
  565. } else p_file_info->filename = strdupz(auth_path_default[i]);
  566. } else if(!strcasecmp(p_file_info->chartname, "syslog_tail")){
  567. const char * const syslog_path_default[] = {
  568. "/var/log/syslog", /* Debian, Ubuntu */
  569. "/var/log/messages", /* RHEL, Red Hat, CentOS, Fedora */
  570. NULL
  571. };
  572. int i = 0;
  573. while(syslog_path_default[i] && access(syslog_path_default[i], R_OK)) i++;
  574. if(!syslog_path_default[i]){
  575. collector_error("[%s]: syslog path invalid, unknown or needs permissions", p_file_info->chartname);
  576. return p_file_info_destroy(p_file_info);
  577. } else p_file_info->filename = strdupz(syslog_path_default[i]);
  578. }
  579. break;
  580. case FLB_WEB_LOG:
  581. if(!strcasecmp(p_file_info->chartname, LOGS_MANAG_CHARTNAME_PREFIX "apache_access_log")){
  582. const char * const apache_access_path_default[] = {
  583. "/var/log/apache/access.log",
  584. "/var/log/apache2/access.log",
  585. "/var/log/apache2/access_log",
  586. "/var/log/httpd/access_log",
  587. "/var/log/httpd-access.log",
  588. NULL
  589. };
  590. int i = 0;
  591. while(apache_access_path_default[i] && access(apache_access_path_default[i], R_OK)) i++;
  592. if(!apache_access_path_default[i]){
  593. collector_error("[%s]: Apache access.log path invalid, unknown or needs permissions", p_file_info->chartname);
  594. return p_file_info_destroy(p_file_info);
  595. } else p_file_info->filename = strdupz(apache_access_path_default[i]);
  596. } else if(!strcasecmp(p_file_info->chartname, LOGS_MANAG_CHARTNAME_PREFIX "nginx_access_log")){
  597. const char * const nginx_access_path_default[] = {
  598. "/var/log/nginx/access.log",
  599. NULL
  600. };
  601. int i = 0;
  602. while(nginx_access_path_default[i] && access(nginx_access_path_default[i], R_OK)) i++;
  603. if(!nginx_access_path_default[i]){
  604. collector_error("[%s]: Nginx access.log path invalid, unknown or needs permissions", p_file_info->chartname);
  605. return p_file_info_destroy(p_file_info);
  606. } else p_file_info->filename = strdupz(nginx_access_path_default[i]);
  607. }
  608. break;
  609. case FLB_KMSG:
  610. if(access(KMSG_DEFAULT_PATH, R_OK)){
  611. collector_error("[%s]: kmsg default path invalid, unknown or needs permissions", p_file_info->chartname);
  612. return p_file_info_destroy(p_file_info);
  613. } else p_file_info->filename = strdupz(KMSG_DEFAULT_PATH);
  614. break;
  615. case FLB_SYSTEMD:
  616. p_file_info->filename = strdupz(SYSTEMD_DEFAULT_PATH);
  617. break;
  618. case FLB_DOCKER_EV:
  619. if(access(DOCKER_EV_DEFAULT_PATH, R_OK)){
  620. collector_error("[%s]: Docker socket default Unix path invalid, unknown or needs permissions", p_file_info->chartname);
  621. return p_file_info_destroy(p_file_info);
  622. } else p_file_info->filename = strdupz(DOCKER_EV_DEFAULT_PATH);
  623. break;
  624. default:
  625. collector_error("[%s]: log path invalid or unknown", p_file_info->chartname);
  626. return p_file_info_destroy(p_file_info);
  627. }
  628. }
  629. p_file_info->file_basename = get_basename(p_file_info->filename);
  630. collector_info("[%s]: p_file_info->filename: %s", p_file_info->chartname,
  631. p_file_info->filename ? p_file_info->filename : "NULL");
  632. collector_info("[%s]: p_file_info->file_basename: %s", p_file_info->chartname,
  633. p_file_info->file_basename ? p_file_info->file_basename : "NULL");
  634. if(unlikely(!p_file_info->filename)) return p_file_info_destroy(p_file_info);
  635. /* -------------------------------------------------------------------------
  636. * Read "update every" and "update timeout" configuration.
  637. * ------------------------------------------------------------------------- */
  638. p_file_info->update_every = appconfig_get_number( &log_management_config, config_section->name,
  639. "update every", g_logs_manag_config.update_every);
  640. collector_info("[%s]: update every = %d", p_file_info->chartname, p_file_info->update_every);
  641. p_file_info->update_timeout = appconfig_get_number( &log_management_config, config_section->name,
  642. "update timeout", g_logs_manag_config.update_timeout);
  643. if(p_file_info->update_timeout < p_file_info->update_every) p_file_info->update_timeout = p_file_info->update_every;
  644. collector_info("[%s]: update timeout = %d", p_file_info->chartname, p_file_info->update_timeout);
  645. /* -------------------------------------------------------------------------
  646. * Read "use log timestamp" configuration.
  647. * ------------------------------------------------------------------------- */
  648. p_file_info->use_log_timestamp = appconfig_get_boolean_ondemand(&log_management_config, config_section->name,
  649. "use log timestamp",
  650. g_logs_manag_config.use_log_timestamp);
  651. collector_info("[%s]: use log timestamp = %s", p_file_info->chartname,
  652. p_file_info->use_log_timestamp ? "auto or yes" : "no");
  653. /* -------------------------------------------------------------------------
  654. * Read compression acceleration configuration.
  655. * ------------------------------------------------------------------------- */
  656. p_file_info->compression_accel = appconfig_get_number( &log_management_config, config_section->name,
  657. "compression acceleration",
  658. g_logs_manag_config.compression_acceleration);
  659. collector_info("[%s]: compression acceleration = %d", p_file_info->chartname, p_file_info->compression_accel);
  660. /* -------------------------------------------------------------------------
  661. * Read DB mode.
  662. * ------------------------------------------------------------------------- */
  663. const char *const db_mode_str = appconfig_get(&log_management_config, config_section->name, "db mode", NULL);
  664. collector_info("[%s]: db mode = %s", p_file_info->chartname, db_mode_str ? db_mode_str : "NULL");
  665. p_file_info->db_mode = db_mode_str_to_db_mode(db_mode_str);
  666. freez((void *)db_mode_str);
  667. /* -------------------------------------------------------------------------
  668. * Read save logs from buffers to DB interval configuration.
  669. * ------------------------------------------------------------------------- */
  670. p_file_info->buff_flush_to_db_interval = appconfig_get_number( &log_management_config, config_section->name,
  671. "circular buffer flush to db",
  672. g_logs_manag_config.buff_flush_to_db_interval);
  673. if(p_file_info->buff_flush_to_db_interval > SAVE_BLOB_TO_DB_MAX) {
  674. p_file_info->buff_flush_to_db_interval = SAVE_BLOB_TO_DB_MAX;
  675. collector_info("[%s]: circular buffer flush to db out of range. Using maximum permitted value: %d",
  676. p_file_info->chartname, p_file_info->buff_flush_to_db_interval);
  677. } else if(p_file_info->buff_flush_to_db_interval < SAVE_BLOB_TO_DB_MIN) {
  678. p_file_info->buff_flush_to_db_interval = SAVE_BLOB_TO_DB_MIN;
  679. collector_info("[%s]: circular buffer flush to db out of range. Using minimum permitted value: %d",
  680. p_file_info->chartname, p_file_info->buff_flush_to_db_interval);
  681. }
  682. collector_info("[%s]: circular buffer flush to db = %d", p_file_info->chartname, p_file_info->buff_flush_to_db_interval);
  683. /* -------------------------------------------------------------------------
  684. * Read BLOB max size configuration.
  685. * ------------------------------------------------------------------------- */
  686. p_file_info->blob_max_size = appconfig_get_number( &log_management_config, config_section->name,
  687. "disk space limit MiB",
  688. g_logs_manag_config.disk_space_limit_in_mib) MiB / BLOB_MAX_FILES;
  689. collector_info("[%s]: BLOB max size = %lld", p_file_info->chartname, (long long)p_file_info->blob_max_size);
  690. /* -------------------------------------------------------------------------
  691. * Read configuration about sending logs to system journal.
  692. * ------------------------------------------------------------------------- */
  693. p_file_info->do_sd_journal_send = appconfig_get_boolean(&log_management_config, config_section->name,
  694. "submit logs to system journal",
  695. g_logs_manag_config.do_sd_journal_send);
  696. /* -------------------------------------------------------------------------
  697. * Read collected logs chart configuration.
  698. * ------------------------------------------------------------------------- */
  699. p_file_info->parser_config = callocz(1, sizeof(Log_parser_config_t));
  700. if(appconfig_get_boolean(&log_management_config, config_section->name,
  701. "collected logs total chart enable",
  702. g_logs_manag_config.enable_collected_logs_total)){
  703. p_file_info->parser_config->chart_config |= CHART_COLLECTED_LOGS_TOTAL;
  704. }
  705. collector_info( "[%s]: collected logs total chart enable = %s", p_file_info->chartname,
  706. (p_file_info->parser_config->chart_config & CHART_COLLECTED_LOGS_TOTAL) ? "yes" : "no");
  707. if(appconfig_get_boolean(&log_management_config, config_section->name,
  708. "collected logs rate chart enable",
  709. g_logs_manag_config.enable_collected_logs_rate)){
  710. p_file_info->parser_config->chart_config |= CHART_COLLECTED_LOGS_RATE;
  711. }
  712. collector_info( "[%s]: collected logs rate chart enable = %s", p_file_info->chartname,
  713. (p_file_info->parser_config->chart_config & CHART_COLLECTED_LOGS_RATE) ? "yes" : "no");
  714. /* -------------------------------------------------------------------------
  715. * Deal with log-type-specific configuration options.
  716. * ------------------------------------------------------------------------- */
  717. if(p_file_info->log_type == FLB_TAIL || p_file_info->log_type == FLB_WEB_LOG){
  718. Flb_tail_config_t *tail_config = callocz(1, sizeof(Flb_tail_config_t));
  719. if(appconfig_get_boolean(&log_management_config, config_section->name, "use inotify", CONFIG_BOOLEAN_YES))
  720. tail_config->use_inotify = 1;
  721. collector_info( "[%s]: use inotify = %s", p_file_info->chartname, tail_config->use_inotify? "yes" : "no");
  722. p_file_info->flb_config = tail_config;
  723. }
  724. if(p_file_info->log_type == FLB_WEB_LOG){
  725. /* Check if a valid web log format configuration is detected */
  726. char *log_format = appconfig_get(&log_management_config, config_section->name, "log format", LOG_PATH_AUTO);
  727. const char delimiter = ' '; // TODO!!: TO READ FROM CONFIG
  728. collector_info("[%s]: log format = %s", p_file_info->chartname, log_format ? log_format : "NULL!");
  729. /* If "log format = auto" or no "log format" config is detected,
  730. * try log format autodetection based on last log file line.
  731. * TODO 1: Add another case in OR where log_format is compared with a valid reg exp.
  732. * TODO 2: Set default log format and delimiter if not found in config? Or auto-detect? */
  733. if(!log_format || !*log_format || !strcmp(log_format, LOG_PATH_AUTO)){
  734. collector_info("[%s]: Attempting auto-detection of log format", p_file_info->chartname);
  735. char *line = read_last_line(p_file_info->filename, 0);
  736. if(!line){
  737. collector_error("[%s]: read_last_line() returned NULL", p_file_info->chartname);
  738. return p_file_info_destroy(p_file_info);
  739. }
  740. p_file_info->parser_config->gen_config = auto_detect_web_log_parser_config(line, delimiter);
  741. freez(line);
  742. }
  743. else{
  744. p_file_info->parser_config->gen_config = read_web_log_parser_config(log_format, delimiter);
  745. collector_info( "[%s]: Read web log parser config: %s", p_file_info->chartname,
  746. p_file_info->parser_config->gen_config ? "success!" : "failed!");
  747. }
  748. freez(log_format);
  749. if(!p_file_info->parser_config->gen_config){
  750. collector_error("[%s]: No valid web log parser config found", p_file_info->chartname);
  751. return p_file_info_destroy(p_file_info);
  752. }
  753. /* Check whether metrics verification during parsing is required */
  754. Web_log_parser_config_t *wblp_config = (Web_log_parser_config_t *) p_file_info->parser_config->gen_config;
  755. wblp_config->verify_parsed_logs = appconfig_get_boolean( &log_management_config, config_section->name,
  756. "verify parsed logs", CONFIG_BOOLEAN_NO);
  757. collector_info("[%s]: verify parsed logs = %d", p_file_info->chartname, wblp_config->verify_parsed_logs);
  758. wblp_config->skip_timestamp_parsing = p_file_info->use_log_timestamp ? 0 : 1;
  759. collector_info("[%s]: skip_timestamp_parsing = %d", p_file_info->chartname, wblp_config->skip_timestamp_parsing);
  760. for(int j = 0; j < wblp_config->num_fields; j++){
  761. if((wblp_config->fields[j] == VHOST_WITH_PORT || wblp_config->fields[j] == VHOST)
  762. && appconfig_get_boolean(&log_management_config, config_section->name, "vhosts chart", CONFIG_BOOLEAN_NO)){
  763. p_file_info->parser_config->chart_config |= CHART_VHOST;
  764. }
  765. if((wblp_config->fields[j] == VHOST_WITH_PORT || wblp_config->fields[j] == PORT)
  766. && appconfig_get_boolean(&log_management_config, config_section->name, "ports chart", CONFIG_BOOLEAN_NO)){
  767. p_file_info->parser_config->chart_config |= CHART_PORT;
  768. }
  769. if((wblp_config->fields[j] == REQ_CLIENT)
  770. && appconfig_get_boolean(&log_management_config, config_section->name, "IP versions chart", CONFIG_BOOLEAN_NO)){
  771. p_file_info->parser_config->chart_config |= CHART_IP_VERSION;
  772. }
  773. if((wblp_config->fields[j] == REQ_CLIENT)
  774. && appconfig_get_boolean(&log_management_config, config_section->name, "unique client IPs - current poll chart", CONFIG_BOOLEAN_NO)){
  775. p_file_info->parser_config->chart_config |= CHART_REQ_CLIENT_CURRENT;
  776. }
  777. if((wblp_config->fields[j] == REQ_CLIENT)
  778. && appconfig_get_boolean(&log_management_config, config_section->name, "unique client IPs - all-time chart", CONFIG_BOOLEAN_NO)){
  779. p_file_info->parser_config->chart_config |= CHART_REQ_CLIENT_ALL_TIME;
  780. }
  781. if((wblp_config->fields[j] == REQ || wblp_config->fields[j] == REQ_METHOD)
  782. && appconfig_get_boolean(&log_management_config, config_section->name, "http request methods chart", CONFIG_BOOLEAN_NO)){
  783. p_file_info->parser_config->chart_config |= CHART_REQ_METHODS;
  784. }
  785. if((wblp_config->fields[j] == REQ || wblp_config->fields[j] == REQ_PROTO)
  786. && appconfig_get_boolean(&log_management_config, config_section->name, "http protocol versions chart", CONFIG_BOOLEAN_NO)){
  787. p_file_info->parser_config->chart_config |= CHART_REQ_PROTO;
  788. }
  789. if((wblp_config->fields[j] == REQ_SIZE || wblp_config->fields[j] == RESP_SIZE)
  790. && appconfig_get_boolean(&log_management_config, config_section->name, "bandwidth chart", CONFIG_BOOLEAN_NO)){
  791. p_file_info->parser_config->chart_config |= CHART_BANDWIDTH;
  792. }
  793. if((wblp_config->fields[j] == REQ_PROC_TIME)
  794. && appconfig_get_boolean(&log_management_config, config_section->name, "timings chart", CONFIG_BOOLEAN_NO)){
  795. p_file_info->parser_config->chart_config |= CHART_REQ_PROC_TIME;
  796. }
  797. if((wblp_config->fields[j] == RESP_CODE)
  798. && appconfig_get_boolean(&log_management_config, config_section->name, "response code families chart", CONFIG_BOOLEAN_NO)){
  799. p_file_info->parser_config->chart_config |= CHART_RESP_CODE_FAMILY;
  800. }
  801. if((wblp_config->fields[j] == RESP_CODE)
  802. && appconfig_get_boolean(&log_management_config, config_section->name, "response codes chart", CONFIG_BOOLEAN_NO)){
  803. p_file_info->parser_config->chart_config |= CHART_RESP_CODE;
  804. }
  805. if((wblp_config->fields[j] == RESP_CODE)
  806. && appconfig_get_boolean(&log_management_config, config_section->name, "response code types chart", CONFIG_BOOLEAN_NO)){
  807. p_file_info->parser_config->chart_config |= CHART_RESP_CODE_TYPE;
  808. }
  809. if((wblp_config->fields[j] == SSL_PROTO)
  810. && appconfig_get_boolean(&log_management_config, config_section->name, "SSL protocols chart", CONFIG_BOOLEAN_NO)){
  811. p_file_info->parser_config->chart_config |= CHART_SSL_PROTO;
  812. }
  813. if((wblp_config->fields[j] == SSL_CIPHER_SUITE)
  814. && appconfig_get_boolean(&log_management_config, config_section->name, "SSL chipher suites chart", CONFIG_BOOLEAN_NO)){
  815. p_file_info->parser_config->chart_config |= CHART_SSL_CIPHER;
  816. }
  817. }
  818. }
  819. else if(p_file_info->log_type == FLB_KMSG){
  820. Flb_kmsg_config_t *kmsg_config = callocz(1, sizeof(Flb_kmsg_config_t));
  821. kmsg_config->prio_level = appconfig_get(&log_management_config, config_section->name, "prio level", "8");
  822. p_file_info->flb_config = kmsg_config;
  823. if(appconfig_get_boolean(&log_management_config, config_section->name, "severity chart", CONFIG_BOOLEAN_NO)) {
  824. p_file_info->parser_config->chart_config |= CHART_SYSLOG_SEVER;
  825. }
  826. if(appconfig_get_boolean(&log_management_config, config_section->name, "subsystem chart", CONFIG_BOOLEAN_NO)) {
  827. p_file_info->parser_config->chart_config |= CHART_KMSG_SUBSYSTEM;
  828. }
  829. if(appconfig_get_boolean(&log_management_config, config_section->name, "device chart", CONFIG_BOOLEAN_NO)) {
  830. p_file_info->parser_config->chart_config |= CHART_KMSG_DEVICE;
  831. }
  832. }
  833. else if(p_file_info->log_type == FLB_SYSTEMD || p_file_info->log_type == FLB_SYSLOG){
  834. if(p_file_info->log_type == FLB_SYSLOG){
  835. Syslog_parser_config_t *syslog_config = callocz(1, sizeof(Syslog_parser_config_t));
  836. /* Read syslog format */
  837. syslog_config->log_format = appconfig_get( &log_management_config,
  838. config_section->name,
  839. "log format", NULL);
  840. collector_info("[%s]: log format = %s", p_file_info->chartname,
  841. syslog_config->log_format ? syslog_config->log_format : "NULL!");
  842. if(!syslog_config->log_format || !*syslog_config->log_format || !strcasecmp(syslog_config->log_format, "auto")){
  843. freez(syslog_config->log_format);
  844. freez(syslog_config);
  845. return p_file_info_destroy(p_file_info);
  846. }
  847. syslog_config->socket_config = callocz(1, sizeof(Flb_socket_config_t));
  848. /* Read syslog socket mode
  849. * see also https://docs.fluentbit.io/manual/pipeline/inputs/syslog#configuration-parameters */
  850. syslog_config->socket_config->mode = appconfig_get( &log_management_config,
  851. config_section->name,
  852. "mode", "unix_udp");
  853. collector_info("[%s]: mode = %s", p_file_info->chartname, syslog_config->socket_config->mode);
  854. /* Check for valid socket path if (mode == unix_udp) or
  855. * (mode == unix_tcp), else read syslog network interface to bind,
  856. * if (mode == udp) or (mode == tcp). */
  857. if( !strcasecmp(syslog_config->socket_config->mode, "unix_udp") ||
  858. !strcasecmp(syslog_config->socket_config->mode, "unix_tcp")){
  859. if(!p_file_info->filename || !*p_file_info->filename || !strcasecmp(p_file_info->filename, LOG_PATH_AUTO)){
  860. // freez(syslog_config->socket_config->mode);
  861. freez(syslog_config->socket_config);
  862. freez(syslog_config->log_format);
  863. freez(syslog_config);
  864. return p_file_info_destroy(p_file_info);
  865. }
  866. syslog_config->socket_config->unix_perm = appconfig_get(&log_management_config,
  867. config_section->name,
  868. "unix_perm", "0644");
  869. collector_info("[%s]: unix_perm = %s", p_file_info->chartname, syslog_config->socket_config->unix_perm);
  870. } else if( !strcasecmp(syslog_config->socket_config->mode, "udp") ||
  871. !strcasecmp(syslog_config->socket_config->mode, "tcp")){
  872. // TODO: Check if listen is in valid format
  873. syslog_config->socket_config->listen = appconfig_get( &log_management_config,
  874. config_section->name,
  875. "listen", "0.0.0.0");
  876. collector_info("[%s]: listen = %s", p_file_info->chartname, syslog_config->socket_config->listen);
  877. syslog_config->socket_config->port = appconfig_get( &log_management_config,
  878. config_section->name,
  879. "port", "5140");
  880. collector_info("[%s]: port = %s", p_file_info->chartname, syslog_config->socket_config->port);
  881. } else {
  882. /* Any other modes are invalid */
  883. // freez(syslog_config->socket_config->mode);
  884. freez(syslog_config->socket_config);
  885. freez(syslog_config->log_format);
  886. freez(syslog_config);
  887. return p_file_info_destroy(p_file_info);
  888. }
  889. p_file_info->parser_config->gen_config = syslog_config;
  890. }
  891. if(appconfig_get_boolean(&log_management_config, config_section->name, "priority value chart", CONFIG_BOOLEAN_NO)) {
  892. p_file_info->parser_config->chart_config |= CHART_SYSLOG_PRIOR;
  893. }
  894. if(appconfig_get_boolean(&log_management_config, config_section->name, "severity chart", CONFIG_BOOLEAN_NO)) {
  895. p_file_info->parser_config->chart_config |= CHART_SYSLOG_SEVER;
  896. }
  897. if(appconfig_get_boolean(&log_management_config, config_section->name, "facility chart", CONFIG_BOOLEAN_NO)) {
  898. p_file_info->parser_config->chart_config |= CHART_SYSLOG_FACIL;
  899. }
  900. }
  901. else if(p_file_info->log_type == FLB_DOCKER_EV){
  902. if(appconfig_get_boolean(&log_management_config, config_section->name, "event type chart", CONFIG_BOOLEAN_NO)) {
  903. p_file_info->parser_config->chart_config |= CHART_DOCKER_EV_TYPE;
  904. }
  905. if(appconfig_get_boolean(&log_management_config, config_section->name, "event action chart", CONFIG_BOOLEAN_NO)) {
  906. p_file_info->parser_config->chart_config |= CHART_DOCKER_EV_ACTION;
  907. }
  908. }
  909. else if(p_file_info->log_type == FLB_SERIAL){
  910. Flb_serial_config_t *serial_config = callocz(1, sizeof(Flb_serial_config_t));
  911. serial_config->bitrate = appconfig_get(&log_management_config, config_section->name, "bitrate", "115200");
  912. serial_config->min_bytes = appconfig_get(&log_management_config, config_section->name, "min bytes", "1");
  913. serial_config->separator = appconfig_get(&log_management_config, config_section->name, "separator", "");
  914. serial_config->format = appconfig_get(&log_management_config, config_section->name, "format", "");
  915. p_file_info->flb_config = serial_config;
  916. }
  917. else if(p_file_info->log_type == FLB_MQTT){
  918. Flb_socket_config_t *socket_config = callocz(1, sizeof(Flb_socket_config_t));
  919. socket_config->listen = appconfig_get(&log_management_config, config_section->name, "listen", "0.0.0.0");
  920. socket_config->port = appconfig_get(&log_management_config, config_section->name, "port", "1883");
  921. p_file_info->flb_config = socket_config;
  922. if(appconfig_get_boolean(&log_management_config, config_section->name, "topic chart", CONFIG_BOOLEAN_NO)) {
  923. p_file_info->parser_config->chart_config |= CHART_MQTT_TOPIC;
  924. }
  925. }
  926. /* -------------------------------------------------------------------------
  927. * Allocate p_file_info->parser_metrics memory.
  928. * ------------------------------------------------------------------------- */
  929. p_file_info->parser_metrics = callocz(1, sizeof(Log_parser_metrics_t));
  930. switch(p_file_info->log_type){
  931. case FLB_WEB_LOG:{
  932. p_file_info->parser_metrics->web_log = callocz(1, sizeof(Web_log_metrics_t));
  933. break;
  934. }
  935. case FLB_KMSG: {
  936. p_file_info->parser_metrics->kernel = callocz(1, sizeof(Kernel_metrics_t));
  937. p_file_info->parser_metrics->kernel->subsystem = dictionary_create( DICT_OPTION_SINGLE_THREADED |
  938. DICT_OPTION_NAME_LINK_DONT_CLONE |
  939. DICT_OPTION_DONT_OVERWRITE_VALUE);
  940. dictionary_register_conflict_callback(p_file_info->parser_metrics->kernel->subsystem, metrics_dict_conflict_cb, NULL);
  941. p_file_info->parser_metrics->kernel->device = dictionary_create(DICT_OPTION_SINGLE_THREADED |
  942. DICT_OPTION_NAME_LINK_DONT_CLONE |
  943. DICT_OPTION_DONT_OVERWRITE_VALUE);
  944. dictionary_register_conflict_callback(p_file_info->parser_metrics->kernel->device, metrics_dict_conflict_cb, NULL);
  945. break;
  946. }
  947. case FLB_SYSTEMD:
  948. case FLB_SYSLOG: {
  949. p_file_info->parser_metrics->systemd = callocz(1, sizeof(Systemd_metrics_t));
  950. break;
  951. }
  952. case FLB_DOCKER_EV: {
  953. p_file_info->parser_metrics->docker_ev = callocz(1, sizeof(Docker_ev_metrics_t));
  954. break;
  955. }
  956. case FLB_MQTT: {
  957. p_file_info->parser_metrics->mqtt = callocz(1, sizeof(Mqtt_metrics_t));
  958. p_file_info->parser_metrics->mqtt->topic = dictionary_create( DICT_OPTION_SINGLE_THREADED |
  959. DICT_OPTION_NAME_LINK_DONT_CLONE |
  960. DICT_OPTION_DONT_OVERWRITE_VALUE);
  961. dictionary_register_conflict_callback(p_file_info->parser_metrics->mqtt->topic, metrics_dict_conflict_cb, NULL);
  962. break;
  963. }
  964. default:
  965. break;
  966. }
  967. /* -------------------------------------------------------------------------
  968. * Configure (optional) custom charts.
  969. * ------------------------------------------------------------------------- */
  970. p_file_info->parser_cus_config = callocz(1, sizeof(Log_parser_cus_config_t *));
  971. p_file_info->parser_metrics->parser_cus = callocz(1, sizeof(Log_parser_cus_metrics_t *));
  972. for(int cus_off = 1; cus_off <= MAX_CUS_CHARTS_PER_SOURCE; cus_off++){
  973. /* Read chart name config */
  974. char *cus_chart_k = mallocz(snprintf(NULL, 0, "custom %d chart", MAX_CUS_CHARTS_PER_SOURCE) + 1);
  975. sprintf(cus_chart_k, "custom %d chart", cus_off);
  976. char *cus_chart_v = appconfig_get(&log_management_config, config_section->name, cus_chart_k, NULL);
  977. debug_log( "cus chart: (%s:%s)", cus_chart_k, cus_chart_v ? cus_chart_v : "NULL");
  978. freez(cus_chart_k);
  979. if(unlikely(!cus_chart_v)){
  980. collector_error("[%s]: custom %d chart = NULL, custom charts for this log source will be disabled.",
  981. p_file_info->chartname, cus_off);
  982. break;
  983. }
  984. netdata_fix_chart_id(cus_chart_v);
  985. /* Read regex config */
  986. char *cus_regex_k = mallocz(snprintf(NULL, 0, "custom %d regex", MAX_CUS_CHARTS_PER_SOURCE) + 1);
  987. sprintf(cus_regex_k, "custom %d regex", cus_off);
  988. char *cus_regex_v = appconfig_get(&log_management_config, config_section->name, cus_regex_k, NULL);
  989. debug_log( "cus regex: (%s:%s)", cus_regex_k, cus_regex_v ? cus_regex_v : "NULL");
  990. freez(cus_regex_k);
  991. if(unlikely(!cus_regex_v)) {
  992. collector_error("[%s]: custom %d regex = NULL, custom charts for this log source will be disabled.",
  993. p_file_info->chartname, cus_off);
  994. freez(cus_chart_v);
  995. break;
  996. }
  997. /* Read regex name config */
  998. char *cus_regex_name_k = mallocz(snprintf(NULL, 0, "custom %d regex name", MAX_CUS_CHARTS_PER_SOURCE) + 1);
  999. sprintf(cus_regex_name_k, "custom %d regex name", cus_off);
  1000. char *cus_regex_name_v = appconfig_get( &log_management_config, config_section->name,
  1001. cus_regex_name_k, cus_regex_v);
  1002. debug_log( "cus regex name: (%s:%s)", cus_regex_name_k, cus_regex_name_v ? cus_regex_name_v : "NULL");
  1003. freez(cus_regex_name_k);
  1004. m_assert(cus_regex_name_v, "cus_regex_name_v cannot be NULL, should be cus_regex_v");
  1005. /* Escape any backslashes in the regex name, to ensure dimension is displayed correctly in charts */
  1006. int regex_name_bslashes = 0;
  1007. char **p_regex_name = &cus_regex_name_v;
  1008. for(char *p = *p_regex_name; *p; p++) if(unlikely(*p == '\\')) regex_name_bslashes++;
  1009. if(regex_name_bslashes) {
  1010. *p_regex_name = reallocz(*p_regex_name, strlen(*p_regex_name) + 1 + regex_name_bslashes);
  1011. for(char *p = *p_regex_name; *p; p++){
  1012. if(unlikely(*p == '\\')){
  1013. memmove(p + 1, p, strlen(p) + 1);
  1014. *p++ = '\\';
  1015. }
  1016. }
  1017. }
  1018. /* Read ignore case config */
  1019. char *cus_ignore_case_k = mallocz(snprintf(NULL, 0, "custom %d ignore case", MAX_CUS_CHARTS_PER_SOURCE) + 1);
  1020. sprintf(cus_ignore_case_k, "custom %d ignore case", cus_off);
  1021. int cus_ignore_case_v = appconfig_get_boolean( &log_management_config,
  1022. config_section->name, cus_ignore_case_k, CONFIG_BOOLEAN_YES);
  1023. debug_log( "cus case: (%s:%s)", cus_ignore_case_k, cus_ignore_case_v ? "yes" : "no");
  1024. freez(cus_ignore_case_k);
  1025. int regex_flags = cus_ignore_case_v ? REG_EXTENDED | REG_NEWLINE | REG_ICASE : REG_EXTENDED | REG_NEWLINE;
  1026. int rc;
  1027. regex_t regex;
  1028. if (unlikely((rc = regcomp(&regex, cus_regex_v, regex_flags)))){
  1029. size_t regcomp_err_str_size = regerror(rc, &regex, 0, 0);
  1030. char *regcomp_err_str = mallocz(regcomp_err_str_size);
  1031. regerror(rc, &regex, regcomp_err_str, regcomp_err_str_size);
  1032. collector_error("[%s]: could not compile regex for custom %d chart: %s due to error: %s. "
  1033. "Custom charts for this log source will be disabled.",
  1034. p_file_info->chartname, cus_off, cus_chart_v, regcomp_err_str);
  1035. freez(regcomp_err_str);
  1036. freez(cus_chart_v);
  1037. freez(cus_regex_v);
  1038. freez(cus_regex_name_v);
  1039. break;
  1040. };
  1041. /* Allocate memory and copy config to p_file_info->parser_cus_config struct */
  1042. p_file_info->parser_cus_config = reallocz( p_file_info->parser_cus_config,
  1043. (cus_off + 1) * sizeof(Log_parser_cus_config_t *));
  1044. p_file_info->parser_cus_config[cus_off - 1] = callocz(1, sizeof(Log_parser_cus_config_t));
  1045. p_file_info->parser_cus_config[cus_off - 1]->chartname = cus_chart_v;
  1046. p_file_info->parser_cus_config[cus_off - 1]->regex_str = cus_regex_v;
  1047. p_file_info->parser_cus_config[cus_off - 1]->regex_name = cus_regex_name_v;
  1048. p_file_info->parser_cus_config[cus_off - 1]->regex = regex;
  1049. /* Initialise custom log parser metrics struct array */
  1050. p_file_info->parser_metrics->parser_cus = reallocz( p_file_info->parser_metrics->parser_cus,
  1051. (cus_off + 1) * sizeof(Log_parser_cus_metrics_t *));
  1052. p_file_info->parser_metrics->parser_cus[cus_off - 1] = callocz(1, sizeof(Log_parser_cus_metrics_t));
  1053. p_file_info->parser_cus_config[cus_off] = NULL;
  1054. p_file_info->parser_metrics->parser_cus[cus_off] = NULL;
  1055. }
  1056. /* -------------------------------------------------------------------------
  1057. * Configure (optional) Fluent Bit outputs.
  1058. * ------------------------------------------------------------------------- */
  1059. Flb_output_config_t **output_next_p = &p_file_info->flb_outputs;
  1060. for(int out_off = 1; out_off <= MAX_OUTPUTS_PER_SOURCE; out_off++){
  1061. /* Read output plugin */
  1062. char *out_plugin_k = callocz(1, snprintf(NULL, 0, "output %d " FLB_OUTPUT_PLUGIN_NAME_KEY, MAX_OUTPUTS_PER_SOURCE) + 1);
  1063. sprintf(out_plugin_k, "output %d " FLB_OUTPUT_PLUGIN_NAME_KEY, out_off);
  1064. char *out_plugin_v = appconfig_get(&log_management_config, config_section->name, out_plugin_k, NULL);
  1065. debug_log( "output %d "FLB_OUTPUT_PLUGIN_NAME_KEY": %s", out_off, out_plugin_v ? out_plugin_v : "NULL");
  1066. freez(out_plugin_k);
  1067. if(unlikely(!out_plugin_v)){
  1068. collector_error("[%s]: output %d "FLB_OUTPUT_PLUGIN_NAME_KEY" = NULL, outputs for this log source will be disabled.",
  1069. p_file_info->chartname, out_off);
  1070. break;
  1071. }
  1072. Flb_output_config_t *output = callocz(1, sizeof(Flb_output_config_t));
  1073. output->id = out_off;
  1074. output->plugin = out_plugin_v;
  1075. /* Read parameters for this output */
  1076. avl_traverse_lock(&config_section->values_index, flb_output_param_get_cb, output);
  1077. *output_next_p = output;
  1078. output_next_p = &output->next;
  1079. }
  1080. /* -------------------------------------------------------------------------
  1081. * Read circular buffer configuration and initialize the buffer.
  1082. * ------------------------------------------------------------------------- */
  1083. size_t circular_buffer_max_size = ((size_t)appconfig_get_number(&log_management_config,
  1084. config_section->name,
  1085. "circular buffer max size MiB",
  1086. g_logs_manag_config.circ_buff_max_size_in_mib)) MiB;
  1087. if(circular_buffer_max_size > CIRCULAR_BUFF_MAX_SIZE_RANGE_MAX) {
  1088. circular_buffer_max_size = CIRCULAR_BUFF_MAX_SIZE_RANGE_MAX;
  1089. collector_info( "[%s]: circular buffer max size out of range. Using maximum permitted value (MiB): %zu",
  1090. p_file_info->chartname, (size_t) (circular_buffer_max_size / (1 MiB)));
  1091. } else if(circular_buffer_max_size < CIRCULAR_BUFF_MAX_SIZE_RANGE_MIN) {
  1092. circular_buffer_max_size = CIRCULAR_BUFF_MAX_SIZE_RANGE_MIN;
  1093. collector_info( "[%s]: circular buffer max size out of range. Using minimum permitted value (MiB): %zu",
  1094. p_file_info->chartname, (size_t) (circular_buffer_max_size / (1 MiB)));
  1095. }
  1096. collector_info("[%s]: circular buffer max size MiB = %zu", p_file_info->chartname, (size_t) (circular_buffer_max_size / (1 MiB)));
  1097. int circular_buffer_allow_dropped_logs = appconfig_get_boolean( &log_management_config,
  1098. config_section->name,
  1099. "circular buffer drop logs if full",
  1100. g_logs_manag_config.circ_buff_drop_logs);
  1101. collector_info("[%s]: circular buffer drop logs if full = %s", p_file_info->chartname,
  1102. circular_buffer_allow_dropped_logs ? "yes" : "no");
  1103. p_file_info->circ_buff = circ_buff_init(p_file_info->buff_flush_to_db_interval,
  1104. circular_buffer_max_size,
  1105. circular_buffer_allow_dropped_logs);
  1106. /* -------------------------------------------------------------------------
  1107. * Initialize rrd related structures.
  1108. * ------------------------------------------------------------------------- */
  1109. p_file_info->chart_meta = callocz(1, sizeof(struct Chart_meta));
  1110. memcpy(p_file_info->chart_meta, &chart_types[p_file_info->log_type], sizeof(struct Chart_meta));
  1111. p_file_info->chart_meta->base_prio = NETDATA_CHART_PRIO_LOGS_BASE + p_file_infos_arr->count * NETDATA_CHART_PRIO_LOGS_INCR;
  1112. netdata_mutex_lock(stdout_mut);
  1113. p_file_info->chart_meta->init(p_file_info);
  1114. fflush(stdout);
  1115. netdata_mutex_unlock(stdout_mut);
  1116. /* -------------------------------------------------------------------------
  1117. * Initialize input plugin for local log sources.
  1118. * ------------------------------------------------------------------------- */
  1119. if(p_file_info->log_source == LOG_SOURCE_LOCAL){
  1120. int rc = flb_add_input(p_file_info);
  1121. if(unlikely(rc)){
  1122. collector_error("[%s]: flb_add_input() error: %d", p_file_info->chartname, rc);
  1123. return p_file_info_destroy(p_file_info);
  1124. }
  1125. }
  1126. /* flb_complete_item_timer_timeout_cb() is needed for both local and
  1127. * non-local sources. */
  1128. p_file_info->flb_tmp_buff_cpy_timer.data = p_file_info;
  1129. if(unlikely(0 != uv_mutex_init(&p_file_info->flb_tmp_buff_mut)))
  1130. fatal("uv_mutex_init(&p_file_info->flb_tmp_buff_mut) failed");
  1131. fatal_assert(0 == uv_timer_init( main_loop,
  1132. &p_file_info->flb_tmp_buff_cpy_timer));
  1133. fatal_assert(0 == uv_timer_start( &p_file_info->flb_tmp_buff_cpy_timer,
  1134. flb_complete_item_timer_timeout_cb, 0,
  1135. p_file_info->update_timeout * MSEC_PER_SEC));
  1136. /* -------------------------------------------------------------------------
  1137. * All set up successfully - add p_file_info to list of all p_file_info structs.
  1138. * ------------------------------------------------------------------------- */
  1139. p_file_infos_arr->data = reallocz(p_file_infos_arr->data, (++p_file_infos_arr->count) * (sizeof p_file_info));
  1140. p_file_infos_arr->data[p_file_infos_arr->count - 1] = p_file_info;
  1141. __atomic_store_n(&p_file_info->state, LOG_SRC_READY, __ATOMIC_RELAXED);
  1142. collector_info("[%s]: initialization completed", p_file_info->chartname);
  1143. }
  1144. void config_file_load( uv_loop_t *main_loop,
  1145. Flb_socket_config_t *p_forward_in_config,
  1146. flb_srvc_config_t *p_flb_srvc_config,
  1147. netdata_mutex_t *stdout_mut){
  1148. int user_default_conf_found = 0;
  1149. struct section *config_section;
  1150. char tmp_name[FILENAME_MAX + 1];
  1151. snprintfz(tmp_name, FILENAME_MAX, "%s/logsmanagement.d", get_user_config_dir());
  1152. DIR *dir = opendir(tmp_name);
  1153. if(dir){
  1154. struct dirent *de = NULL;
  1155. while ((de = readdir(dir))) {
  1156. size_t d_name_len = strlen(de->d_name);
  1157. if (de->d_type == DT_DIR || d_name_len < 6 || strncmp(&de->d_name[d_name_len - 5], ".conf", sizeof(".conf")))
  1158. continue;
  1159. if(!user_default_conf_found && !strncmp(de->d_name, "default.conf", sizeof("default.conf")))
  1160. user_default_conf_found = 1;
  1161. snprintfz(tmp_name, FILENAME_MAX, "%s/logsmanagement.d/%s", get_user_config_dir(), de->d_name);
  1162. collector_info("loading config:%s", tmp_name);
  1163. log_management_config = (struct config){
  1164. .first_section = NULL,
  1165. .last_section = NULL,
  1166. .mutex = NETDATA_MUTEX_INITIALIZER,
  1167. .index = {
  1168. .avl_tree = {
  1169. .root = NULL,
  1170. .compar = appconfig_section_compare
  1171. },
  1172. .rwlock = AVL_LOCK_INITIALIZER
  1173. }
  1174. };
  1175. if(!appconfig_load(&log_management_config, tmp_name, 0, NULL))
  1176. continue;
  1177. config_section = log_management_config.first_section;
  1178. do {
  1179. config_section_init(main_loop, config_section, p_forward_in_config, p_flb_srvc_config, stdout_mut);
  1180. config_section = config_section->next;
  1181. } while(config_section);
  1182. }
  1183. closedir(dir);
  1184. }
  1185. if(!user_default_conf_found){
  1186. collector_info("CONFIG: cannot load user config '%s/logsmanagement.d/default.conf'. Will try stock config.", get_user_config_dir());
  1187. snprintfz(tmp_name, FILENAME_MAX, "%s/logsmanagement.d/default.conf", get_stock_config_dir());
  1188. if(!appconfig_load(&log_management_config, tmp_name, 0, NULL)){
  1189. collector_error("CONFIG: cannot load stock config '%s/logsmanagement.d/default.conf'. Logs management will be disabled.", get_stock_config_dir());
  1190. exit(1);
  1191. }
  1192. config_section = log_management_config.first_section;
  1193. do {
  1194. config_section_init(main_loop, config_section, p_forward_in_config, p_flb_srvc_config, stdout_mut);
  1195. config_section = config_section->next;
  1196. } while(config_section);
  1197. }
  1198. }