root/src/noit_check.c

Revision f1a1f3626f188720b8d36a420db03c7d0db435bc, 21.4 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

mae stutter configurable (sure helps with rapid testing)

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