static int metric_summary(datum_t *key, datum_t *val, void *arg) { client_t *client = (client_t*) arg; char *name = (char*) key->data; char *type; char sum[256]; Metric_t *metric = (Metric_t*) val->data; struct type_tag *tt; int rc,i; type = getfield(metric->strings, metric->type); tt = in_type_list(type, strlen(type)); if (!tt) return 0; /* We sum everything in double to properly combine integer sources (3.0) with float sources (3.1). This also avoids wraparound errors: for example memory KB exceeding 4TB. */ switch (tt->type) { case INT: case UINT: sprintf(sum, "%.f", metric->val.d); break; case FLOAT: sprintf(sum, "%.*f", (int) metric->precision, metric->val.d); break; default: break; } char buf[16 * 1024]; char *b = buf; #define xml_print(client, ...) 0; b += snprintf(b, sizeof(buf) - (b - buf), __VA_ARGS__); rc = xml_print(client, "<METRICS NAME=\"%s\" SUM=\"%s\" NUM=\"%u\" " "TYPE=\"%s\" UNITS=\"%s\" SLOPE=\"%s\" SOURCE=\"%s\">\n", name, sum, metric->num, "double", /* we always report double sums */ getfield(metric->strings, metric->units), getfield(metric->strings, metric->slope), getfield(metric->strings, metric->source)); rc = xml_print(client, "<EXTRA_DATA>\n"); for (i=0; !rc && i<metric->ednameslen; i++) { rc=xml_print(client, "<EXTRA_ELEMENT NAME=\"%s\" VAL=\"%s\"/>\n", getfield(metric->strings, metric->ednames[i]), getfield(metric->strings, metric->edvalues[i])); } rc = xml_print(client, "</EXTRA_DATA>\n"); rc=xml_print(client, "</METRICS>\n"); #undef xml_print rc = xml_print(client, "%s", buf); return rc; }
/* Write a metric summary value to the RRD database. */ static int finish_processing_source(datum_t *key, datum_t *val, void *arg) { xmldata_t *xmldata = (xmldata_t *) arg; char *name, *type; char sum[512]; char num[256]; Metric_t *metric; struct type_tag *tt; llist_entry *le; name = (char*) key->data; metric = (Metric_t*) val->data; type = getfield(metric->strings, metric->type); /* Don't save to RRD if the datasource is dead or write_rrds is off */ if( xmldata->ds->dead || gmetad_config.write_rrds != 1) return 1; tt = in_type_list(type, strlen(type)); if (!tt) return 0; /* Don't save to RRD if this is a metric not to be summarized */ if (llist_search(&(gmetad_config.unsummarized_metrics), (void *)name, llist_strncmp, &le) == 0) return 0; switch (tt->type) { case INT: case UINT: sprintf(sum, "%.f", metric->val.d); break; case FLOAT: sprintf(sum, "%.*f", (int) metric->precision, metric->val.d); break; default: break; } sprintf(num, "%u", metric->num); /* Save the data to a round robin database if this data source is * alive. */ if (!xmldata->ds->dead && !xmldata->rval) { debug_msg("Writing Summary data for source %s, metric %s", xmldata->sourcename, name); xmldata->rval = write_data_to_rrd(xmldata->sourcename, NULL, name, sum, num, xmldata->ds->step, xmldata->source.localtime, cstr_to_slope(getfield(metric->strings, metric->slope))); } return xmldata->rval; }
/* Sums the metric summaries from all data sources. */ static int sum_metrics(datum_t *key, datum_t *val, void *arg) { datum_t *hash_datum, *rdatum; Metric_t *rootmetric, *metric; char *type; struct type_tag *tt; int do_sum = 1; metric = (Metric_t *) val->data; type = getfield(metric->strings, metric->type); hash_datum = hash_lookup(key, root.metric_summary); if (!hash_datum) { hash_datum = datum_new((char*) metric, val->size); do_sum = 0; } rootmetric = (Metric_t*) hash_datum->data; if (do_sum) { tt = in_type_list(type, strlen(type)); if (!tt) { datum_free(hash_datum); return 0; } /* We sum everything in double to properly combine integer sources (3.0) with float sources (3.1). This also avoids wraparound errors: for example memory KB exceeding 4TB. */ switch (tt->type) { case INT: case UINT: case FLOAT: rootmetric->val.d += metric->val.d; break; default: break; } rootmetric->num += metric->num; } rdatum = hash_insert(key, hash_datum, root.metric_summary); datum_free(hash_datum); if (!rdatum) return 1; else return 0; }
static int write_root_summary(datum_t *key, datum_t *val, void *arg) { char *name, *type; char sum[256]; char num[256]; Metric_t *metric; int rc; struct type_tag *tt; llist_entry *le; char *p; name = (char*) key->data; metric = (Metric_t*) val->data; type = getfield(metric->strings, metric->type); /* Summarize all numeric metrics */ tt = in_type_list(type, strlen(type)); /* Don't write a summary for an unknown or STRING type */ if (!tt || (tt->type == STRING)) return 0; /* Don't write a summary for metrics not to be summarized */ if (llist_search(&(gmetad_config.unsummarized_metrics), (void *)key->data, llist_strncmp, &le) == 0) return 0; /* Don't write a summary for metris that appears to be sFlow VM metrics */ if (gmetad_config.unsummarized_sflow_vm_metrics && (p = strchr(name, '.')) != NULL && *(p+1) == 'v') return 0; ganglia_scoreboard_inc(METS_SUMRZ_ROOT); /* We log all our sums in double which does not suffer from wraparound errors: for example memory KB exceeding 4TB. -twitham */ sprintf(sum, "%.5f", metric->val.d); sprintf(num, "%u", metric->num); /* err_msg("Writing Overall Summary for metric %s (%s)", name, sum); */ /* Save the data to a rrd file unless write_rrds == off */ if (gmetad_config.write_rrds == 0) return 0; debug_msg("Writing Root Summary data for metric %s", name); rc = write_data_to_rrd( NULL, NULL, name, sum, num, 15, 0, cstr_to_slope(getfield(metric->strings, metric->slope))); if (rc) { err_msg("Unable to write meta data for metric %s to RRD", name); } return 0; }
static int write_root_summary(datum_t *key, datum_t *val, void *arg) { char *name, *type; char sum[256]; char num[256]; Metric_t *metric; int rc; struct type_tag *tt; name = (char*) key->data; metric = (Metric_t*) val->data; type = getfield(metric->strings, metric->type); /* Summarize all numeric metrics */ tt = in_type_list(type, strlen(type)); /* Don't write a summary for an unknown or STRING type. */ if (!tt || (tt->type == STRING)) return 0; /* We log all our sums in double which does not suffer from wraparound errors: for example memory KB exceeding 4TB. -twitham */ sprintf(sum, "%.5f", metric->val.d); sprintf(num, "%u", metric->num); /* err_msg("Writing Overall Summary for metric %s (%s)", name, sum); */ /* Save the data to a rrd file unless write_rrds == off */ if (gmetad_config.write_rrds == 0) return 0; rc = write_data_to_rrd( NULL, NULL, name, sum, num, 15, 0, metric->slope); if (rc) { err_msg("Unable to write meta data for metric %s to RRD", name); } return 0; }
static int startElement_METRICS(void *data, const char *el, const char **attr) { xmldata_t *xmldata = (xmldata_t *)data; struct xml_tag *xt; struct type_tag *tt; datum_t *hash_datum = NULL; datum_t *rdatum; datum_t hashkey, hashval; const char *name = NULL; const char *metricval = NULL; const char *metricnum = NULL; const char *type = NULL; int i; hash_t *summary; Metric_t *metric; /* In non-scalable mode, we do not process summary data. */ if (!gmetad_config.scalable_mode) return 0; /* Get name for hash key, and val/type for summaries. */ for(i = 0; attr[i]; i+=2) { xt = in_xml_list(attr[i], strlen(attr[i])); if (!xt) continue; switch (xt->tag) { case NAME_TAG: name = attr[i+1]; hashkey.data = (void*) name; hashkey.size = strlen(name) + 1; break; case TYPE_TAG: type = attr[i+1]; break; case SUM_TAG: metricval = attr[i+1]; break; case NUM_TAG: metricnum = attr[i+1]; default: break; } } summary = xmldata->source.metric_summary; hash_datum = hash_lookup(&hashkey, summary); if (!hash_datum) { metric = &(xmldata->metric); memset((void*) metric, 0, sizeof(*metric)); fillmetric(attr, metric, type); } else { memcpy(&xmldata->metric, hash_datum->data, hash_datum->size); datum_free(hash_datum); metric = &(xmldata->metric); tt = in_type_list(type, strlen(type)); if (!tt) return 0; switch (tt->type) { case INT: case UINT: case FLOAT: metric->val.d += (double) strtod(metricval, (char**) NULL); break; default: break; } metric->num += atoi(metricnum); } /* Update metric in summary table. */ hashval.size = sizeof(*metric) - GMETAD_FRAMESIZE + metric->stringslen; hashval.data = (void*) metric; summary = xmldata->source.metric_summary; rdatum = hash_insert(&hashkey, &hashval, summary); if (!rdatum) { err_msg("Could not insert %s metric", name); return 1; } return 0; }
/* Populates a Metric_t structure from a list of XML metric attribute strings. * We need the type string here because we cannot be sure it comes before * the metric value in the attribute list. */ static void fillmetric(const char** attr, Metric_t *metric, const char* type) { int i; /* INV: always points to the next free byte in metric.strings buffer. */ int edge = 0; struct type_tag *tt; struct xml_tag *xt; char *metricval, *p; /* For old versions of gmond. */ metric->slope = -1; for(i = 0; attr[i] ; i+=2) { /* Only process the XML tags that gmetad is interested in */ xt = in_xml_list (attr[i], strlen(attr[i])); if (!xt) continue; switch( xt->tag ) { case SUM_TAG: case VAL_TAG: metricval = (char*) attr[i+1]; tt = in_type_list(type, strlen(type)); if (!tt) return; switch (tt->type) { case INT: case TIMESTAMP: case UINT: case FLOAT: metric->val.d = (double) strtod(metricval, (char**) NULL); p = strrchr(metricval, '.'); if (p) metric->precision = (short int) strlen(p+1); break; case STRING: /* We store string values in the 'valstr' field. */ break; } metric->valstr = addstring(metric->strings, &edge, metricval); break; case TYPE_TAG: metric->type = addstring(metric->strings, &edge, attr[i+1]); break; case UNITS_TAG: metric->units = addstring(metric->strings, &edge, attr[i+1]); break; case TN_TAG: metric->tn = atoi(attr[i+1]); break; case TMAX_TAG: metric->tmax = atoi(attr[i+1]); break; case DMAX_TAG: metric->dmax = atoi(attr[i+1]); break; case SLOPE_TAG: metric->slope = addstring(metric->strings, &edge, attr[i+1]); break; case SOURCE_TAG: metric->source = addstring(metric->strings, &edge, attr[i+1]); break; case NUM_TAG: metric->num = atoi(attr[i+1]); break; default: break; } } metric->stringslen = edge; /* We are ok with growing metric values b/c we write to a full-sized * buffer in xmldata. */ }
static int startElement_METRIC(void *data, const char *el, const char **attr) { xmldata_t *xmldata = (xmldata_t *)data; ganglia_slope_t slope = GANGLIA_SLOPE_UNSPECIFIED; struct xml_tag *xt; struct type_tag *tt; datum_t *hash_datum = NULL; datum_t *rdatum; datum_t hashkey, hashval; const char *name = NULL; const char *metricval = NULL; const char *type = NULL; int do_summary; int i, edge, carbon_ret; hash_t *summary; Metric_t *metric; if (!xmldata->host_alive ) return 0; /* Get name for hash key, and val/type for summaries. */ for(i = 0; attr[i]; i+=2) { xt = in_xml_list(attr[i], strlen(attr[i])); if (!xt) continue; switch (xt->tag) { case NAME_TAG: name = attr[i+1]; hashkey.data = (void*) name; hashkey.size = strlen(name) + 1; break; case VAL_TAG: metricval = attr[i+1]; break; case TYPE_TAG: type = attr[i+1]; break; case SLOPE_TAG: slope = cstr_to_slope(attr[i+1]); default: break; } } metric = &(xmldata->metric); memset((void*) metric, 0, sizeof(*metric)); /* Summarize all numeric metrics */ do_summary = 0; tt = in_type_list(type, strlen(type)); if (!tt) return 0; if (tt->type==INT || tt->type==UINT || tt->type==FLOAT) do_summary = 1; /* Only keep metric details if we are the authority on this cluster. */ if (authority_mode(xmldata)) { /* Save the data to a round robin database if the data source is alive */ fillmetric(attr, metric, type); if (metric->dmax && metric->tn > metric->dmax) return 0; if (do_summary && !xmldata->ds->dead && !xmldata->rval) { debug_msg("Updating host %s, metric %s", xmldata->hostname, name); if ( gmetad_config.write_rrds == 1 ) xmldata->rval = write_data_to_rrd(xmldata->sourcename, xmldata->hostname, name, metricval, NULL, xmldata->ds->step, xmldata->source.localtime, slope); if (gmetad_config.carbon_server) // if the user has specified a carbon server, send the metric to carbon as well carbon_ret=write_data_to_carbon(xmldata->sourcename, xmldata->hostname, name, metricval,xmldata->source.localtime); } metric->id = METRIC_NODE; metric->report_start = metric_report_start; metric->report_end = metric_report_end; edge = metric->stringslen; metric->name = addstring(metric->strings, &edge, name); metric->stringslen = edge; /* Set local idea of T0. */ metric->t0 = xmldata->now; metric->t0.tv_sec -= metric->tn; /* Trim metric structure to the correct length. */ hashval.size = sizeof(*metric) - GMETAD_FRAMESIZE + metric->stringslen; hashval.data = (void*) metric; /* Update full metric in cluster host table. */ rdatum = hash_insert(&hashkey, &hashval, xmldata->host.metrics); if (!rdatum) { err_msg("Could not insert %s metric", name); } } /* Always update summary for numeric metrics. */ if (do_summary) { summary = xmldata->source.metric_summary; hash_datum = hash_lookup(&hashkey, summary); if (!hash_datum) { if (!authority_mode(xmldata)) { metric = &(xmldata->metric); memset((void*) metric, 0, sizeof(*metric)); fillmetric(attr, metric, type); } /* else we have already filled in the metric above. */ } else { memcpy(&xmldata->metric, hash_datum->data, hash_datum->size); datum_free(hash_datum); metric = &(xmldata->metric); switch (tt->type) { case INT: case UINT: case FLOAT: metric->val.d += (double) strtod(metricval, (char**) NULL); break; default: break; } } metric->num++; metric->t0 = xmldata->now; /* tell cleanup thread we are using this */ /* Trim metric structure to the correct length. Tricky. */ hashval.size = sizeof(*metric) - GMETAD_FRAMESIZE + metric->stringslen; hashval.data = (void*) metric; /* Update metric in summary table. */ rdatum = hash_insert(&hashkey, &hashval, summary); if (!rdatum) err_msg("Could not insert %s metric", name); } return 0; }