health_log.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "health.h"
  3. // ----------------------------------------------------------------------------
  4. // health alarm log load/save
  5. // no need for locking - only one thread is reading / writing the alarms log
  6. inline int health_alarm_log_open(RRDHOST *host) {
  7. if(host->health_log_fp)
  8. fclose(host->health_log_fp);
  9. host->health_log_fp = fopen(host->health_log_filename, "a");
  10. if(host->health_log_fp) {
  11. if (setvbuf(host->health_log_fp, NULL, _IOLBF, 0) != 0)
  12. error("HEALTH [%s]: cannot set line buffering on health log file '%s'.", host->hostname, host->health_log_filename);
  13. return 0;
  14. }
  15. error("HEALTH [%s]: cannot open health log file '%s'. Health data will be lost in case of netdata or server crash.", host->hostname, host->health_log_filename);
  16. return -1;
  17. }
  18. static inline void health_alarm_log_close(RRDHOST *host) {
  19. if(host->health_log_fp) {
  20. fclose(host->health_log_fp);
  21. host->health_log_fp = NULL;
  22. }
  23. }
  24. static inline void health_log_rotate(RRDHOST *host) {
  25. static size_t rotate_every = 0;
  26. if(unlikely(rotate_every == 0)) {
  27. rotate_every = (size_t)config_get_number(CONFIG_SECTION_HEALTH, "rotate log every lines", 2000);
  28. if(rotate_every < 100) rotate_every = 100;
  29. }
  30. if(unlikely(host->health_log_entries_written > rotate_every)) {
  31. if(unlikely(host->health_log_fp)) {
  32. health_alarm_log_close(host);
  33. char old_filename[FILENAME_MAX + 1];
  34. snprintfz(old_filename, FILENAME_MAX, "%s.old", host->health_log_filename);
  35. if(unlink(old_filename) == -1 && errno != ENOENT)
  36. error("HEALTH [%s]: cannot remove old alarms log file '%s'", host->hostname, old_filename);
  37. if(link(host->health_log_filename, old_filename) == -1 && errno != ENOENT)
  38. error("HEALTH [%s]: cannot move file '%s' to '%s'.", host->hostname, host->health_log_filename, old_filename);
  39. if(unlink(host->health_log_filename) == -1 && errno != ENOENT)
  40. error("HEALTH [%s]: cannot remove old alarms log file '%s'", host->hostname, host->health_log_filename);
  41. // open it with truncate
  42. host->health_log_fp = fopen(host->health_log_filename, "w");
  43. if(host->health_log_fp)
  44. fclose(host->health_log_fp);
  45. else
  46. error("HEALTH [%s]: cannot truncate health log '%s'", host->hostname, host->health_log_filename);
  47. host->health_log_fp = NULL;
  48. host->health_log_entries_written = 0;
  49. health_alarm_log_open(host);
  50. }
  51. }
  52. }
  53. inline void health_label_log_save(RRDHOST *host) {
  54. health_log_rotate(host);
  55. if(unlikely(host->health_log_fp)) {
  56. BUFFER *wb = buffer_create(1024);
  57. rrdhost_check_rdlock(host);
  58. netdata_rwlock_rdlock(&host->labels.labels_rwlock);
  59. struct label *l=localhost->labels.head;
  60. while (l != NULL) {
  61. buffer_sprintf(wb,"%s=%s\t ", l->key, l->value);
  62. l = l->next;
  63. }
  64. netdata_rwlock_unlock(&host->labels.labels_rwlock);
  65. char *write = (char *) buffer_tostring(wb) ;
  66. write[wb->len-2] = '\n';
  67. write[wb->len-1] = '\0';
  68. if (unlikely(fprintf(host->health_log_fp, "L\t%s"
  69. , write
  70. ) < 0))
  71. error("HEALTH [%s]: failed to save alarm log entry to '%s'. Health data may be lost in case of abnormal restart.",
  72. host->hostname, host->health_log_filename);
  73. else {
  74. host->health_log_entries_written++;
  75. }
  76. buffer_free(wb);
  77. }
  78. }
  79. inline void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae) {
  80. health_log_rotate(host);
  81. if(unlikely(host->health_log_fp)) {
  82. if(unlikely(fprintf(host->health_log_fp
  83. , "%c\t%s"
  84. "\t%08x\t%08x\t%08x\t%08x\t%08x"
  85. "\t%08x\t%08x\t%08x"
  86. "\t%08x\t%08x\t%08x"
  87. "\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s"
  88. "\t%d\t%d\t%d\t%d"
  89. "\t" CALCULATED_NUMBER_FORMAT_AUTO "\t" CALCULATED_NUMBER_FORMAT_AUTO
  90. "\t%016"PRIx64""
  91. "\t%s\t%s\t%s"
  92. "\n"
  93. , (ae->flags & HEALTH_ENTRY_FLAG_SAVED)?'U':'A'
  94. , host->hostname
  95. , ae->unique_id
  96. , ae->alarm_id
  97. , ae->alarm_event_id
  98. , ae->updated_by_id
  99. , ae->updates_id
  100. , (uint32_t)ae->when
  101. , (uint32_t)ae->duration
  102. , (uint32_t)ae->non_clear_duration
  103. , (uint32_t)ae->flags
  104. , (uint32_t)ae->exec_run_timestamp
  105. , (uint32_t)ae->delay_up_to_timestamp
  106. , (ae->name)?ae->name:""
  107. , (ae->chart)?ae->chart:""
  108. , (ae->family)?ae->family:""
  109. , (ae->exec)?ae->exec:""
  110. , (ae->recipient)?ae->recipient:""
  111. , (ae->source)?ae->source:""
  112. , (ae->units)?ae->units:""
  113. , (ae->info)?ae->info:""
  114. , ae->exec_code
  115. , ae->new_status
  116. , ae->old_status
  117. , ae->delay
  118. , ae->new_value
  119. , ae->old_value
  120. , (uint64_t)ae->last_repeat
  121. , (ae->classification)?ae->classification:"Unknown"
  122. , (ae->component)?ae->component:"Unknown"
  123. , (ae->type)?ae->type:"Unknown"
  124. ) < 0))
  125. error("HEALTH [%s]: failed to save alarm log entry to '%s'. Health data may be lost in case of abnormal restart.", host->hostname, host->health_log_filename);
  126. else {
  127. ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
  128. host->health_log_entries_written++;
  129. }
  130. }else
  131. sql_health_alarm_log_save(host, ae);
  132. #ifdef ENABLE_ACLK
  133. if (netdata_cloud_setting) {
  134. sql_queue_alarm_to_aclk(host, ae);
  135. }
  136. #endif
  137. }
  138. static uint32_t is_valid_alarm_id(RRDHOST *host, const char *chart, const char *name, uint32_t alarm_id)
  139. {
  140. uint32_t hash_chart = simple_hash(chart);
  141. uint32_t hash_name = simple_hash(name);
  142. ALARM_ENTRY *ae;
  143. for(ae = host->health_log.alarms; ae ;ae = ae->next) {
  144. if (unlikely(
  145. ae->alarm_id == alarm_id && (!(ae->hash_name == hash_name && ae->hash_chart == hash_chart &&
  146. !strcmp(name, ae->name) && !strcmp(chart, ae->chart))))) {
  147. return 0;
  148. }
  149. }
  150. return 1;
  151. }
  152. static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char *filename) {
  153. errno = 0;
  154. char *s, *buf = mallocz(65536 + 1);
  155. size_t line = 0, len = 0;
  156. ssize_t loaded = 0, updated = 0, errored = 0, duplicate = 0;
  157. netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
  158. while((s = fgets_trim_len(buf, 65536, fp, &len))) {
  159. host->health_log_entries_written++;
  160. line++;
  161. int max_entries = 33, entries = 0;
  162. char *pointers[max_entries];
  163. pointers[entries++] = s++;
  164. while(*s) {
  165. if(unlikely(*s == '\t')) {
  166. *s = '\0';
  167. pointers[entries++] = ++s;
  168. if(entries >= max_entries) {
  169. error("HEALTH [%s]: line %zu of file '%s' has more than %d entries. Ignoring excessive entries.", host->hostname, line, filename, max_entries);
  170. break;
  171. }
  172. }
  173. else s++;
  174. }
  175. if(likely(*pointers[0] == 'L'))
  176. continue;
  177. if(likely(*pointers[0] == 'U' || *pointers[0] == 'A')) {
  178. ALARM_ENTRY *ae = NULL;
  179. if(entries < 27) {
  180. error("HEALTH [%s]: line %zu of file '%s' should have at least 27 entries, but it has %d. Ignoring it.", host->hostname, line, filename, entries);
  181. errored++;
  182. continue;
  183. }
  184. // check that we have valid ids
  185. uint32_t unique_id = (uint32_t)strtoul(pointers[2], NULL, 16);
  186. if(!unique_id) {
  187. error("HEALTH [%s]: line %zu of file '%s' states alarm entry with invalid unique id %u (%s). Ignoring it.", host->hostname, line, filename, unique_id, pointers[2]);
  188. errored++;
  189. continue;
  190. }
  191. uint32_t alarm_id = (uint32_t)strtoul(pointers[3], NULL, 16);
  192. if(!alarm_id) {
  193. error("HEALTH [%s]: line %zu of file '%s' states alarm entry for invalid alarm id %u (%s). Ignoring it.", host->hostname, line, filename, alarm_id, pointers[3]);
  194. errored++;
  195. continue;
  196. }
  197. // Check if we got last_repeat field
  198. time_t last_repeat = 0;
  199. if(entries > 27) {
  200. char* alarm_name = pointers[13];
  201. last_repeat = (time_t)strtoul(pointers[27], NULL, 16);
  202. RRDCALC *rc = alarm_max_last_repeat(host, alarm_name,simple_hash(alarm_name));
  203. if (!rc) {
  204. for(rc = host->alarms; rc ; rc = rc->next) {
  205. RRDCALC *rdcmp = (RRDCALC *) avl_insert_lock(&(host)->alarms_idx_name, (avl_t *)rc);
  206. if(rdcmp != rc) {
  207. error("Cannot insert the alarm index ID using log %s", rc->name);
  208. }
  209. }
  210. rc = alarm_max_last_repeat(host, alarm_name,simple_hash(alarm_name));
  211. }
  212. if(unlikely(rc)) {
  213. if (rrdcalc_isrepeating(rc)) {
  214. rc->last_repeat = last_repeat;
  215. // We iterate through repeating alarm entries only to
  216. // find the latest last_repeat timestamp. Otherwise,
  217. // there is no need to keep them in memory.
  218. continue;
  219. }
  220. }
  221. }
  222. if(unlikely(*pointers[0] == 'A')) {
  223. // make sure it is properly numbered
  224. if(unlikely(host->health_log.alarms && unique_id < host->health_log.alarms->unique_id)) {
  225. error( "HEALTH [%s]: line %zu of file '%s' has alarm log entry %u in wrong order. Ignoring it."
  226. , host->hostname, line, filename, unique_id);
  227. errored++;
  228. continue;
  229. }
  230. ae = callocz(1, sizeof(ALARM_ENTRY));
  231. }
  232. else if(unlikely(*pointers[0] == 'U')) {
  233. // find the original
  234. for(ae = host->health_log.alarms; ae ; ae = ae->next) {
  235. if(unlikely(unique_id == ae->unique_id)) {
  236. if(unlikely(*pointers[0] == 'A')) {
  237. error("HEALTH [%s]: line %zu of file '%s' adds duplicate alarm log entry %u. Using the later."
  238. , host->hostname, line, filename, unique_id);
  239. *pointers[0] = 'U';
  240. duplicate++;
  241. }
  242. break;
  243. }
  244. else if(unlikely(unique_id > ae->unique_id)) {
  245. // no need to continue
  246. // the linked list is sorted
  247. ae = NULL;
  248. break;
  249. }
  250. }
  251. }
  252. // if not found, skip this line
  253. if(unlikely(!ae)) {
  254. // error("HEALTH [%s]: line %zu of file '%s' updates alarm log entry with unique id %u, but it is not found.", host->hostname, line, filename, unique_id);
  255. continue;
  256. }
  257. // check for a possible host mismatch
  258. //if(strcmp(pointers[1], host->hostname))
  259. // error("HEALTH [%s]: line %zu of file '%s' provides an alarm for host '%s' but this is named '%s'.", host->hostname, line, filename, pointers[1], host->hostname);
  260. ae->unique_id = unique_id;
  261. if (!is_valid_alarm_id(host, pointers[14], pointers[13], alarm_id))
  262. alarm_id = rrdcalc_get_unique_id(host, pointers[14], pointers[13], NULL);
  263. ae->alarm_id = alarm_id;
  264. ae->alarm_event_id = (uint32_t)strtoul(pointers[4], NULL, 16);
  265. ae->updated_by_id = (uint32_t)strtoul(pointers[5], NULL, 16);
  266. ae->updates_id = (uint32_t)strtoul(pointers[6], NULL, 16);
  267. ae->when = (uint32_t)strtoul(pointers[7], NULL, 16);
  268. ae->duration = (uint32_t)strtoul(pointers[8], NULL, 16);
  269. ae->non_clear_duration = (uint32_t)strtoul(pointers[9], NULL, 16);
  270. ae->flags = (uint32_t)strtoul(pointers[10], NULL, 16);
  271. ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
  272. ae->exec_run_timestamp = (uint32_t)strtoul(pointers[11], NULL, 16);
  273. ae->delay_up_to_timestamp = (uint32_t)strtoul(pointers[12], NULL, 16);
  274. freez(ae->name);
  275. ae->name = strdupz(pointers[13]);
  276. ae->hash_name = simple_hash(ae->name);
  277. freez(ae->chart);
  278. ae->chart = strdupz(pointers[14]);
  279. ae->hash_chart = simple_hash(ae->chart);
  280. freez(ae->family);
  281. ae->family = strdupz(pointers[15]);
  282. freez(ae->exec);
  283. ae->exec = strdupz(pointers[16]);
  284. if(!*ae->exec) { freez(ae->exec); ae->exec = NULL; }
  285. freez(ae->recipient);
  286. ae->recipient = strdupz(pointers[17]);
  287. if(!*ae->recipient) { freez(ae->recipient); ae->recipient = NULL; }
  288. freez(ae->source);
  289. ae->source = strdupz(pointers[18]);
  290. if(!*ae->source) { freez(ae->source); ae->source = NULL; }
  291. freez(ae->units);
  292. ae->units = strdupz(pointers[19]);
  293. if(!*ae->units) { freez(ae->units); ae->units = NULL; }
  294. freez(ae->info);
  295. ae->info = strdupz(pointers[20]);
  296. if(!*ae->info) { freez(ae->info); ae->info = NULL; }
  297. ae->exec_code = str2i(pointers[21]);
  298. ae->new_status = str2i(pointers[22]);
  299. ae->old_status = str2i(pointers[23]);
  300. ae->delay = str2i(pointers[24]);
  301. ae->new_value = str2l(pointers[25]);
  302. ae->old_value = str2l(pointers[26]);
  303. ae->last_repeat = last_repeat;
  304. if (likely(entries > 30)) {
  305. freez(ae->classification);
  306. ae->classification = strdupz(pointers[28]);
  307. if(!*ae->classification) { freez(ae->classification); ae->classification = NULL; }
  308. freez(ae->component);
  309. ae->component = strdupz(pointers[29]);
  310. if(!*ae->component) { freez(ae->component); ae->component = NULL; }
  311. freez(ae->type);
  312. ae->type = strdupz(pointers[30]);
  313. if(!*ae->type) { freez(ae->type); ae->type = NULL; }
  314. }
  315. char value_string[100 + 1];
  316. freez(ae->old_value_string);
  317. freez(ae->new_value_string);
  318. ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
  319. ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
  320. // add it to host if not already there
  321. if(unlikely(*pointers[0] == 'A')) {
  322. ae->next = host->health_log.alarms;
  323. host->health_log.alarms = ae;
  324. sql_health_alarm_log_insert(host, ae);
  325. loaded++;
  326. }
  327. else {
  328. sql_health_alarm_log_update(host, ae);
  329. updated++;
  330. }
  331. if(unlikely(ae->unique_id > host->health_max_unique_id))
  332. host->health_max_unique_id = ae->unique_id;
  333. if(unlikely(ae->alarm_id >= host->health_max_alarm_id))
  334. host->health_max_alarm_id = ae->alarm_id;
  335. }
  336. else {
  337. error("HEALTH [%s]: line %zu of file '%s' is invalid (unrecognized entry type '%s').", host->hostname, line, filename, pointers[0]);
  338. errored++;
  339. }
  340. }
  341. netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
  342. freez(buf);
  343. if(!host->health_max_unique_id) host->health_max_unique_id = (uint32_t)now_realtime_sec();
  344. if(!host->health_max_alarm_id) host->health_max_alarm_id = (uint32_t)now_realtime_sec();
  345. host->health_log.next_log_id = host->health_max_unique_id + 1;
  346. if (unlikely(!host->health_log.next_alarm_id || host->health_log.next_alarm_id <= host->health_max_alarm_id))
  347. host->health_log.next_alarm_id = host->health_max_alarm_id + 1;
  348. debug(D_HEALTH, "HEALTH [%s]: loaded file '%s' with %zd new alarm entries, updated %zd alarms, errors %zd entries, duplicate %zd", host->hostname, filename, loaded, updated, errored, duplicate);
  349. return loaded;
  350. }
  351. inline void health_alarm_log_load(RRDHOST *host) {
  352. health_alarm_log_close(host);
  353. char filename[FILENAME_MAX + 1];
  354. snprintfz(filename, FILENAME_MAX, "%s.old", host->health_log_filename);
  355. FILE *fp = fopen(filename, "r");
  356. if(!fp)
  357. error("HEALTH [%s]: cannot open health file: %s", host->hostname, filename);
  358. else {
  359. health_alarm_log_read(host, fp, filename);
  360. fclose(fp);
  361. }
  362. host->health_log_entries_written = 0;
  363. fp = fopen(host->health_log_filename, "r");
  364. if(!fp)
  365. error("HEALTH [%s]: cannot open health file: %s", host->hostname, host->health_log_filename);
  366. else {
  367. health_alarm_log_read(host, fp, host->health_log_filename);
  368. fclose(fp);
  369. }
  370. }
  371. // ----------------------------------------------------------------------------
  372. // health alarm log management
  373. inline ALARM_ENTRY* health_create_alarm_entry(
  374. RRDHOST *host,
  375. uint32_t alarm_id,
  376. uint32_t alarm_event_id,
  377. uuid_t config_hash_id,
  378. time_t when,
  379. const char *name,
  380. const char *chart,
  381. const char *family,
  382. const char *class,
  383. const char *component,
  384. const char *type,
  385. const char *exec,
  386. const char *recipient,
  387. time_t duration,
  388. calculated_number old_value,
  389. calculated_number new_value,
  390. RRDCALC_STATUS old_status,
  391. RRDCALC_STATUS new_status,
  392. const char *source,
  393. const char *units,
  394. const char *info,
  395. int delay,
  396. uint32_t flags
  397. ) {
  398. debug(D_HEALTH, "Health adding alarm log entry with id: %u", host->health_log.next_log_id);
  399. ALARM_ENTRY *ae = callocz(1, sizeof(ALARM_ENTRY));
  400. ae->name = strdupz(name);
  401. ae->hash_name = simple_hash(ae->name);
  402. if(chart) {
  403. ae->chart = strdupz(chart);
  404. ae->hash_chart = simple_hash(ae->chart);
  405. }
  406. uuid_copy(ae->config_hash_id, *((uuid_t *) config_hash_id));
  407. if(family)
  408. ae->family = strdupz(family);
  409. if (class)
  410. ae->classification = strdupz(class);
  411. if (component)
  412. ae->component = strdupz(component);
  413. if (type)
  414. ae->type = strdupz(type);
  415. if(exec) ae->exec = strdupz(exec);
  416. if(recipient) ae->recipient = strdupz(recipient);
  417. if(source) ae->source = strdupz(source);
  418. if(units) ae->units = strdupz(units);
  419. ae->unique_id = host->health_log.next_log_id++;
  420. ae->alarm_id = alarm_id;
  421. ae->alarm_event_id = alarm_event_id;
  422. ae->when = when;
  423. ae->old_value = old_value;
  424. ae->new_value = new_value;
  425. char value_string[100 + 1];
  426. ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
  427. ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
  428. char *replaced_info = NULL;
  429. if (likely(info)) {
  430. char *m;
  431. replaced_info = strdupz(info);
  432. size_t pos = 0;
  433. while ((m = strstr(replaced_info + pos, "$family"))) {
  434. char *buf = NULL;
  435. pos = m - replaced_info;
  436. buf = find_and_replace(replaced_info, "$family", (ae->family) ? ae->family : "", m);
  437. freez(replaced_info);
  438. replaced_info = strdupz(buf);
  439. freez(buf);
  440. }
  441. }
  442. if(replaced_info) ae->info = strdupz(replaced_info);
  443. freez(replaced_info);
  444. ae->old_status = old_status;
  445. ae->new_status = new_status;
  446. ae->duration = duration;
  447. ae->delay = delay;
  448. ae->delay_up_to_timestamp = when + delay;
  449. ae->flags |= flags;
  450. ae->last_repeat = 0;
  451. if(ae->old_status == RRDCALC_STATUS_WARNING || ae->old_status == RRDCALC_STATUS_CRITICAL)
  452. ae->non_clear_duration += ae->duration;
  453. return ae;
  454. }
  455. inline void health_alarm_log(
  456. RRDHOST *host,
  457. ALARM_ENTRY *ae
  458. ) {
  459. debug(D_HEALTH, "Health adding alarm log entry with id: %u", ae->unique_id);
  460. if(unlikely(alarm_entry_isrepeating(host, ae))) {
  461. error("Repeating alarms cannot be added to host's alarm log entries. It seems somewhere in the logic, API is being misused. Alarm id: %u", ae->alarm_id);
  462. return;
  463. }
  464. // link it
  465. netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
  466. ae->next = host->health_log.alarms;
  467. host->health_log.alarms = ae;
  468. host->health_log.count++;
  469. netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
  470. // match previous alarms
  471. netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
  472. ALARM_ENTRY *t;
  473. for(t = host->health_log.alarms ; t ; t = t->next) {
  474. if(t != ae && t->alarm_id == ae->alarm_id) {
  475. if(!(t->flags & HEALTH_ENTRY_FLAG_UPDATED) && !t->updated_by_id) {
  476. t->flags |= HEALTH_ENTRY_FLAG_UPDATED;
  477. t->updated_by_id = ae->unique_id;
  478. ae->updates_id = t->unique_id;
  479. if((t->new_status == RRDCALC_STATUS_WARNING || t->new_status == RRDCALC_STATUS_CRITICAL) &&
  480. (t->old_status == RRDCALC_STATUS_WARNING || t->old_status == RRDCALC_STATUS_CRITICAL))
  481. ae->non_clear_duration += t->non_clear_duration;
  482. health_alarm_log_save(host, t);
  483. }
  484. // no need to continue
  485. break;
  486. }
  487. }
  488. netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
  489. health_alarm_log_save(host, ae);
  490. }
  491. inline void health_alarm_log_free_one_nochecks_nounlink(ALARM_ENTRY *ae) {
  492. freez(ae->name);
  493. freez(ae->chart);
  494. freez(ae->family);
  495. freez(ae->classification);
  496. freez(ae->component);
  497. freez(ae->type);
  498. freez(ae->exec);
  499. freez(ae->recipient);
  500. freez(ae->source);
  501. freez(ae->units);
  502. freez(ae->info);
  503. freez(ae->old_value_string);
  504. freez(ae->new_value_string);
  505. freez(ae);
  506. }
  507. inline void health_alarm_log_free(RRDHOST *host) {
  508. rrdhost_check_wrlock(host);
  509. netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
  510. ALARM_ENTRY *ae;
  511. while((ae = host->health_log.alarms)) {
  512. host->health_log.alarms = ae->next;
  513. health_alarm_log_free_one_nochecks_nounlink(ae);
  514. }
  515. netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
  516. }