root/src/modules/httptrap.c

Revision 9c44e5a54c4ada69e5e61476fc5775b6e4d96c14, 20.3 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 months ago)

Make stats on checks use epoch memory reclamation.

  • 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   char array_depth[MAX_DEPTH];
81   unsigned char last_special_key;
82   unsigned char saw_complex_type;
83   metric_type_t last_type;
84   struct value_list *last_value;
85   int cnt;
86   mtev_boolean immediate;
87 };
88
89 #define NEW_LV(json,a) do { \
90   struct value_list *nlv = malloc(sizeof(*nlv)); \
91   nlv->v = a; \
92   nlv->next = json->last_value; \
93   json->last_value = nlv; \
94 } while(0)
95
96 static mtev_boolean
97 mtev_httptrap_check_aynsch(noit_module_t *self,
98                            noit_check_t *check) {
99   const char *config_val;
100   httptrap_mod_config_t *conf;
101   if(!self) return mtev_true;
102   conf = noit_module_get_userdata(self);
103   if(!conf) return mtev_true;
104   mtev_boolean is_asynch = conf->asynch_metrics;
105   if(mtev_hash_retr_str(check->config,
106                         "asynch_metrics", strlen("asynch_metrics"),
107                         (const char **)&config_val)) {
108     if(!strcasecmp(config_val, "false") || !strcasecmp(config_val, "off"))
109       is_asynch = mtev_false;
110     else if(!strcasecmp(config_val, "true") || !strcasecmp(config_val, "on"))
111       is_asynch = mtev_true;
112   }
113
114   if(is_asynch) check->flags |= NP_SUPPRESS_METRICS;
115   else check->flags &= ~NP_SUPPRESS_METRICS;
116   return is_asynch;
117 }
118
119 static void
120 set_array_key(struct rest_json_payload *json) {
121   if(json->array_depth[json->depth] > 0) {
122     char str[256];
123     int strLen;
124     snprintf(str, sizeof(str), "%d", json->array_depth[json->depth] - 1);
125     json->array_depth[json->depth]++;
126     strLen = strlen(str);
127     if(json->keys[json->depth]) free(json->keys[json->depth]);
128     json->keys[json->depth] = NULL;
129     if(json->depth == 0) {
130       json->keys[json->depth] = malloc(strLen+1);
131       memcpy(json->keys[json->depth], str, strLen);
132       json->keys[json->depth][strLen] = '\0';
133     }
134     else {
135       int uplen = strlen(json->keys[json->depth-1]);
136       if(uplen + 1 + strLen > 255) return;
137       json->keys[json->depth] = malloc(uplen + 1 + strLen + 1);
138       memcpy(json->keys[json->depth], json->keys[json->depth-1], uplen);
139       json->keys[json->depth][uplen] = json->delimiter;
140       memcpy(json->keys[json->depth] + uplen + 1, str, strLen);
141       json->keys[json->depth][uplen + 1 + strLen] = '\0';
142     }
143   }
144 }
145 static int
146 httptrap_yajl_cb_null(void *ctx) {
147   struct rest_json_payload *json = ctx;
148   if(json->depth<0) return 0;
149   set_array_key(json);
150   if(json->last_special_key == 0x2) {
151     NEW_LV(json, NULL);
152     return 1;
153   }
154   if(json->last_special_key) return 0;
155   noit_stats_set_metric(json->check,
156       json->keys[json->depth], METRIC_INT32, NULL);
157   if(json->immediate)
158     noit_stats_log_immediate_metric(json->check,
159         json->keys[json->depth], METRIC_INT32, NULL);
160   json->cnt++;
161   return 1;
162 }
163 static int
164 httptrap_yajl_cb_boolean(void *ctx, int boolVal) {
165   int ival;
166   struct rest_json_payload *json = ctx;
167   if(json->depth<0) return 0;
168   set_array_key(json);
169   if(json->last_special_key == 0x2) {
170     NEW_LV(json, strdup(boolVal ? "1" : "0"));
171     return 1;
172   }
173   if(json->last_special_key) return 0;
174   ival = boolVal ? 1 : 0;
175   noit_stats_set_metric(json->check,
176       json->keys[json->depth], METRIC_INT32, &ival);
177   if(json->immediate)
178     noit_stats_log_immediate_metric(json->check,
179         json->keys[json->depth], METRIC_INT32, &ival);
180   json->cnt++;
181   return 1;
182 }
183 static int
184 httptrap_yajl_cb_number(void *ctx, const char * numberVal,
185                         size_t numberLen) {
186   char val[128];
187   struct rest_json_payload *json = ctx;
188   if(json->depth<0) return 0;
189   set_array_key(json);
190   if(json->last_special_key == 0x2) {
191     char *str;
192     str = malloc(numberLen+1);
193     memcpy(str, numberVal, numberLen);
194     str[numberLen] = '\0';
195     NEW_LV(json, str);
196     return 1;
197   }
198   if(json->last_special_key) return 0;
199   if(numberLen > sizeof(val)-1) numberLen = sizeof(val)-1;
200   memcpy(val, numberVal, numberLen);
201   val[numberLen] = '\0';
202   noit_stats_set_metric(json->check,
203       json->keys[json->depth], METRIC_GUESS, val);
204   if(json->immediate)
205     noit_stats_log_immediate_metric(json->check,
206         json->keys[json->depth], METRIC_GUESS, val);
207   json->cnt++;
208   return 1;
209 }
210 static int
211 httptrap_yajl_cb_string(void *ctx, const unsigned char * stringVal,
212                         size_t stringLen) {
213   struct rest_json_payload *json = ctx;
214   char val[4096];
215   if(json->depth<0) return 0;
216   set_array_key(json);
217   if(json->last_special_key == 0x1) {
218     if(stringLen != 1) return 0;
219     if(*stringVal == 'L' || *stringVal == 'l' ||
220         *stringVal == 'I' || *stringVal == 'i' ||
221         *stringVal == 'n' || *stringVal == 's') {
222       json->last_type = *stringVal;
223       json->saw_complex_type |= 0x1;
224       return 1;
225     }
226     return 0;
227   }
228   else if(json->last_special_key == 0x2) {
229     char *str;
230     str = malloc(stringLen+1);
231     memcpy(str, stringVal, stringLen);
232     str[stringLen] = '\0';
233     NEW_LV(json, str);
234     json->saw_complex_type |= 0x2;
235     return 1;
236   }
237   if(stringLen > sizeof(val)-1) stringLen = sizeof(val)-1;
238   memcpy(val, stringVal, stringLen);
239   val[stringLen] = '\0';
240   noit_stats_set_metric(json->check,
241       json->keys[json->depth], METRIC_GUESS, val);
242   if(json->immediate)
243     noit_stats_log_immediate_metric(json->check,
244         json->keys[json->depth], METRIC_GUESS, val);
245   json->cnt++;
246   return 1;
247 }
248 static int
249 httptrap_yajl_cb_start_map(void *ctx) {
250   struct rest_json_payload *json = ctx;
251   set_array_key(json);
252   json->depth++;
253   if(json->depth >= MAX_DEPTH) return 0;
254   return 1;
255 }
256 static int
257 httptrap_yajl_cb_end_map(void *ctx) {
258   struct value_list *p, *last_p = NULL;
259   struct rest_json_payload *json = ctx;
260   json->depth--;
261   if(json->saw_complex_type == 0x3) {
262     long double total = 0, cnt = 0;
263     mtev_boolean use_avg = mtev_false;
264     for(p=json->last_value;p;p=p->next) {
265       noit_stats_set_metric_coerce(json->check,
266           json->keys[json->depth], json->last_type, p->v);
267       last_p = p;
268       if(p->v != NULL &&
269          (json->last_type == 'L' || json->last_type == 'l' ||
270           json->last_type == 'I' || json->last_type == 'i' ||
271           json->last_type == 'n')) {
272         total += strtold(p->v, NULL);
273         cnt = cnt + 1;
274         use_avg = mtev_true;
275       }
276       json->cnt++;
277     }
278     if(json->immediate && last_p != NULL) {
279       if(use_avg) {
280         double avg = total / cnt;
281         noit_stats_log_immediate_metric(json->check,
282             json->keys[json->depth], 'n', &avg);
283       }
284       else {
285         noit_stats_log_immediate_metric(json->check,
286             json->keys[json->depth], json->last_type, last_p->v);
287       }
288     }
289   }
290   json->saw_complex_type = 0;
291   for(p=json->last_value;p;) {
292     struct value_list *savenext;
293     savenext = p->next;
294     if(p->v) free(p->v);
295     savenext = p->next;
296     free(p);
297     p = savenext;
298   }
299   json->last_value = NULL;
300   return 1;
301 }
302 static int
303 httptrap_yajl_cb_start_array(void *ctx) {
304   struct rest_json_payload *json = ctx;
305   json->depth++;
306   json->array_depth[json->depth]++;
307   return 1;
308 }
309 static int
310 httptrap_yajl_cb_end_array(void *ctx) {
311   struct rest_json_payload *json = ctx;
312   json->array_depth[json->depth] = 0;
313   json->depth--;
314   return 1;
315 }
316 static int
317 httptrap_yajl_cb_map_key(void *ctx, const unsigned char * key,
318                          size_t stringLen) {
319   struct rest_json_payload *json = ctx;
320   if(stringLen > 255) return 0;
321   if(json->keys[json->depth]) free(json->keys[json->depth]);
322   json->keys[json->depth] = NULL;
323   if(stringLen == 5 && memcmp(key, "_type", 5) == 0) {
324     json->last_special_key = 0x1;
325     if(json->depth > 0) json->keys[json->depth] = strdup(json->keys[json->depth-1]);
326     return 1;
327   }
328   if(stringLen == 6 && memcmp(key, "_value", 6) == 0) {
329     if(json->depth > 0) json->keys[json->depth] = strdup(json->keys[json->depth-1]);
330     json->last_special_key = 0x2;
331     json->saw_complex_type |= 0x2;
332     return 1;
333   }
334   json->last_special_key = 0;
335   if(json->depth == 0) {
336     json->keys[json->depth] = malloc(stringLen+1);
337     memcpy(json->keys[json->depth], key, stringLen);
338     json->keys[json->depth][stringLen] = '\0';
339   }
340   else {
341     int uplen = strlen(json->keys[json->depth-1]);
342     if(uplen + 1 + stringLen > 255) return 0;
343     json->keys[json->depth] = malloc(uplen + 1 + stringLen + 1);
344     memcpy(json->keys[json->depth], json->keys[json->depth-1], uplen);
345     json->keys[json->depth][uplen] = json->delimiter;
346     memcpy(json->keys[json->depth] + uplen + 1, key, stringLen);
347     json->keys[json->depth][uplen + 1 + stringLen] = '\0';
348   }
349   return 1;
350 }
351 static yajl_callbacks httptrap_yajl_callbacks = {
352   .yajl_null = httptrap_yajl_cb_null,
353   .yajl_boolean = httptrap_yajl_cb_boolean,
354   .yajl_number = httptrap_yajl_cb_number,
355   .yajl_string = httptrap_yajl_cb_string,
356   .yajl_start_map = httptrap_yajl_cb_start_map,
357   .yajl_map_key = httptrap_yajl_cb_map_key,
358   .yajl_end_map = httptrap_yajl_cb_end_map,
359   .yajl_start_array = httptrap_yajl_cb_start_array,
360   .yajl_end_array = httptrap_yajl_cb_end_array
361 };
362
363 static void
364 rest_json_payload_free(void *f) {
365   int i;
366   struct rest_json_payload *json = f;
367   if(json->parser) yajl_free(json->parser);
368   if(json->error) free(json->error);
369   for(i=0;i<MAX_DEPTH;i++)
370     if(json->keys[i]) free(json->keys[i]);
371   if(json->last_value) free(json->last_value);
372   free(json);
373 }
374
375 static struct rest_json_payload *
376 rest_get_json_upload(mtev_http_rest_closure_t *restc,
377                     int *mask, int *complete) {
378   struct rest_json_payload *rxc;
379   mtev_http_request *req = mtev_http_session_request(restc->http_ctx);
380   httptrap_closure_t *ccl;
381   int content_length;
382   char buffer[32768];
383
384   content_length = mtev_http_request_content_length(req);
385   rxc = restc->call_closure;
386   ccl = rxc->check->closure;
387   rxc->immediate = mtev_httptrap_check_aynsch(ccl->self, rxc->check);
388   while(!rxc->complete) {
389     int len;
390     len = mtev_http_session_req_consume(
391             restc->http_ctx, buffer,
392             MIN(content_length - rxc->len, sizeof(buffer)),
393             sizeof(buffer),
394             mask);
395     if(len > 0) {
396       yajl_status status;
397       status = yajl_parse(rxc->parser, (unsigned char *)buffer, len);
398       if(status != yajl_status_ok) {
399         unsigned char *err;
400         *complete = 1;
401         err = yajl_get_error(rxc->parser, 0, (unsigned char *)buffer, len);
402         rxc->error = strdup((char *)err);
403         yajl_free_error(rxc->parser, err);
404         return rxc;
405       }
406       rxc->len += len;
407     }
408     if(len < 0 && errno == EAGAIN) return NULL;
409     else if(len < 0) {
410       *complete = 1;
411       return NULL;
412     }
413     content_length = mtev_http_request_content_length(req);
414     if((mtev_http_request_payload_chunked(req) && len == 0) ||
415        (rxc->len == content_length)) {
416       rxc->complete = 1;
417       yajl_complete_parse(rxc->parser);
418     }
419   }
420
421   *complete = 1;
422   return rxc;
423 }
424
425 static int httptrap_submit(noit_module_t *self, noit_check_t *check,
426                            noit_check_t *cause) {
427   httptrap_closure_t *ccl;
428   struct timeval duration;
429   /* We are passive, so we don't do anything for transient checks */
430   if(check->flags & NP_TRANSIENT) return 0;
431
432   mtev_httptrap_check_aynsch(self, check);
433   if(!check->closure) {
434     ccl = check->closure = (void *)calloc(1, sizeof(httptrap_closure_t));
435     memset(ccl, 0, sizeof(httptrap_closure_t));
436     ccl->self = self;
437   } else {
438     // Don't count the first run
439     struct timeval now, *last;
440     stats_t *inprogress;
441     char human_buffer[256];
442     ccl = (httptrap_closure_t*)check->closure;
443     gettimeofday(&now, NULL);
444     sub_timeval(now, check->last_fire_time, &duration);
445     noit_stats_set_whence(check, &now);
446     noit_stats_set_duration(check, duration.tv_sec * 1000 + duration.tv_usec / 1000);
447
448     snprintf(human_buffer, sizeof(human_buffer),
449              "dur=%ld,run=%d,stats=%d", duration.tv_sec * 1000 + duration.tv_usec / 1000,
450              check->generation, ccl->stats_count);
451     mtevL(nldeb, "httptrap(%s) [%s]\n", check->target, human_buffer);
452
453     // Not sure what to do here
454     noit_stats_set_available(check, (ccl->stats_count > 0) ?
455         NP_AVAILABLE : NP_UNAVAILABLE);
456     noit_stats_set_state(check, (ccl->stats_count > 0) ?
457         NP_GOOD : NP_BAD);
458     noit_stats_set_status(check, human_buffer);
459     if(check->last_fire_time.tv_sec)
460       noit_check_passive_set_stats(check);
461
462     inprogress = noit_check_get_stats_inprogress(check);
463     last = noit_check_stats_whence(inprogress, NULL);
464     memcpy(&check->last_fire_time, last, sizeof(duration));
465   }
466   ccl->stats_count = 0;
467   return 0;
468 }
469
470 static int
471 push_payload_at_check(struct rest_json_payload *rxc) {
472   httptrap_closure_t *ccl;
473   mtev_boolean immediate;
474   char key[256];
475
476   if (!rxc->check || strcmp(rxc->check->module, "httptrap")) return 0;
477   if (rxc->check->closure == NULL) return 0;
478   ccl = rxc->check->closure;
479   immediate = mtev_httptrap_check_aynsch(ccl->self,rxc->check);
480
481   /* do it here */
482   ccl->stats_count = rxc->cnt;
483   return rxc->cnt;
484 }
485
486 static int
487 rest_httptrap_handler(mtev_http_rest_closure_t *restc,
488                       int npats, char **pats) {
489   int mask, complete = 0, cnt;
490   struct rest_json_payload *rxc = NULL;
491   const char *error = "internal error", *secret = NULL;
492   mtev_http_session_ctx *ctx = restc->http_ctx;
493   char json_out[128];
494   noit_check_t *check;
495   uuid_t check_id;
496
497   if(npats != 2) {
498     error = "bad uri";
499     goto error;
500   }
501   if(uuid_parse(pats[0], check_id)) {
502     error = "uuid parse error";
503     goto error;
504   }
505
506   if(restc->call_closure == NULL) {
507     httptrap_closure_t *ccl;
508     const char *delimiter = NULL;
509     rxc = restc->call_closure = calloc(1, sizeof(*rxc));
510     rxc->delimiter = DEFAULT_HTTPTRAP_DELIMITER;
511     check = noit_poller_lookup(check_id);
512     if(!check || strcmp(check->module, "httptrap")) {
513       error = "no such httptrap check";
514       goto error;
515     }
516     (void)mtev_hash_retr_str(check->config, "secret", strlen("secret"), &secret);
517     if(!secret) secret = "";
518     if(strcmp(pats[1], secret)) {
519       error = "secret mismatch";
520       goto error;
521     }
522     (void)mtev_hash_retr_str(check->config, "delimiter", strlen("delimiter"), &delimiter);
523     if(delimiter && *delimiter) rxc->delimiter = *delimiter;
524     rxc->check = check;
525     ccl = check->closure;
526     if(!ccl) {
527       error = "noitd is booting, try again in a bit";
528       goto error;
529     }
530     rxc->parser = yajl_alloc(&httptrap_yajl_callbacks, NULL, rxc);
531     rxc->depth = -1;
532     yajl_config(rxc->parser, yajl_allow_comments, 1);
533     yajl_config(rxc->parser, yajl_dont_validate_strings, 1);
534     yajl_config(rxc->parser, yajl_allow_trailing_garbage, 1);
535     yajl_config(rxc->parser, yajl_allow_partial_values, 1);
536     restc->call_closure_free = rest_json_payload_free;
537   }
538   else rxc = restc->call_closure;
539
540   /* flip threads */
541   {
542     mtev_http_connection *conn = mtev_http_session_connection(ctx);
543     eventer_t e = mtev_http_connection_event(conn);
544     if(e) {
545       pthread_t tgt = CHOOSE_EVENTER_THREAD_FOR_CHECK(rxc->check);
546       if(!pthread_equal(e->thr_owner, tgt)) {
547         e->thr_owner = tgt;
548         return EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
549       }
550     }
551   }
552
553   rxc = rest_get_json_upload(restc, &mask, &complete);
554   if(rxc == NULL && !complete) return mask;
555
556   if(!rxc) goto error;
557   if(rxc->error) goto error;
558
559   cnt = push_payload_at_check(rxc);
560
561   mtev_http_response_ok(ctx, "application/json");
562   snprintf(json_out, sizeof(json_out),
563            "{ \"stats\": %d }", cnt);
564   mtev_http_response_append(ctx, json_out, strlen(json_out));
565   mtev_http_response_end(ctx);
566   return 0;
567
568  error:
569   mtev_http_response_server_error(ctx, "application/json");
570   mtev_http_response_append(ctx, "{ error: \"", 10);
571   if(rxc && rxc->error) error = rxc->error;
572   mtev_http_response_append(ctx, error, strlen(error));
573   mtev_http_response_append(ctx, "\" }", 3);
574   mtev_http_response_end(ctx);
575   return 0;
576 }
577
578 static int mtev_httptrap_initiate_check(noit_module_t *self,
579                                         noit_check_t *check,
580                                         int once, noit_check_t *cause) {
581   check->flags |= NP_PASSIVE_COLLECTION;
582   if (check->closure == NULL) {
583     httptrap_closure_t *ccl;
584     ccl = check->closure = (void *)calloc(1, sizeof(httptrap_closure_t));
585     ccl->self = self;
586   }
587   INITIATE_CHECK(httptrap_submit, self, check, cause);
588   return 0;
589 }
590
591 static int mtev_httptrap_config(noit_module_t *self, mtev_hash_table *options) {
592   httptrap_mod_config_t *conf;
593   conf = noit_module_get_userdata(self);
594   if(conf) {
595     if(conf->options) {
596       mtev_hash_destroy(conf->options, free, free);
597       free(conf->options);
598     }
599   }
600   else
601     conf = calloc(1, sizeof(*conf));
602   conf->options = options;
603   noit_module_set_userdata(self, conf);
604   return 1;
605 }
606
607 static int mtev_httptrap_onload(mtev_image_t *self) {
608   if(!nlerr) nlerr = mtev_log_stream_find("error/httptrap");
609   if(!nldeb) nldeb = mtev_log_stream_find("debug/httptrap");
610   if(!nlerr) nlerr = noit_error;
611   if(!nldeb) nldeb = noit_debug;
612   return 0;
613 }
614
615 static int mtev_httptrap_init(noit_module_t *self) {
616   const char *config_val;
617   httptrap_mod_config_t *conf;
618   conf = noit_module_get_userdata(self);
619
620   conf->asynch_metrics = mtev_true;
621   if(mtev_hash_retr_str(conf->options,
622                         "asynch_metrics", strlen("asynch_metrics"),
623                         (const char **)&config_val)) {
624     if(!strcasecmp(config_val, "false") || !strcasecmp(config_val, "off"))
625       conf->asynch_metrics = mtev_false;
626   }
627
628   noit_module_set_userdata(self, conf);
629
630   /* register rest handler */
631   mtev_http_rest_register("PUT", "/module/httptrap/",
632                           "^(" UUID_REGEX ")/([^/]*).*$",
633                           rest_httptrap_handler);
634   mtev_http_rest_register("POST", "/module/httptrap/",
635                           "^(" UUID_REGEX ")/([^/]*).*$",
636                           rest_httptrap_handler);
637   return 0;
638 }
639
640 #include "httptrap.xmlh"
641 noit_module_t httptrap = {
642   {
643     .magic = NOIT_MODULE_MAGIC,
644     .version = NOIT_MODULE_ABI_VERSION,
645     .name = "httptrap",
646     .description = "httptrap collection",
647     .xml_description = httptrap_xml_description,
648     .onload = mtev_httptrap_onload
649   },
650   mtev_httptrap_config,
651   mtev_httptrap_init,
652   mtev_httptrap_initiate_check,
653   NULL
654 };
Note: See TracBrowser for help on using the browser.