static struct json_object * stats_to_json(stats_t *c) { struct json_object *doc; doc = json_object_new_object(); mtev_hash_table *metrics; mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *data; metrics = noit_check_stats_metrics(c); while(mtev_hash_next(metrics, &iter, &k, &klen, &data)) { char buff[256]; metric_t *m = (metric_t *)data; struct json_object *metric = json_object_new_object(); buff[0] = m->metric_type; buff[1] = '\0'; json_object_object_add(metric, "_type", json_object_new_string(buff)); if(m->metric_value.s) { int rv; rv = noit_stats_snprint_metric_value(buff, sizeof(buff), m); if(rv >= 0) json_object_object_add(metric, "_value", json_object_new_string(buff)); } json_object_object_add(doc, m->metric_name, metric); } return doc; }
static void nc_print_stat_metrics(mtev_console_closure_t ncct, noit_check_t *check, stats_t *c) { int mcount=0, cnt=0; const char **sorted_keys; char buff[256]; mtev_boolean filtered; mtev_hash_table *metrics; mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *data; metrics = noit_check_stats_metrics(c); memset(&iter, 0, sizeof(iter)); while(mtev_hash_next(metrics, &iter, &k, &klen, &data)) cnt++; sorted_keys = malloc(cnt * sizeof(*sorted_keys)); memset(&iter, 0, sizeof(iter)); while(mtev_hash_next(metrics, &iter, &k, &klen, &data)) { if(sorted_keys && mcount < cnt) sorted_keys[mcount++] = k; else { noit_stats_snprint_metric(buff, sizeof(buff), (metric_t *)data); filtered = !noit_apply_filterset(check->filterset, check, (metric_t *)data); nc_printf(ncct, " %c%s\n", filtered ? '*' : ' ', buff); } } if(sorted_keys) { int j; qsort(sorted_keys, mcount, sizeof(*sorted_keys), _qsort_string_compare); for(j=0;j<mcount;j++) { if(mtev_hash_retrieve(metrics, sorted_keys[j], strlen(sorted_keys[j]), &data)) { noit_stats_snprint_metric(buff, sizeof(buff), (metric_t *)data); filtered = !noit_apply_filterset(check->filterset, check, (metric_t *)data); nc_printf(ncct, " %c%s\n", filtered ? '*' : ' ', buff); } } free(sorted_keys); } }
static void add_metrics_to_node(stats_t *c, xmlNodePtr metrics, const char *type, int include_time) { mtev_hash_table *mets; mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *data; xmlNodePtr tmp; mets = noit_check_stats_metrics(c); while(mtev_hash_next(mets, &iter, &k, &klen, &data)) { char buff[256]; metric_t *m = (metric_t *)data; xmlAddChild(metrics, (tmp = xmlNewNode(NULL, (xmlChar *)"metric"))); xmlSetProp(tmp, (xmlChar *)"name", (xmlChar *)m->metric_name); buff[0] = m->metric_type; buff[1] = '\0'; xmlSetProp(tmp, (xmlChar *)"type", (xmlChar *)buff); if(m->metric_value.s) { int rv; rv = noit_stats_snprint_metric_value(buff, sizeof(buff), m); if(rv < 0) xmlSetProp(tmp, (xmlChar *)"error", (xmlChar *)"unknown type"); else xmlNodeAddContent(tmp, (xmlChar *)buff); } } xmlSetProp(metrics, (xmlChar *)"type", (const xmlChar *) type); if(include_time) { struct timeval *f = noit_check_stats_whence(c, NULL); char timestr[20]; snprintf(timestr, sizeof(timestr), "%0.3f", f->tv_sec + (f->tv_usec / 1000000.0)); xmlSetProp(metrics, (xmlChar *)"timestamp", (xmlChar *)timestr); } }
static int noit_console_show_check(mtev_console_closure_t ncct, int argc, char **argv, mtev_console_state_t *state, void *closure) { int i, cnt; mtev_conf_t_userdata_t *info; char xpath[1024]; xmlXPathObjectPtr pobj = NULL; xmlXPathContextPtr xpath_ctxt = NULL; mtev_conf_xml_xpath(NULL, &xpath_ctxt); if(argc > 1) { nc_printf(ncct, "requires zero or one arguments\n"); return -1; } info = mtev_console_userdata_get(ncct, MTEV_CONF_T_USERDATA); /* We many not be in conf-t mode -- that's fine */ if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info, argc ? argv[0] : NULL)) { nc_printf(ncct, "could not find check '%s'\n", argv[0]); return -1; } pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt); if(!pobj || pobj->type != XPATH_NODESET || xmlXPathNodeSetIsEmpty(pobj->nodesetval)) { nc_printf(ncct, "no checks found\n"); goto out; } cnt = xmlXPathNodeSetGetLength(pobj->nodesetval); if(info && cnt != 1) { nc_printf(ncct, "Ambiguous check specified\n"); goto out; } for(i=0; i<cnt; i++) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *data; uuid_t checkid; noit_check_t *check; mtev_hash_table *config; xmlNodePtr node, anode, mnode = NULL; char *uuid_conf; char *module, *value; node = (mtev_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i); uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid"); if(!uuid_conf || uuid_parse(uuid_conf, checkid)) { nc_printf(ncct, "%s has invalid or missing UUID!\n", (char *)xmlGetNodePath(node) + strlen("/noit")); continue; } nc_printf(ncct, "==== %s ====\n", uuid_conf); xmlFree(uuid_conf); #define MYATTR(a,n,b) _mtev_conf_get_string(node, &(n), "@" #a, &(b)) #define INHERIT(a,n,b) \ _mtev_conf_get_string(node, &(n), "ancestor-or-self::node()/@" #a, &(b)) #define SHOW_ATTR(a) do { \ anode = NULL; \ value = NULL; \ INHERIT(a, anode, value); \ nc_attr_show(ncct, #a, node, anode, value); \ if(value != NULL) free(value); \ } while(0) if(!INHERIT(module, mnode, module)) module = NULL; if(MYATTR(name, anode, value)) { nc_printf(ncct, " name: %s\n", value); free(value); } else nc_printf(ncct, " name: %s [from module]\n", module ? module : "[undef]"); nc_attr_show(ncct, "module", node, mnode, module); if(module) free(module); SHOW_ATTR(target); SHOW_ATTR(seq); SHOW_ATTR(resolve_rtype); SHOW_ATTR(period); SHOW_ATTR(timeout); SHOW_ATTR(oncheck); SHOW_ATTR(filterset); SHOW_ATTR(disable); /* Print out all the config settings */ config = mtev_conf_get_hash(node, "config"); while(mtev_hash_next(config, &iter, &k, &klen, &data)) { nc_printf(ncct, " config::%s: %s\n", k, (const char *)data); } mtev_hash_destroy(config, free, free); free(config); check = noit_poller_lookup(checkid); if(!check) { nc_printf(ncct, " ERROR: not in running system\n"); } else { int idx = 0; stats_t *c; struct timeval *whence; mtev_hash_table *metrics; nc_printf(ncct, " target_ip: %s\n", check->target_ip); nc_printf(ncct, " currently: %08x ", check->flags); if(NOIT_CHECK_RUNNING(check)) { nc_printf(ncct, "running"); idx++; } if(NOIT_CHECK_KILLED(check)) nc_printf(ncct, "%skilled", idx++?",":""); if(!NOIT_CHECK_CONFIGURED(check)) nc_printf(ncct, "%sunconfig", idx++?",":""); if(NOIT_CHECK_DISABLED(check)) nc_printf(ncct, "%sdisabled", idx++?",":""); if(!idx) nc_printf(ncct, "idle"); nc_write(ncct, "\n", 1); if (check->fire_event != NULL) { struct timeval now, diff; mtev_gettimeofday(&now, NULL); sub_timeval(check->fire_event->whence, now, &diff); nc_printf(ncct, " next run: %0.3f seconds\n", diff.tv_sec + (diff.tv_usec / 1000000.0)); } else { nc_printf(ncct, " next run: unscheduled\n"); } c = noit_check_get_stats_current(check); whence = noit_check_stats_whence(c, NULL); if(whence->tv_sec == 0) { nc_printf(ncct, " last run: never\n"); } else { const char *status; struct timeval now, *then, diff; mtev_gettimeofday(&now, NULL); then = noit_check_stats_whence(c, NULL); sub_timeval(now, *then, &diff); nc_printf(ncct, " last run: %0.3f seconds ago\n", diff.tv_sec + (diff.tv_usec / 1000000.0)); nc_printf(ncct, " availability/state: %s/%s\n", noit_check_available_string(noit_check_stats_available(c, NULL)), noit_check_state_string(noit_check_stats_state(c, NULL))); status = noit_check_stats_status(c, NULL); nc_printf(ncct, " status: %s\n", status); nc_printf(ncct, " feeds: %d\n", check->feeds ? check->feeds->size : 0); } c = noit_check_get_stats_inprogress(check); metrics = noit_check_stats_metrics(c); if(mtev_hash_size(metrics) > 0) { nc_printf(ncct, " metrics (inprogress):\n"); nc_print_stat_metrics(ncct, check, c); } c = noit_check_get_stats_current(check); metrics = noit_check_stats_metrics(c); if(mtev_hash_size(metrics)) { nc_printf(ncct, " metrics (current):\n"); nc_print_stat_metrics(ncct, check, c); } c = noit_check_get_stats_previous(check); metrics = noit_check_stats_metrics(c); if(mtev_hash_size(metrics) > 0) { nc_printf(ncct, " metrics (previous):\n"); nc_print_stat_metrics(ncct, check, c); } } } out: if(pobj) xmlXPathFreeObject(pobj); return 0; }
static int rest_httptrap_handler(mtev_http_rest_closure_t *restc, int npats, char **pats) { int mask, complete = 0, cnt; struct rest_json_payload *rxc = NULL; const char *error = "internal error", *secret = NULL; mtev_http_session_ctx *ctx = restc->http_ctx; const unsigned int DEBUGDATA_OUT_SIZE=4096; const unsigned int JSON_OUT_SIZE=DEBUGDATA_OUT_SIZE+128; char json_out[JSON_OUT_SIZE]; char debugdata_out[DEBUGDATA_OUT_SIZE]; int debugflag=0; const char *debugchkflag; noit_check_t *check; uuid_t check_id; mtev_http_request *req; mtev_hash_table *hdrs; if(npats != 2) { error = "bad uri"; goto error; } if(uuid_parse(pats[0], check_id)) { error = "uuid parse error"; goto error; } if(restc->call_closure == NULL) { mtev_boolean allowed = mtev_false; httptrap_closure_t *ccl = NULL; const char *delimiter = NULL; rxc = restc->call_closure = calloc(1, sizeof(*rxc)); rxc->delimiter = DEFAULT_HTTPTRAP_DELIMITER; check = noit_poller_lookup(check_id); if(!check) { error = "no such check"; goto error; } if(!httptrap_surrogate && strcmp(check->module, "httptrap")) { error = "no such httptrap check"; goto error; } /* check "secret" then "httptrap_secret" as a fallback */ (void)mtev_hash_retr_str(check->config, "secret", strlen("secret"), &secret); if(!secret) (void)mtev_hash_retr_str(check->config, "httptrap_secret", strlen("httptrap_secret"), &secret); if(secret && !strcmp(pats[1], secret)) allowed = mtev_true; if(!allowed && cross_module_reverse_allowed(check, pats[1])) allowed = mtev_true; if(!allowed) { error = "secret mismatch"; goto error; } /* check "delimiter" then "httptrap_delimiter" as a fallback */ (void)mtev_hash_retr_str(check->config, "delimiter", strlen("delimiter"), &delimiter); if(!delimiter) (void)mtev_hash_retr_str(check->config, "httptrap_delimiter", strlen("httptrap_delimiter"), &delimiter); if(delimiter && *delimiter) rxc->delimiter = *delimiter; rxc->check = check; uuid_copy(rxc->check_id, check_id); rxc->parser = yajl_alloc(&httptrap_yajl_callbacks, NULL, rxc); rxc->depth = -1; yajl_config(rxc->parser, yajl_allow_comments, 1); yajl_config(rxc->parser, yajl_dont_validate_strings, 1); yajl_config(rxc->parser, yajl_allow_trailing_garbage, 1); yajl_config(rxc->parser, yajl_allow_partial_values, 1); restc->call_closure_free = rest_json_payload_free; } else rxc = restc->call_closure; /* flip threads */ { mtev_http_connection *conn = mtev_http_session_connection(ctx); eventer_t e = mtev_http_connection_event(conn); if(e) { pthread_t tgt = CHOOSE_EVENTER_THREAD_FOR_CHECK(rxc->check); if(!pthread_equal(e->thr_owner, tgt)) { e->thr_owner = tgt; return EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION; } } } rxc = rest_get_json_upload(restc, &mask, &complete); if(rxc == NULL && !complete) return mask; if(!rxc) goto error; if(rxc->error) goto error; cnt = rxc->cnt; mtev_http_response_status_set(ctx, 200, "OK"); mtev_http_response_header_set(ctx, "Content-Type", "application/json"); mtev_http_response_option_set(ctx, MTEV_HTTP_CLOSE); /*Examine headers for x-circonus-httptrap-debug flag*/ req = mtev_http_session_request(ctx); hdrs = mtev_http_request_headers_table(req); /*Check if debug header passed in. If present and set to true, set debugflag value to one.*/ if(mtev_hash_retr_str(hdrs, "x-circonus-httptrap-debug", strlen("x-circonus-httptrap-debug"), &debugchkflag)) { if (strcmp(debugchkflag,"true")==0) { debugflag=1; } } /*If debugflag remains zero, simply output the number of metrics.*/ if (debugflag==0) { snprintf(json_out, sizeof(json_out), "{ \"stats\": %d }", cnt); } /*Otherwise, if set to one, output current metrics in addition to number of current metrics.*/ else if (debugflag==1) { stats_t *c; mtev_hash_table *metrics; /*Retrieve check information.*/ check = noit_poller_lookup(check_id); c = noit_check_get_stats_current(check); metrics = noit_check_stats_metrics(c); mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *data; int written=0; int offset=0; memset(debugdata_out,'\0',sizeof(debugdata_out)); /*Extract metrics*/ while(mtev_hash_next(metrics, &iter, &k, &klen, &data)) { char buff[256]; int toWrite = DEBUGDATA_OUT_SIZE-offset; metric_t *tmp=(metric_t *)data; char *metric_name=tmp->metric_name; metric_type_t metric_type=tmp->metric_type; noit_stats_snprint_metric_value(buff, sizeof(buff), tmp); written = snprintf(debugdata_out + offset, toWrite, "\"%s\": {\"_type\":\"%c\",\"_value\":\"%s\"},", metric_name,metric_type,buff); if(toWrite < written) { break; } offset += written; } /*Set last character to empty-don't want extra comma in output*/ if (offset>1) { snprintf(debugdata_out + (offset-1), 1, "%s"," "); } /*Output stats and metrics.*/ snprintf(json_out, sizeof(json_out)+strlen(debugdata_out), "{ \"stats\": %d, \"metrics\": {%s } }", cnt, debugdata_out); } mtev_http_response_append(ctx, json_out, strlen(json_out)); mtev_http_response_end(ctx); return 0; error: mtev_http_response_server_error(ctx, "application/json"); mtev_http_response_append(ctx, "{ \"error\": \"", 12); if(rxc && rxc->error) error = rxc->error; mtev_http_response_append(ctx, error, strlen(error)); mtev_http_response_append(ctx, "\" }", 3); mtev_http_response_end(ctx); return 0; }