root/src/noit_check.c

Revision 8a8881805e928890782ec2bddac168e025513149, 21.3 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 11 years ago)

make modules that don't implement parts of the API not crash the system

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