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 int do_test(mtev_hash_lock_mode_t lock_mode) { mtev_hash_table hash; mtev_hash_init_locks(&hash, 400, lock_mode); pthread_t threads[THREAD_COUNT]; for (int i = 0; i < THREAD_COUNT; i++) { pthread_create(&threads[i], NULL, thread_func, &hash); } for (int i = 0; i < THREAD_COUNT; i++) { pthread_join(threads[i], NULL); } mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *data; while(mtev_hash_next(&hash, &iter, &k, &klen, &data)) { printf("%s\n", k); } mtev_hash_destroy(&hash, free, NULL); return 0; }
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); } }
int mtev_hash_next_str(mtev_hash_table *h, mtev_hash_iter *iter, const char **k, int *klen, const char **dstr) { void *data = NULL; int rv; /* Leave this hash_next for ABI safety. * (this mtev_hash_iter could be too small) */ rv = mtev_hash_next(h,iter,k,klen,&data); *dstr = data; return rv; }
int noit_jlog_foreach_feed_stats(int (*f)(jlog_feed_stats_t *, void *), void *c) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *key; int klen, cnt = 0; void *vs; while(mtev_hash_next(&feed_stats, &iter, &key, &klen, &vs)) { cnt += f((jlog_feed_stats_t *)vs, c); } return cnt; }
static void heartbeat_all_metrics(struct histogram_config *conf, noit_check_t *check, mtev_hash_table *metrics) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *data; u_int64_t s = time(NULL); while(mtev_hash_next(metrics, &iter, &k, &klen, &data)) { histotier *ht = data; update_histotier(ht, s, conf, check, k, 0, 0); } }
static int prune_old_dedupe_hashes(eventer_t e, int mask, void *unused, struct timeval *now) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; uint64_t now_hrtime = mtev_gethrtime() / 1000000000; const char *k; int klen; void *data; struct hash_and_time *hash_with_time; struct removable_hashes { uint64_t key; struct hash_and_time *data; struct removable_hashes *next; }; struct removable_hashes *head = NULL; struct removable_hashes *tail = NULL; /* build a list of expirable items */ while(mtev_hash_next(&dedupe_hashes, &iter, &k, &klen, &data)) { hash_with_time = data; if (now_hrtime > hash_with_time->last_touched_s && now_hrtime - hash_with_time->last_touched_s > 10) { struct removable_hashes *h = calloc(1, sizeof(struct removable_hashes)); h->key = *(uint64_t *)k; h->data = hash_with_time; if (tail != NULL) { tail->next = h; } tail = h; if (head == NULL) { head = tail; } } } /* expire them */ while (head != NULL) { mtev_hash_delete(&dedupe_hashes, (const char *)&head->key, sizeof(head->key), free, NULL); mtev_hash_destroy(&head->data->hash, free, NULL); free(head->data); struct removable_hashes *prev = head; head = head->next; free(prev); } e->whence.tv_sec = now->tv_sec + 5; return 1; }
static void noit_fq_free_metric_hash(void *d) { mtev_hash_table *metrics_table = (mtev_hash_table *)d; if (metrics_table) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; void *entry; const char *key; int klen; while(mtev_hash_next(metrics_table, &iter, &key, &klen, &entry)) { if (key) free((char *)key); if (entry) free ((void *)entry); } } free(metrics_table); }
static void histogram_sweep_calculations(struct histogram_config *conf, noit_check_t *check) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *metric_name; int klen; void *data; mtev_hash_table *metrics; stats_t *c; double *out_q; c = noit_check_get_stats_current(check); /* Only need to do work if it's asked for */ if(!conf->mean && !conf->sum && conf->n_quantiles < 1) return; metrics = noit_check_get_module_metadata(check, histogram_module_id); if(!metrics) return; out_q = alloca(sizeof(double *) * conf->n_quantiles); u_int64_t s = time(NULL); while(mtev_hash_next(metrics, &iter, &metric_name, &klen, &data)) { char mname[1024]; histotier *ht = data; if(ht->last_aggr == NULL) continue; if(conf->mean) { double mean_value; snprintf(mname, sizeof(mname), "%s:mean", metric_name); mean_value = hist_approx_mean(ht->last_aggr); noit_stats_set_metric(check, mname, METRIC_DOUBLE, &mean_value); } if(conf->sum) { double sum; snprintf(mname, sizeof(mname), "%s:sum", metric_name); sum = hist_approx_sum(ht->last_aggr); noit_stats_set_metric(check, mname, METRIC_DOUBLE, &sum); } if(conf->n_quantiles) { if(hist_approx_quantile(ht->last_aggr, conf->quantiles, conf->n_quantiles, out_q) == 0) { int i; for(i=0;i<conf->n_quantiles;i++) { snprintf(mname, sizeof(mname), "%s:q(%0.5f)", metric_name, conf->quantiles[i]); noit_stats_set_metric(check, mname, METRIC_DOUBLE, &out_q[i]); } } } } }
int mtev_dso_list(mtev_hash_table *t, const char ***f) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *name; int klen, i = 0; void *vhdr; if(mtev_hash_size(t) == 0) { *f = NULL; return 0; } *f = calloc(mtev_hash_size(t), sizeof(**f)); while(mtev_hash_next(t, &iter, (const char **)&name, &klen, &vhdr)) { (*f)[i++] = name; } return i; }
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 void mtev_capabilities_tobuff(mtev_capsvc_closure_t *cl, eventer_func_t curr) { const char **mod_names; struct utsname utsn; char vbuff[128], bwstr[4]; mtev_hash_table *lc; mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen, i, nmods; void *data; struct timeval now; struct dso_type *t; xmlDocPtr xmldoc; xmlNodePtr root, cmds, bi, ri, mods, feat; /* fill out capabilities */ /* Create an XML Document */ xmldoc = xmlNewDoc((xmlChar *)"1.0"); root = xmlNewDocNode(xmldoc, NULL, (xmlChar *)capabilities_namespace, NULL); xmlDocSetRootElement(xmldoc, root); /* Fill in the document */ mtev_build_version(vbuff, sizeof(vbuff)); xmlNewTextChild(root, NULL, (xmlChar *)"version", (xmlChar *)vbuff); snprintf(bwstr, sizeof(bwstr), "%d", (int)sizeof(void *)*8); /* Build info */ bi = xmlNewNode(NULL, (xmlChar *)"unameBuild"); xmlSetProp(bi, (xmlChar *)"bitwidth", (xmlChar *)bwstr); xmlAddChild(root, bi); xmlNewTextChild(bi, NULL, (xmlChar *)"sysname", (xmlChar *)UNAME_S); xmlNewTextChild(bi, NULL, (xmlChar *)"nodename", (xmlChar *)UNAME_N); xmlNewTextChild(bi, NULL, (xmlChar *)"release", (xmlChar *)UNAME_R); xmlNewTextChild(bi, NULL, (xmlChar *)"version", (xmlChar *)UNAME_V); xmlNewTextChild(bi, NULL, (xmlChar *)"machine", (xmlChar *)UNAME_M); /* Run info */ ri = xmlNewNode(NULL, (xmlChar *)"unameRun"); xmlSetProp(ri, (xmlChar *)"bitwidth", (xmlChar *)bwstr); xmlAddChild(root, ri); if(uname(&utsn) < 0) { xmlNewTextChild(ri, NULL, (xmlChar *)"error", (xmlChar *)strerror(errno)); } else { xmlNewTextChild(ri, NULL, (xmlChar *)"sysname", (xmlChar *)utsn.sysname); xmlNewTextChild(ri, NULL, (xmlChar *)"nodename", (xmlChar *)utsn.nodename); xmlNewTextChild(ri, NULL, (xmlChar *)"release", (xmlChar *)utsn.release); xmlNewTextChild(ri, NULL, (xmlChar *)"version", (xmlChar *)utsn.version); xmlNewTextChild(ri, NULL, (xmlChar *)"machine", (xmlChar *)utsn.machine); } /* features */ feat = xmlNewNode(NULL, (xmlChar *)"features"); xmlAddChild(root, feat); if(mtev_hash_size(&features)) { mtev_hash_iter iter2 = MTEV_HASH_ITER_ZERO; void *vfv; const char *f; int flen; while(mtev_hash_next(&features, &iter2, &f, &flen, &vfv)) { xmlNodePtr featnode; featnode = xmlNewNode(NULL, (xmlChar *)"feature"); xmlSetProp(featnode, (xmlChar *)"name", (xmlChar *)f); if(vfv) xmlSetProp(featnode, (xmlChar *)"version", (xmlChar *)vfv); xmlAddChild(feat, featnode); } } /* time (poor man's time check) */ gettimeofday(&now, NULL); snprintf(vbuff, sizeof(vbuff), "%llu.%03d", (unsigned long long)now.tv_sec, (int)(now.tv_usec / 1000)); xmlNewTextChild(root, NULL, (xmlChar *)"current_time", (xmlChar *)vbuff); cmds = xmlNewNode(NULL, (xmlChar *)"services"); xmlAddChild(root, cmds); lc = mtev_listener_commands(); while(mtev_hash_next(lc, &iter, &k, &klen, &data)) { xmlNodePtr cnode; char hexcode[11]; const char *name; eventer_func_t *f = (eventer_func_t *)k; mtev_hash_table *sc = (mtev_hash_table *)data; mtev_hash_iter sc_iter = MTEV_HASH_ITER_ZERO; const char *sc_k; int sc_klen; void *sc_data; name = eventer_name_for_callback(*f); cnode = xmlNewNode(NULL, (xmlChar *)"service"); xmlSetProp(cnode, (xmlChar *)"name", name ? (xmlChar *)name : NULL); if(*f == curr) xmlSetProp(cnode, (xmlChar *)"connected", (xmlChar *)"true"); xmlAddChild(cmds, cnode); while(mtev_hash_next(sc, &sc_iter, &sc_k, &sc_klen, &sc_data)) { xmlNodePtr scnode; char *name_copy, *version = NULL; eventer_func_t *f = (eventer_func_t *)sc_data; snprintf(hexcode, sizeof(hexcode), "0x%08x", *((u_int32_t *)sc_k)); name = eventer_name_for_callback(*f); name_copy = strdup(name ? name : "[[unknown]]"); version = strchr(name_copy, '/'); if(version) *version++ = '\0'; scnode = xmlNewNode(NULL, (xmlChar *)"command"); xmlSetProp(scnode, (xmlChar *)"name", (xmlChar *)name_copy); if(version) xmlSetProp(scnode, (xmlChar *)"version", (xmlChar *)version); xmlSetProp(scnode, (xmlChar *)"code", (xmlChar *)hexcode); xmlAddChild(cnode, scnode); free(name_copy); } } mods = xmlNewNode(NULL, (xmlChar *)"modules"); xmlAddChild(root, mods); #define list_modules(func, name) do { \ nmods = func(&mod_names); \ for(i=0; i<nmods; i++) { \ xmlNodePtr pnode; \ pnode = xmlNewNode(NULL, (xmlChar *)"module"); \ xmlSetProp(pnode, (xmlChar *)"type", (xmlChar *)name); \ xmlSetProp(pnode, (xmlChar *)"name", (xmlChar *)mod_names[i]); \ xmlAddChild(mods, pnode); \ } \ if(mod_names) free(mod_names); \ } while(0) for(t = mtev_dso_get_types(); t; t = t->next) list_modules(t->list, t->name); /* Write it out to a buffer and copy it for writing */ cl->buff = mtev_xmlSaveToBuffer(xmldoc); cl->towrite = strlen(cl->buff); /* Clean up after ourselves */ xmlFreeDoc(xmldoc); }
static int rest_show_check(mtev_http_rest_closure_t *restc, int npats, char **pats) { mtev_http_session_ctx *ctx = restc->http_ctx; xmlXPathObjectPtr pobj = NULL; xmlXPathContextPtr xpath_ctxt = NULL; xmlDocPtr doc = NULL; xmlNodePtr node, root, attr, config, state, tmp, anode; uuid_t checkid; noit_check_t *check; char xpath[1024], *uuid_conf, *module = NULL, *value = NULL; int rv, mod, mod_cnt, cnt, error_code = 500; mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *data; mtev_hash_table *configh; if(npats != 2 && npats != 3) goto error; rv = noit_check_xpath(xpath, sizeof(xpath), pats[0], pats[1]); if(rv == 0) goto not_found; if(rv < 0) goto error; mtev_conf_xml_xpath(NULL, &xpath_ctxt); pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt); if(!pobj || pobj->type != XPATH_NODESET || xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto not_found; cnt = xmlXPathNodeSetGetLength(pobj->nodesetval); if(cnt != 1) goto error; node = (mtev_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0); uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid"); if(!uuid_conf || uuid_parse(uuid_conf, checkid)) goto error; if(npats == 3 && !strcmp(pats[2], ".json")) { return rest_show_check_json(restc, checkid); } doc = xmlNewDoc((xmlChar *)"1.0"); root = xmlNewDocNode(doc, NULL, (xmlChar *)"check", NULL); xmlDocSetRootElement(doc, root); #define MYATTR(node,a,n,b) _mtev_conf_get_string(node, &(n), "@" #a, &(b)) #define INHERIT(node,a,n,b) \ _mtev_conf_get_string(node, &(n), "ancestor-or-self::node()/@" #a, &(b)) #define SHOW_ATTR(parent, node, a) do { \ char *_value = NULL; \ INHERIT(node, a, anode, _value); \ if(_value != NULL) { \ int clen, plen;\ char *_cpath, *_apath; \ xmlNodePtr child; \ _cpath = node ? (char *)xmlGetNodePath(node) : strdup(""); \ _apath = anode ? (char *)xmlGetNodePath(anode) : strdup(""); \ clen = strlen(_cpath); \ plen = strlen("/noit/checks"); \ child = xmlNewNode(NULL, (xmlChar *)#a); \ xmlNodeAddContent(child, (xmlChar *)_value); \ if(!strncmp(_cpath, _apath, clen) && _apath[clen] == '/') { \ } \ else { \ xmlSetProp(child, (xmlChar *)"inherited", (xmlChar *)_apath+plen); \ } \ xmlAddChild(parent, child); \ free(_cpath); \ free(_apath); \ free(_value); \ } \ } while(0) attr = xmlNewNode(NULL, (xmlChar *)"attributes"); xmlAddChild(root, attr); SHOW_ATTR(attr,node,uuid); SHOW_ATTR(attr,node,seq); /* Name is odd, it falls back transparently to module */ if(!INHERIT(node, module, tmp, module)) module = NULL; xmlAddChild(attr, (tmp = xmlNewNode(NULL, (xmlChar *)"name"))); if(MYATTR(node, name, anode, value)) xmlNodeAddContent(tmp, (xmlChar *)value); else if(module) xmlNodeAddContent(tmp, (xmlChar *)module); if(value) free(value); if(module) free(module); SHOW_ATTR(attr,node,module); SHOW_ATTR(attr,node,target); SHOW_ATTR(attr,node,resolve_rtype); SHOW_ATTR(attr,node,seq); SHOW_ATTR(attr,node,period); SHOW_ATTR(attr,node,timeout); SHOW_ATTR(attr,node,oncheck); SHOW_ATTR(attr,node,filterset); SHOW_ATTR(attr,node,disable); /* Add the config */ config = xmlNewNode(NULL, (xmlChar *)"config"); configh = mtev_conf_get_hash(node, "config"); while(mtev_hash_next(configh, &iter, &k, &klen, &data)) NODE_CONTENT(config, k, data); mtev_hash_destroy(configh, free, free); free(configh); mod_cnt = noit_check_registered_module_cnt(); for(mod=0; mod<mod_cnt; mod++) { xmlNsPtr ns; const char *nsname; char buff[256]; nsname = noit_check_registered_module(mod); snprintf(buff, sizeof(buff), "noit://module/%s", nsname); ns = xmlSearchNs(root->doc, root, (xmlChar *)nsname); if(!ns) ns = xmlNewNs(root, (xmlChar *)buff, (xmlChar *)nsname); if(ns) { configh = mtev_conf_get_namespaced_hash(node, "config", nsname); if(configh) { memset(&iter, 0, sizeof(iter)); while(mtev_hash_next(configh, &iter, &k, &klen, &data)) { NS_NODE_CONTENT(config, ns, "value", data, xmlSetProp(tmp, (xmlChar *)"name", (xmlChar *)k); ); } mtev_hash_destroy(configh, free, free); free(configh); } } }
struct json_object * noit_check_state_as_json(noit_check_t *check, int full) { stats_t *c; char seq_str[64]; char id_str[UUID_STR_LEN+1]; struct json_object *j_last_run, *j_next_run; struct timeval *t; u_int64_t ms = 0; struct json_object *doc; uuid_unparse_lower(check->checkid, id_str); doc = json_object_new_object(); json_object_object_add(doc, "id", json_object_new_string(id_str)); json_object_object_add(doc, "name", json_object_new_string(check->name)); json_object_object_add(doc, "module", json_object_new_string(check->module)); json_object_object_add(doc, "target", json_object_new_string(check->target)); json_object_object_add(doc, "target_ip", json_object_new_string(check->target_ip)); json_object_object_add(doc, "filterset", json_object_new_string(check->filterset)); snprintf(seq_str, sizeof(seq_str), "%lld", (long long)check->config_seq); json_object_object_add(doc, "seq", json_object_new_string(seq_str)); json_object_object_add(doc, "period", json_object_new_int(check->period)); json_object_object_add(doc, "timeout", json_object_new_int(check->timeout)); json_object_object_add(doc, "flags", json_object_new_int(check->flags)); c = noit_check_get_stats_current(check); t = noit_check_stats_whence(c, NULL); j_last_run = json_object_new_int(ms); json_object_set_int_overflow(j_last_run, json_overflow_uint64); ms = t->tv_sec; ms *= 1000ULL; ms += t->tv_usec/1000; json_object_set_uint64(j_last_run, ms); json_object_object_add(doc, "last_run", j_last_run); t = check->fire_event ? &check->fire_event->whence : NULL; if(t) { j_next_run = json_object_new_int(ms); json_object_set_int_overflow(j_next_run, json_overflow_uint64); ms = t->tv_sec; ms *= 1000ULL; ms += t->tv_usec/1000; json_object_set_uint64(j_next_run, ms); json_object_object_add(doc, "next_run", j_next_run); } if(full) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *data; mtev_hash_table *configh; char timestr[20]; struct json_object *status, *metrics, *config; /* config */ config = json_object_new_object(); configh = check->config; while(mtev_hash_next(configh, &iter, &k, &klen, &data)) json_object_object_add(config, k, json_object_new_string(data)); json_object_object_add(doc, "config", config); /* status */ status = json_object_new_object(); switch(noit_check_stats_available(c, NULL)) { case NP_UNKNOWN: break; case NP_AVAILABLE: json_object_object_add(status, "available", json_object_new_boolean(1)); break; case NP_UNAVAILABLE: json_object_object_add(status, "available", json_object_new_boolean(0)); break; } switch(noit_check_stats_state(c, NULL)) { case NP_UNKNOWN: break; case NP_GOOD: json_object_object_add(status, "good", json_object_new_boolean(1)); break; case NP_BAD: json_object_object_add(status, "good", json_object_new_boolean(0)); break; } json_object_object_add(doc, "status", status); metrics = json_object_new_object(); t = noit_check_stats_whence(c, NULL); if(t->tv_sec) { json_object_object_add(metrics, "current", stats_to_json(c)); snprintf(timestr, sizeof(timestr), "%llu%03d", (unsigned long long int)t->tv_sec, (int)(t->tv_usec / 1000)); json_object_object_add(metrics, "current_timestamp", json_object_new_string(timestr)); } c = noit_check_get_stats_inprogress(check); t = noit_check_stats_whence(c, NULL); if(t->tv_sec) { json_object_object_add(metrics, "inprogress", stats_to_json(c)); snprintf(timestr, sizeof(timestr), "%llu%03d", (unsigned long long int)t->tv_sec, (int)(t->tv_usec / 1000)); json_object_object_add(metrics, "inprogress_timestamp", json_object_new_string(timestr)); } c = noit_check_get_stats_previous(check); t = noit_check_stats_whence(c, NULL); if(t->tv_sec) { json_object_object_add(metrics, "previous", stats_to_json(c)); snprintf(timestr, sizeof(timestr), "%llu%03d", (unsigned long long int)t->tv_sec, (int)(t->tv_usec / 1000)); json_object_object_add(metrics, "previous_timestamp", json_object_new_string(timestr)); } json_object_object_add(doc, "metrics", metrics); } return doc; }
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; }
static int stratcon_datastore_journal_sync(eventer_t e, int mask, void *closure, struct timeval *now) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *vij; interim_journal_t *ij; syncset_t *syncset = closure; if((mask & EVENTER_ASYNCH) == EVENTER_ASYNCH) { if(syncset->completion) { eventer_add(syncset->completion); eventer_trigger(syncset->completion, EVENTER_READ | EVENTER_WRITE); } free(syncset); return 0; } if(!((mask & EVENTER_ASYNCH_WORK) == EVENTER_ASYNCH_WORK)) return 0; mtevL(ds_deb, "Syncing journal sets...\n"); if (syncset->ws) { while(mtev_hash_next(syncset->ws, &iter, &k, &klen, &vij)) { char tmppath[PATH_MAX], id_str[32]; int suffix_idx; ij = vij; mtevL(ds_deb, "Syncing journal set [%s,%s,%s]\n", ij->remote_str, ij->remote_cn, ij->fqdn); strlcpy(tmppath, ij->filename, sizeof(tmppath)); suffix_idx = strlen(ij->filename) - 4; /* . t m p */ ij->filename[suffix_idx] = '\0'; if(rename(tmppath, ij->filename) != 0) { if(errno == EEXIST) { unlink(ij->filename); if(rename(tmppath, ij->filename) != 0) goto rename_failed; } else { rename_failed: mtevL(noit_error, "rename failed(%s): (%s->%s)\n", strerror(errno), tmppath, ij->filename); exit(-1); } } if(ij->fd >= 0) { fsync(ij->fd); close(ij->fd); } ij->fd = -1; snprintf(id_str, sizeof(id_str), "%d", ij->storagenode_id); stratcon_ingest(ij->filename, ij->remote_str, ij->remote_cn, id_str, mtev_false); } mtev_hash_destroy(syncset->ws, free, interim_journal_free); free(syncset->ws); } else { mtevL(noit_error, "attempted to sync non-existing working set\n"); } return 0; }
static int noit_console_config_show(mtev_console_closure_t ncct, int argc, char **argv, mtev_console_state_t *state, void *closure) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *data; int i, cnt, titled = 0, cliplen = 0; const char *path = "", *basepath = NULL; char xpath[1024]; mtev_conf_t_userdata_t *info = NULL; mtev_hash_table *config; xmlXPathObjectPtr pobj = NULL; xmlXPathContextPtr xpath_ctxt = NULL, current_ctxt; xmlDocPtr master_config = NULL; xmlNodePtr node = NULL; mtev_conf_xml_xpath(&master_config, &xpath_ctxt); if(argc > 1) { nc_printf(ncct, "too many arguments\n"); return -1; } info = mtev_console_userdata_get(ncct, MTEV_CONF_T_USERDATA); if(info && info->path) path = basepath = info->path; if(!info && argc == 0) { nc_printf(ncct, "argument required when not in configuration mode\n"); return -1; } if(argc == 1) path = argv[0]; if(!basepath) basepath = path; /* { / } is a special case */ if(!strcmp(basepath, "/")) basepath = ""; if(!strcmp(path, "/")) path = ""; if(!master_config) { nc_printf(ncct, "no config\n"); return -1; } /* { / } is the only path that will end with a / * in XPath { / / * } means something _entirely different than { / * } * Ever notice how it is hard to describe xpath in C comments? */ /* We don't want to show the root node */ cliplen = strlen("/noit/"); /* If we are in configuration mode * and we are without an argument or the argument is absolute, * clip the current path off */ if(info && (argc == 0 || path[0] != '/')) cliplen += strlen(basepath); if(!path[0] || path[0] == '/') /* base only, or absolute path requested */ snprintf(xpath, sizeof(xpath), "/noit%s/@*", path); else snprintf(xpath, sizeof(xpath), "/noit%s/%s/@*", basepath, path); current_ctxt = xpath_ctxt; pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt); if(!pobj || pobj->type != XPATH_NODESET) { nc_printf(ncct, "no such object\n"); goto bad; } cnt = xmlXPathNodeSetGetLength(pobj->nodesetval); titled = 0; for(i=0; i<cnt; i++) { node = (mtev_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i); if(!strcmp((char *)node->name, "check")) continue; if(node->children && node->children == xmlGetLastChild(node) && xmlNodeIsText(node->children)) { char *node_str, *xmlpath; node_str = (char *)xmlXPathCastNodeToString(node->children); xmlpath = (char *)xmlGetNodePath(node); if(!titled++) nc_printf(ncct, "== Section Settings ==\n"); nc_printf(ncct, "%s: %s\n", xmlpath + cliplen, node_str); free(xmlpath); free(node_str); } } xmlXPathFreeObject(pobj); /* Print out all the config settings */ if(!path[0] || path[0] == '/') /* base only, or absolute path requested */ snprintf(xpath, sizeof(xpath), "/noit%s", path); else snprintf(xpath, sizeof(xpath), "/noit%s/%s", basepath, path); pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt); if(!pobj || pobj->type != XPATH_NODESET) { nc_printf(ncct, "no such object\n"); goto bad; } cnt = xmlXPathNodeSetGetLength(pobj->nodesetval); if(cnt > 0) { node = (mtev_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0); titled = 0; config = mtev_conf_get_hash(node, "config"); while(mtev_hash_next(config, &iter, &k, &klen, &data)) { if(!titled++) nc_printf(ncct, "== Section [Aggregated] Config ==\n"); nc_printf(ncct, "config::%s: %s\n", k, (const char *)data); } mtev_hash_destroy(config, free, free); free(config); } xmlXPathFreeObject(pobj); /* _shorten string_ turning last { / @ * } to { / * } */ if(!path[0] || path[0] == '/') /* base only, or absolute path requested */ snprintf(xpath, sizeof(xpath), "/noit%s/*", path); else snprintf(xpath, sizeof(xpath), "/noit%s/%s/*", basepath, path); pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt); if(!pobj || pobj->type != XPATH_NODESET) { nc_printf(ncct, "no such object\n"); goto bad; } cnt = xmlXPathNodeSetGetLength(pobj->nodesetval); titled = 0; for(i=0; i<cnt; i++) { char *xmlpath; node = (mtev_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i); if(!strcmp((char *)node->name, "check")) continue; if(!strcmp((char *)node->name, "filterset")) continue; xmlpath = (char *)xmlGetNodePath(node); if(strcmp(xmlpath + cliplen, "config")) { if(!(node->children && node->children == xmlGetLastChild(node) && xmlNodeIsText(node->children))) { if(!titled++) nc_printf(ncct, "== Subsections ==\n"); nc_printf(ncct, "%s\n", xmlpath + cliplen); } } free(xmlpath); } titled = 0; for(i=0; i<cnt; i++) { node = (mtev_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i); if(!strcmp((char *)node->name, "filterset")) { xmlAttr *attr; char *filter_name = NULL; for(attr=node->properties; attr; attr = attr->next) { if(!strcmp((char *)attr->name, "name")) filter_name = (char *)xmlXPathCastNodeToString(attr->children); } if(filter_name) { nc_printf(ncct, "filterset[@name=\"%s\"]\n", filter_name); xmlFree(filter_name); } else nc_printf(ncct, "fitlerset\n"); } else if(!strcmp((char *)node->name, "check")) { int busted = 1; xmlAttr *attr; char *uuid_str = NULL; uuid_t checkid; if(!titled++) nc_printf(ncct, "== Checks ==\n"); for(attr=node->properties; attr; attr = attr->next) { if(!strcmp((char *)attr->name, "uuid")) { uuid_str = (char *)xmlXPathCastNodeToString(attr->children); break; } } nc_printf(ncct, "check[@uuid=\"%s\"] ", uuid_str ? uuid_str : "undefined"); if(uuid_str && uuid_parse(uuid_str, checkid) == 0) { noit_check_t *check; check = noit_poller_lookup(checkid); if(check) { busted = 0; nc_printf(ncct, "%s`%s`%s", check->target, check->module, check->name); } } if(uuid_str) free(uuid_str); if(busted) nc_printf(ncct, "[check not in running system]"); nc_write(ncct, "\n", 1); } } xmlXPathFreeObject(pobj); return 0; bad: if(pobj) xmlXPathFreeObject(pobj); return -1; }
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; }
int noit_filtersets_cull_unused() { mtev_hash_table active = MTEV_HASH_EMPTY; char *buffer = NULL; mtev_conf_section_t *declares; int i, n_uses = 0, n_declares = 0, removed = 0; const char *declare_xpath = "//filterset[@name and not (@cull='false')]"; declares = mtev_conf_get_sections(NULL, declare_xpath, &n_declares); if(declares) { /* store all unit filtersets used */ for(i=0;i<n_declares;i++) { if(!buffer) buffer = malloc(128); if(mtev_conf_get_stringbuf(declares[i], "@name", buffer, 128)) { if(mtev_hash_store(&active, buffer, strlen(buffer), declares[i])) { buffer = NULL; } else { void *vnode = NULL; /* We've just hit a duplicate.... check to see if there's an existing * entry and if there is, load the latest one and delete the old * one. */ mtev_hash_retrieve(&active, buffer, strlen(buffer), &vnode); if (vnode) { noit_filter_compile_add(declares[i]); CONF_REMOVE(vnode); xmlUnlinkNode(vnode); xmlFreeNode(vnode); removed++; if(mtev_hash_replace(&active, buffer, strlen(buffer), declares[i], free, NULL)) { buffer = NULL; } } } } } if(buffer) free(buffer); free(declares); } n_uses = noit_poller_do(filterset_accum, &active); if(n_uses > 0 && mtev_hash_size(&active) > 0) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *filter_name; int filter_name_len; void *vnode; while(mtev_hash_next(&active, &iter, &filter_name, &filter_name_len, &vnode)) { if(noit_filter_remove(vnode)) { CONF_REMOVE(vnode); xmlUnlinkNode(vnode); xmlFreeNode(vnode); removed++; } } } mtev_hash_destroy(&active, free, NULL); return removed; }
static void mtev_capabilities_tobuff_json(mtev_capsvc_closure_t *cl, eventer_func_t curr) { const char **mod_names; struct utsname utsn; char vbuff[128]; mtev_hash_table *lc; mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen, i, nmods; void *data; struct timeval now; struct dso_type *t; struct json_object *doc; struct json_object *svcs, *bi, *ri, *mods, *feat; /* fill out capabilities */ /* Create an XML Document */ doc = json_object_new_object(); /* Fill in the document */ mtev_build_version(vbuff, sizeof(vbuff)); json_object_object_add(doc, "version", json_object_new_string(vbuff)); /* Build info */ bi = json_object_new_object(); json_object_object_add(bi, "bitwidth", json_object_new_int(sizeof(void *)*8)); json_object_object_add(bi, "sysname", json_object_new_string(UNAME_S)); json_object_object_add(bi, "nodename", json_object_new_string(UNAME_N)); json_object_object_add(bi, "release", json_object_new_string(UNAME_R)); json_object_object_add(bi, "version", json_object_new_string(UNAME_V)); json_object_object_add(bi, "machine", json_object_new_string(UNAME_M)); json_object_object_add(doc, "unameBuild", bi); /* Run info */ ri = json_object_new_object(); json_object_object_add(ri, "bitwidth", json_object_new_int(sizeof(void *)*8)); if(uname(&utsn) < 0) { json_object_object_add(ri, "error", json_object_new_string(strerror(errno))); } else { json_object_object_add(ri, "sysname", json_object_new_string(utsn.sysname)); json_object_object_add(ri, "nodename", json_object_new_string(utsn.nodename)); json_object_object_add(ri, "release", json_object_new_string(utsn.release)); json_object_object_add(ri, "version", json_object_new_string(utsn.version)); json_object_object_add(ri, "machine", json_object_new_string(utsn.machine)); } json_object_object_add(doc, "unameRun", ri); /* features */ feat = json_object_new_object(); if(mtev_hash_size(&features)) { mtev_hash_iter iter2 = MTEV_HASH_ITER_ZERO; void *vfv; const char *f; int flen; while(mtev_hash_next(&features, &iter2, &f, &flen, &vfv)) { struct json_object *featnode; featnode = json_object_new_object(); if(vfv) json_object_object_add(featnode, "version", json_object_new_string(vfv)); json_object_object_add(feat, f, featnode); } } json_object_object_add(doc, "features", feat); /* time (poor man's time check) */ gettimeofday(&now, NULL); snprintf(vbuff, sizeof(vbuff), "%llu%03d", (unsigned long long)now.tv_sec, (int)(now.tv_usec / 1000)); json_object_object_add(doc, "current_time", json_object_new_string(vbuff)); svcs = json_object_new_object(); lc = mtev_listener_commands(); while(mtev_hash_next(lc, &iter, &k, &klen, &data)) { struct json_object *cnode, *cmds; char hexcode[11]; const char *name; eventer_func_t *f = (eventer_func_t *)k; mtev_hash_table *sc = (mtev_hash_table *)data; mtev_hash_iter sc_iter = MTEV_HASH_ITER_ZERO; const char *sc_k; int sc_klen; void *sc_data; name = eventer_name_for_callback(*f); cnode = json_object_new_object(); if(klen == 8) snprintf(hexcode, sizeof(hexcode), "0x%0llx", (unsigned long long int)(vpsized_uint)**f); else snprintf(hexcode, sizeof(hexcode), "0x%0x", (unsigned int)(vpsized_uint)**f); json_object_object_add(svcs, hexcode, cnode); if(name) json_object_object_add(cnode, name, json_object_new_string(name)); cmds = json_object_new_object(); json_object_object_add(cnode, "commands", cmds); while(mtev_hash_next(sc, &sc_iter, &sc_k, &sc_klen, &sc_data)) { struct json_object *scnode; char *name_copy, *version = NULL; eventer_func_t *f = (eventer_func_t *)sc_data; scnode = json_object_new_object(); snprintf(hexcode, sizeof(hexcode), "0x%08x", *((u_int32_t *)sc_k)); name = eventer_name_for_callback(*f); name_copy = strdup(name ? name : "[[unknown]]"); version = strchr(name_copy, '/'); if(version) *version++ = '\0'; json_object_object_add(scnode, "name", json_object_new_string(name_copy)); if(version) json_object_object_add(scnode, "version", json_object_new_string(version)); json_object_object_add(cmds, hexcode, scnode); free(name_copy); } } json_object_object_add(doc, "services", svcs); mods = json_object_new_object(); #define list_modules_json(func, name) do { \ nmods = func(&mod_names); \ for(i=0; i<nmods; i++) { \ struct json_object *pnode; \ pnode = json_object_new_object(); \ json_object_object_add(pnode, "type", json_object_new_string(name)); \ json_object_object_add(mods, mod_names[i], pnode); \ } \ if(mod_names) free(mod_names); \ } while(0) for(t = mtev_dso_get_types(); t; t = t->next) list_modules_json(t->list, t->name); json_object_object_add(doc, "modules", mods); /* Write it out to a buffer and copy it for writing */ cl->buff = strdup(json_object_to_json_string(doc)); cl->towrite = strlen(cl->buff); /* Clean up after ourselves */ json_object_put(doc); }
int mtev_hash_adv(mtev_hash_table *h, mtev_hash_iter *iter) { return mtev_hash_next(h, iter, &iter->key.str, &iter->klen, &iter->value.ptr); }