/** Refresh and send the stats to the collectd server * */ void rs_stats_collectd_do_stats(rs_t *conf, rs_stats_tmpl_t *tmpls, struct timeval *now) { rs_stats_tmpl_t *tmpl = tmpls; char identifier[6 * LCC_NAME_LEN]; int i; while (tmpl) { /* * Refresh the value of whatever were sending */ for (i = 0; i < (int) tmpl->value->values_len; i++) { tmpl->value_tmpl[i].cb(conf, &tmpl->value_tmpl[i]); } tmpl->value->time = now->tv_sec; lcc_identifier_to_string(conf->stats.handle, identifier, sizeof(identifier), &tmpl->value->identifier); if (lcc_putval(conf->stats.handle, tmpl->value) < 0) { char const *error; error = lcc_strerror(conf->stats.handle); ERROR("Failed PUTVAL \"%s\" interval=%i %" PRIu64 " : %s", identifier, (int) tmpl->value->interval, (uint64_t) tmpl->value->time, error ? error : "unknown error"); } tmpl = tmpl->next; } }
static int putval (lcc_connection_t *c, int argc, char **argv) { lcc_value_list_t vl = LCC_VALUE_LIST_INIT; /* 64 ought to be enough for anybody ;-) */ value_t values[64]; int values_types[64]; size_t values_len = 0; int status; int i; assert (strcasecmp (argv[0], "putval") == 0); if (argc < 3) { fprintf (stderr, "ERROR: putval: Missing identifier " "and/or value list.\n"); return (-1); } vl.values = values; vl.values_types = values_types; status = parse_identifier (c, argv[1], &vl.identifier); if (status != 0) return (status); for (i = 2; i < argc; ++i) { char *tmp; tmp = strchr (argv[i], (int)'='); if (tmp != NULL) { /* option */ char *key = argv[i]; char *value = tmp; *value = '\0'; ++value; if (strcasecmp (key, "interval") == 0) { char *endptr; vl.interval = strtol (value, &endptr, 0); if (endptr == value) { fprintf (stderr, "ERROR: Failed to parse interval as number: %s.\n", value); return (-1); } else if ((endptr != NULL) && (*endptr != '\0')) { fprintf (stderr, "WARNING: Ignoring trailing garbage after " "interval: %s.\n", endptr); } } else { fprintf (stderr, "ERROR: putval: Unknown option `%s'.\n", key); return (-1); } } else { /* value list */ char *value; tmp = strchr (argv[i], (int)':'); if (tmp == NULL) { fprintf (stderr, "ERROR: putval: Invalid value list: %s.\n", argv[i]); return (-1); } *tmp = '\0'; ++tmp; if (strcasecmp (argv[i], "N") == 0) { vl.time = 0; } else { char *endptr; vl.time = strtol (argv[i], &endptr, 0); if (endptr == argv[i]) { fprintf (stderr, "ERROR: Failed to parse time as number: %s.\n", argv[i]); return (-1); } else if ((endptr != NULL) && (*endptr != '\0')) { fprintf (stderr, "ERROR: Garbage after time: %s.\n", endptr); return (-1); } } values_len = 0; value = tmp; while (value != 0) { char *dot, *endptr; tmp = strchr (value, (int)':'); if (tmp != NULL) { *tmp = '\0'; ++tmp; } /* This is a bit of a hack, but parsing types.db just does not make * much sense imho -- the server might have different types defined * anyway. Also, lcc uses the type information for formatting the * number only, so the real meaning does not matter. -tokkee */ dot = strchr (value, (int)'.'); endptr = NULL; if (strcasecmp (value, "U") == 0) { values[values_len].gauge = NAN; values_types[values_len] = LCC_TYPE_GAUGE; } else if (dot) { /* floating point value */ values[values_len].gauge = strtod (value, &endptr); values_types[values_len] = LCC_TYPE_GAUGE; } else { /* integer */ values[values_len].counter = strtol (value, &endptr, 0); values_types[values_len] = LCC_TYPE_COUNTER; } ++values_len; if (endptr == value) { fprintf (stderr, "ERROR: Failed to parse value as number: %s.\n", argv[i]); return (-1); } else if ((endptr != NULL) && (*endptr != '\0')) { fprintf (stderr, "ERROR: Garbage after value: %s.\n", endptr); return (-1); } value = tmp; } assert (values_len >= 1); vl.values_len = values_len; status = lcc_putval (c, &vl); if (status != 0) { fprintf (stderr, "ERROR: %s\n", lcc_strerror (c)); return (-1); } } } if (values_len == 0) { fprintf (stderr, "ERROR: putval: Missing value list(s).\n"); return (-1); } return (0); } /* putval */