root/src/noit_check.c

Revision 4b96846179a35015ac0b22d5fe9e9f92480f06a5, 21.5 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 10 years ago)

check code consolidation. allow modules to be more terse and add convenience functions to make writing completely asynch checkers much easier. (add a postgres proof-of-concept asynch checker

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