#include #include #include #include #include #define STB_DS_IMPLEMENTATION #include "stb_ds.h" struct event { int64_t t; double v; }; struct metric { char *key; struct event *value; // array }; struct metric *metrics; int timecmp(const void *a, const void *b) { struct event *ea = (struct event *)a; struct event *eb = (struct event *)b; if (ea->t < eb->t) return -1; else if (ea->t > eb->t) return 1; else return 0; // needed? } static int mystrcmp(const void *a, const void *b) { return strcmp((char *)a, (char *)b); } void normalize(char *name, char *end, char *out) { // XXX handle "" char *brace = strchr(name, '{'); end--; if (!name || !brace || *end != '}') { fprintf(stderr, "invalid name: %s\n", name); return; } *end = ','; printf("LINE %s", name); char **labels = 0; for (char *s = brace + 1; s && s < end; s = strchr(s + 1, ',')) { if (*s == ',') s++; if (*s == ',') continue; /* empty label */ if (s == end) break; printf("label: %s\n", s); arrput(labels, s); } qsort(labels, arrlen(labels), sizeof (char *), mystrcmp); memcpy(out, name, brace - name); char *t = out + (brace - name); *t++ = '{'; for (ssize_t i = 0; i < arrlen(labels); i++) { printf("append %s %d\n", labels[i], end - labels[i]); char *stop = memccpy(t, labels[i], ',', end - labels[i]); if (stop) { printf("copied %d\n", stop - t); t = stop; } else { break; } } *t++ = '}'; *t = 0; printf("outf=%s\n", out); } int main() { sh_new_arena(metrics); char name[255]; char lastname[255]; char *line = 0; size_t linebuflen = 0; ssize_t linelen = 0; int i = 0; while ((linelen = getdelim(&line, &linebuflen, '\n', stdin)) >= 0) { char *start = strchr(line, ' '); if (!start) { fprintf(stderr, "skipping invalid line: %s\n", line); continue; } char *start2 = strchr(start+1, ' '); if (!start2) { fprintf(stderr, "skipping invalid line: %s\n", line); continue; } struct event ev; char *eend; ev.v = strtod(start, &eend); ev.t = strtoll(eend+1, 0, 10); if (start - line > (ssize_t)sizeof name) { fprintf(stderr, "metric too long: %s\n", line); continue; } memcpy(name, line, start-line); name[start-line] = 0; // move into normalize if (!strchr(name, '{')) strcat(name, "{}"); // XXX normalize(line, start, name); // ts = ts / 1000; // XXX if (strcmp(name, lastname) == 0) { // same name, skip hash lookup, use old i } else { if (shgeti(metrics, name) < 0) shput(metrics, name, 0); i = shgeti(metrics, name); } arrput(metrics[i].value, ev); strcpy(lastname, name); } // XXX output order of metrics? for (int m = 0; m < shlen(metrics); m++) { // ensure events are ordered by time qsort(metrics[m].value, arrlen(metrics[m].value), sizeof (struct event), timecmp); int64_t t, pt = INT64_MIN; double v; for (ssize_t i = 0; i < arrlen(metrics[m].value); i++) { t = metrics[m].value[i].t; v = metrics[m].value[i].v; if (t == pt) { fprintf(stderr, "duplicate timestamp: %s %ld\n", metrics[m].key, t); continue; } printf("%s %f %ld\n", metrics[m].key, v, t); pt = t; } } }