root/src/noit_check.c

Revision 057e0c6fdd21f0c4e9158d3ae149de09dd80dfd9, 25.2 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

change noit_conf_boolean to noit_conf... more sense. refs #34

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