root/src/noit_check_log.c

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

simplify this and fix a bug in UUID construction on new bundles

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34
35 #include <uuid/uuid.h>
36 #include <netinet/in.h>
37
38 #include "noit_check.h"
39 #include "noit_filters.h"
40 #include "utils/noit_log.h"
41 #include "jlog/jlog.h"
42
43 #include "bundle.pb-c.h"
44 #include "noit_check_log_helpers.h"
45
46 /* Log format is tab delimited:
47  * NOIT CONFIG (implemented in noit_conf.c):
48  *  'n' TIMESTAMP strlen(xmlconfig) base64(gzip(xmlconfig))
49  *
50  * DELETE:
51  *  'D' TIMESTAMP UUID
52  *
53  * CHECK:
54  *  'C' TIMESTAMP UUID TARGET MODULE NAME
55  *
56  * STATUS:
57  *  'S' TIMESTAMP UUID STATE AVAILABILITY DURATION STATUS_MESSAGE
58  *
59  * METRICS:
60  *  'M' TIMESTAMP UUID NAME TYPE VALUE
61  *
62  * BUNDLE
63  *  'B#' TIMESTAMP UUID TARGET MODULE NAME strlen(base64(gzipped(payload))) base64(gzipped(payload))
64  * 
65  */
66
67 static noit_log_stream_t check_log = NULL;
68 static noit_log_stream_t status_log = NULL;
69 static noit_log_stream_t metrics_log = NULL;
70 static noit_log_stream_t delete_log = NULL;
71 static noit_log_stream_t bundle_log = NULL;
72 static bool use_compression = true;
73
74 #define SECPART(a) ((unsigned long)(a)->tv_sec)
75 #define MSECPART(a) ((unsigned long)((a)->tv_usec / 1000))
76 #define MAKE_CHECK_UUID_STR(uuid_str, len, ls, check) do { \
77   noit_boolean extended_id = noit_false; \
78   const char *v; \
79   v = noit_log_stream_get_property(ls, "extended_id"); \
80   if(v && !strcmp(v, "on")) extended_id = noit_true; \
81   uuid_str[0] = '\0'; \
82   if(extended_id) { \
83     strlcat(uuid_str, check->target, len-37); \
84     strlcat(uuid_str, "`", len-37); \
85     strlcat(uuid_str, check->module, len-37); \
86     strlcat(uuid_str, "`", len-37); \
87     strlcat(uuid_str, check->name, len-37); \
88     strlcat(uuid_str, "`", len-37); \
89   } \
90   uuid_unparse_lower(check->checkid, uuid_str + strlen(uuid_str)); \
91 } while(0)
92
93 static void
94 handle_extra_feeds(noit_check_t *check,
95                    int (*log_f)(noit_log_stream_t ls, noit_check_t *check)) {
96   noit_log_stream_t ls;
97   noit_skiplist_node *curr, *next;
98   const char *feed_name;
99
100   if(!check->feeds) return;
101   curr = next = noit_skiplist_getlist(check->feeds);
102   while(curr) {
103     /* We advance next here (before we try to use curr).
104      * We may need to remove the node we're looking at and that would
105      * disturb the iterator, so advance in advance. */
106     noit_skiplist_next(check->feeds, &next);
107     feed_name = (char *)curr->data;
108     ls = noit_log_stream_find(feed_name);
109     if(!ls || log_f(ls, check)) {
110       noit_check_transient_remove_feed(check, feed_name);
111       /* noit_skiplisti_remove(check->feeds, curr, free); */
112     }
113     curr = next;
114   }
115   /* We're done... we may have destroyed the last feed.
116    * that combined with transience means we should kill the check */
117   /* noit_check_transient_remove_feed(check, NULL); */
118 }
119
120 static int
121 _noit_check_log_delete(noit_log_stream_t ls,
122                        noit_check_t *check) {
123   stats_t *c;
124   char uuid_str[256*3+37];
125   SETUP_LOG(delete, );
126   MAKE_CHECK_UUID_STR(uuid_str, sizeof(uuid_str), status_log, check);
127
128   c = &check->stats.current;
129   return noit_log(ls, &c->whence, __FILE__, __LINE__,
130                   "D\t%lu.%03lu\t%s\n",
131                   SECPART(&c->whence), MSECPART(&c->whence), uuid_str);
132 }
133 void
134 noit_check_log_delete(noit_check_t *check) {
135   if(!(check->flags & NP_TRANSIENT)) {
136     handle_extra_feeds(check, _noit_check_log_delete);
137     SETUP_LOG(delete, return);
138     _noit_check_log_delete(delete_log, check);
139   }
140 }
141
142 static int
143 _noit_check_log_check(noit_log_stream_t ls,
144                       noit_check_t *check) {
145   struct timeval __now;
146   char uuid_str[256*3+37];
147   SETUP_LOG(check, );
148   MAKE_CHECK_UUID_STR(uuid_str, sizeof(uuid_str), check_log, check);
149
150   gettimeofday(&__now, NULL);
151   return noit_log(ls, &__now, __FILE__, __LINE__,
152                   "C\t%lu.%03lu\t%s\t%s\t%s\t%s\n",
153                   SECPART(&__now), MSECPART(&__now),
154                   uuid_str, check->target, check->module, check->name);
155 }
156
157 void
158 noit_check_log_check(noit_check_t *check) {
159   if(!(check->flags & NP_TRANSIENT)) {
160     handle_extra_feeds(check, _noit_check_log_check);
161     SETUP_LOG(check, return);
162     _noit_check_log_check(check_log, check);
163   }
164 }
165
166 static int
167 _noit_check_log_status(noit_log_stream_t ls,
168                        noit_check_t *check) {
169   stats_t *c;
170   char uuid_str[256*3+37];
171   SETUP_LOG(status, );
172   MAKE_CHECK_UUID_STR(uuid_str, sizeof(uuid_str), status_log, check);
173
174   c = &check->stats.current;
175   return noit_log(ls, &c->whence, __FILE__, __LINE__,
176                   "S\t%lu.%03lu\t%s\t%c\t%c\t%d\t%s\n",
177                   SECPART(&c->whence), MSECPART(&c->whence), uuid_str,
178                   (char)c->state, (char)c->available, c->duration, c->status);
179 }
180 void
181 noit_check_log_status(noit_check_t *check) {
182   handle_extra_feeds(check, _noit_check_log_status);
183   if(!(check->flags & (NP_TRANSIENT | NP_SUPPRESS_STATUS))) {
184     SETUP_LOG(status, return);
185     _noit_check_log_status(status_log, check);
186   }
187 }
188 static int
189 _noit_check_log_metric(noit_log_stream_t ls, noit_check_t *check,
190                        const char *uuid_str,
191                        struct timeval *whence, metric_t *m) {
192   char our_uuid_str[256*3+37];
193   int srv = 0;
194   if(!noit_apply_filterset(check->filterset, check, m)) return 0;
195   if(!ls->enabled) return 0;
196
197   if(!uuid_str) {
198     MAKE_CHECK_UUID_STR(our_uuid_str, sizeof(our_uuid_str), metrics_log, check);
199     uuid_str = our_uuid_str;
200   }
201
202   if(!m->metric_value.s) { /* they are all null */
203     srv = noit_log(ls, whence, __FILE__, __LINE__,
204                    "M\t%lu.%03lu\t%s\t%s\t%c\t[[null]]\n",
205                    SECPART(whence), MSECPART(whence), uuid_str,
206                    m->metric_name, m->metric_type);
207   }
208   else {
209     switch(m->metric_type) {
210       case METRIC_INT32:
211         srv = noit_log(ls, whence, __FILE__, __LINE__,
212                        "M\t%lu.%03lu\t%s\t%s\t%c\t%d\n",
213                        SECPART(whence), MSECPART(whence), uuid_str,
214                        m->metric_name, m->metric_type, *(m->metric_value.i));
215         break;
216       case METRIC_UINT32:
217         srv = noit_log(ls, whence, __FILE__, __LINE__,
218                        "M\t%lu.%03lu\t%s\t%s\t%c\t%u\n",
219                        SECPART(whence), MSECPART(whence), uuid_str,
220                        m->metric_name, m->metric_type, *(m->metric_value.I));
221         break;
222       case METRIC_INT64:
223         srv = noit_log(ls, whence, __FILE__, __LINE__,
224                        "M\t%lu.%03lu\t%s\t%s\t%c\t%lld\n",
225                        SECPART(whence), MSECPART(whence), uuid_str,
226                        m->metric_name, m->metric_type,
227                        (long long int)*(m->metric_value.l));
228         break;
229       case METRIC_UINT64:
230         srv = noit_log(ls, whence, __FILE__, __LINE__,
231                        "M\t%lu.%03lu\t%s\t%s\t%c\t%llu\n",
232                        SECPART(whence), MSECPART(whence), uuid_str,
233                        m->metric_name, m->metric_type,
234                        (long long unsigned int)*(m->metric_value.L));
235         break;
236       case METRIC_DOUBLE:
237         srv = noit_log(ls, whence, __FILE__, __LINE__,
238                        "M\t%lu.%03lu\t%s\t%s\t%c\t%.12e\n",
239                        SECPART(whence), MSECPART(whence), uuid_str,
240                        m->metric_name, m->metric_type, *(m->metric_value.n));
241         break;
242       case METRIC_STRING:
243         srv = noit_log(ls, whence, __FILE__, __LINE__,
244                        "M\t%lu.%03lu\t%s\t%s\t%c\t%s\n",
245                        SECPART(whence), MSECPART(whence), uuid_str,
246                        m->metric_name, m->metric_type, m->metric_value.s);
247         break;
248       default:
249         noitL(noit_error, "Unknown metric type '%c' 0x%x\n",
250               m->metric_type, m->metric_type);
251     }
252   }
253   return srv;
254 }
255 static int
256 _noit_check_log_metrics(noit_log_stream_t ls, noit_check_t *check) {
257   int rv = 0;
258   int srv;
259   char uuid_str[256*3+37];
260   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
261   const char *key;
262   int klen;
263   stats_t *c;
264   void *vm;
265   SETUP_LOG(metrics, );
266   MAKE_CHECK_UUID_STR(uuid_str, sizeof(uuid_str), metrics_log, check);
267
268   c = &check->stats.current;
269   while(noit_hash_next(&c->metrics, &iter, &key, &klen, &vm)) {
270     /* If we apply the filter set and it returns false, we don't log */
271     metric_t *m = (metric_t *)vm;
272     srv = _noit_check_log_metric(ls, check, uuid_str, &c->whence, m);
273     if(srv) rv = srv;
274   }
275   return rv;
276 }
277 void
278 noit_check_log_metrics(noit_check_t *check) {
279   handle_extra_feeds(check, _noit_check_log_metrics);
280   if(!(check->flags & (NP_TRANSIENT | NP_SUPPRESS_METRICS))) {
281     SETUP_LOG(metrics, return);
282     _noit_check_log_metrics(metrics_log, check);
283   }
284 }
285
286
287 static int
288 _noit_check_log_bundle_metric(noit_log_stream_t ls, Metric *metric, metric_t *m) {
289   metric->metrictype = (int)m->metric_type;
290
291   metric->name = m->metric_name;
292   switch (m->metric_type) {
293     case METRIC_INT32:
294       metric->has_valuei32 = true;
295       metric->valuei32 = *(m->metric_value.i); break;
296     case METRIC_UINT32:
297       metric->has_valueui32 = true;
298       metric->valueui32 = *(m->metric_value.I); break;
299     case METRIC_INT64:
300       metric->has_valuei64 = true;
301       metric->valuei64 = *(m->metric_value.l); break;
302     case METRIC_UINT64:
303       metric->has_valueui64 = true;
304       metric->valueui64 = *(m->metric_value.L); break;
305     case METRIC_DOUBLE:
306       metric->has_valuedbl = true;
307       metric->valuedbl = *(m->metric_value.n); break;
308     case METRIC_STRING:
309       metric->valuestr = m->metric_value.s; break;
310     default:
311       return -1;
312   }
313   return 0;
314 }
315
316 static int
317 noit_check_log_bundle_serialize(noit_log_stream_t ls, noit_check_t *check) {
318   int rv = 0;
319   char uuid_str[256*3+37];
320   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
321   noit_hash_iter iter2 = NOIT_HASH_ITER_ZERO;
322   const char *key;
323   int klen, i=0, size, j;
324   unsigned int out_size;
325   stats_t *c;
326   void *vm;
327   char *buf, *out_buf;
328   noit_compression_type_t comp;
329   Bundle bundle = BUNDLE__INIT;
330   SETUP_LOG(bundle, );
331   MAKE_CHECK_UUID_STR(uuid_str, sizeof(uuid_str), bundle_log, check);
332
333   // Get a bundle
334   c = &check->stats.current;
335
336   // Set attributes
337   bundle.available = c->available;
338   bundle.state = c->state;
339   bundle.duration = c->duration;
340   bundle.status = c->status;
341
342
343   // Just count
344   while(noit_hash_next(&c->metrics, &iter, &key, &klen, &vm)) {
345     bundle.n_metrics++;
346   }
347
348   bundle.metrics = malloc(bundle.n_metrics * sizeof(Metric*));
349
350   // Now convert
351   while(noit_hash_next(&c->metrics, &iter2, &key, &klen, &vm)) {
352     /* If we apply the filter set and it returns false, we don't log */
353     metric_t *m = (metric_t *)vm;
354     bundle.metrics[i] = malloc(sizeof(Metric));
355     metric__init(bundle.metrics[i]);
356     _noit_check_log_bundle_metric(ls, bundle.metrics[i], m);
357     i++;
358   }
359
360   size = bundle__get_packed_size(&bundle);
361   buf = malloc(size);
362   bundle__pack(&bundle, (uint8_t*)buf);
363
364   // Compress + B64
365   comp = use_compression ? NOIT_COMPRESS_ZLIB : NOIT_COMPRESS_NONE;
366   noit_check_log_bundle_compress_b64(comp, buf, size, &out_buf, &out_size);
367   noit_log(ls, &(c->whence), __FILE__, __LINE__,
368            "B%c\t%lu.%03lu\t%s\t%s\t%s\t%s\t%d\t%.*s\n",
369            use_compression ? '1' : '2',
370            SECPART(&(c->whence)), MSECPART(&(c->whence)),
371            uuid_str, check->target, check->module, check->name, size,
372            (unsigned int)out_size, out_buf);
373
374   free(buf);
375   free(out_buf);
376   // Free all the resources
377   for (j=0; j<i; j++) {
378     free(bundle.metrics[j]);
379   }
380   free(bundle.metrics);
381   return rv;
382 }
383
384 void
385 noit_check_log_bundle(noit_check_t *check) {
386   handle_extra_feeds(check, noit_check_log_bundle_serialize);
387   if(!(check->flags & (NP_TRANSIENT | NP_SUPPRESS_STATUS | NP_SUPPRESS_METRICS))) {
388     SETUP_LOG(bundle, return);
389     noit_check_log_bundle_serialize(bundle_log, check);
390   }
391 }
392
393 void
394 noit_check_log_metric(noit_check_t *check, struct timeval *whence,
395                       metric_t *m) {
396   char uuid_str[256*3+37];
397   MAKE_CHECK_UUID_STR(uuid_str, sizeof(uuid_str), metrics_log, check);
398
399   /* handle feeds -- hust like handle_extra_feeds, but this
400    * is with different arguments.
401    */
402   if(check->feeds) {
403     noit_skiplist_node *curr, *next;
404     curr = next = noit_skiplist_getlist(check->feeds);
405     while(curr) {
406       const char *feed_name = (char *)curr->data;
407       noit_log_stream_t ls = noit_log_stream_find(feed_name);
408       noit_skiplist_next(check->feeds, &next);
409       if(!ls || _noit_check_log_metric(ls, check, uuid_str, whence, m))
410         noit_check_transient_remove_feed(check, feed_name);
411       curr = next;
412     }
413   }
414   if(!(check->flags & NP_TRANSIENT)) {
415     SETUP_LOG(metrics, return);
416     _noit_check_log_metric(metrics_log, check, uuid_str, whence, m);
417   }
418 }
419
420 int
421 noit_stats_snprint_metric(char *b, int l, metric_t *m) {
422   int rv, nl;
423   nl = snprintf(b, l, "%s[%c] = ", m->metric_name, m->metric_type);
424   if(nl >= l || nl <= 0) return nl;
425   rv = noit_stats_snprint_metric_value(b+nl, l-nl, m);
426   if(rv == -1)
427     rv = snprintf(b+nl, l-nl, "[[unknown type]]");
428   return rv + nl;
429 }
430
Note: See TracBrowser for help on using the browser.