root/src/noit_check.c

Revision 5e653fe60dcc517ff76c1f3bb82cee19b3c51fa5, 22.0 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 7 years ago)

fixes #30

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <ctype.h>
12 #include <assert.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15
16 #include "utils/noit_log.h"
17 #include "utils/noit_hash.h"
18 #include "utils/noit_skiplist.h"
19 #include "noit_conf.h"
20 #include "noit_check.h"
21 #include "noit_module.h"
22 #include "noit_console.h"
23 #include "eventer/eventer.h"
24
25 /* 60 seconds of possible stutter */
26 #define MAX_INITIAL_STUTTER 60
27
28 static noit_hash_table polls = NOIT_HASH_EMPTY;
29 static noit_skiplist polls_by_name = { 0 };
30 static u_int32_t __config_load_generation = 0;
31 struct uuid_dummy {
32   uuid_t foo;
33 };
34
35 static void register_console_check_commands();
36
37 #define UUID_SIZE sizeof(struct uuid_dummy)
38
39 const char *
40 noit_check_available_string(int16_t available) {
41   switch(available) {
42     case NP_AVAILABLE:    return "available";
43     case NP_UNAVAILABLE:  return "unavailable";
44     case NP_UNKNOWN:      return "unknown";
45   }
46   return "???";
47 }
48 const char *
49 noit_check_state_string(int16_t state) {
50   switch(state) {
51     case NP_GOOD:         return "good";
52     case NP_BAD:          return "bad";
53     case NP_UNKNOWN:      return "unknown";
54   }
55   return "???";
56 }
57 static int __check_name_compare(const void *a, const void *b) {
58   const noit_check_t *ac = a;
59   const noit_check_t *bc = b;
60   int rv;
61   if((rv = strcmp(ac->target, bc->target)) != 0) return rv;
62   if((rv = strcmp(ac->name, bc->name)) != 0) return rv;
63   return 0;
64 }
65 int
66 noit_check_max_initial_stutter() {
67   int stutter;
68   if(!noit_conf_get_int(NULL, "/noit/checks/@max_initial_stutter", &stutter))
69     stutter = MAX_INITIAL_STUTTER;
70   return stutter * 1000;
71 }
72 void
73 noit_check_fake_last_check(noit_check_t *check,
74                            struct timeval *lc, struct timeval *_now) {
75   struct timeval now, period;
76   double r;
77   int offset, max;
78
79   r = drand48();
80   max = noit_check_max_initial_stutter();
81   offset = r * (MIN(max, check->period));
82   period.tv_sec = (check->period - offset) / 1000;
83   period.tv_usec = ((check->period - offset) % 1000) * 1000;
84   if(!_now) {
85     gettimeofday(&now, NULL);
86     _now = &now;
87   }
88   sub_timeval(*_now, period, lc);
89 }
90 void
91 noit_poller_process_checks(const char *xpath) {
92   int i, flags, cnt = 0;
93   noit_conf_section_t *sec;
94   __config_load_generation++;
95   sec = noit_conf_get_sections(NULL, xpath, &cnt);
96   for(i=0; i<cnt; i++) {
97     noit_check_t *existing_check;
98     char uuid_str[37];
99     char target[256];
100     char module[256];
101     char name[256];
102     char filterset[256];
103     char oncheck[1024] = "";
104     int no_period = 0;
105     int no_oncheck = 0;
106     int period = 0, timeout = 0;
107     noit_conf_boolean disabled = noit_false, busted = noit_false;
108     uuid_t uuid, out_uuid;
109     noit_hash_table *options;
110
111 #define NEXT(...) noitL(noit_stderr, __VA_ARGS__); continue
112 #define MYATTR(type,a,...) noit_conf_get_##type(sec[i], "@" #a, __VA_ARGS__)
113 #define INHERIT(type,a,...) \
114   noit_conf_get_##type(sec[i], "ancestor-or-self::node()/@" #a, __VA_ARGS__)
115
116     if(!MYATTR(stringbuf, uuid, uuid_str, sizeof(uuid_str))) {
117       noitL(noit_stderr, "check %d has no uuid\n", i+1);
118       continue;
119     }
120
121     if(uuid_parse(uuid_str, uuid)) {
122       noitL(noit_stderr, "check uuid: '%s' is invalid\n", uuid_str);
123       continue;
124     }
125
126     if(!INHERIT(stringbuf, target, target, sizeof(target))) {
127       noitL(noit_stderr, "check uuid: '%s' has no target\n", uuid_str);
128       busted = noit_true;
129     }
130     if(!INHERIT(stringbuf, module, module, sizeof(module))) {
131       noitL(noit_stderr, "check uuid: '%s' has no module\n", uuid_str);
132       busted = noit_true;
133     }
134
135     if(!INHERIT(stringbuf, filterset, filterset, sizeof(filterset)))
136       filterset[0] = '\0';
137
138     if(!MYATTR(stringbuf, name, name, sizeof(name)))
139       strlcpy(name, module, sizeof(name));
140
141     if(!INHERIT(int, period, &period) || period == 0)
142       no_period = 1;
143
144     if(!INHERIT(stringbuf, oncheck, oncheck, sizeof(oncheck)) || !oncheck[0])
145       no_oncheck = 1;
146
147     if(no_period && no_oncheck) {
148       noitL(noit_stderr, "check uuid: '%s' has neither period nor oncheck\n",
149             uuid_str);
150       busted = noit_true;
151     }
152     if(!(no_period || no_oncheck)) {
153       noitL(noit_stderr, "check uuid: '%s' has oncheck and period.\n",
154             uuid_str);
155       busted = noit_true;
156     }
157     if(!INHERIT(int, timeout, &timeout)) {
158       noitL(noit_stderr, "check uuid: '%s' has no timeout\n", uuid_str);
159       busted = noit_true;
160     }
161     if(!no_period && timeout >= period) {
162       noitL(noit_stderr, "check uuid: '%s' timeout > period\n", uuid_str);
163       timeout = period/2;
164     }
165     options = noit_conf_get_hash(sec[i], "config");
166
167     INHERIT(boolean, disable, &disabled);
168     flags = 0;
169     if(busted) flags |= NP_UNCONFIG;
170     if(disabled) flags |= NP_DISABLED;
171
172     if(noit_hash_retrieve(&polls, (char *)uuid, UUID_SIZE,
173                           (void **)&existing_check)) {
174       /* Once set, we can never change it. */
175       assert(!existing_check->module || !existing_check->module[0] ||
176              !strcmp(existing_check->module, module));
177       /* Only set it if it is not yet set */
178       if(!existing_check->module || !existing_check->module[0]) {
179         if(existing_check->module) free(existing_check->module);
180         existing_check->module = strdup(module);
181       }
182       noit_check_update(existing_check, target, name, filterset, options,
183                            period, timeout, oncheck[0] ? oncheck : NULL,
184                            flags);
185       noitL(noit_debug, "reloaded uuid: %s\n", uuid_str);
186     }
187     else {
188       noit_poller_schedule(target, module, name, filterset, options,
189                            period, timeout, oncheck[0] ? oncheck : NULL,
190                            flags, uuid, out_uuid);
191       noitL(noit_debug, "loaded uuid: %s\n", uuid_str);
192     }
193
194     noit_hash_destroy(options, free, free);
195     free(options);
196   }
197   if(sec) free(sec);
198 }
199
200 void
201 noit_poller_initiate() {
202   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
203   uuid_t key_id;
204   int klen;
205   noit_check_t *check;
206   while(noit_hash_next(&polls, &iter, (const char **)key_id, &klen,
207                        (void **)&check)) {
208     noit_module_t *mod;
209     mod = noit_module_lookup(check->module);
210     if(mod && mod->initiate_check) {
211       if(NOIT_CHECK_LIVE(check))
212         continue;
213       if((check->flags & NP_DISABLED) == 0) {
214         mod->initiate_check(mod, check, 0, NULL);
215       }
216       else
217         noitL(noit_debug, "Skipping %s`%s, disabled.\n",
218               check->target, check->name);
219     }
220     else {
221       noitL(noit_stderr, "Cannot find module '%s'\n", check->module);
222       check->flags |= NP_DISABLED;
223     }
224   }
225 }
226
227 void
228 noit_poller_flush_epoch(int oldest_allowed) {
229   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
230   uuid_t key_id;
231   int klen;
232   noit_check_t *check, *tofree = NULL;
233
234   /* Cleanup any previous causal map */
235   while(noit_hash_next(&polls, &iter, (const char **)key_id, &klen,
236                        (void **)&check)) {
237     /* We don't free the one we're looking at... we free it on the next
238      * pass.  This leaves out iterator in good shape.  We just need to
239      * remember to free it one last time outside the while loop, down...
240      */
241     if(tofree) {
242       noit_poller_deschedule(tofree->checkid);
243       tofree = NULL;
244     }
245     if(check->generation < oldest_allowed) {
246       tofree = check;
247     }
248   }
249   /* ... here */
250   if(tofree) noit_poller_deschedule(tofree->checkid);
251 }
252
253 void
254 noit_poller_make_causal_map() {
255   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
256   uuid_t key_id;
257   int klen;
258   noit_check_t *check, *parent;
259
260   /* Cleanup any previous causal map */
261   while(noit_hash_next(&polls, &iter, (const char **)key_id, &klen,
262                        (void **)&check)) {
263     dep_list_t *dep;
264     while((dep = check->causal_checks) != NULL) {
265       check->causal_checks = dep->next;
266       free(dep);
267     }
268   }
269
270   memset(&iter, 0, sizeof(iter));
271   /* Walk all checks and add check dependencies to their parents */
272   while(noit_hash_next(&polls, &iter, (const char **)key_id, &klen,
273                        (void **)&check)) {
274     if(check->oncheck) {
275       /* This service is causally triggered by another service */
276       char fullcheck[1024];
277       char *name = check->oncheck;
278       char *target = NULL;
279
280       noitL(noit_debug, "Searching for upstream trigger on %s\n", name);
281       if((target = strchr(check->oncheck, '`')) != NULL) {
282         strlcpy(fullcheck, check->oncheck, target - check->oncheck);
283         name = target + 1;
284         target = fullcheck;
285       }
286       else
287        target = check->target;
288
289       parent = noit_poller_lookup_by_name(target, name);
290       if(!parent) {
291         check->flags |= NP_DISABLED;
292         noitL(noit_stderr, "Disabling check %s`%s, can't find oncheck %s`%s\n",
293               check->target, check->name, target, name);
294       }
295       else {
296         dep_list_t *dep;
297         dep = malloc(sizeof(*dep));
298         dep->check = check;
299         dep->next = parent->causal_checks;
300         parent->causal_checks = dep;
301         noitL(noit_debug, "Causal map %s`%s --> %s`%s\n",
302               parent->target, parent->name, check->target, check->name);
303       }
304     }
305   }
306 }
307 void
308 noit_poller_reload(const char *xpath)
309 {
310   noit_poller_process_checks(xpath ? xpath : "/noit/checks//check");
311   if(!xpath) {
312     /* Full reload, we need to wipe old checks */
313     noit_poller_flush_epoch(__config_load_generation);
314   }
315   noit_poller_make_causal_map();
316   noit_poller_initiate();
317 }
318 void
319 noit_poller_init() {
320   noit_skiplist_init(&polls_by_name);
321   noit_skiplist_set_compare(&polls_by_name, __check_name_compare,
322                             __check_name_compare);
323   register_console_check_commands();
324   noit_poller_reload(NULL);
325 }
326
327 int
328 noit_check_update(noit_check_t *new_check,
329                   const char *target,
330                   const char *name,
331                   const char *filterset,
332                   noit_hash_table *config,
333                   u_int32_t period,
334                   u_int32_t timeout,
335                   const char *oncheck,
336                   int flags) {
337   int8_t family;
338   int rv;
339   int mask = NP_DISABLED | NP_UNCONFIG;
340   union {
341     struct in_addr addr4;
342     struct in6_addr addr6;
343   } a;
344
345
346   family = AF_INET;
347   rv = inet_pton(family, target, &a);
348   if(rv != 1) {
349     family = AF_INET6;
350     rv = inet_pton(family, target, &a);
351     if(rv != 1) {
352       noitL(noit_stderr, "Cannot translate '%s' to IP\n", target);
353       memset(&a, 0, sizeof(a));
354       flags |= (NP_UNCONFIG & NP_DISABLED);
355     }
356   }
357
358   new_check->generation = __config_load_generation;
359   new_check->target_family = family;
360   memcpy(&new_check->target_addr, &a, sizeof(a));
361   if(new_check->target) free(new_check->target);
362   new_check->target = strdup(target);
363   if(new_check->name) free(new_check->name);
364   new_check->name = name ? strdup(name): NULL;
365   if(new_check->filterset) free(new_check->filterset);
366   new_check->filterset = filterset ? strdup(filterset): NULL;
367
368   if(config != NULL) {
369     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
370     const char *k;
371     int klen;
372     void *data;
373     if(new_check->config) noit_hash_delete_all(new_check->config, free, free);
374     else new_check->config = calloc(1, sizeof(*new_check->config));
375     while(noit_hash_next(config, &iter, &k, &klen, &data)) {
376       noit_hash_store(new_check->config, strdup(k), klen, strdup((char *)data));
377     }
378   }
379   if(new_check->oncheck) free(new_check->oncheck);
380   new_check->oncheck = oncheck ? strdup(oncheck) : NULL;
381   new_check->period = period;
382   new_check->timeout = timeout;
383
384   /* Unset what could be set.. then set what should be set */
385   new_check->flags = (new_check->flags & ~mask) | flags;
386
387   /* This remove could fail -- no big deal */
388   noit_skiplist_remove(&polls_by_name, new_check, NULL);
389
390   /* This insert could fail.. which means we have a conflict on
391    * target`name.  That should result in the check being disabled. */
392   if(!noit_skiplist_insert(&polls_by_name, new_check)) {
393     noitL(noit_stderr, "Check %s`%s disabled due to naming conflict\n",
394           new_check->target, new_check->name);
395     new_check->flags |= NP_DISABLED;
396   }
397   noit_check_log_check(new_check);
398   return 0;
399 }
400 int
401 noit_poller_schedule(const char *target,
402                      const char *module,
403                      const char *name,
404                      const char *filterset,
405                      noit_hash_table *config,
406                      u_int32_t period,
407                      u_int32_t timeout,
408                      const char *oncheck,
409                      int flags,
410                      uuid_t in,
411                      uuid_t out) {
412   noit_check_t *new_check;
413   new_check = calloc(1, sizeof(*new_check));
414   if(!new_check) return -1;
415
416   /* The module and the UUID can never be changed */
417   new_check->module = strdup(module);
418   if(uuid_is_null(in))
419     uuid_generate(new_check->checkid);
420   else
421     uuid_copy(new_check->checkid, in);
422
423   noit_check_update(new_check, target, name, filterset, config,
424                     period, timeout, oncheck, flags);
425   assert(noit_hash_store(&polls,
426                          (char *)new_check->checkid, UUID_SIZE,
427                          new_check));
428   uuid_copy(out, new_check->checkid);
429
430   return 0;
431 }
432
433 int
434 noit_poller_deschedule(uuid_t in) {
435   noit_check_t *checker;
436   noit_module_t *mod;
437   if(noit_hash_retrieve(&polls,
438                         (char *)in, UUID_SIZE,
439                         (void **)&checker) == 0) {
440     return -1;
441   }
442   if(checker->flags & NP_RUNNING) {
443     checker->flags |= NP_KILLED;
444     return 0;
445   }
446   checker->flags |= NP_KILLED;
447
448   noit_skiplist_remove(&polls_by_name, checker, NULL);
449   noit_hash_delete(&polls, (char *)in, UUID_SIZE, NULL, NULL);
450
451   mod = noit_module_lookup(checker->module);
452   if(mod->cleanup) mod->cleanup(mod, checker);
453   if(checker->fire_event) {
454      eventer_remove(checker->fire_event);
455      free(checker->fire_event->closure);
456      eventer_free(checker->fire_event);
457      checker->fire_event = NULL;
458   }
459   if(checker->closure) free(checker->closure);
460   if(checker->target) free(checker->target);
461   if(checker->module) free(checker->module);
462   if(checker->name) free(checker->name);
463   if(checker->config) {
464     noit_hash_destroy(checker->config, free, free);
465     free(checker->config);
466     checker->config = NULL;
467   }
468   free(checker);
469   return 0;
470 }
471
472 noit_check_t *
473 noit_poller_lookup(uuid_t in) {
474   noit_check_t *check;
475   if(noit_hash_retrieve(&polls,
476                         (char *)in, UUID_SIZE,
477                         (void **)&check)) {
478     return check;
479   }
480   return NULL;
481 }
482 noit_check_t *
483 noit_poller_lookup_by_name(char *target, char *name) {
484   noit_check_t *check, *tmp_check;
485   tmp_check = calloc(1, sizeof(*tmp_check));
486   tmp_check->target = target;
487   tmp_check->name = name;
488   check = noit_skiplist_find(&polls_by_name, tmp_check, NULL);
489   free(tmp_check);
490   return check;
491 }
492
493 void
494 noit_check_stats_clear(stats_t *s) {
495   memset(s, 0, sizeof(*s));
496   s->state = NP_UNKNOWN;
497   s->available = NP_UNKNOWN;
498 }
499 static void
500 __free_metric(void *vm) {
501   metric_t *m = vm;
502   free(m->metric_name);
503   if(m->metric_value.i) free(m->metric_value.i);
504   free(m);
505 }
506
507 void
508 __stats_add_metric(stats_t *newstate, metric_t *m) {
509   noit_hash_replace(&newstate->metrics, m->metric_name, strlen(m->metric_name),
510                     m, NULL, __free_metric);
511 }
512
513 static size_t
514 noit_metric_sizes(metric_type_t type, void *value) {
515   switch(type) {
516     case METRIC_INT32:
517     case METRIC_UINT32:
518       return sizeof(int32_t);
519     case METRIC_INT64:
520     case METRIC_UINT64:
521       return sizeof(int64_t);
522     case METRIC_DOUBLE:
523       return sizeof(double);
524     case METRIC_STRING:
525       return strlen((char *)value) + 1;
526     case METRIC_GUESS:
527       break;
528   }
529   assert(type != type);
530   return 0;
531 }
532 static metric_type_t
533 noit_metric_guess_type(const char *s, void **replacement) {
534   char *copy, *cp, *trailer, *rpl;
535   int negative = 0, bigF = 0;
536   metric_type_t type = METRIC_STRING;
537
538   if(!s) return METRIC_GUESS;
539   copy = cp = strdup(s);
540
541   /* TRIM the string */
542   while(*cp && isspace(*cp)) cp++; /* ltrim */
543   s = cp; /* found a good starting point */
544   while(*cp) cp++; /* advance to \0 */
545   cp--; /* back up one */
546   while(cp > s && isspace(*cp)) *cp-- = '\0'; /* rtrim */
547
548   /* Find the first space */
549   cp = (char *)s;
550   while(*cp && !isspace(*cp)) cp++;
551   trailer = cp;
552   cp--; /* backup one */
553   if(cp > s && *cp == '%') *cp-- = '\0'; /* chop a last % is there is one */
554
555   while(*trailer && isspace(*trailer)) *trailer++ = '\0'; /* rtrim */
556
557   /* string was       '  -1.23e-01%  inodes used  ' */
558   /* copy is (~ = \0) '  -1.23e-01~  inodes used~~' */
559   /*                     ^           ^              */
560   /*                     s           trailer        */
561
562   /* So, the trailer must not contain numbers */
563   while(*trailer) { if(isdigit(*trailer)) goto notanumber; trailer++; }
564
565   /* And the 's' must be of the form:
566    *  0) may start with a sign [-+]?
567    *  1) [1-9][0-9]*
568    *  2) [0]?.[0-9]+
569    *  3) 0
570    *  4) [1-9][0-9]*.[0-9]+
571    *  5) all of the above ending with e[+-][0-9]+
572    */
573    rpl = (char *)s;
574    /* CASE 0 */
575    if(s[0] == '-' || s[0] == '+') {
576      if(s[0] == '-') negative = 1;
577      s++;
578    }
579
580    if(s[0] == '.') goto decimal; /* CASE 2 */
581    if(s[0] == '0') { /* CASE 2 & 3 */
582      s++;
583      if(!s[0]) goto scanint; /* CASE 3 */
584      if(s[0] == '.') goto decimal; /* CASE 2 */
585      goto notanumber;
586    }
587    if(s[0] >= '1' && s[0] <= '9') { /* CASE 1 & 4 */
588      s++;
589      while(isdigit(s[0])) s++; /* CASE 1 & 4 */
590      if(!s[0]) goto scanint; /* CASE 1 */
591      if(s[0] == '.') goto decimal; /* CASE 4 */
592      goto notanumber;
593    }
594    /* Not case 1,2,3,4 */
595    goto notanumber;
596
597   decimal:
598    s++;
599    if(!isdigit(s[0])) goto notanumber;
600    s++;
601    while(isdigit(s[0])) s++;
602    if(!s[0]) goto scandouble;
603    if(s[0] == 'e' || s[0] == 'E') goto exponent; /* CASE 5 */
604    goto notanumber;
605
606   exponent:
607    if(s[0] == 'E') bigF = 1; /* We want the caps variant */
608    s++;
609    if(s[0] != '-' && s[0] != '+') goto notanumber;
610    s++;
611    if(!isdigit(s[0])) goto notanumber;
612    s++;
613    while(isdigit(s[0])) s++;
614    if(!s[0]) goto scandouble;
615    goto notanumber;
616
617  scanint:
618    if(negative) {
619      int64_t *v;
620      v = calloc(1, sizeof(*v));
621      *v = strtoll(rpl, NULL, 10);
622      *replacement = v;
623      type = METRIC_INT64;
624      goto alldone;
625    }
626    else {
627      u_int64_t *v;
628      v = calloc(1, sizeof(*v));
629      *v = strtoull(rpl, NULL, 10);
630      *replacement = v;
631      type = METRIC_UINT64;
632      goto alldone;
633    }
634  scandouble:
635    {
636      double *v;
637      v = calloc(1, sizeof(*v));
638      *v = strtod(rpl, NULL);
639      *replacement = v;
640      type = METRIC_DOUBLE;
641      goto alldone;
642    }
643
644  alldone:
645  notanumber:
646   free(copy);
647   return type;
648 }
649 void
650 noit_stats_set_metric(stats_t *newstate, const char *name, metric_type_t type,
651                       void *value) {
652   metric_t *m;
653   void *replacement = NULL;
654   if(type == METRIC_GUESS)
655     type = noit_metric_guess_type((char *)value, &replacement);
656   if(type == METRIC_GUESS) return;
657
658   m = calloc(1, sizeof(*m));
659   m->metric_name = strdup(name);
660   m->metric_type = type;
661   if(replacement)
662     m->metric_value.vp = replacement;
663   else if(value) {
664     size_t len;
665     len = noit_metric_sizes(type, value);
666     m->metric_value.vp = calloc(1, len);
667     memcpy(m->metric_value.vp, value, len);
668   }
669   __stats_add_metric(newstate, m);
670 }
671
672 void
673 noit_check_set_stats(struct _noit_module *module,
674                      noit_check_t *check, stats_t *newstate) {
675   int report_change = 0;
676   dep_list_t *dep;
677   if(check->stats.previous.status)
678     free(check->stats.previous.status);
679   noit_hash_destroy(&check->stats.previous.metrics, NULL, __free_metric);
680   memcpy(&check->stats.previous, &check->stats.current, sizeof(stats_t));
681   memcpy(&check->stats.current, newstate, sizeof(stats_t));
682   if(check->stats.current.status)
683     check->stats.current.status = strdup(check->stats.current.status);
684
685   /* check for state changes */
686   if(check->stats.current.available != NP_UNKNOWN &&
687      check->stats.previous.available != NP_UNKNOWN &&
688      check->stats.current.available != check->stats.previous.available)
689     report_change = 1;
690   if(check->stats.current.state != NP_UNKNOWN &&
691      check->stats.previous.state != NP_UNKNOWN &&
692      check->stats.current.state != check->stats.previous.state)
693     report_change = 1;
694
695   noitL(noit_error, "%s`%s <- [%s]\n", check->target, check->name,
696         check->stats.current.status);
697   if(report_change) {
698     noitL(noit_error, "%s`%s -> [%s:%s]\n",
699           check->target, check->name,
700           noit_check_available_string(check->stats.current.available),
701           noit_check_state_string(check->stats.current.state));
702   }
703
704   /* Write out our status */
705   noit_check_log_status(check);
706   /* Write out all metrics */
707   noit_check_log_metrics(check);
708
709   for(dep = check->causal_checks; dep; dep = dep->next) {
710     noit_module_t *mod;
711     mod = noit_module_lookup(dep->check->module);
712     assert(mod);
713     noitL(noit_debug, "Firing %s`%s in response to %s`%s\n",
714           dep->check->target, dep->check->name,
715           check->target, check->name);
716     if((dep->check->flags & NP_DISABLED) == 0)
717       if(mod->initiate_check)
718         mod->initiate_check(mod, dep->check, 1, check);
719   }
720 }
721
722 static void
723 nc_printf_check_brief(noit_console_closure_t ncct,
724                       noit_check_t *check) {
725   char out[512];
726   char uuid_str[37];
727   snprintf(out, sizeof(out), "%s`%s", check->target, check->name);
728   uuid_unparse_lower(check->checkid, uuid_str);
729   nc_printf(ncct, "%s %s\n", uuid_str, out);
730   if(check->stats.current.status)
731     nc_printf(ncct, "\t%s\n", check->stats.current.status);
732 }
733
734 static int
735 noit_console_show_checks(noit_console_closure_t ncct,
736                          int argc, char **argv,
737                          noit_console_state_t *dstate,
738                          void *closure) {
739   struct timeval _now;
740   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
741   uuid_t key_id;
742   int klen;
743   noit_check_t *check;
744
745   gettimeofday(&_now, NULL);
746   while(noit_hash_next(&polls, &iter, (const char **)key_id, &klen,
747                        (void **)&check)) {
748     nc_printf_check_brief(ncct, check);
749   }
750   return 0;
751 }
752
753 static void
754 register_console_check_commands() {
755   noit_console_state_t *tl;
756   cmd_info_t *showcmd;
757
758   tl = noit_console_state_initial();
759   showcmd = noit_console_state_get_cmd(tl, "show");
760   assert(showcmd && showcmd->dstate);
761
762   noit_console_state_add_cmd(showcmd->dstate,
763     NCSCMD("checks", noit_console_show_checks, NULL, NULL));
764 }
765
Note: See TracBrowser for help on using the browser.