log.c 77 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. // do not REMOVE this, it is used by systemd-journal includes to prevent saving the file, function, line of the
  3. // source code that makes the calls, allowing our loggers to log the lines of source code that actually log
  4. #define SD_JOURNAL_SUPPRESS_LOCATION
  5. #include "../libnetdata.h"
  6. #ifdef __FreeBSD__
  7. #include <sys/endian.h>
  8. #endif
  9. #ifdef __APPLE__
  10. #include <machine/endian.h>
  11. #endif
  12. #ifdef HAVE_BACKTRACE
  13. #include <execinfo.h>
  14. #endif
  15. #ifdef HAVE_SYSTEMD
  16. #include <systemd/sd-journal.h>
  17. #endif
  18. #include <syslog.h>
  19. const char *program_name = "";
  20. uint64_t debug_flags = 0;
  21. #ifdef ENABLE_ACLK
  22. int aclklog_enabled = 0;
  23. #endif
  24. // ----------------------------------------------------------------------------
  25. struct nd_log_source;
  26. static bool nd_log_limit_reached(struct nd_log_source *source);
  27. // ----------------------------------------------------------------------------
  28. // logging method
  29. typedef enum __attribute__((__packed__)) {
  30. NDLM_DISABLED = 0,
  31. NDLM_DEVNULL,
  32. NDLM_DEFAULT,
  33. NDLM_JOURNAL,
  34. NDLM_SYSLOG,
  35. NDLM_STDOUT,
  36. NDLM_STDERR,
  37. NDLM_FILE,
  38. } ND_LOG_METHOD;
  39. static struct {
  40. ND_LOG_METHOD method;
  41. const char *name;
  42. } nd_log_methods[] = {
  43. { .method = NDLM_DISABLED, .name = "none" },
  44. { .method = NDLM_DEVNULL, .name = "/dev/null" },
  45. { .method = NDLM_DEFAULT, .name = "default" },
  46. { .method = NDLM_JOURNAL, .name = "journal" },
  47. { .method = NDLM_SYSLOG, .name = "syslog" },
  48. { .method = NDLM_STDOUT, .name = "stdout" },
  49. { .method = NDLM_STDERR, .name = "stderr" },
  50. { .method = NDLM_FILE, .name = "file" },
  51. };
  52. static ND_LOG_METHOD nd_log_method2id(const char *method) {
  53. if(!method || !*method)
  54. return NDLM_DEFAULT;
  55. size_t entries = sizeof(nd_log_methods) / sizeof(nd_log_methods[0]);
  56. for(size_t i = 0; i < entries ;i++) {
  57. if(strcmp(nd_log_methods[i].name, method) == 0)
  58. return nd_log_methods[i].method;
  59. }
  60. return NDLM_FILE;
  61. }
  62. static const char *nd_log_id2method(ND_LOG_METHOD method) {
  63. size_t entries = sizeof(nd_log_methods) / sizeof(nd_log_methods[0]);
  64. for(size_t i = 0; i < entries ;i++) {
  65. if(method == nd_log_methods[i].method)
  66. return nd_log_methods[i].name;
  67. }
  68. return "unknown";
  69. }
  70. #define IS_VALID_LOG_METHOD_FOR_EXTERNAL_PLUGINS(ndlo) ((ndlo) == NDLM_JOURNAL || (ndlo) == NDLM_SYSLOG || (ndlo) == NDLM_STDERR)
  71. const char *nd_log_method_for_external_plugins(const char *s) {
  72. if(s && *s) {
  73. ND_LOG_METHOD method = nd_log_method2id(s);
  74. if(IS_VALID_LOG_METHOD_FOR_EXTERNAL_PLUGINS(method))
  75. return nd_log_id2method(method);
  76. }
  77. return nd_log_id2method(NDLM_STDERR);
  78. }
  79. // ----------------------------------------------------------------------------
  80. // workaround strerror_r()
  81. #if defined(STRERROR_R_CHAR_P)
  82. // GLIBC version of strerror_r
  83. static const char *strerror_result(const char *a, const char *b) { (void)b; return a; }
  84. #elif defined(HAVE_STRERROR_R)
  85. // POSIX version of strerror_r
  86. static const char *strerror_result(int a, const char *b) { (void)a; return b; }
  87. #elif defined(HAVE_C__GENERIC)
  88. // what a trick!
  89. // http://stackoverflow.com/questions/479207/function-overloading-in-c
  90. static const char *strerror_result_int(int a, const char *b) { (void)a; return b; }
  91. static const char *strerror_result_string(const char *a, const char *b) { (void)b; return a; }
  92. #define strerror_result(a, b) _Generic((a), \
  93. int: strerror_result_int, \
  94. char *: strerror_result_string \
  95. )(a, b)
  96. #else
  97. #error "cannot detect the format of function strerror_r()"
  98. #endif
  99. static const char *errno2str(int errnum, char *buf, size_t size) {
  100. return strerror_result(strerror_r(errnum, buf, size), buf);
  101. }
  102. // ----------------------------------------------------------------------------
  103. // facilities
  104. //
  105. // sys/syslog.h (Linux)
  106. // sys/sys/syslog.h (FreeBSD)
  107. // bsd/sys/syslog.h (darwin-xnu)
  108. static struct {
  109. int facility;
  110. const char *name;
  111. } nd_log_facilities[] = {
  112. { LOG_AUTH, "auth" },
  113. { LOG_AUTHPRIV, "authpriv" },
  114. { LOG_CRON, "cron" },
  115. { LOG_DAEMON, "daemon" },
  116. { LOG_FTP, "ftp" },
  117. { LOG_KERN, "kern" },
  118. { LOG_LPR, "lpr" },
  119. { LOG_MAIL, "mail" },
  120. { LOG_NEWS, "news" },
  121. { LOG_SYSLOG, "syslog" },
  122. { LOG_USER, "user" },
  123. { LOG_UUCP, "uucp" },
  124. { LOG_LOCAL0, "local0" },
  125. { LOG_LOCAL1, "local1" },
  126. { LOG_LOCAL2, "local2" },
  127. { LOG_LOCAL3, "local3" },
  128. { LOG_LOCAL4, "local4" },
  129. { LOG_LOCAL5, "local5" },
  130. { LOG_LOCAL6, "local6" },
  131. { LOG_LOCAL7, "local7" },
  132. #ifdef __FreeBSD__
  133. { LOG_CONSOLE, "console" },
  134. { LOG_NTP, "ntp" },
  135. // FreeBSD does not consider 'security' as deprecated.
  136. { LOG_SECURITY, "security" },
  137. #else
  138. // For all other O/S 'security' is mapped to 'auth'.
  139. { LOG_AUTH, "security" },
  140. #endif
  141. #ifdef __APPLE__
  142. { LOG_INSTALL, "install" },
  143. { LOG_NETINFO, "netinfo" },
  144. { LOG_RAS, "ras" },
  145. { LOG_REMOTEAUTH, "remoteauth" },
  146. { LOG_LAUNCHD, "launchd" },
  147. #endif
  148. };
  149. static int nd_log_facility2id(const char *facility) {
  150. size_t entries = sizeof(nd_log_facilities) / sizeof(nd_log_facilities[0]);
  151. for(size_t i = 0; i < entries ;i++) {
  152. if(strcmp(nd_log_facilities[i].name, facility) == 0)
  153. return nd_log_facilities[i].facility;
  154. }
  155. return LOG_DAEMON;
  156. }
  157. static const char *nd_log_id2facility(int facility) {
  158. size_t entries = sizeof(nd_log_facilities) / sizeof(nd_log_facilities[0]);
  159. for(size_t i = 0; i < entries ;i++) {
  160. if(nd_log_facilities[i].facility == facility)
  161. return nd_log_facilities[i].name;
  162. }
  163. return "daemon";
  164. }
  165. // ----------------------------------------------------------------------------
  166. // priorities
  167. static struct {
  168. ND_LOG_FIELD_PRIORITY priority;
  169. const char *name;
  170. } nd_log_priorities[] = {
  171. { .priority = NDLP_EMERG, .name = "emergency" },
  172. { .priority = NDLP_EMERG, .name = "emerg" },
  173. { .priority = NDLP_ALERT, .name = "alert" },
  174. { .priority = NDLP_CRIT, .name = "critical" },
  175. { .priority = NDLP_CRIT, .name = "crit" },
  176. { .priority = NDLP_ERR, .name = "error" },
  177. { .priority = NDLP_ERR, .name = "err" },
  178. { .priority = NDLP_WARNING, .name = "warning" },
  179. { .priority = NDLP_WARNING, .name = "warn" },
  180. { .priority = NDLP_NOTICE, .name = "notice" },
  181. { .priority = NDLP_INFO, .name = NDLP_INFO_STR },
  182. { .priority = NDLP_DEBUG, .name = "debug" },
  183. };
  184. int nd_log_priority2id(const char *priority) {
  185. size_t entries = sizeof(nd_log_priorities) / sizeof(nd_log_priorities[0]);
  186. for(size_t i = 0; i < entries ;i++) {
  187. if(strcmp(nd_log_priorities[i].name, priority) == 0)
  188. return nd_log_priorities[i].priority;
  189. }
  190. return NDLP_INFO;
  191. }
  192. const char *nd_log_id2priority(ND_LOG_FIELD_PRIORITY priority) {
  193. size_t entries = sizeof(nd_log_priorities) / sizeof(nd_log_priorities[0]);
  194. for(size_t i = 0; i < entries ;i++) {
  195. if(priority == nd_log_priorities[i].priority)
  196. return nd_log_priorities[i].name;
  197. }
  198. return NDLP_INFO_STR;
  199. }
  200. // ----------------------------------------------------------------------------
  201. // log sources
  202. const char *nd_log_sources[] = {
  203. [NDLS_UNSET] = "UNSET",
  204. [NDLS_ACCESS] = "access",
  205. [NDLS_ACLK] = "aclk",
  206. [NDLS_COLLECTORS] = "collector",
  207. [NDLS_DAEMON] = "daemon",
  208. [NDLS_HEALTH] = "health",
  209. [NDLS_DEBUG] = "debug",
  210. };
  211. size_t nd_log_source2id(const char *source, ND_LOG_SOURCES def) {
  212. size_t entries = sizeof(nd_log_sources) / sizeof(nd_log_sources[0]);
  213. for(size_t i = 0; i < entries ;i++) {
  214. if(strcmp(nd_log_sources[i], source) == 0)
  215. return i;
  216. }
  217. return def;
  218. }
  219. static const char *nd_log_id2source(ND_LOG_SOURCES source) {
  220. size_t entries = sizeof(nd_log_sources) / sizeof(nd_log_sources[0]);
  221. if(source < entries)
  222. return nd_log_sources[source];
  223. return nd_log_sources[NDLS_COLLECTORS];
  224. }
  225. // ----------------------------------------------------------------------------
  226. // log output formats
  227. typedef enum __attribute__((__packed__)) {
  228. NDLF_JOURNAL,
  229. NDLF_LOGFMT,
  230. NDLF_JSON,
  231. } ND_LOG_FORMAT;
  232. static struct {
  233. ND_LOG_FORMAT format;
  234. const char *name;
  235. } nd_log_formats[] = {
  236. { .format = NDLF_JOURNAL, .name = "journal" },
  237. { .format = NDLF_LOGFMT, .name = "logfmt" },
  238. { .format = NDLF_JSON, .name = "json" },
  239. };
  240. static ND_LOG_FORMAT nd_log_format2id(const char *format) {
  241. if(!format || !*format)
  242. return NDLF_LOGFMT;
  243. size_t entries = sizeof(nd_log_formats) / sizeof(nd_log_formats[0]);
  244. for(size_t i = 0; i < entries ;i++) {
  245. if(strcmp(nd_log_formats[i].name, format) == 0)
  246. return nd_log_formats[i].format;
  247. }
  248. return NDLF_LOGFMT;
  249. }
  250. static const char *nd_log_id2format(ND_LOG_FORMAT format) {
  251. size_t entries = sizeof(nd_log_formats) / sizeof(nd_log_formats[0]);
  252. for(size_t i = 0; i < entries ;i++) {
  253. if(format == nd_log_formats[i].format)
  254. return nd_log_formats[i].name;
  255. }
  256. return "logfmt";
  257. }
  258. // ----------------------------------------------------------------------------
  259. // format dates
  260. void log_date(char *buffer, size_t len, time_t now) {
  261. if(unlikely(!buffer || !len))
  262. return;
  263. time_t t = now;
  264. struct tm *tmp, tmbuf;
  265. tmp = localtime_r(&t, &tmbuf);
  266. if (unlikely(!tmp)) {
  267. buffer[0] = '\0';
  268. return;
  269. }
  270. if (unlikely(strftime(buffer, len, "%Y-%m-%d %H:%M:%S", tmp) == 0))
  271. buffer[0] = '\0';
  272. buffer[len - 1] = '\0';
  273. }
  274. // ----------------------------------------------------------------------------
  275. struct nd_log_limit {
  276. usec_t started_monotonic_ut;
  277. uint32_t counter;
  278. uint32_t prevented;
  279. uint32_t throttle_period;
  280. uint32_t logs_per_period;
  281. uint32_t logs_per_period_backup;
  282. };
  283. #define ND_LOG_LIMITS_DEFAULT (struct nd_log_limit){ .logs_per_period = ND_LOG_DEFAULT_THROTTLE_LOGS, .logs_per_period_backup = ND_LOG_DEFAULT_THROTTLE_LOGS, .throttle_period = ND_LOG_DEFAULT_THROTTLE_PERIOD, }
  284. #define ND_LOG_LIMITS_UNLIMITED (struct nd_log_limit){ .logs_per_period = 0, .logs_per_period_backup = 0, .throttle_period = 0, }
  285. struct nd_log_source {
  286. SPINLOCK spinlock;
  287. ND_LOG_METHOD method;
  288. ND_LOG_FORMAT format;
  289. const char *filename;
  290. int fd;
  291. FILE *fp;
  292. ND_LOG_FIELD_PRIORITY min_priority;
  293. const char *pending_msg;
  294. struct nd_log_limit limits;
  295. };
  296. static __thread ND_LOG_SOURCES overwrite_thread_source = 0;
  297. void nd_log_set_thread_source(ND_LOG_SOURCES source) {
  298. overwrite_thread_source = source;
  299. }
  300. static struct {
  301. uuid_t invocation_id;
  302. ND_LOG_SOURCES overwrite_process_source;
  303. struct nd_log_source sources[_NDLS_MAX];
  304. struct {
  305. bool initialized;
  306. } journal;
  307. struct {
  308. bool initialized;
  309. int fd;
  310. char filename[FILENAME_MAX + 1];
  311. } journal_direct;
  312. struct {
  313. bool initialized;
  314. int facility;
  315. } syslog;
  316. struct {
  317. SPINLOCK spinlock;
  318. bool initialized;
  319. } std_output;
  320. struct {
  321. SPINLOCK spinlock;
  322. bool initialized;
  323. } std_error;
  324. } nd_log = {
  325. .overwrite_process_source = 0,
  326. .journal = {
  327. .initialized = false,
  328. },
  329. .journal_direct = {
  330. .initialized = false,
  331. .fd = -1,
  332. },
  333. .syslog = {
  334. .initialized = false,
  335. .facility = LOG_DAEMON,
  336. },
  337. .std_output = {
  338. .spinlock = NETDATA_SPINLOCK_INITIALIZER,
  339. .initialized = false,
  340. },
  341. .std_error = {
  342. .spinlock = NETDATA_SPINLOCK_INITIALIZER,
  343. .initialized = false,
  344. },
  345. .sources = {
  346. [NDLS_UNSET] = {
  347. .spinlock = NETDATA_SPINLOCK_INITIALIZER,
  348. .method = NDLM_DISABLED,
  349. .format = NDLF_JOURNAL,
  350. .filename = NULL,
  351. .fd = -1,
  352. .fp = NULL,
  353. .min_priority = NDLP_EMERG,
  354. .limits = ND_LOG_LIMITS_UNLIMITED,
  355. },
  356. [NDLS_ACCESS] = {
  357. .spinlock = NETDATA_SPINLOCK_INITIALIZER,
  358. .method = NDLM_DEFAULT,
  359. .format = NDLF_LOGFMT,
  360. .filename = LOG_DIR "/access.log",
  361. .fd = -1,
  362. .fp = NULL,
  363. .min_priority = NDLP_DEBUG,
  364. .limits = ND_LOG_LIMITS_UNLIMITED,
  365. },
  366. [NDLS_ACLK] = {
  367. .spinlock = NETDATA_SPINLOCK_INITIALIZER,
  368. .method = NDLM_FILE,
  369. .format = NDLF_LOGFMT,
  370. .filename = LOG_DIR "/aclk.log",
  371. .fd = -1,
  372. .fp = NULL,
  373. .min_priority = NDLP_DEBUG,
  374. .limits = ND_LOG_LIMITS_UNLIMITED,
  375. },
  376. [NDLS_COLLECTORS] = {
  377. .spinlock = NETDATA_SPINLOCK_INITIALIZER,
  378. .method = NDLM_DEFAULT,
  379. .format = NDLF_LOGFMT,
  380. .filename = LOG_DIR "/collectors.log",
  381. .fd = STDERR_FILENO,
  382. .fp = NULL,
  383. .min_priority = NDLP_INFO,
  384. .limits = ND_LOG_LIMITS_DEFAULT,
  385. },
  386. [NDLS_DEBUG] = {
  387. .spinlock = NETDATA_SPINLOCK_INITIALIZER,
  388. .method = NDLM_DISABLED,
  389. .format = NDLF_LOGFMT,
  390. .filename = LOG_DIR "/debug.log",
  391. .fd = STDOUT_FILENO,
  392. .fp = NULL,
  393. .min_priority = NDLP_DEBUG,
  394. .limits = ND_LOG_LIMITS_UNLIMITED,
  395. },
  396. [NDLS_DAEMON] = {
  397. .spinlock = NETDATA_SPINLOCK_INITIALIZER,
  398. .method = NDLM_DEFAULT,
  399. .filename = LOG_DIR "/daemon.log",
  400. .format = NDLF_LOGFMT,
  401. .fd = -1,
  402. .fp = NULL,
  403. .min_priority = NDLP_INFO,
  404. .limits = ND_LOG_LIMITS_DEFAULT,
  405. },
  406. [NDLS_HEALTH] = {
  407. .spinlock = NETDATA_SPINLOCK_INITIALIZER,
  408. .method = NDLM_DEFAULT,
  409. .format = NDLF_LOGFMT,
  410. .filename = LOG_DIR "/health.log",
  411. .fd = -1,
  412. .fp = NULL,
  413. .min_priority = NDLP_DEBUG,
  414. .limits = ND_LOG_LIMITS_UNLIMITED,
  415. },
  416. },
  417. };
  418. __attribute__((constructor)) void initialize_invocation_id(void) {
  419. // check for a NETDATA_INVOCATION_ID
  420. if(uuid_parse_flexi(getenv("NETDATA_INVOCATION_ID"), nd_log.invocation_id) != 0) {
  421. // not found, check for systemd set INVOCATION_ID
  422. if(uuid_parse_flexi(getenv("INVOCATION_ID"), nd_log.invocation_id) != 0) {
  423. // not found, generate a new one
  424. uuid_generate_random(nd_log.invocation_id);
  425. }
  426. }
  427. char uuid[UUID_COMPACT_STR_LEN];
  428. uuid_unparse_lower_compact(nd_log.invocation_id, uuid);
  429. setenv("NETDATA_INVOCATION_ID", uuid, 1);
  430. }
  431. int nd_log_health_fd(void) {
  432. if(nd_log.sources[NDLS_HEALTH].method == NDLM_FILE && nd_log.sources[NDLS_HEALTH].fd != -1)
  433. return nd_log.sources[NDLS_HEALTH].fd;
  434. return STDERR_FILENO;
  435. }
  436. void nd_log_set_user_settings(ND_LOG_SOURCES source, const char *setting) {
  437. char buf[FILENAME_MAX + 100];
  438. if(setting && *setting)
  439. strncpyz(buf, setting, sizeof(buf) - 1);
  440. else
  441. buf[0] = '\0';
  442. struct nd_log_source *ls = &nd_log.sources[source];
  443. char *output = strrchr(buf, '@');
  444. if(!output)
  445. // all of it is the output
  446. output = buf;
  447. else {
  448. // we found an '@', the next char is the output
  449. *output = '\0';
  450. output++;
  451. // parse the other params
  452. char *remaining = buf;
  453. while(remaining) {
  454. char *value = strsep_skip_consecutive_separators(&remaining, ",");
  455. if (!value || !*value) continue;
  456. char *name = strsep_skip_consecutive_separators(&value, "=");
  457. if (!name || !*name) continue;
  458. if(strcmp(name, "logfmt") == 0)
  459. ls->format = NDLF_LOGFMT;
  460. else if(strcmp(name, "json") == 0)
  461. ls->format = NDLF_JSON;
  462. else if(strcmp(name, "journal") == 0)
  463. ls->format = NDLF_JOURNAL;
  464. else if(strcmp(name, "level") == 0 && value && *value)
  465. ls->min_priority = nd_log_priority2id(value);
  466. else if(strcmp(name, "protection") == 0 && value && *value) {
  467. if(strcmp(value, "off") == 0 || strcmp(value, "none") == 0) {
  468. ls->limits = ND_LOG_LIMITS_UNLIMITED;
  469. ls->limits.counter = 0;
  470. ls->limits.prevented = 0;
  471. }
  472. else {
  473. ls->limits = ND_LOG_LIMITS_DEFAULT;
  474. char *slash = strchr(value, '/');
  475. if(slash) {
  476. *slash = '\0';
  477. slash++;
  478. ls->limits.logs_per_period = ls->limits.logs_per_period_backup = str2u(value);
  479. ls->limits.throttle_period = str2u(slash);
  480. }
  481. else {
  482. ls->limits.logs_per_period = ls->limits.logs_per_period_backup = str2u(value);
  483. ls->limits.throttle_period = ND_LOG_DEFAULT_THROTTLE_PERIOD;
  484. }
  485. }
  486. }
  487. else
  488. nd_log(NDLS_DAEMON, NDLP_ERR, "Error while parsing configuration of log source '%s'. "
  489. "In config '%s', '%s' is not understood.",
  490. nd_log_id2source(source), setting, name);
  491. }
  492. }
  493. if(!output || !*output || strcmp(output, "none") == 0 || strcmp(output, "off") == 0) {
  494. ls->method = NDLM_DISABLED;
  495. ls->filename = "/dev/null";
  496. }
  497. else if(strcmp(output, "journal") == 0) {
  498. ls->method = NDLM_JOURNAL;
  499. ls->filename = NULL;
  500. }
  501. else if(strcmp(output, "syslog") == 0) {
  502. ls->method = NDLM_SYSLOG;
  503. ls->filename = NULL;
  504. }
  505. else if(strcmp(output, "/dev/null") == 0) {
  506. ls->method = NDLM_DEVNULL;
  507. ls->filename = "/dev/null";
  508. }
  509. else if(strcmp(output, "system") == 0) {
  510. if(ls->fd == STDERR_FILENO) {
  511. ls->method = NDLM_STDERR;
  512. ls->filename = NULL;
  513. ls->fd = STDERR_FILENO;
  514. }
  515. else {
  516. ls->method = NDLM_STDOUT;
  517. ls->filename = NULL;
  518. ls->fd = STDOUT_FILENO;
  519. }
  520. }
  521. else if(strcmp(output, "stderr") == 0) {
  522. ls->method = NDLM_STDERR;
  523. ls->filename = NULL;
  524. ls->fd = STDERR_FILENO;
  525. }
  526. else if(strcmp(output, "stdout") == 0) {
  527. ls->method = NDLM_STDOUT;
  528. ls->filename = NULL;
  529. ls->fd = STDOUT_FILENO;
  530. }
  531. else {
  532. ls->method = NDLM_FILE;
  533. ls->filename = strdupz(output);
  534. }
  535. #if defined(NETDATA_INTERNAL_CHECKS) || defined(NETDATA_DEV_MODE)
  536. ls->min_priority = NDLP_DEBUG;
  537. #endif
  538. if(source == NDLS_COLLECTORS) {
  539. // set the method for the collector processes we will spawn
  540. ND_LOG_METHOD method;
  541. ND_LOG_FORMAT format = ls->format;
  542. ND_LOG_FIELD_PRIORITY priority = ls->min_priority;
  543. if(ls->method == NDLM_SYSLOG || ls->method == NDLM_JOURNAL)
  544. method = ls->method;
  545. else
  546. method = NDLM_STDERR;
  547. setenv("NETDATA_LOG_METHOD", nd_log_id2method(method), 1);
  548. setenv("NETDATA_LOG_FORMAT", nd_log_id2format(format), 1);
  549. setenv("NETDATA_LOG_LEVEL", nd_log_id2priority(priority), 1);
  550. }
  551. }
  552. void nd_log_set_priority_level(const char *setting) {
  553. if(!setting || !*setting)
  554. setting = "info";
  555. ND_LOG_FIELD_PRIORITY priority = nd_log_priority2id(setting);
  556. #if defined(NETDATA_INTERNAL_CHECKS) || defined(NETDATA_DEV_MODE)
  557. priority = NDLP_DEBUG;
  558. #endif
  559. nd_log.sources[NDLS_DAEMON].min_priority = priority;
  560. nd_log.sources[NDLS_COLLECTORS].min_priority = priority;
  561. // the right one
  562. setenv("NETDATA_LOG_LEVEL", nd_log_id2priority(priority), 1);
  563. }
  564. void nd_log_set_facility(const char *facility) {
  565. if(!facility || !*facility)
  566. facility = "daemon";
  567. nd_log.syslog.facility = nd_log_facility2id(facility);
  568. setenv("NETDATA_SYSLOG_FACILITY", nd_log_id2facility(nd_log.syslog.facility), 1);
  569. }
  570. void nd_log_set_flood_protection(size_t logs, time_t period) {
  571. nd_log.sources[NDLS_DAEMON].limits.logs_per_period =
  572. nd_log.sources[NDLS_DAEMON].limits.logs_per_period_backup;
  573. nd_log.sources[NDLS_COLLECTORS].limits.logs_per_period =
  574. nd_log.sources[NDLS_COLLECTORS].limits.logs_per_period_backup = logs;
  575. nd_log.sources[NDLS_DAEMON].limits.throttle_period =
  576. nd_log.sources[NDLS_COLLECTORS].limits.throttle_period = period;
  577. char buf[100];
  578. snprintfz(buf, sizeof(buf), "%" PRIu64, (uint64_t )period);
  579. setenv("NETDATA_ERRORS_THROTTLE_PERIOD", buf, 1);
  580. snprintfz(buf, sizeof(buf), "%" PRIu64, (uint64_t )logs);
  581. setenv("NETDATA_ERRORS_PER_PERIOD", buf, 1);
  582. }
  583. static bool nd_log_journal_systemd_init(void) {
  584. #ifdef HAVE_SYSTEMD
  585. nd_log.journal.initialized = true;
  586. #else
  587. nd_log.journal.initialized = false;
  588. #endif
  589. return nd_log.journal.initialized;
  590. }
  591. static void nd_log_journal_direct_set_env(void) {
  592. if(nd_log.sources[NDLS_COLLECTORS].method == NDLM_JOURNAL)
  593. setenv("NETDATA_SYSTEMD_JOURNAL_PATH", nd_log.journal_direct.filename, 1);
  594. }
  595. static bool nd_log_journal_direct_init(const char *path) {
  596. if(nd_log.journal_direct.initialized) {
  597. nd_log_journal_direct_set_env();
  598. return true;
  599. }
  600. int fd;
  601. char filename[FILENAME_MAX + 1];
  602. if(!is_path_unix_socket(path)) {
  603. journal_construct_path(filename, sizeof(filename), netdata_configured_host_prefix, "netdata");
  604. if (!is_path_unix_socket(filename) || (fd = journal_direct_fd(filename)) == -1) {
  605. journal_construct_path(filename, sizeof(filename), netdata_configured_host_prefix, NULL);
  606. if (!is_path_unix_socket(filename) || (fd = journal_direct_fd(filename)) == -1) {
  607. journal_construct_path(filename, sizeof(filename), NULL, "netdata");
  608. if (!is_path_unix_socket(filename) || (fd = journal_direct_fd(filename)) == -1) {
  609. journal_construct_path(filename, sizeof(filename), NULL, NULL);
  610. if (!is_path_unix_socket(filename) || (fd = journal_direct_fd(filename)) == -1)
  611. return false;
  612. }
  613. }
  614. }
  615. }
  616. else {
  617. snprintfz(filename, sizeof(filename), "%s", path);
  618. fd = journal_direct_fd(filename);
  619. }
  620. if(fd < 0)
  621. return false;
  622. nd_log.journal_direct.fd = fd;
  623. nd_log.journal_direct.initialized = true;
  624. strncpyz(nd_log.journal_direct.filename, filename, sizeof(nd_log.journal_direct.filename) - 1);
  625. nd_log_journal_direct_set_env();
  626. return true;
  627. }
  628. static void nd_log_syslog_init() {
  629. if(nd_log.syslog.initialized)
  630. return;
  631. openlog(program_name, LOG_PID, nd_log.syslog.facility);
  632. nd_log.syslog.initialized = true;
  633. }
  634. void nd_log_initialize_for_external_plugins(const char *name) {
  635. // if we don't run under Netdata, log to stderr,
  636. // otherwise, use the logging method Netdata wants us to use.
  637. setenv("NETDATA_LOG_METHOD", "stderr", 0);
  638. setenv("NETDATA_LOG_FORMAT", "logfmt", 0);
  639. nd_log.overwrite_process_source = NDLS_COLLECTORS;
  640. program_name = name;
  641. for(size_t i = 0; i < _NDLS_MAX ;i++) {
  642. nd_log.sources[i].method = STDERR_FILENO;
  643. nd_log.sources[i].fd = -1;
  644. nd_log.sources[i].fp = NULL;
  645. }
  646. nd_log_set_priority_level(getenv("NETDATA_LOG_LEVEL"));
  647. nd_log_set_facility(getenv("NETDATA_SYSLOG_FACILITY"));
  648. time_t period = 1200;
  649. size_t logs = 200;
  650. const char *s = getenv("NETDATA_ERRORS_THROTTLE_PERIOD");
  651. if(s && *s >= '0' && *s <= '9') {
  652. period = str2l(s);
  653. if(period < 0) period = 0;
  654. }
  655. s = getenv("NETDATA_ERRORS_PER_PERIOD");
  656. if(s && *s >= '0' && *s <= '9')
  657. logs = str2u(s);
  658. nd_log_set_flood_protection(logs, period);
  659. if(!netdata_configured_host_prefix) {
  660. s = getenv("NETDATA_HOST_PREFIX");
  661. if(s && *s)
  662. netdata_configured_host_prefix = (char *)s;
  663. }
  664. ND_LOG_METHOD method = nd_log_method2id(getenv("NETDATA_LOG_METHOD"));
  665. ND_LOG_FORMAT format = nd_log_format2id(getenv("NETDATA_LOG_FORMAT"));
  666. if(!IS_VALID_LOG_METHOD_FOR_EXTERNAL_PLUGINS(method)) {
  667. if(is_stderr_connected_to_journal()) {
  668. nd_log(NDLS_COLLECTORS, NDLP_WARNING, "NETDATA_LOG_METHOD is not set. Using journal.");
  669. method = NDLM_JOURNAL;
  670. }
  671. else {
  672. nd_log(NDLS_COLLECTORS, NDLP_WARNING, "NETDATA_LOG_METHOD is not set. Using stderr.");
  673. method = NDLM_STDERR;
  674. }
  675. }
  676. switch(method) {
  677. case NDLM_JOURNAL:
  678. if(!nd_log_journal_direct_init(getenv("NETDATA_SYSTEMD_JOURNAL_PATH")) ||
  679. !nd_log_journal_direct_init(NULL) || !nd_log_journal_systemd_init()) {
  680. nd_log(NDLS_COLLECTORS, NDLP_WARNING, "Failed to initialize journal. Using stderr.");
  681. method = NDLM_STDERR;
  682. }
  683. break;
  684. case NDLM_SYSLOG:
  685. nd_log_syslog_init();
  686. break;
  687. default:
  688. method = NDLM_STDERR;
  689. break;
  690. }
  691. for(size_t i = 0; i < _NDLS_MAX ;i++) {
  692. nd_log.sources[i].method = method;
  693. nd_log.sources[i].format = format;
  694. nd_log.sources[i].fd = -1;
  695. nd_log.sources[i].fp = NULL;
  696. }
  697. // nd_log(NDLS_COLLECTORS, NDLP_NOTICE, "FINAL_LOG_METHOD: %s", nd_log_id2method(method));
  698. }
  699. static bool nd_log_replace_existing_fd(struct nd_log_source *e, int new_fd) {
  700. if(new_fd == -1 || e->fd == -1 ||
  701. (e->fd == STDOUT_FILENO && nd_log.std_output.initialized) ||
  702. (e->fd == STDERR_FILENO && nd_log.std_error.initialized))
  703. return false;
  704. if(new_fd != e->fd) {
  705. int t = dup2(new_fd, e->fd);
  706. bool ret = true;
  707. if (t == -1) {
  708. netdata_log_error("Cannot dup2() new fd %d to old fd %d for '%s'", new_fd, e->fd, e->filename);
  709. ret = false;
  710. }
  711. else
  712. close(new_fd);
  713. if(e->fd == STDOUT_FILENO)
  714. nd_log.std_output.initialized = true;
  715. else if(e->fd == STDERR_FILENO)
  716. nd_log.std_error.initialized = true;
  717. return ret;
  718. }
  719. return false;
  720. }
  721. static void nd_log_open(struct nd_log_source *e, ND_LOG_SOURCES source) {
  722. if(e->method == NDLM_DEFAULT)
  723. nd_log_set_user_settings(source, e->filename);
  724. if((e->method == NDLM_FILE && !e->filename) ||
  725. (e->method == NDLM_DEVNULL && e->fd == -1))
  726. e->method = NDLM_DISABLED;
  727. if(e->fp)
  728. fflush(e->fp);
  729. switch(e->method) {
  730. case NDLM_SYSLOG:
  731. nd_log_syslog_init();
  732. break;
  733. case NDLM_JOURNAL:
  734. nd_log_journal_direct_init(NULL);
  735. nd_log_journal_systemd_init();
  736. break;
  737. case NDLM_STDOUT:
  738. e->fp = stdout;
  739. e->fd = STDOUT_FILENO;
  740. break;
  741. case NDLM_DISABLED:
  742. break;
  743. case NDLM_DEFAULT:
  744. case NDLM_STDERR:
  745. e->method = NDLM_STDERR;
  746. e->fp = stderr;
  747. e->fd = STDERR_FILENO;
  748. break;
  749. case NDLM_DEVNULL:
  750. case NDLM_FILE: {
  751. int fd = open(e->filename, O_WRONLY | O_APPEND | O_CREAT, 0664);
  752. if(fd == -1) {
  753. if(e->fd != STDOUT_FILENO && e->fd != STDERR_FILENO) {
  754. e->fd = STDERR_FILENO;
  755. e->method = NDLM_STDERR;
  756. netdata_log_error("Cannot open log file '%s'. Falling back to stderr.", e->filename);
  757. }
  758. else
  759. netdata_log_error("Cannot open log file '%s'. Leaving fd %d as-is.", e->filename, e->fd);
  760. }
  761. else {
  762. if (!nd_log_replace_existing_fd(e, fd)) {
  763. if(e->fd == STDOUT_FILENO || e->fd == STDERR_FILENO) {
  764. if(e->fd == STDOUT_FILENO)
  765. e->method = NDLM_STDOUT;
  766. else if(e->fd == STDERR_FILENO)
  767. e->method = NDLM_STDERR;
  768. // we have dup2() fd, so we can close the one we opened
  769. if(fd != STDOUT_FILENO && fd != STDERR_FILENO)
  770. close(fd);
  771. }
  772. else
  773. e->fd = fd;
  774. }
  775. }
  776. // at this point we have e->fd set properly
  777. if(e->fd == STDOUT_FILENO)
  778. e->fp = stdout;
  779. else if(e->fd == STDERR_FILENO)
  780. e->fp = stderr;
  781. if(!e->fp) {
  782. e->fp = fdopen(e->fd, "a");
  783. if (!e->fp) {
  784. netdata_log_error("Cannot fdopen() fd %d ('%s')", e->fd, e->filename);
  785. if(e->fd != STDOUT_FILENO && e->fd != STDERR_FILENO)
  786. close(e->fd);
  787. e->fp = stderr;
  788. e->fd = STDERR_FILENO;
  789. }
  790. }
  791. else {
  792. if (setvbuf(e->fp, NULL, _IOLBF, 0) != 0)
  793. netdata_log_error("Cannot set line buffering on fd %d ('%s')", e->fd, e->filename);
  794. }
  795. }
  796. break;
  797. }
  798. }
  799. static void nd_log_stdin_init(int fd, const char *filename) {
  800. int f = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0664);
  801. if(f == -1)
  802. return;
  803. if(f != fd) {
  804. dup2(f, fd);
  805. close(f);
  806. }
  807. }
  808. void nd_log_initialize(void) {
  809. nd_log_stdin_init(STDIN_FILENO, "/dev/null");
  810. for(size_t i = 0 ; i < _NDLS_MAX ; i++)
  811. nd_log_open(&nd_log.sources[i], i);
  812. }
  813. void nd_log_reopen_log_files(void) {
  814. netdata_log_info("Reopening all log files.");
  815. nd_log.std_output.initialized = false;
  816. nd_log.std_error.initialized = false;
  817. nd_log_initialize();
  818. netdata_log_info("Log files re-opened.");
  819. }
  820. void chown_open_file(int fd, uid_t uid, gid_t gid) {
  821. if(fd == -1) return;
  822. struct stat buf;
  823. if(fstat(fd, &buf) == -1) {
  824. netdata_log_error("Cannot fstat() fd %d", fd);
  825. return;
  826. }
  827. if((buf.st_uid != uid || buf.st_gid != gid) && S_ISREG(buf.st_mode)) {
  828. if(fchown(fd, uid, gid) == -1)
  829. netdata_log_error("Cannot fchown() fd %d.", fd);
  830. }
  831. }
  832. void nd_log_chown_log_files(uid_t uid, gid_t gid) {
  833. for(size_t i = 0 ; i < _NDLS_MAX ; i++) {
  834. if(nd_log.sources[i].fd != -1 && nd_log.sources[i].fd != STDIN_FILENO)
  835. chown_open_file(nd_log.sources[i].fd, uid, gid);
  836. }
  837. }
  838. // ----------------------------------------------------------------------------
  839. // annotators
  840. struct log_field;
  841. static void errno_annotator(BUFFER *wb, const char *key, struct log_field *lf);
  842. static void priority_annotator(BUFFER *wb, const char *key, struct log_field *lf);
  843. static void timestamp_usec_annotator(BUFFER *wb, const char *key, struct log_field *lf);
  844. // ----------------------------------------------------------------------------
  845. typedef void (*annotator_t)(BUFFER *wb, const char *key, struct log_field *lf);
  846. struct log_field {
  847. const char *journal;
  848. const char *logfmt;
  849. annotator_t logfmt_annotator;
  850. struct log_stack_entry entry;
  851. };
  852. #define THREAD_LOG_STACK_MAX 50
  853. static __thread struct log_stack_entry *thread_log_stack_base[THREAD_LOG_STACK_MAX];
  854. static __thread size_t thread_log_stack_next = 0;
  855. static __thread struct log_field thread_log_fields[_NDF_MAX] = {
  856. // THE ORDER DEFINES THE ORDER FIELDS WILL APPEAR IN logfmt
  857. [NDF_STOP] = { // processing will not stop on this - so it is ok to be first
  858. .journal = NULL,
  859. .logfmt = NULL,
  860. .logfmt_annotator = NULL,
  861. },
  862. [NDF_TIMESTAMP_REALTIME_USEC] = {
  863. .journal = NULL,
  864. .logfmt = "time",
  865. .logfmt_annotator = timestamp_usec_annotator,
  866. },
  867. [NDF_SYSLOG_IDENTIFIER] = {
  868. .journal = "SYSLOG_IDENTIFIER", // standard journald field
  869. .logfmt = "comm",
  870. },
  871. [NDF_LOG_SOURCE] = {
  872. .journal = "ND_LOG_SOURCE",
  873. .logfmt = "source",
  874. },
  875. [NDF_PRIORITY] = {
  876. .journal = "PRIORITY", // standard journald field
  877. .logfmt = "level",
  878. .logfmt_annotator = priority_annotator,
  879. },
  880. [NDF_ERRNO] = {
  881. .journal = "ERRNO", // standard journald field
  882. .logfmt = "errno",
  883. .logfmt_annotator = errno_annotator,
  884. },
  885. [NDF_INVOCATION_ID] = {
  886. .journal = "INVOCATION_ID", // standard journald field
  887. .logfmt = NULL,
  888. },
  889. [NDF_LINE] = {
  890. .journal = "CODE_LINE", // standard journald field
  891. .logfmt = NULL,
  892. },
  893. [NDF_FILE] = {
  894. .journal = "CODE_FILE", // standard journald field
  895. .logfmt = NULL,
  896. },
  897. [NDF_FUNC] = {
  898. .journal = "CODE_FUNC", // standard journald field
  899. .logfmt = NULL,
  900. },
  901. [NDF_TID] = {
  902. .journal = "TID", // standard journald field
  903. .logfmt = "tid",
  904. },
  905. [NDF_THREAD_TAG] = {
  906. .journal = "THREAD_TAG",
  907. .logfmt = "thread",
  908. },
  909. [NDF_MESSAGE_ID] = {
  910. .journal = "MESSAGE_ID",
  911. .logfmt = "msg_id",
  912. },
  913. [NDF_MODULE] = {
  914. .journal = "ND_MODULE",
  915. .logfmt = "module",
  916. },
  917. [NDF_NIDL_NODE] = {
  918. .journal = "ND_NIDL_NODE",
  919. .logfmt = "node",
  920. },
  921. [NDF_NIDL_INSTANCE] = {
  922. .journal = "ND_NIDL_INSTANCE",
  923. .logfmt = "instance",
  924. },
  925. [NDF_NIDL_CONTEXT] = {
  926. .journal = "ND_NIDL_CONTEXT",
  927. .logfmt = "context",
  928. },
  929. [NDF_NIDL_DIMENSION] = {
  930. .journal = "ND_NIDL_DIMENSION",
  931. .logfmt = "dimension",
  932. },
  933. [NDF_SRC_TRANSPORT] = {
  934. .journal = "ND_SRC_TRANSPORT",
  935. .logfmt = "src_transport",
  936. },
  937. [NDF_ACCOUNT_ID] = {
  938. .journal = "ND_ACCOUNT_ID",
  939. .logfmt = "account",
  940. },
  941. [NDF_USER_NAME] = {
  942. .journal = "ND_USER_NAME",
  943. .logfmt = "user",
  944. },
  945. [NDF_USER_ROLE] = {
  946. .journal = "ND_USER_ROLE",
  947. .logfmt = "role",
  948. },
  949. [NDF_SRC_IP] = {
  950. .journal = "ND_SRC_IP",
  951. .logfmt = "src_ip",
  952. },
  953. [NDF_SRC_FORWARDED_HOST] = {
  954. .journal = "ND_SRC_FORWARDED_HOST",
  955. .logfmt = "src_forwarded_host",
  956. },
  957. [NDF_SRC_FORWARDED_FOR] = {
  958. .journal = "ND_SRC_FORWARDED_FOR",
  959. .logfmt = "src_forwarded_for",
  960. },
  961. [NDF_SRC_PORT] = {
  962. .journal = "ND_SRC_PORT",
  963. .logfmt = "src_port",
  964. },
  965. [NDF_SRC_CAPABILITIES] = {
  966. .journal = "ND_SRC_CAPABILITIES",
  967. .logfmt = "src_capabilities",
  968. },
  969. [NDF_DST_TRANSPORT] = {
  970. .journal = "ND_DST_TRANSPORT",
  971. .logfmt = "dst_transport",
  972. },
  973. [NDF_DST_IP] = {
  974. .journal = "ND_DST_IP",
  975. .logfmt = "dst_ip",
  976. },
  977. [NDF_DST_PORT] = {
  978. .journal = "ND_DST_PORT",
  979. .logfmt = "dst_port",
  980. },
  981. [NDF_DST_CAPABILITIES] = {
  982. .journal = "ND_DST_CAPABILITIES",
  983. .logfmt = "dst_capabilities",
  984. },
  985. [NDF_REQUEST_METHOD] = {
  986. .journal = "ND_REQUEST_METHOD",
  987. .logfmt = "req_method",
  988. },
  989. [NDF_RESPONSE_CODE] = {
  990. .journal = "ND_RESPONSE_CODE",
  991. .logfmt = "code",
  992. },
  993. [NDF_CONNECTION_ID] = {
  994. .journal = "ND_CONNECTION_ID",
  995. .logfmt = "conn",
  996. },
  997. [NDF_TRANSACTION_ID] = {
  998. .journal = "ND_TRANSACTION_ID",
  999. .logfmt = "transaction",
  1000. },
  1001. [NDF_RESPONSE_SENT_BYTES] = {
  1002. .journal = "ND_RESPONSE_SENT_BYTES",
  1003. .logfmt = "sent_bytes",
  1004. },
  1005. [NDF_RESPONSE_SIZE_BYTES] = {
  1006. .journal = "ND_RESPONSE_SIZE_BYTES",
  1007. .logfmt = "size_bytes",
  1008. },
  1009. [NDF_RESPONSE_PREPARATION_TIME_USEC] = {
  1010. .journal = "ND_RESPONSE_PREP_TIME_USEC",
  1011. .logfmt = "prep_ut",
  1012. },
  1013. [NDF_RESPONSE_SENT_TIME_USEC] = {
  1014. .journal = "ND_RESPONSE_SENT_TIME_USEC",
  1015. .logfmt = "sent_ut",
  1016. },
  1017. [NDF_RESPONSE_TOTAL_TIME_USEC] = {
  1018. .journal = "ND_RESPONSE_TOTAL_TIME_USEC",
  1019. .logfmt = "total_ut",
  1020. },
  1021. [NDF_ALERT_ID] = {
  1022. .journal = "ND_ALERT_ID",
  1023. .logfmt = "alert_id",
  1024. },
  1025. [NDF_ALERT_UNIQUE_ID] = {
  1026. .journal = "ND_ALERT_UNIQUE_ID",
  1027. .logfmt = "alert_unique_id",
  1028. },
  1029. [NDF_ALERT_TRANSITION_ID] = {
  1030. .journal = "ND_ALERT_TRANSITION_ID",
  1031. .logfmt = "alert_transition_id",
  1032. },
  1033. [NDF_ALERT_EVENT_ID] = {
  1034. .journal = "ND_ALERT_EVENT_ID",
  1035. .logfmt = "alert_event_id",
  1036. },
  1037. [NDF_ALERT_CONFIG_HASH] = {
  1038. .journal = "ND_ALERT_CONFIG",
  1039. .logfmt = "alert_config",
  1040. },
  1041. [NDF_ALERT_NAME] = {
  1042. .journal = "ND_ALERT_NAME",
  1043. .logfmt = "alert",
  1044. },
  1045. [NDF_ALERT_CLASS] = {
  1046. .journal = "ND_ALERT_CLASS",
  1047. .logfmt = "alert_class",
  1048. },
  1049. [NDF_ALERT_COMPONENT] = {
  1050. .journal = "ND_ALERT_COMPONENT",
  1051. .logfmt = "alert_component",
  1052. },
  1053. [NDF_ALERT_TYPE] = {
  1054. .journal = "ND_ALERT_TYPE",
  1055. .logfmt = "alert_type",
  1056. },
  1057. [NDF_ALERT_EXEC] = {
  1058. .journal = "ND_ALERT_EXEC",
  1059. .logfmt = "alert_exec",
  1060. },
  1061. [NDF_ALERT_RECIPIENT] = {
  1062. .journal = "ND_ALERT_RECIPIENT",
  1063. .logfmt = "alert_recipient",
  1064. },
  1065. [NDF_ALERT_VALUE] = {
  1066. .journal = "ND_ALERT_VALUE",
  1067. .logfmt = "alert_value",
  1068. },
  1069. [NDF_ALERT_VALUE_OLD] = {
  1070. .journal = "ND_ALERT_VALUE_OLD",
  1071. .logfmt = "alert_value_old",
  1072. },
  1073. [NDF_ALERT_STATUS] = {
  1074. .journal = "ND_ALERT_STATUS",
  1075. .logfmt = "alert_status",
  1076. },
  1077. [NDF_ALERT_STATUS_OLD] = {
  1078. .journal = "ND_ALERT_STATUS_OLD",
  1079. .logfmt = "alert_value_old",
  1080. },
  1081. [NDF_ALERT_UNITS] = {
  1082. .journal = "ND_ALERT_UNITS",
  1083. .logfmt = "alert_units",
  1084. },
  1085. [NDF_ALERT_SUMMARY] = {
  1086. .journal = "ND_ALERT_SUMMARY",
  1087. .logfmt = "alert_summary",
  1088. },
  1089. [NDF_ALERT_INFO] = {
  1090. .journal = "ND_ALERT_INFO",
  1091. .logfmt = "alert_info",
  1092. },
  1093. [NDF_ALERT_DURATION] = {
  1094. .journal = "ND_ALERT_DURATION",
  1095. .logfmt = "alert_duration",
  1096. },
  1097. [NDF_ALERT_NOTIFICATION_REALTIME_USEC] = {
  1098. .journal = "ND_ALERT_NOTIFICATION_TIMESTAMP_USEC",
  1099. .logfmt = "alert_notification_timestamp",
  1100. .logfmt_annotator = timestamp_usec_annotator,
  1101. },
  1102. // put new items here
  1103. // leave the request URL and the message last
  1104. [NDF_REQUEST] = {
  1105. .journal = "ND_REQUEST",
  1106. .logfmt = "request",
  1107. },
  1108. [NDF_MESSAGE] = {
  1109. .journal = "MESSAGE",
  1110. .logfmt = "msg",
  1111. },
  1112. };
  1113. #define THREAD_FIELDS_MAX (sizeof(thread_log_fields) / sizeof(thread_log_fields[0]))
  1114. ND_LOG_FIELD_ID nd_log_field_id_by_name(const char *field, size_t len) {
  1115. for(size_t i = 0; i < THREAD_FIELDS_MAX ;i++) {
  1116. if(thread_log_fields[i].journal && strlen(thread_log_fields[i].journal) == len && strncmp(field, thread_log_fields[i].journal, len) == 0)
  1117. return i;
  1118. }
  1119. return NDF_STOP;
  1120. }
  1121. void log_stack_pop(void *ptr) {
  1122. if(!ptr) return;
  1123. struct log_stack_entry *lgs = *(struct log_stack_entry (*)[])ptr;
  1124. if(unlikely(!thread_log_stack_next || lgs != thread_log_stack_base[thread_log_stack_next - 1])) {
  1125. fatal("You cannot pop in the middle of the stack, or an item not in the stack");
  1126. return;
  1127. }
  1128. thread_log_stack_next--;
  1129. }
  1130. void log_stack_push(struct log_stack_entry *lgs) {
  1131. if(!lgs || thread_log_stack_next >= THREAD_LOG_STACK_MAX) return;
  1132. thread_log_stack_base[thread_log_stack_next++] = lgs;
  1133. }
  1134. // ----------------------------------------------------------------------------
  1135. // json formatter
  1136. static void nd_logger_json(BUFFER *wb, struct log_field *fields, size_t fields_max) {
  1137. // --- FIELD_PARSER_VERSIONS ---
  1138. //
  1139. // IMPORTANT:
  1140. // THERE ARE 6 VERSIONS OF THIS CODE
  1141. //
  1142. // 1. journal (direct socket API),
  1143. // 2. journal (libsystemd API),
  1144. // 3. logfmt,
  1145. // 4. json,
  1146. // 5. convert to uint64
  1147. // 6. convert to int64
  1148. //
  1149. // UPDATE ALL OF THEM FOR NEW FEATURES OR FIXES
  1150. buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
  1151. CLEAN_BUFFER *tmp = NULL;
  1152. for (size_t i = 0; i < fields_max; i++) {
  1153. if (!fields[i].entry.set || !fields[i].logfmt)
  1154. continue;
  1155. const char *key = fields[i].logfmt;
  1156. const char *s = NULL;
  1157. switch(fields[i].entry.type) {
  1158. case NDFT_TXT:
  1159. s = fields[i].entry.txt;
  1160. break;
  1161. case NDFT_STR:
  1162. s = string2str(fields[i].entry.str);
  1163. break;
  1164. case NDFT_BFR:
  1165. s = buffer_tostring(fields[i].entry.bfr);
  1166. break;
  1167. case NDFT_U64:
  1168. buffer_json_member_add_uint64(wb, key, fields[i].entry.u64);
  1169. break;
  1170. case NDFT_I64:
  1171. buffer_json_member_add_int64(wb, key, fields[i].entry.i64);
  1172. break;
  1173. case NDFT_DBL:
  1174. buffer_json_member_add_double(wb, key, fields[i].entry.dbl);
  1175. break;
  1176. case NDFT_UUID:
  1177. if(!uuid_is_null(*fields[i].entry.uuid)) {
  1178. char u[UUID_COMPACT_STR_LEN];
  1179. uuid_unparse_lower_compact(*fields[i].entry.uuid, u);
  1180. buffer_json_member_add_string(wb, key, u);
  1181. }
  1182. break;
  1183. case NDFT_CALLBACK: {
  1184. if(!tmp)
  1185. tmp = buffer_create(1024, NULL);
  1186. else
  1187. buffer_flush(tmp);
  1188. if(fields[i].entry.cb.formatter(tmp, fields[i].entry.cb.formatter_data))
  1189. s = buffer_tostring(tmp);
  1190. else
  1191. s = NULL;
  1192. }
  1193. break;
  1194. default:
  1195. s = "UNHANDLED";
  1196. break;
  1197. }
  1198. if(s && *s)
  1199. buffer_json_member_add_string(wb, key, s);
  1200. }
  1201. buffer_json_finalize(wb);
  1202. }
  1203. // ----------------------------------------------------------------------------
  1204. // logfmt formatter
  1205. static int64_t log_field_to_int64(struct log_field *lf) {
  1206. // --- FIELD_PARSER_VERSIONS ---
  1207. //
  1208. // IMPORTANT:
  1209. // THERE ARE 6 VERSIONS OF THIS CODE
  1210. //
  1211. // 1. journal (direct socket API),
  1212. // 2. journal (libsystemd API),
  1213. // 3. logfmt,
  1214. // 4. json,
  1215. // 5. convert to uint64
  1216. // 6. convert to int64
  1217. //
  1218. // UPDATE ALL OF THEM FOR NEW FEATURES OR FIXES
  1219. CLEAN_BUFFER *tmp = NULL;
  1220. const char *s = NULL;
  1221. switch(lf->entry.type) {
  1222. case NDFT_UUID:
  1223. case NDFT_UNSET:
  1224. return 0;
  1225. case NDFT_TXT:
  1226. s = lf->entry.txt;
  1227. break;
  1228. case NDFT_STR:
  1229. s = string2str(lf->entry.str);
  1230. break;
  1231. case NDFT_BFR:
  1232. s = buffer_tostring(lf->entry.bfr);
  1233. break;
  1234. case NDFT_CALLBACK:
  1235. tmp = buffer_create(0, NULL);
  1236. if(lf->entry.cb.formatter(tmp, lf->entry.cb.formatter_data))
  1237. s = buffer_tostring(tmp);
  1238. else
  1239. s = NULL;
  1240. break;
  1241. case NDFT_U64:
  1242. return (int64_t)lf->entry.u64;
  1243. case NDFT_I64:
  1244. return (int64_t)lf->entry.i64;
  1245. case NDFT_DBL:
  1246. return (int64_t)lf->entry.dbl;
  1247. }
  1248. if(s && *s)
  1249. return str2ll(s, NULL);
  1250. return 0;
  1251. }
  1252. static uint64_t log_field_to_uint64(struct log_field *lf) {
  1253. // --- FIELD_PARSER_VERSIONS ---
  1254. //
  1255. // IMPORTANT:
  1256. // THERE ARE 6 VERSIONS OF THIS CODE
  1257. //
  1258. // 1. journal (direct socket API),
  1259. // 2. journal (libsystemd API),
  1260. // 3. logfmt,
  1261. // 4. json,
  1262. // 5. convert to uint64
  1263. // 6. convert to int64
  1264. //
  1265. // UPDATE ALL OF THEM FOR NEW FEATURES OR FIXES
  1266. CLEAN_BUFFER *tmp = NULL;
  1267. const char *s = NULL;
  1268. switch(lf->entry.type) {
  1269. case NDFT_UUID:
  1270. case NDFT_UNSET:
  1271. return 0;
  1272. case NDFT_TXT:
  1273. s = lf->entry.txt;
  1274. break;
  1275. case NDFT_STR:
  1276. s = string2str(lf->entry.str);
  1277. break;
  1278. case NDFT_BFR:
  1279. s = buffer_tostring(lf->entry.bfr);
  1280. break;
  1281. case NDFT_CALLBACK:
  1282. tmp = buffer_create(0, NULL);
  1283. if(lf->entry.cb.formatter(tmp, lf->entry.cb.formatter_data))
  1284. s = buffer_tostring(tmp);
  1285. else
  1286. s = NULL;
  1287. break;
  1288. case NDFT_U64:
  1289. return lf->entry.u64;
  1290. case NDFT_I64:
  1291. return lf->entry.i64;
  1292. case NDFT_DBL:
  1293. return (uint64_t) lf->entry.dbl;
  1294. }
  1295. if(s && *s)
  1296. return str2uint64_t(s, NULL);
  1297. return 0;
  1298. }
  1299. static void timestamp_usec_annotator(BUFFER *wb, const char *key, struct log_field *lf) {
  1300. usec_t ut = log_field_to_uint64(lf);
  1301. if(!ut)
  1302. return;
  1303. char datetime[RFC3339_MAX_LENGTH];
  1304. rfc3339_datetime_ut(datetime, sizeof(datetime), ut, 3, false);
  1305. if(buffer_strlen(wb))
  1306. buffer_fast_strcat(wb, " ", 1);
  1307. buffer_strcat(wb, key);
  1308. buffer_fast_strcat(wb, "=", 1);
  1309. buffer_json_strcat(wb, datetime);
  1310. }
  1311. static void errno_annotator(BUFFER *wb, const char *key, struct log_field *lf) {
  1312. int64_t errnum = log_field_to_int64(lf);
  1313. if(errnum == 0)
  1314. return;
  1315. char buf[1024];
  1316. const char *s = errno2str((int)errnum, buf, sizeof(buf));
  1317. if(buffer_strlen(wb))
  1318. buffer_fast_strcat(wb, " ", 1);
  1319. buffer_strcat(wb, key);
  1320. buffer_fast_strcat(wb, "=\"", 2);
  1321. buffer_print_int64(wb, errnum);
  1322. buffer_fast_strcat(wb, ", ", 2);
  1323. buffer_json_strcat(wb, s);
  1324. buffer_fast_strcat(wb, "\"", 1);
  1325. }
  1326. static void priority_annotator(BUFFER *wb, const char *key, struct log_field *lf) {
  1327. uint64_t pri = log_field_to_uint64(lf);
  1328. if(buffer_strlen(wb))
  1329. buffer_fast_strcat(wb, " ", 1);
  1330. buffer_strcat(wb, key);
  1331. buffer_fast_strcat(wb, "=", 1);
  1332. buffer_strcat(wb, nd_log_id2priority(pri));
  1333. }
  1334. static bool needs_quotes_for_logfmt(const char *s)
  1335. {
  1336. static bool safe_for_logfmt[256] = {
  1337. [' '] = true, ['!'] = true, ['"'] = false, ['#'] = true, ['$'] = true, ['%'] = true, ['&'] = true,
  1338. ['\''] = true, ['('] = true, [')'] = true, ['*'] = true, ['+'] = true, [','] = true, ['-'] = true,
  1339. ['.'] = true, ['/'] = true, ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true,
  1340. ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true, [':'] = true, [';'] = true,
  1341. ['<'] = true, ['='] = true, ['>'] = true, ['?'] = true, ['@'] = true, ['A'] = true, ['B'] = true,
  1342. ['C'] = true, ['D'] = true, ['E'] = true, ['F'] = true, ['G'] = true, ['H'] = true, ['I'] = true,
  1343. ['J'] = true, ['K'] = true, ['L'] = true, ['M'] = true, ['N'] = true, ['O'] = true, ['P'] = true,
  1344. ['Q'] = true, ['R'] = true, ['S'] = true, ['T'] = true, ['U'] = true, ['V'] = true, ['W'] = true,
  1345. ['X'] = true, ['Y'] = true, ['Z'] = true, ['['] = true, ['\\'] = false, [']'] = true, ['^'] = true,
  1346. ['_'] = true, ['`'] = true, ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true,
  1347. ['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true, ['k'] = true, ['l'] = true,
  1348. ['m'] = true, ['n'] = true, ['o'] = true, ['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true,
  1349. ['t'] = true, ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true, ['z'] = true,
  1350. ['{'] = true, ['|'] = true, ['}'] = true, ['~'] = true, [0x7f] = true,
  1351. };
  1352. if(!*s)
  1353. return true;
  1354. while(*s) {
  1355. if(*s == '=' || isspace(*s) || !safe_for_logfmt[(uint8_t)*s])
  1356. return true;
  1357. s++;
  1358. }
  1359. return false;
  1360. }
  1361. static void string_to_logfmt(BUFFER *wb, const char *s)
  1362. {
  1363. bool spaces = needs_quotes_for_logfmt(s);
  1364. if(spaces)
  1365. buffer_fast_strcat(wb, "\"", 1);
  1366. buffer_json_strcat(wb, s);
  1367. if(spaces)
  1368. buffer_fast_strcat(wb, "\"", 1);
  1369. }
  1370. static void nd_logger_logfmt(BUFFER *wb, struct log_field *fields, size_t fields_max)
  1371. {
  1372. // --- FIELD_PARSER_VERSIONS ---
  1373. //
  1374. // IMPORTANT:
  1375. // THERE ARE 6 VERSIONS OF THIS CODE
  1376. //
  1377. // 1. journal (direct socket API),
  1378. // 2. journal (libsystemd API),
  1379. // 3. logfmt,
  1380. // 4. json,
  1381. // 5. convert to uint64
  1382. // 6. convert to int64
  1383. //
  1384. // UPDATE ALL OF THEM FOR NEW FEATURES OR FIXES
  1385. CLEAN_BUFFER *tmp = NULL;
  1386. for (size_t i = 0; i < fields_max; i++) {
  1387. if (!fields[i].entry.set || !fields[i].logfmt)
  1388. continue;
  1389. const char *key = fields[i].logfmt;
  1390. if(fields[i].logfmt_annotator)
  1391. fields[i].logfmt_annotator(wb, key, &fields[i]);
  1392. else {
  1393. if(buffer_strlen(wb))
  1394. buffer_fast_strcat(wb, " ", 1);
  1395. switch(fields[i].entry.type) {
  1396. case NDFT_TXT:
  1397. if(*fields[i].entry.txt) {
  1398. buffer_strcat(wb, key);
  1399. buffer_fast_strcat(wb, "=", 1);
  1400. string_to_logfmt(wb, fields[i].entry.txt);
  1401. }
  1402. break;
  1403. case NDFT_STR:
  1404. buffer_strcat(wb, key);
  1405. buffer_fast_strcat(wb, "=", 1);
  1406. string_to_logfmt(wb, string2str(fields[i].entry.str));
  1407. break;
  1408. case NDFT_BFR:
  1409. if(buffer_strlen(fields[i].entry.bfr)) {
  1410. buffer_strcat(wb, key);
  1411. buffer_fast_strcat(wb, "=", 1);
  1412. string_to_logfmt(wb, buffer_tostring(fields[i].entry.bfr));
  1413. }
  1414. break;
  1415. case NDFT_U64:
  1416. buffer_strcat(wb, key);
  1417. buffer_fast_strcat(wb, "=", 1);
  1418. buffer_print_uint64(wb, fields[i].entry.u64);
  1419. break;
  1420. case NDFT_I64:
  1421. buffer_strcat(wb, key);
  1422. buffer_fast_strcat(wb, "=", 1);
  1423. buffer_print_int64(wb, fields[i].entry.i64);
  1424. break;
  1425. case NDFT_DBL:
  1426. buffer_strcat(wb, key);
  1427. buffer_fast_strcat(wb, "=", 1);
  1428. buffer_print_netdata_double(wb, fields[i].entry.dbl);
  1429. break;
  1430. case NDFT_UUID:
  1431. if(!uuid_is_null(*fields[i].entry.uuid)) {
  1432. char u[UUID_COMPACT_STR_LEN];
  1433. uuid_unparse_lower_compact(*fields[i].entry.uuid, u);
  1434. buffer_strcat(wb, key);
  1435. buffer_fast_strcat(wb, "=", 1);
  1436. buffer_fast_strcat(wb, u, sizeof(u) - 1);
  1437. }
  1438. break;
  1439. case NDFT_CALLBACK: {
  1440. if(!tmp)
  1441. tmp = buffer_create(1024, NULL);
  1442. else
  1443. buffer_flush(tmp);
  1444. if(fields[i].entry.cb.formatter(tmp, fields[i].entry.cb.formatter_data)) {
  1445. buffer_strcat(wb, key);
  1446. buffer_fast_strcat(wb, "=", 1);
  1447. string_to_logfmt(wb, buffer_tostring(tmp));
  1448. }
  1449. }
  1450. break;
  1451. default:
  1452. buffer_strcat(wb, "UNHANDLED");
  1453. break;
  1454. }
  1455. }
  1456. }
  1457. }
  1458. // ----------------------------------------------------------------------------
  1459. // journal logger
  1460. bool nd_log_journal_socket_available(void) {
  1461. if(netdata_configured_host_prefix && *netdata_configured_host_prefix) {
  1462. char filename[FILENAME_MAX + 1];
  1463. snprintfz(filename, sizeof(filename), "%s%s",
  1464. netdata_configured_host_prefix, "/run/systemd/journal/socket");
  1465. if(is_path_unix_socket(filename))
  1466. return true;
  1467. }
  1468. return is_path_unix_socket("/run/systemd/journal/socket");
  1469. }
  1470. static bool nd_logger_journal_libsystemd(struct log_field *fields, size_t fields_max) {
  1471. #ifdef HAVE_SYSTEMD
  1472. // --- FIELD_PARSER_VERSIONS ---
  1473. //
  1474. // IMPORTANT:
  1475. // THERE ARE 6 VERSIONS OF THIS CODE
  1476. //
  1477. // 1. journal (direct socket API),
  1478. // 2. journal (libsystemd API),
  1479. // 3. logfmt,
  1480. // 4. json,
  1481. // 5. convert to uint64
  1482. // 6. convert to int64
  1483. //
  1484. // UPDATE ALL OF THEM FOR NEW FEATURES OR FIXES
  1485. struct iovec iov[fields_max];
  1486. int iov_count = 0;
  1487. memset(iov, 0, sizeof(iov));
  1488. CLEAN_BUFFER *tmp = NULL;
  1489. for (size_t i = 0; i < fields_max; i++) {
  1490. if (!fields[i].entry.set || !fields[i].journal)
  1491. continue;
  1492. const char *key = fields[i].journal;
  1493. char *value = NULL;
  1494. int rc = 0;
  1495. switch (fields[i].entry.type) {
  1496. case NDFT_TXT:
  1497. if(*fields[i].entry.txt)
  1498. rc = asprintf(&value, "%s=%s", key, fields[i].entry.txt);
  1499. break;
  1500. case NDFT_STR:
  1501. rc = asprintf(&value, "%s=%s", key, string2str(fields[i].entry.str));
  1502. break;
  1503. case NDFT_BFR:
  1504. if(buffer_strlen(fields[i].entry.bfr))
  1505. rc = asprintf(&value, "%s=%s", key, buffer_tostring(fields[i].entry.bfr));
  1506. break;
  1507. case NDFT_U64:
  1508. rc = asprintf(&value, "%s=%" PRIu64, key, fields[i].entry.u64);
  1509. break;
  1510. case NDFT_I64:
  1511. rc = asprintf(&value, "%s=%" PRId64, key, fields[i].entry.i64);
  1512. break;
  1513. case NDFT_DBL:
  1514. rc = asprintf(&value, "%s=%f", key, fields[i].entry.dbl);
  1515. break;
  1516. case NDFT_UUID:
  1517. if(!uuid_is_null(*fields[i].entry.uuid)) {
  1518. char u[UUID_COMPACT_STR_LEN];
  1519. uuid_unparse_lower_compact(*fields[i].entry.uuid, u);
  1520. rc = asprintf(&value, "%s=%s", key, u);
  1521. }
  1522. break;
  1523. case NDFT_CALLBACK: {
  1524. if(!tmp)
  1525. tmp = buffer_create(1024, NULL);
  1526. else
  1527. buffer_flush(tmp);
  1528. if(fields[i].entry.cb.formatter(tmp, fields[i].entry.cb.formatter_data))
  1529. rc = asprintf(&value, "%s=%s", key, buffer_tostring(tmp));
  1530. }
  1531. break;
  1532. default:
  1533. rc = asprintf(&value, "%s=%s", key, "UNHANDLED");
  1534. break;
  1535. }
  1536. if (rc != -1 && value) {
  1537. iov[iov_count].iov_base = value;
  1538. iov[iov_count].iov_len = strlen(value);
  1539. iov_count++;
  1540. }
  1541. }
  1542. int r = sd_journal_sendv(iov, iov_count);
  1543. // Clean up allocated memory
  1544. for (int i = 0; i < iov_count; i++) {
  1545. if (iov[i].iov_base != NULL) {
  1546. free(iov[i].iov_base);
  1547. }
  1548. }
  1549. return r == 0;
  1550. #else
  1551. return false;
  1552. #endif
  1553. }
  1554. static bool nd_logger_journal_direct(struct log_field *fields, size_t fields_max) {
  1555. if(!nd_log.journal_direct.initialized)
  1556. return false;
  1557. // --- FIELD_PARSER_VERSIONS ---
  1558. //
  1559. // IMPORTANT:
  1560. // THERE ARE 6 VERSIONS OF THIS CODE
  1561. //
  1562. // 1. journal (direct socket API),
  1563. // 2. journal (libsystemd API),
  1564. // 3. logfmt,
  1565. // 4. json,
  1566. // 5. convert to uint64
  1567. // 6. convert to int64
  1568. //
  1569. // UPDATE ALL OF THEM FOR NEW FEATURES OR FIXES
  1570. CLEAN_BUFFER *wb = buffer_create(4096, NULL);
  1571. CLEAN_BUFFER *tmp = NULL;
  1572. for (size_t i = 0; i < fields_max; i++) {
  1573. if (!fields[i].entry.set || !fields[i].journal)
  1574. continue;
  1575. const char *key = fields[i].journal;
  1576. const char *s = NULL;
  1577. switch(fields[i].entry.type) {
  1578. case NDFT_TXT:
  1579. s = fields[i].entry.txt;
  1580. break;
  1581. case NDFT_STR:
  1582. s = string2str(fields[i].entry.str);
  1583. break;
  1584. case NDFT_BFR:
  1585. s = buffer_tostring(fields[i].entry.bfr);
  1586. break;
  1587. case NDFT_U64:
  1588. buffer_strcat(wb, key);
  1589. buffer_putc(wb, '=');
  1590. buffer_print_uint64(wb, fields[i].entry.u64);
  1591. buffer_putc(wb, '\n');
  1592. break;
  1593. case NDFT_I64:
  1594. buffer_strcat(wb, key);
  1595. buffer_putc(wb, '=');
  1596. buffer_print_int64(wb, fields[i].entry.i64);
  1597. buffer_putc(wb, '\n');
  1598. break;
  1599. case NDFT_DBL:
  1600. buffer_strcat(wb, key);
  1601. buffer_putc(wb, '=');
  1602. buffer_print_netdata_double(wb, fields[i].entry.dbl);
  1603. buffer_putc(wb, '\n');
  1604. break;
  1605. case NDFT_UUID:
  1606. if(!uuid_is_null(*fields[i].entry.uuid)) {
  1607. char u[UUID_COMPACT_STR_LEN];
  1608. uuid_unparse_lower_compact(*fields[i].entry.uuid, u);
  1609. buffer_strcat(wb, key);
  1610. buffer_putc(wb, '=');
  1611. buffer_fast_strcat(wb, u, sizeof(u) - 1);
  1612. buffer_putc(wb, '\n');
  1613. }
  1614. break;
  1615. case NDFT_CALLBACK: {
  1616. if(!tmp)
  1617. tmp = buffer_create(1024, NULL);
  1618. else
  1619. buffer_flush(tmp);
  1620. if(fields[i].entry.cb.formatter(tmp, fields[i].entry.cb.formatter_data))
  1621. s = buffer_tostring(tmp);
  1622. else
  1623. s = NULL;
  1624. }
  1625. break;
  1626. default:
  1627. s = "UNHANDLED";
  1628. break;
  1629. }
  1630. if(s && *s) {
  1631. buffer_strcat(wb, key);
  1632. if(!strchr(s, '\n')) {
  1633. buffer_putc(wb, '=');
  1634. buffer_strcat(wb, s);
  1635. buffer_putc(wb, '\n');
  1636. }
  1637. else {
  1638. buffer_putc(wb, '\n');
  1639. size_t size = strlen(s);
  1640. uint64_t le_size = htole64(size);
  1641. buffer_memcat(wb, &le_size, sizeof(le_size));
  1642. buffer_memcat(wb, s, size);
  1643. buffer_putc(wb, '\n');
  1644. }
  1645. }
  1646. }
  1647. return journal_direct_send(nd_log.journal_direct.fd, buffer_tostring(wb), buffer_strlen(wb));
  1648. }
  1649. // ----------------------------------------------------------------------------
  1650. // syslog logger - uses logfmt
  1651. static bool nd_logger_syslog(int priority, ND_LOG_FORMAT format __maybe_unused, struct log_field *fields, size_t fields_max) {
  1652. CLEAN_BUFFER *wb = buffer_create(1024, NULL);
  1653. nd_logger_logfmt(wb, fields, fields_max);
  1654. syslog(priority, "%s", buffer_tostring(wb));
  1655. return true;
  1656. }
  1657. // ----------------------------------------------------------------------------
  1658. // file logger - uses logfmt
  1659. static bool nd_logger_file(FILE *fp, ND_LOG_FORMAT format, struct log_field *fields, size_t fields_max) {
  1660. BUFFER *wb = buffer_create(1024, NULL);
  1661. if(format == NDLF_JSON)
  1662. nd_logger_json(wb, fields, fields_max);
  1663. else
  1664. nd_logger_logfmt(wb, fields, fields_max);
  1665. int r = fprintf(fp, "%s\n", buffer_tostring(wb));
  1666. fflush(fp);
  1667. buffer_free(wb);
  1668. return r > 0;
  1669. }
  1670. // ----------------------------------------------------------------------------
  1671. // logger router
  1672. static ND_LOG_METHOD nd_logger_select_output(ND_LOG_SOURCES source, FILE **fpp, SPINLOCK **spinlock) {
  1673. *spinlock = NULL;
  1674. ND_LOG_METHOD output = nd_log.sources[source].method;
  1675. switch(output) {
  1676. case NDLM_JOURNAL:
  1677. if(unlikely(!nd_log.journal_direct.initialized && !nd_log.journal.initialized)) {
  1678. output = NDLM_FILE;
  1679. *fpp = stderr;
  1680. *spinlock = &nd_log.std_error.spinlock;
  1681. }
  1682. else {
  1683. *fpp = NULL;
  1684. *spinlock = NULL;
  1685. }
  1686. break;
  1687. case NDLM_SYSLOG:
  1688. if(unlikely(!nd_log.syslog.initialized)) {
  1689. output = NDLM_FILE;
  1690. *spinlock = &nd_log.std_error.spinlock;
  1691. *fpp = stderr;
  1692. }
  1693. else {
  1694. *spinlock = NULL;
  1695. *fpp = NULL;
  1696. }
  1697. break;
  1698. case NDLM_FILE:
  1699. if(!nd_log.sources[source].fp) {
  1700. *fpp = stderr;
  1701. *spinlock = &nd_log.std_error.spinlock;
  1702. }
  1703. else {
  1704. *fpp = nd_log.sources[source].fp;
  1705. *spinlock = &nd_log.sources[source].spinlock;
  1706. }
  1707. break;
  1708. case NDLM_STDOUT:
  1709. output = NDLM_FILE;
  1710. *fpp = stdout;
  1711. *spinlock = &nd_log.std_output.spinlock;
  1712. break;
  1713. default:
  1714. case NDLM_DEFAULT:
  1715. case NDLM_STDERR:
  1716. output = NDLM_FILE;
  1717. *fpp = stderr;
  1718. *spinlock = &nd_log.std_error.spinlock;
  1719. break;
  1720. case NDLM_DISABLED:
  1721. case NDLM_DEVNULL:
  1722. output = NDLM_DISABLED;
  1723. *fpp = NULL;
  1724. *spinlock = NULL;
  1725. break;
  1726. }
  1727. return output;
  1728. }
  1729. // ----------------------------------------------------------------------------
  1730. // high level logger
  1731. static void nd_logger_log_fields(SPINLOCK *spinlock, FILE *fp, bool limit, ND_LOG_FIELD_PRIORITY priority,
  1732. ND_LOG_METHOD output, struct nd_log_source *source,
  1733. struct log_field *fields, size_t fields_max) {
  1734. if(spinlock)
  1735. spinlock_lock(spinlock);
  1736. // check the limits
  1737. if(limit && nd_log_limit_reached(source))
  1738. goto cleanup;
  1739. if(output == NDLM_JOURNAL) {
  1740. if(!nd_logger_journal_direct(fields, fields_max) && !nd_logger_journal_libsystemd(fields, fields_max)) {
  1741. // we can't log to journal, let's log to stderr
  1742. if(spinlock)
  1743. spinlock_unlock(spinlock);
  1744. output = NDLM_FILE;
  1745. spinlock = &nd_log.std_error.spinlock;
  1746. fp = stderr;
  1747. if(spinlock)
  1748. spinlock_lock(spinlock);
  1749. }
  1750. }
  1751. if(output == NDLM_SYSLOG)
  1752. nd_logger_syslog(priority, source->format, fields, fields_max);
  1753. if(output == NDLM_FILE)
  1754. nd_logger_file(fp, source->format, fields, fields_max);
  1755. cleanup:
  1756. if(spinlock)
  1757. spinlock_unlock(spinlock);
  1758. }
  1759. static void nd_logger_unset_all_thread_fields(void) {
  1760. size_t fields_max = THREAD_FIELDS_MAX;
  1761. for(size_t i = 0; i < fields_max ; i++)
  1762. thread_log_fields[i].entry.set = false;
  1763. }
  1764. static void nd_logger_merge_log_stack_to_thread_fields(void) {
  1765. for(size_t c = 0; c < thread_log_stack_next ;c++) {
  1766. struct log_stack_entry *lgs = thread_log_stack_base[c];
  1767. for(size_t i = 0; lgs[i].id != NDF_STOP ; i++) {
  1768. if(lgs[i].id >= _NDF_MAX || !lgs[i].set)
  1769. continue;
  1770. struct log_stack_entry *e = &lgs[i];
  1771. ND_LOG_STACK_FIELD_TYPE type = lgs[i].type;
  1772. // do not add empty / unset fields
  1773. if((type == NDFT_TXT && (!e->txt || !*e->txt)) ||
  1774. (type == NDFT_BFR && (!e->bfr || !buffer_strlen(e->bfr))) ||
  1775. (type == NDFT_STR && !e->str) ||
  1776. (type == NDFT_UUID && (!e->uuid || uuid_is_null(*e->uuid))) ||
  1777. (type == NDFT_CALLBACK && !e->cb.formatter) ||
  1778. type == NDFT_UNSET)
  1779. continue;
  1780. thread_log_fields[lgs[i].id].entry = *e;
  1781. }
  1782. }
  1783. }
  1784. static void nd_logger(const char *file, const char *function, const unsigned long line,
  1785. ND_LOG_SOURCES source, ND_LOG_FIELD_PRIORITY priority, bool limit, int saved_errno,
  1786. const char *fmt, va_list ap) {
  1787. SPINLOCK *spinlock;
  1788. FILE *fp;
  1789. ND_LOG_METHOD output = nd_logger_select_output(source, &fp, &spinlock);
  1790. if(output != NDLM_FILE && output != NDLM_JOURNAL && output != NDLM_SYSLOG)
  1791. return;
  1792. // mark all fields as unset
  1793. nd_logger_unset_all_thread_fields();
  1794. // flatten the log stack into the fields
  1795. nd_logger_merge_log_stack_to_thread_fields();
  1796. // set the common fields that are automatically set by the logging subsystem
  1797. if(likely(!thread_log_fields[NDF_INVOCATION_ID].entry.set))
  1798. thread_log_fields[NDF_INVOCATION_ID].entry = ND_LOG_FIELD_UUID(NDF_INVOCATION_ID, &nd_log.invocation_id);
  1799. if(likely(!thread_log_fields[NDF_LOG_SOURCE].entry.set))
  1800. thread_log_fields[NDF_LOG_SOURCE].entry = ND_LOG_FIELD_TXT(NDF_LOG_SOURCE, nd_log_id2source(source));
  1801. else {
  1802. ND_LOG_SOURCES src = source;
  1803. if(thread_log_fields[NDF_LOG_SOURCE].entry.type == NDFT_TXT)
  1804. src = nd_log_source2id(thread_log_fields[NDF_LOG_SOURCE].entry.txt, source);
  1805. else if(thread_log_fields[NDF_LOG_SOURCE].entry.type == NDFT_U64)
  1806. src = thread_log_fields[NDF_LOG_SOURCE].entry.u64;
  1807. if(src != source && src < _NDLS_MAX) {
  1808. source = src;
  1809. output = nd_logger_select_output(source, &fp, &spinlock);
  1810. if(output != NDLM_FILE && output != NDLM_JOURNAL && output != NDLM_SYSLOG)
  1811. return;
  1812. }
  1813. }
  1814. if(likely(!thread_log_fields[NDF_SYSLOG_IDENTIFIER].entry.set))
  1815. thread_log_fields[NDF_SYSLOG_IDENTIFIER].entry = ND_LOG_FIELD_TXT(NDF_SYSLOG_IDENTIFIER, program_name);
  1816. if(likely(!thread_log_fields[NDF_LINE].entry.set)) {
  1817. thread_log_fields[NDF_LINE].entry = ND_LOG_FIELD_U64(NDF_LINE, line);
  1818. thread_log_fields[NDF_FILE].entry = ND_LOG_FIELD_TXT(NDF_FILE, file);
  1819. thread_log_fields[NDF_FUNC].entry = ND_LOG_FIELD_TXT(NDF_FUNC, function);
  1820. }
  1821. if(likely(!thread_log_fields[NDF_PRIORITY].entry.set)) {
  1822. thread_log_fields[NDF_PRIORITY].entry = ND_LOG_FIELD_U64(NDF_PRIORITY, priority);
  1823. }
  1824. if(likely(!thread_log_fields[NDF_TID].entry.set))
  1825. thread_log_fields[NDF_TID].entry = ND_LOG_FIELD_U64(NDF_TID, gettid());
  1826. char os_threadname[NETDATA_THREAD_NAME_MAX + 1];
  1827. if(likely(!thread_log_fields[NDF_THREAD_TAG].entry.set)) {
  1828. const char *thread_tag = netdata_thread_tag();
  1829. if(!netdata_thread_tag_exists()) {
  1830. if (!netdata_thread_tag_exists()) {
  1831. os_thread_get_current_name_np(os_threadname);
  1832. if ('\0' != os_threadname[0])
  1833. /* If it is not an empty string replace "MAIN" thread_tag */
  1834. thread_tag = os_threadname;
  1835. }
  1836. }
  1837. thread_log_fields[NDF_THREAD_TAG].entry = ND_LOG_FIELD_TXT(NDF_THREAD_TAG, thread_tag);
  1838. // TODO: fix the ND_MODULE in logging by setting proper module name in threads
  1839. // if(!thread_log_fields[NDF_MODULE].entry.set)
  1840. // thread_log_fields[NDF_MODULE].entry = ND_LOG_FIELD_CB(NDF_MODULE, thread_tag_to_module, (void *)thread_tag);
  1841. }
  1842. if(likely(!thread_log_fields[NDF_TIMESTAMP_REALTIME_USEC].entry.set))
  1843. thread_log_fields[NDF_TIMESTAMP_REALTIME_USEC].entry = ND_LOG_FIELD_U64(NDF_TIMESTAMP_REALTIME_USEC, now_realtime_usec());
  1844. if(saved_errno != 0 && !thread_log_fields[NDF_ERRNO].entry.set)
  1845. thread_log_fields[NDF_ERRNO].entry = ND_LOG_FIELD_I64(NDF_ERRNO, saved_errno);
  1846. CLEAN_BUFFER *wb = NULL;
  1847. if(fmt && !thread_log_fields[NDF_MESSAGE].entry.set) {
  1848. wb = buffer_create(1024, NULL);
  1849. buffer_vsprintf(wb, fmt, ap);
  1850. thread_log_fields[NDF_MESSAGE].entry = ND_LOG_FIELD_TXT(NDF_MESSAGE, buffer_tostring(wb));
  1851. }
  1852. nd_logger_log_fields(spinlock, fp, limit, priority, output, &nd_log.sources[source],
  1853. thread_log_fields, THREAD_FIELDS_MAX);
  1854. if(nd_log.sources[source].pending_msg) {
  1855. // log a pending message
  1856. nd_logger_unset_all_thread_fields();
  1857. thread_log_fields[NDF_TIMESTAMP_REALTIME_USEC].entry = (struct log_stack_entry){
  1858. .set = true,
  1859. .type = NDFT_U64,
  1860. .u64 = now_realtime_usec(),
  1861. };
  1862. thread_log_fields[NDF_LOG_SOURCE].entry = (struct log_stack_entry){
  1863. .set = true,
  1864. .type = NDFT_TXT,
  1865. .txt = nd_log_id2source(source),
  1866. };
  1867. thread_log_fields[NDF_SYSLOG_IDENTIFIER].entry = (struct log_stack_entry){
  1868. .set = true,
  1869. .type = NDFT_TXT,
  1870. .txt = program_name,
  1871. };
  1872. thread_log_fields[NDF_MESSAGE].entry = (struct log_stack_entry){
  1873. .set = true,
  1874. .type = NDFT_TXT,
  1875. .txt = nd_log.sources[source].pending_msg,
  1876. };
  1877. nd_logger_log_fields(spinlock, fp, false, priority, output,
  1878. &nd_log.sources[source],
  1879. thread_log_fields, THREAD_FIELDS_MAX);
  1880. freez((void *)nd_log.sources[source].pending_msg);
  1881. nd_log.sources[source].pending_msg = NULL;
  1882. }
  1883. errno = 0;
  1884. }
  1885. static ND_LOG_SOURCES nd_log_validate_source(ND_LOG_SOURCES source) {
  1886. if(source >= _NDLS_MAX)
  1887. source = NDLS_DAEMON;
  1888. if(overwrite_thread_source)
  1889. source = overwrite_thread_source;
  1890. if(nd_log.overwrite_process_source)
  1891. source = nd_log.overwrite_process_source;
  1892. return source;
  1893. }
  1894. // ----------------------------------------------------------------------------
  1895. // public API for loggers
  1896. void netdata_logger(ND_LOG_SOURCES source, ND_LOG_FIELD_PRIORITY priority, const char *file, const char *function, unsigned long line, const char *fmt, ... )
  1897. {
  1898. int saved_errno = errno;
  1899. source = nd_log_validate_source(source);
  1900. if((source == NDLS_DAEMON || source == NDLS_COLLECTORS) && priority > nd_log.sources[source].min_priority)
  1901. return;
  1902. va_list args;
  1903. va_start(args, fmt);
  1904. nd_logger(file, function, line, source, priority,
  1905. source == NDLS_DAEMON || source == NDLS_COLLECTORS,
  1906. saved_errno, fmt, args);
  1907. va_end(args);
  1908. }
  1909. void netdata_logger_with_limit(ERROR_LIMIT *erl, ND_LOG_SOURCES source, ND_LOG_FIELD_PRIORITY priority, const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, const char *fmt, ... ) {
  1910. int saved_errno = errno;
  1911. source = nd_log_validate_source(source);
  1912. if(erl->sleep_ut)
  1913. sleep_usec(erl->sleep_ut);
  1914. spinlock_lock(&erl->spinlock);
  1915. erl->count++;
  1916. time_t now = now_boottime_sec();
  1917. if(now - erl->last_logged < erl->log_every) {
  1918. spinlock_unlock(&erl->spinlock);
  1919. return;
  1920. }
  1921. spinlock_unlock(&erl->spinlock);
  1922. va_list args;
  1923. va_start(args, fmt);
  1924. nd_logger(file, function, line, source, priority,
  1925. source == NDLS_DAEMON || source == NDLS_COLLECTORS,
  1926. saved_errno, fmt, args);
  1927. va_end(args);
  1928. erl->last_logged = now;
  1929. erl->count = 0;
  1930. }
  1931. void netdata_logger_fatal( const char *file, const char *function, const unsigned long line, const char *fmt, ... ) {
  1932. int saved_errno = errno;
  1933. ND_LOG_SOURCES source = NDLS_DAEMON;
  1934. source = nd_log_validate_source(source);
  1935. va_list args;
  1936. va_start(args, fmt);
  1937. nd_logger(file, function, line, source, NDLP_ALERT, true, saved_errno, fmt, args);
  1938. va_end(args);
  1939. char date[LOG_DATE_LENGTH];
  1940. log_date(date, LOG_DATE_LENGTH, now_realtime_sec());
  1941. char action_data[70+1];
  1942. snprintfz(action_data, 70, "%04lu@%-10.10s:%-15.15s/%d", line, file, function, saved_errno);
  1943. char os_threadname[NETDATA_THREAD_NAME_MAX + 1];
  1944. const char *thread_tag = netdata_thread_tag();
  1945. if(!netdata_thread_tag_exists()) {
  1946. if (!netdata_thread_tag_exists()) {
  1947. os_thread_get_current_name_np(os_threadname);
  1948. if ('\0' != os_threadname[0])
  1949. /* If it is not an empty string replace "MAIN" thread_tag */
  1950. thread_tag = os_threadname;
  1951. }
  1952. }
  1953. if(!thread_tag)
  1954. thread_tag = "UNKNOWN";
  1955. const char *tag_to_send = thread_tag;
  1956. // anonymize thread names
  1957. if(strncmp(thread_tag, THREAD_TAG_STREAM_RECEIVER, strlen(THREAD_TAG_STREAM_RECEIVER)) == 0)
  1958. tag_to_send = THREAD_TAG_STREAM_RECEIVER;
  1959. if(strncmp(thread_tag, THREAD_TAG_STREAM_SENDER, strlen(THREAD_TAG_STREAM_SENDER)) == 0)
  1960. tag_to_send = THREAD_TAG_STREAM_SENDER;
  1961. char action_result[60+1];
  1962. snprintfz(action_result, 60, "%s:%s", program_name, tag_to_send);
  1963. #ifdef HAVE_BACKTRACE
  1964. int fd = nd_log.sources[NDLS_DAEMON].fd;
  1965. if(fd == -1)
  1966. fd = STDERR_FILENO;
  1967. int nptrs;
  1968. void *buffer[10000];
  1969. nptrs = backtrace(buffer, sizeof(buffer));
  1970. if(nptrs)
  1971. backtrace_symbols_fd(buffer, nptrs, fd);
  1972. #endif
  1973. #ifdef NETDATA_INTERNAL_CHECKS
  1974. abort();
  1975. #endif
  1976. netdata_cleanup_and_exit(1, "FATAL", action_result, action_data);
  1977. }
  1978. // ----------------------------------------------------------------------------
  1979. // log limits
  1980. void nd_log_limits_reset(void) {
  1981. usec_t now_ut = now_monotonic_usec();
  1982. spinlock_lock(&nd_log.std_output.spinlock);
  1983. spinlock_lock(&nd_log.std_error.spinlock);
  1984. for(size_t i = 0; i < _NDLS_MAX ;i++) {
  1985. spinlock_lock(&nd_log.sources[i].spinlock);
  1986. nd_log.sources[i].limits.prevented = 0;
  1987. nd_log.sources[i].limits.counter = 0;
  1988. nd_log.sources[i].limits.started_monotonic_ut = now_ut;
  1989. nd_log.sources[i].limits.logs_per_period = nd_log.sources[i].limits.logs_per_period_backup;
  1990. spinlock_unlock(&nd_log.sources[i].spinlock);
  1991. }
  1992. spinlock_unlock(&nd_log.std_output.spinlock);
  1993. spinlock_unlock(&nd_log.std_error.spinlock);
  1994. }
  1995. void nd_log_limits_unlimited(void) {
  1996. nd_log_limits_reset();
  1997. for(size_t i = 0; i < _NDLS_MAX ;i++) {
  1998. nd_log.sources[i].limits.logs_per_period = 0;
  1999. }
  2000. }
  2001. static bool nd_log_limit_reached(struct nd_log_source *source) {
  2002. if(source->limits.throttle_period == 0 || source->limits.logs_per_period == 0)
  2003. return false;
  2004. usec_t now_ut = now_monotonic_usec();
  2005. if(!source->limits.started_monotonic_ut)
  2006. source->limits.started_monotonic_ut = now_ut;
  2007. source->limits.counter++;
  2008. if(now_ut - source->limits.started_monotonic_ut > (usec_t)source->limits.throttle_period) {
  2009. if(source->limits.prevented) {
  2010. BUFFER *wb = buffer_create(1024, NULL);
  2011. buffer_sprintf(wb,
  2012. "LOG FLOOD PROTECTION: resuming logging "
  2013. "(prevented %"PRIu32" logs in the last %"PRIu32" seconds).",
  2014. source->limits.prevented,
  2015. source->limits.throttle_period);
  2016. if(source->pending_msg)
  2017. freez((void *)source->pending_msg);
  2018. source->pending_msg = strdupz(buffer_tostring(wb));
  2019. buffer_free(wb);
  2020. }
  2021. // restart the period accounting
  2022. source->limits.started_monotonic_ut = now_ut;
  2023. source->limits.counter = 1;
  2024. source->limits.prevented = 0;
  2025. // log this error
  2026. return false;
  2027. }
  2028. if(source->limits.counter > source->limits.logs_per_period) {
  2029. if(!source->limits.prevented) {
  2030. BUFFER *wb = buffer_create(1024, NULL);
  2031. buffer_sprintf(wb,
  2032. "LOG FLOOD PROTECTION: too many logs (%"PRIu32" logs in %"PRId64" seconds, threshold is set to %"PRIu32" logs "
  2033. "in %"PRIu32" seconds). Preventing more logs from process '%s' for %"PRId64" seconds.",
  2034. source->limits.counter,
  2035. (int64_t)((now_ut - source->limits.started_monotonic_ut) / USEC_PER_SEC),
  2036. source->limits.logs_per_period,
  2037. source->limits.throttle_period,
  2038. program_name,
  2039. (int64_t)(((source->limits.started_monotonic_ut + (source->limits.throttle_period * USEC_PER_SEC) - now_ut)) / USEC_PER_SEC)
  2040. );
  2041. if(source->pending_msg)
  2042. freez((void *)source->pending_msg);
  2043. source->pending_msg = strdupz(buffer_tostring(wb));
  2044. buffer_free(wb);
  2045. }
  2046. source->limits.prevented++;
  2047. // prevent logging this error
  2048. #ifdef NETDATA_INTERNAL_CHECKS
  2049. return false;
  2050. #else
  2051. return true;
  2052. #endif
  2053. }
  2054. return false;
  2055. }