root/src/modules/httptrap.c

Revision 50ab0bcf2f9d8948a11dfa59b49c927b3d4e1cac, 23.1 kB (checked in by Ihimu Ukpo <ihimu.ukpo@circonus.com>, 1 week ago)

Added support for metric key/value pair output to HTTP trap check status.

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2011, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  * Copyright (c) 2011-2015, Circonus, Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  *       copyright notice, this list of conditions and the following
14  *       disclaimer in the documentation and/or other materials provided
15  *       with the distribution.
16  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
17  *       of its contributors may be used to endorse or promote products
18  *       derived from this software without specific prior written
19  *       permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
32
33 #include <mtev_defines.h>
34
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include <assert.h>
39 #include <math.h>
40 #include <ctype.h>
41 #include <yajl/yajl_parse.h>
42
43 #include <mtev_rest.h>
44 #include <mtev_hash.h>
45
46 #include "noit_module.h"
47 #include "noit_check.h"
48 #include "noit_check_tools.h"
49 #include "noit_mtev_bridge.h"
50
51 #define DEFAULT_HTTPTRAP_DELIMITER '`'
52 #define MAX_DEPTH 32
53
54 static mtev_log_stream_t nlerr = NULL;
55 static mtev_log_stream_t nldeb = NULL;
56
57 typedef struct _mod_config {
58   mtev_hash_table *options;
59   mtev_boolean asynch_metrics;
60 } httptrap_mod_config_t;
61
62 typedef struct httptrap_closure_s {
63   noit_module_t *self;
64   int stats_count;
65 } httptrap_closure_t;
66
67 struct value_list {
68   char *v;
69   struct value_list *next;
70 };
71 struct rest_json_payload {
72   noit_check_t *check;
73   yajl_handle parser;
74   int len;
75   int complete;
76   char delimiter;
77   char *error;
78   int depth;
79   char *keys[MAX_DEPTH];
80   int array_depth[MAX_DEPTH];
81   unsigned char last_special_key;
82   unsigned char saw_complex_type;
83  
84   metric_type_t last_type;
85   struct value_list *last_value;
86   int cnt;
87   mtev_boolean immediate;
88 };
89
90 #define NEW_LV(json,a) do { \
91   struct value_list *nlv = malloc(sizeof(*nlv)); \
92   nlv->v = a; \
93   nlv->next = json->last_value; \
94   json->last_value = nlv; \
95 } while(0)
96
97 static mtev_boolean
98 mtev_httptrap_check_aynsch(noit_module_t *self,
99                            noit_check_t *check) {
100   const char *config_val;
101   httptrap_mod_config_t *conf;
102   if(!self) return mtev_true;
103   conf = noit_module_get_userdata(self);
104   if(!conf) return mtev_true;
105   mtev_boolean is_asynch = conf->asynch_metrics;
106   if(mtev_hash_retr_str(check->config,
107                         "asynch_metrics", strlen("asynch_metrics"),
108                         (const char **)&config_val)) {
109     if(!strcasecmp(config_val, "false") || !strcasecmp(config_val, "off"))
110       is_asynch = mtev_false;
111     else if(!strcasecmp(config_val, "true") || !strcasecmp(config_val, "on"))
112       is_asynch = mtev_true;
113   }
114
115   if(is_asynch) check->flags |= NP_SUPPRESS_METRICS;
116   else check->flags &= ~NP_SUPPRESS_METRICS;
117   return is_asynch;
118 }
119
120 static int
121 set_array_key(struct rest_json_payload *json) {
122   if(json->array_depth[json->depth] > 0) {
123     char str[256];
124     int strLen;
125     snprintf(str, sizeof(str), "%d", json->array_depth[json->depth] - 1);
126     json->array_depth[json->depth]++;
127     strLen = strlen(str);
128     if(json->keys[json->depth]) free(json->keys[json->depth]);
129     json->keys[json->depth] = NULL;
130     if(json->depth == 0) {
131       json->keys[json->depth] = malloc(strLen+1);
132       memcpy(json->keys[json->depth], str, strLen);
133       json->keys[json->depth][strLen] = '\0';
134     }
135     else {
136       int uplen = strlen(json->keys[json->depth-1]);
137       /* This is too large.... return an error */
138       if(uplen + 1 + strLen > 255) {
139         return -1;
140       }
141       json->keys[json->depth] = malloc(uplen + 1 + strLen + 1);
142       memcpy(json->keys[json->depth], json->keys[json->depth-1], uplen);
143       json->keys[json->depth][uplen] = json->delimiter;
144       memcpy(json->keys[json->depth] + uplen + 1, str, strLen);
145       json->keys[json->depth][uplen + 1 + strLen] = '\0';
146     }
147   }
148   return 0;
149 }
150 static int
151 httptrap_yajl_cb_null(void *ctx) {
152   struct rest_json_payload *json = ctx;
153   int rv;
154   if(json->depth<0) return 0;
155   rv = set_array_key(json);
156   if(json->last_special_key == 0x2) {
157     NEW_LV(json, NULL);
158     return 1;
159   }
160   if(json->last_special_key) return 0;
161   if(rv) return 1;
162   if(json->keys[json->depth]) {
163     noit_stats_set_metric(json->check,
164         json->keys[json->depth], METRIC_INT32, NULL);
165     if(json->immediate)
166       noit_stats_log_immediate_metric(json->check,
167           json->keys[json->depth], METRIC_INT32, NULL);
168     json->cnt++;
169   }
170   return 1;
171 }
172 static int
173 httptrap_yajl_cb_boolean(void *ctx, int boolVal) {
174   int ival, rv;
175   struct rest_json_payload *json = ctx;
176   mtevL(mtev_error, "BOOL\n");
177   if(json->depth<0) return 0;
178   rv = set_array_key(json);
179   if(json->last_special_key == 0x2) {
180     NEW_LV(json, strdup(boolVal ? "1" : "0"));
181     return 1;
182   }
183   if(json->last_special_key) return 0;
184   if(rv) return 1;
185   if(json->keys[json->depth]) {
186     ival = boolVal ? 1 : 0;
187     noit_stats_set_metric(json->check,
188         json->keys[json->depth], METRIC_INT32, &ival);
189     if(json->immediate)
190       noit_stats_log_immediate_metric(json->check,
191           json->keys[json->depth], METRIC_INT32, &ival);
192     json->cnt++;
193   }
194   return 1;
195 }
196 static int
197 httptrap_yajl_cb_number(void *ctx, const char * numberVal,
198                         size_t numberLen) {
199   char val[128];
200   struct rest_json_payload *json = ctx;
201   int rv;
202   if(json->depth<0) return 0;
203   rv = set_array_key(json);
204   if(json->last_special_key == 0x2) {
205     char *str;
206     str = malloc(numberLen+1);
207     memcpy(str, numberVal, numberLen);
208     str[numberLen] = '\0';
209     NEW_LV(json, str);
210     return 1;
211   }
212   if(rv) return 1;
213   if(json->last_special_key) return 0;
214   if(json->keys[json->depth]) {
215     if(numberLen > sizeof(val)-1) numberLen = sizeof(val)-1;
216     memcpy(val, numberVal, numberLen);
217     val[numberLen] = '\0';
218     noit_stats_set_metric(json->check,
219         json->keys[json->depth], METRIC_GUESS, val);
220     if(json->immediate)
221       noit_stats_log_immediate_metric(json->check,
222           json->keys[json->depth], METRIC_GUESS, val);
223     json->cnt++;
224   }
225   return 1;
226 }
227 static int
228 httptrap_yajl_cb_string(void *ctx, const unsigned char * stringVal,
229                         size_t stringLen) {
230   struct rest_json_payload *json = ctx;
231   char val[4096];
232   int rv;
233   if(json->depth<0) return 0;
234   rv = set_array_key(json);
235   if(json->last_special_key == 0x1) {
236     if(stringLen != 1) return 0;
237     if(*stringVal == 'L' || *stringVal == 'l' ||
238         *stringVal == 'I' || *stringVal == 'i' ||
239         *stringVal == 'n' || *stringVal == 's') {
240       json->last_type = *stringVal;
241       json->saw_complex_type |= 0x1;
242       return 1;
243     }
244     return 0;
245   }
246   else if(json->last_special_key == 0x2) {
247     char *str;
248     str = malloc(stringLen+1);
249     memcpy(str, stringVal, stringLen);
250     str[stringLen] = '\0';
251     NEW_LV(json, str);
252     json->saw_complex_type |= 0x2;
253     return 1;
254   }
255   if(rv) return 1;
256   if(json->keys[json->depth]) {
257     if(stringLen > sizeof(val)-1) stringLen = sizeof(val)-1;
258     memcpy(val, stringVal, stringLen);
259     val[stringLen] = '\0';
260     noit_stats_set_metric(json->check,
261         json->keys[json->depth], METRIC_GUESS, val);
262     if(json->immediate)
263       noit_stats_log_immediate_metric(json->check,
264           json->keys[json->depth], METRIC_GUESS, val);
265     json->cnt++;
266   }
267   return 1;
268 }
269 static int
270 httptrap_yajl_cb_start_map(void *ctx) {
271   struct rest_json_payload *json = ctx;
272   if(set_array_key(json)) return 1;
273   json->depth++;
274   if(json->depth >= MAX_DEPTH) return 0;
275   return 1;
276 }
277 static int
278 httptrap_yajl_cb_end_map(void *ctx) {
279   struct value_list *p, *last_p = NULL;
280   struct rest_json_payload *json = ctx;
281   json->depth--;
282   if(json->saw_complex_type == 0x3) {
283     long double total = 0, cnt = 0;
284     mtev_boolean use_avg = mtev_false;
285     for(p=json->last_value;p;p=p->next) {
286       noit_stats_set_metric_coerce(json->check,
287           json->keys[json->depth], json->last_type, p->v);
288       last_p = p;
289       if(p->v != NULL &&
290          (json->last_type == 'L' || json->last_type == 'l' ||
291           json->last_type == 'I' || json->last_type == 'i' ||
292           json->last_type == 'n')) {
293         total += strtold(p->v, NULL);
294         cnt = cnt + 1;
295         use_avg = mtev_true;
296       }
297       json->cnt++;
298     }
299     if(json->immediate && last_p != NULL) {
300       if(use_avg) {
301         double avg = total / cnt;
302         noit_stats_log_immediate_metric(json->check,
303             json->keys[json->depth], 'n', &avg);
304       }
305       else {
306         noit_stats_log_immediate_metric(json->check,
307             json->keys[json->depth], json->last_type, last_p->v);
308       }
309     }
310   }
311   json->saw_complex_type = 0;
312   for(p=json->last_value;p;) {
313     struct value_list *savenext;
314     savenext = p->next;
315     if(p->v) free(p->v);
316     savenext = p->next;
317     free(p);
318     p = savenext;
319   }
320   json->last_value = NULL;
321   return 1;
322 }
323 static int
324 httptrap_yajl_cb_start_array(void *ctx) {
325   struct rest_json_payload *json = ctx;
326   json->depth++;
327   json->array_depth[json->depth]++;
328   return 1;
329 }
330 static int
331 httptrap_yajl_cb_end_array(void *ctx) {
332   struct rest_json_payload *json = ctx;
333   json->array_depth[json->depth] = 0;
334   json->depth--;
335   return 1;
336 }
337 static int
338 httptrap_yajl_cb_map_key(void *ctx, const unsigned char * key,
339                          size_t stringLen) {
340   struct rest_json_payload *json = ctx;
341   if(stringLen > 255) return 0;
342   if(json->keys[json->depth]) free(json->keys[json->depth]);
343   json->keys[json->depth] = NULL;
344   if(stringLen == 5 && memcmp(key, "_type", 5) == 0) {
345     json->last_special_key = 0x1;
346     if(json->depth > 0) json->keys[json->depth] = strdup(json->keys[json->depth-1]);
347     return 1;
348   }
349   if(stringLen == 6 && memcmp(key, "_value", 6) == 0) {
350     if(json->depth > 0) json->keys[json->depth] = strdup(json->keys[json->depth-1]);
351     json->last_special_key = 0x2;
352     json->saw_complex_type |= 0x2;
353     return 1;
354   }
355   json->last_special_key = 0;
356   if(json->depth == 0) {
357     json->keys[json->depth] = malloc(stringLen+1);
358     memcpy(json->keys[json->depth], key, stringLen);
359     json->keys[json->depth][stringLen] = '\0';
360   }
361   else {
362     int uplen = strlen(json->keys[json->depth-1]);
363     if(uplen + 1 + stringLen > 255) return 0;
364     json->keys[json->depth] = malloc(uplen + 1 + stringLen + 1);
365     memcpy(json->keys[json->depth], json->keys[json->depth-1], uplen);
366     json->keys[json->depth][uplen] = json->delimiter;
367     memcpy(json->keys[json->depth] + uplen + 1, key, stringLen);
368     json->keys[json->depth][uplen + 1 + stringLen] = '\0';
369   }
370   return 1;
371 }
372 static yajl_callbacks httptrap_yajl_callbacks = {
373   .yajl_null = httptrap_yajl_cb_null,
374   .yajl_boolean = httptrap_yajl_cb_boolean,
375   .yajl_number = httptrap_yajl_cb_number,
376   .yajl_string = httptrap_yajl_cb_string,
377   .yajl_start_map = httptrap_yajl_cb_start_map,
378   .yajl_map_key = httptrap_yajl_cb_map_key,
379   .yajl_end_map = httptrap_yajl_cb_end_map,
380   .yajl_start_array = httptrap_yajl_cb_start_array,
381   .yajl_end_array = httptrap_yajl_cb_end_array
382 };
383
384 static void
385 rest_json_payload_free(void *f) {
386   int i;
387   struct rest_json_payload *json = f;
388   if(json->parser) yajl_free(json->parser);
389   if(json->error) free(json->error);
390   for(i=0;i<MAX_DEPTH;i++)
391     if(json->keys[i]) free(json->keys[i]);
392   if(json->last_value) free(json->last_value);
393   free(json);
394 }
395
396 static struct rest_json_payload *
397 rest_get_json_upload(mtev_http_rest_closure_t *restc,
398                     int *mask, int *complete) {
399   struct rest_json_payload *rxc;
400   mtev_http_request *req = mtev_http_session_request(restc->http_ctx);
401   httptrap_closure_t *ccl;
402   int content_length;
403   char buffer[32768];
404
405   content_length = mtev_http_request_content_length(req);
406   rxc = restc->call_closure;
407   ccl = rxc->check->closure;
408   rxc->immediate = mtev_httptrap_check_aynsch(ccl->self, rxc->check);
409   while(!rxc->complete) {
410     int len;
411     len = mtev_http_session_req_consume(
412             restc->http_ctx, buffer,
413             MIN(content_length - rxc->len, sizeof(buffer)),
414             sizeof(buffer),
415             mask);
416     if(len > 0) {
417       yajl_status status;
418       status = yajl_parse(rxc->parser, (unsigned char *)buffer, len);
419       if(status != yajl_status_ok) {
420         unsigned char *err;
421         *complete = 1;
422         err = yajl_get_error(rxc->parser, 0, (unsigned char *)buffer, len);
423         rxc->error = strdup((char *)err);
424         yajl_free_error(rxc->parser, err);
425         return rxc;
426       }
427       rxc->len += len;
428     }
429     if(len < 0 && errno == EAGAIN) return NULL;
430     else if(len < 0) {
431       *complete = 1;
432       return NULL;
433     }
434     content_length = mtev_http_request_content_length(req);
435     if((mtev_http_request_payload_chunked(req) && len == 0) ||
436        (rxc->len == content_length)) {
437       rxc->complete = 1;
438       yajl_complete_parse(rxc->parser);
439     }
440   }
441
442   *complete = 1;
443   return rxc;
444 }
445
446 static int httptrap_submit(noit_module_t *self, noit_check_t *check,
447                            noit_check_t *cause) {
448   httptrap_closure_t *ccl;
449   struct timeval duration;
450   /* We are passive, so we don't do anything for transient checks */
451   if(check->flags & NP_TRANSIENT) return 0;
452
453   mtev_httptrap_check_aynsch(self, check);
454   if(!check->closure) {
455     ccl = check->closure = (void *)calloc(1, sizeof(httptrap_closure_t));
456     memset(ccl, 0, sizeof(httptrap_closure_t));
457     ccl->self = self;
458   } else {
459     // Don't count the first run
460     struct timeval now, *last;
461     stats_t *inprogress;
462     char human_buffer[256];
463     ccl = (httptrap_closure_t*)check->closure;
464     gettimeofday(&now, NULL);
465     sub_timeval(now, check->last_fire_time, &duration);
466     noit_stats_set_whence(check, &now);
467     noit_stats_set_duration(check, duration.tv_sec * 1000 + duration.tv_usec / 1000);
468
469     snprintf(human_buffer, sizeof(human_buffer),
470              "dur=%ld,run=%d,stats=%d", duration.tv_sec * 1000 + duration.tv_usec / 1000,
471              check->generation, ccl->stats_count);
472     mtevL(nldeb, "httptrap(%s) [%s]\n", check->target, human_buffer);
473
474     // Not sure what to do here
475     noit_stats_set_available(check, (ccl->stats_count > 0) ?
476         NP_AVAILABLE : NP_UNAVAILABLE);
477     noit_stats_set_state(check, (ccl->stats_count > 0) ?
478         NP_GOOD : NP_BAD);
479     noit_stats_set_status(check, human_buffer);
480     if(check->last_fire_time.tv_sec)
481       noit_check_passive_set_stats(check);
482
483     inprogress = noit_check_get_stats_inprogress(check);
484     last = noit_check_stats_whence(inprogress, NULL);
485     memcpy(&check->last_fire_time, last, sizeof(duration));
486   }
487   ccl->stats_count = 0;
488   return 0;
489 }
490
491 static int
492 push_payload_at_check(struct rest_json_payload *rxc) {
493   httptrap_closure_t *ccl;
494   mtev_boolean immediate;
495   char key[256];
496
497   if (!rxc->check || strcmp(rxc->check->module, "httptrap")) return 0;
498   if (rxc->check->closure == NULL) return 0;
499   ccl = rxc->check->closure;
500   immediate = mtev_httptrap_check_aynsch(ccl->self,rxc->check);
501
502   /* do it here */
503   ccl->stats_count = rxc->cnt;
504   return rxc->cnt;
505 }
506
507 static int
508 rest_httptrap_handler(mtev_http_rest_closure_t *restc,
509                       int npats, char **pats) {
510   int mask, complete = 0, cnt;
511   struct rest_json_payload *rxc = NULL;
512   const char *error = "internal error", *secret = NULL;
513   mtev_http_session_ctx *ctx = restc->http_ctx;
514   const unsigned int DEBUGDATA_OUT_SIZE=4096;
515   const unsigned int JSON_OUT_SIZE=DEBUGDATA_OUT_SIZE+128;
516   char json_out[JSON_OUT_SIZE];
517   char debugdata_out[DEBUGDATA_OUT_SIZE];
518   int debugflag=0;
519   const char *debugchkflag;
520   noit_check_t *check;
521   uuid_t check_id;
522   mtev_http_request *req;
523   mtev_hash_table *hdrs;
524
525   if(npats != 2) {
526     error = "bad uri";
527     goto error;
528   }
529   if(uuid_parse(pats[0], check_id)) {
530     error = "uuid parse error";
531     goto error;
532   }
533
534   if(restc->call_closure == NULL) {
535     httptrap_closure_t *ccl;
536     const char *delimiter = NULL;
537     rxc = restc->call_closure = calloc(1, sizeof(*rxc));
538     rxc->delimiter = DEFAULT_HTTPTRAP_DELIMITER;
539     check = noit_poller_lookup(check_id);
540     if(!check || strcmp(check->module, "httptrap")) {
541       error = "no such httptrap check";
542       goto error;
543     }
544    
545     (void)mtev_hash_retr_str(check->config, "secret", strlen("secret"), &secret);
546     if(!secret) secret = "";
547     if(strcmp(pats[1], secret)) {
548       error = "secret mismatch";
549       goto error;
550     }
551     (void)mtev_hash_retr_str(check->config, "delimiter", strlen("delimiter"), &delimiter);
552     if(delimiter && *delimiter) rxc->delimiter = *delimiter;
553     rxc->check = check;
554     ccl = check->closure;
555     if(!ccl) {
556       error = "noitd is booting, try again in a bit";
557       goto error;
558     }
559     rxc->parser = yajl_alloc(&httptrap_yajl_callbacks, NULL, rxc);
560     rxc->depth = -1;
561     yajl_config(rxc->parser, yajl_allow_comments, 1);
562     yajl_config(rxc->parser, yajl_dont_validate_strings, 1);
563     yajl_config(rxc->parser, yajl_allow_trailing_garbage, 1);
564     yajl_config(rxc->parser, yajl_allow_partial_values, 1);
565     restc->call_closure_free = rest_json_payload_free;
566   }
567   else rxc = restc->call_closure;
568
569   /* flip threads */
570   {
571     mtev_http_connection *conn = mtev_http_session_connection(ctx);
572     eventer_t e = mtev_http_connection_event(conn);
573     if(e) {
574       pthread_t tgt = CHOOSE_EVENTER_THREAD_FOR_CHECK(rxc->check);
575       if(!pthread_equal(e->thr_owner, tgt)) {
576         e->thr_owner = tgt;
577         return EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
578       }
579     }
580   }
581
582   rxc = rest_get_json_upload(restc, &mask, &complete);
583   if(rxc == NULL && !complete) return mask;
584
585   if(!rxc) goto error;
586   if(rxc->error) goto error;
587
588   cnt = push_payload_at_check(rxc);
589  
590   mtev_http_response_ok(ctx, "application/json");
591  
592   /*Examine headers for x-circonus-httptrap-debug flag*/
593   req = mtev_http_session_request(ctx);
594   hdrs = mtev_http_request_headers_table(req);
595    
596   /*Check if debug header passed in. If present and set to true, set debugflag value to one.*/
597   if(mtev_hash_retr_str(hdrs, "x-circonus-httptrap-debug", strlen("x-circonus-httptrap-debug"), &debugchkflag))
598   {
599     if (strcmp(debugchkflag,"true")==0)
600     {
601       debugflag=1;
602     }
603   }
604    
605   /*If debugflag remains zero, simply output the number of metrics.*/
606   if (debugflag==0)
607   {
608     snprintf(json_out, sizeof(json_out),
609            "{ \"stats\": %d }", cnt);   
610   }
611  
612   /*Otherwise, if set to one, output current metrics in addition to number of current metrics.*/
613   else if (debugflag==1)
614   {       
615       stats_t *c;
616       mtev_hash_table *metrics;
617        
618       /*Retrieve check information.*/       
619       check = noit_poller_lookup(check_id);
620       c = noit_check_get_stats_current(check);
621       metrics = noit_check_stats_metrics(c);
622       mtev_hash_iter iter = MTEV_HASH_ITER_ZERO;
623       const char *k;
624       int klen;
625       void *data;
626       int written=0;
627       int offset=0;
628       memset(debugdata_out,'\0',sizeof(debugdata_out));
629      
630       /*Extract metrics*/
631       while(mtev_hash_next(metrics, &iter, &k, &klen, &data))
632       {
633         char buff[256];
634         int toWrite = DEBUGDATA_OUT_SIZE-offset;
635         metric_t *tmp=(metric_t *)data;
636         char *metric_name=tmp->metric_name;
637         metric_type_t metric_type=tmp->metric_type;
638         noit_stats_snprint_metric_value(buff, sizeof(buff), tmp);
639         written = snprintf(debugdata_out + offset, toWrite, "\"%s\": {\"_type\":\"%c\",\"_value\":\"%s\"},", metric_name,metric_type,buff);
640         if(toWrite < written)
641         {
642             break;
643         }
644         offset += written;
645       }
646        
647       /*Set last character to empty-don't want extra comma in output*/
648       if (offset>1)
649       {
650         snprintf(debugdata_out + (offset-1), 1, "%s"," ");
651       }
652      
653       /*Output stats and metrics.*/
654       snprintf(json_out, sizeof(json_out)+strlen(debugdata_out),
655              "{ \"stats\": %d, \"metrics\": {%s } }", cnt, debugdata_out);
656   }
657
658   mtev_http_response_append(ctx, json_out, strlen(json_out));
659   mtev_http_response_end(ctx);
660   return 0;
661
662  error:
663   mtev_http_response_server_error(ctx, "application/json");
664   mtev_http_response_append(ctx, "{ error: \"", 10);
665   if(rxc && rxc->error) error = rxc->error;
666   mtev_http_response_append(ctx, error, strlen(error));
667   mtev_http_response_append(ctx, "\" }", 3);
668   mtev_http_response_end(ctx);
669   return 0;
670 }
671
672 static int mtev_httptrap_initiate_check(noit_module_t *self,
673                                         noit_check_t *check,
674                                         int once, noit_check_t *cause) {
675   check->flags |= NP_PASSIVE_COLLECTION;
676   if (check->closure == NULL) {
677     httptrap_closure_t *ccl;
678     ccl = check->closure = (void *)calloc(1, sizeof(httptrap_closure_t));
679     ccl->self = self;
680   }
681   INITIATE_CHECK(httptrap_submit, self, check, cause);
682   return 0;
683 }
684
685 static int mtev_httptrap_config(noit_module_t *self, mtev_hash_table *options) {
686   httptrap_mod_config_t *conf;
687   conf = noit_module_get_userdata(self);
688   if(conf) {
689     if(conf->options) {
690       mtev_hash_destroy(conf->options, free, free);
691       free(conf->options);
692     }
693   }
694   else
695     conf = calloc(1, sizeof(*conf));
696   conf->options = options;
697   noit_module_set_userdata(self, conf);
698   return 1;
699 }
700
701 static int mtev_httptrap_onload(mtev_image_t *self) {
702   if(!nlerr) nlerr = mtev_log_stream_find("error/httptrap");
703   if(!nldeb) nldeb = mtev_log_stream_find("debug/httptrap");
704   if(!nlerr) nlerr = noit_error;
705   if(!nldeb) nldeb = noit_debug;
706   return 0;
707 }
708
709 static int mtev_httptrap_init(noit_module_t *self) {
710   const char *config_val;
711   httptrap_mod_config_t *conf;
712   conf = noit_module_get_userdata(self);
713
714   conf->asynch_metrics = mtev_true;
715   if(mtev_hash_retr_str(conf->options,
716                         "asynch_metrics", strlen("asynch_metrics"),
717                         (const char **)&config_val)) {
718     if(!strcasecmp(config_val, "false") || !strcasecmp(config_val, "off"))
719       conf->asynch_metrics = mtev_false;
720   }
721
722   noit_module_set_userdata(self, conf);
723
724   /* register rest handler */
725   mtev_http_rest_register("PUT", "/module/httptrap/",
726                           "^(" UUID_REGEX ")/([^/]*).*$",
727                           rest_httptrap_handler);
728   mtev_http_rest_register("POST", "/module/httptrap/",
729                           "^(" UUID_REGEX ")/([^/]*).*$",
730                           rest_httptrap_handler);
731   return 0;
732 }
733
734 #include "httptrap.xmlh"
735 noit_module_t httptrap = {
736   {
737     .magic = NOIT_MODULE_MAGIC,
738     .version = NOIT_MODULE_ABI_VERSION,
739     .name = "httptrap",
740     .description = "httptrap collection",
741     .xml_description = httptrap_xml_description,
742     .onload = mtev_httptrap_onload
743   },
744   mtev_httptrap_config,
745   mtev_httptrap_init,
746   mtev_httptrap_initiate_check,
747   NULL
748 };
Note: See TracBrowser for help on using the browser.