nd_log-init.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "nd_log-internals.h"
  3. // --------------------------------------------------------------------------------------------------------------------
  4. __attribute__((constructor)) void initialize_invocation_id(void) {
  5. // check for a NETDATA_INVOCATION_ID
  6. if(uuid_parse_flexi(getenv("NETDATA_INVOCATION_ID"), nd_log.invocation_id) != 0) {
  7. // not found, check for systemd set INVOCATION_ID
  8. if(uuid_parse_flexi(getenv("INVOCATION_ID"), nd_log.invocation_id) != 0) {
  9. // not found, generate a new one
  10. uuid_generate_random(nd_log.invocation_id);
  11. }
  12. }
  13. char uuid[UUID_COMPACT_STR_LEN];
  14. uuid_unparse_lower_compact(nd_log.invocation_id, uuid);
  15. nd_setenv("NETDATA_INVOCATION_ID", uuid, 1);
  16. }
  17. // --------------------------------------------------------------------------------------------------------------------
  18. void nd_log_initialize_for_external_plugins(const char *name) {
  19. // if we don't run under Netdata, log to stderr,
  20. // otherwise, use the logging method Netdata wants us to use.
  21. #if defined(OS_WINDOWS)
  22. #if defined(HAVE_ETW)
  23. nd_setenv("NETDATA_LOG_METHOD", ETW_NAME, 0);
  24. nd_setenv("NETDATA_LOG_FORMAT", ETW_NAME, 0);
  25. #elif defined(HAVE_WEL)
  26. nd_setenv("NETDATA_LOG_METHOD", WEL_NAME, 0);
  27. nd_setenv("NETDATA_LOG_FORMAT", WEL_NAME, 0);
  28. #else
  29. nd_setenv("NETDATA_LOG_METHOD", "stderr", 0);
  30. nd_setenv("NETDATA_LOG_FORMAT", "logfmt", 0);
  31. #endif
  32. #else
  33. nd_setenv("NETDATA_LOG_METHOD", "stderr", 0);
  34. nd_setenv("NETDATA_LOG_FORMAT", "logfmt", 0);
  35. #endif
  36. nd_log.overwrite_process_source = NDLS_COLLECTORS;
  37. program_name = name;
  38. for(size_t i = 0; i < _NDLS_MAX ;i++) {
  39. nd_log.sources[i].method = STDERR_FILENO;
  40. nd_log.sources[i].fd = -1;
  41. nd_log.sources[i].fp = NULL;
  42. }
  43. nd_log_set_priority_level(getenv("NETDATA_LOG_LEVEL"));
  44. nd_log_set_facility(getenv("NETDATA_SYSLOG_FACILITY"));
  45. time_t period = 1200;
  46. size_t logs = 200;
  47. const char *s = getenv("NETDATA_ERRORS_THROTTLE_PERIOD");
  48. if(s && *s >= '0' && *s <= '9') {
  49. period = str2l(s);
  50. if(period < 0) period = 0;
  51. }
  52. s = getenv("NETDATA_ERRORS_PER_PERIOD");
  53. if(s && *s >= '0' && *s <= '9')
  54. logs = str2u(s);
  55. nd_log_set_flood_protection(logs, period);
  56. if(!netdata_configured_host_prefix) {
  57. s = getenv("NETDATA_HOST_PREFIX");
  58. if(s && *s)
  59. netdata_configured_host_prefix = (char *)s;
  60. }
  61. ND_LOG_METHOD method = nd_log_method2id(getenv("NETDATA_LOG_METHOD"));
  62. ND_LOG_FORMAT format = nd_log_format2id(getenv("NETDATA_LOG_FORMAT"));
  63. if(!IS_VALID_LOG_METHOD_FOR_EXTERNAL_PLUGINS(method)) {
  64. if(is_stderr_connected_to_journal()) {
  65. nd_log(NDLS_COLLECTORS, NDLP_WARNING, "NETDATA_LOG_METHOD is not set. Using journal.");
  66. method = NDLM_JOURNAL;
  67. }
  68. else {
  69. nd_log(NDLS_COLLECTORS, NDLP_WARNING, "NETDATA_LOG_METHOD is not set. Using stderr.");
  70. method = NDLM_STDERR;
  71. }
  72. }
  73. switch(method) {
  74. case NDLM_JOURNAL:
  75. if(!nd_log_journal_direct_init(getenv("NETDATA_SYSTEMD_JOURNAL_PATH")) ||
  76. !nd_log_journal_direct_init(NULL) || !nd_log_journal_systemd_init()) {
  77. nd_log(NDLS_COLLECTORS, NDLP_WARNING, "Failed to initialize journal. Using stderr.");
  78. method = NDLM_STDERR;
  79. }
  80. break;
  81. #if defined(OS_WINDOWS)
  82. #if defined(HAVE_ETW)
  83. case NDLM_ETW:
  84. if(!nd_log_init_etw()) {
  85. nd_log(NDLS_COLLECTORS, NDLP_WARNING, "Failed to initialize Events Tracing for Windows (ETW). Using stderr.");
  86. method = NDLM_STDERR;
  87. }
  88. break;
  89. #endif
  90. #if defined(HAVE_WEL)
  91. case NDLM_WEL:
  92. if(!nd_log_init_wel()) {
  93. nd_log(NDLS_COLLECTORS, NDLP_WARNING, "Failed to initialize Windows Event Log (WEL). Using stderr.");
  94. method = NDLM_STDERR;
  95. }
  96. break;
  97. #endif
  98. #endif
  99. case NDLM_SYSLOG:
  100. nd_log_init_syslog();
  101. break;
  102. default:
  103. method = NDLM_STDERR;
  104. break;
  105. }
  106. for(size_t i = 0; i < _NDLS_MAX ;i++) {
  107. nd_log.sources[i].method = method;
  108. nd_log.sources[i].format = format;
  109. nd_log.sources[i].fd = -1;
  110. nd_log.sources[i].fp = NULL;
  111. }
  112. // nd_log(NDLS_COLLECTORS, NDLP_NOTICE, "FINAL_LOG_METHOD: %s", nd_log_id2method(method));
  113. }
  114. // --------------------------------------------------------------------------------------------------------------------
  115. void nd_log_open(struct nd_log_source *e, ND_LOG_SOURCES source) {
  116. if(e->method == NDLM_DEFAULT)
  117. nd_log_set_user_settings(source, e->filename);
  118. if((e->method == NDLM_FILE && !e->filename) ||
  119. (e->method == NDLM_DEVNULL && e->fd == -1))
  120. e->method = NDLM_DISABLED;
  121. if(e->fp)
  122. fflush(e->fp);
  123. switch(e->method) {
  124. case NDLM_SYSLOG:
  125. nd_log_init_syslog();
  126. break;
  127. case NDLM_JOURNAL:
  128. nd_log_journal_direct_init(NULL);
  129. nd_log_journal_systemd_init();
  130. break;
  131. #if defined(OS_WINDOWS)
  132. #if defined(HAVE_ETW)
  133. case NDLM_ETW:
  134. nd_log_init_etw();
  135. break;
  136. #endif
  137. #if defined(HAVE_WEL)
  138. case NDLM_WEL:
  139. nd_log_init_wel();
  140. break;
  141. #endif
  142. #endif
  143. case NDLM_STDOUT:
  144. e->fp = stdout;
  145. e->fd = STDOUT_FILENO;
  146. break;
  147. case NDLM_DISABLED:
  148. break;
  149. case NDLM_DEFAULT:
  150. case NDLM_STDERR:
  151. e->method = NDLM_STDERR;
  152. e->fp = stderr;
  153. e->fd = STDERR_FILENO;
  154. break;
  155. case NDLM_DEVNULL:
  156. case NDLM_FILE: {
  157. int fd = open(e->filename, O_WRONLY | O_APPEND | O_CREAT, 0664);
  158. if(fd == -1) {
  159. if(e->fd != STDOUT_FILENO && e->fd != STDERR_FILENO) {
  160. e->fd = STDERR_FILENO;
  161. e->method = NDLM_STDERR;
  162. netdata_log_error("Cannot open log file '%s'. Falling back to stderr.", e->filename);
  163. }
  164. else
  165. netdata_log_error("Cannot open log file '%s'. Leaving fd %d as-is.", e->filename, e->fd);
  166. }
  167. else {
  168. if (!nd_log_replace_existing_fd(e, fd)) {
  169. if(e->fd == STDOUT_FILENO || e->fd == STDERR_FILENO) {
  170. if(e->fd == STDOUT_FILENO)
  171. e->method = NDLM_STDOUT;
  172. else if(e->fd == STDERR_FILENO)
  173. e->method = NDLM_STDERR;
  174. // we have dup2() fd, so we can close the one we opened
  175. if(fd != STDOUT_FILENO && fd != STDERR_FILENO)
  176. close(fd);
  177. }
  178. else
  179. e->fd = fd;
  180. }
  181. }
  182. // at this point we have e->fd set properly
  183. if(e->fd == STDOUT_FILENO)
  184. e->fp = stdout;
  185. else if(e->fd == STDERR_FILENO)
  186. e->fp = stderr;
  187. if(!e->fp) {
  188. e->fp = fdopen(e->fd, "a");
  189. if (!e->fp) {
  190. netdata_log_error("Cannot fdopen() fd %d ('%s')", e->fd, e->filename);
  191. if(e->fd != STDOUT_FILENO && e->fd != STDERR_FILENO)
  192. close(e->fd);
  193. e->fp = stderr;
  194. e->fd = STDERR_FILENO;
  195. }
  196. }
  197. else {
  198. if (setvbuf(e->fp, NULL, _IOLBF, 0) != 0)
  199. netdata_log_error("Cannot set line buffering on fd %d ('%s')", e->fd, e->filename);
  200. }
  201. }
  202. break;
  203. }
  204. }
  205. // --------------------------------------------------------------------------------------------------------------------
  206. void nd_log_stdin_init(int fd, const char *filename) {
  207. int f = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0664);
  208. if(f == -1)
  209. return;
  210. if(f != fd) {
  211. dup2(f, fd);
  212. close(f);
  213. }
  214. }
  215. void nd_log_initialize(void) {
  216. nd_log_stdin_init(STDIN_FILENO, "/dev/null");
  217. for(size_t i = 0 ; i < _NDLS_MAX ; i++)
  218. nd_log_open(&nd_log.sources[i], i);
  219. }
  220. void nd_log_reopen_log_files(bool log) {
  221. if(log)
  222. netdata_log_info("Reopening all log files.");
  223. nd_log_initialize();
  224. if(log)
  225. netdata_log_info("Log files re-opened.");
  226. }
  227. void nd_log_reopen_log_files_for_spawn_server(const char *name) {
  228. gettid_uncached();
  229. if(nd_log.syslog.initialized) {
  230. closelog();
  231. nd_log.syslog.initialized = false;
  232. nd_log_init_syslog();
  233. }
  234. if(nd_log.journal_direct.initialized) {
  235. close(nd_log.journal_direct.fd);
  236. nd_log.journal_direct.fd = -1;
  237. nd_log.journal_direct.initialized = false;
  238. nd_log_journal_direct_init(NULL);
  239. }
  240. for(size_t i = 0; i < _NDLS_MAX ;i++) {
  241. if(i != NDLS_COLLECTORS && i != NDLS_DAEMON) continue;
  242. spinlock_init(&nd_log.sources[i].spinlock);
  243. nd_log.sources[i].fd = -1;
  244. nd_log.sources[i].fp = NULL;
  245. nd_log.sources[i].pending_msg = NULL;
  246. #if defined(OS_WINDOWS)
  247. nd_log.sources[i].hEventLog = NULL;
  248. #endif
  249. }
  250. for(size_t i = 0; i < _NDLS_MAX ;i++) {
  251. if(i == NDLS_COLLECTORS || i == NDLS_DAEMON) continue;
  252. nd_log.sources[i].method = NDLM_DISABLED;
  253. }
  254. spinlock_init(&nd_log.std_output.spinlock);
  255. spinlock_init(&nd_log.std_error.spinlock);
  256. nd_log.journal.initialized = false;
  257. nd_log.journal_direct.initialized = false;
  258. nd_log.syslog.initialized = false;
  259. nd_log.eventlog.initialized = false;
  260. nd_log.std_output.initialized = false;
  261. nd_log.std_error.initialized = false;
  262. nd_log_initialize_for_external_plugins(name);
  263. }