From 3dd312223647cc5cef24cb753d080071ff2545d8 Mon Sep 17 00:00:00 2001 From: Unbit Date: Mon, 21 Oct 2013 10:37:50 +0200 Subject: [PATCH] ported rrdtool to the metric api --- plugins/rrdtool/rrdtool.c | 225 ++++++++++++++++++++------------------ 1 file changed, 118 insertions(+), 107 deletions(-) diff --git a/plugins/rrdtool/rrdtool.c b/plugins/rrdtool/rrdtool.c index e7b2dc17..ea1f8588 100644 --- a/plugins/rrdtool/rrdtool.c +++ b/plugins/rrdtool/rrdtool.c @@ -1,30 +1,38 @@ -#include "../../uwsgi.h" +#include extern struct uwsgi_server uwsgi; -struct uwsgi_rrdtool { +static struct uwsgi_rrdtool { void *lib; + char *lib_name; + int (*create)(int, char **); int (*update)(int, char **); - struct uwsgi_string_list *rrd; - int max_ds; + int freq; char *update_area; + struct uwsgi_string_list *directory; + + struct uwsgi_stats_pusher *pusher; } u_rrd; -struct uwsgi_option rrdtool_options[] = { - {"rrdtool", required_argument, 0, "collect requests data in the specified rrd file", uwsgi_opt_add_string_list, &u_rrd.rrd, UWSGI_OPT_MASTER}, +static struct uwsgi_option rrdtool_options[] = { + {"rrdtool", required_argument, 0, "store rrd files in the specified directory", uwsgi_opt_add_string_list, &u_rrd.directory, UWSGI_OPT_MASTER|UWSGI_OPT_METRICS}, {"rrdtool-freq", required_argument, 0, "set collect frequency", uwsgi_opt_set_int, &u_rrd.freq, 0}, - {"rrdtool-max-ds", required_argument, 0, "set maximum number of data sources", uwsgi_opt_set_int, &u_rrd.max_ds, 0}, + {"rrdtool-lib", required_argument, 0, "set the name of rrd library (default: librrd.so)", uwsgi_opt_set_str, &u_rrd.lib_name, 0}, {0, 0, 0, 0, 0, 0, 0}, }; -int rrdtool_init() { +static int rrdtool_init() { - u_rrd.lib = dlopen("librrd.so", RTLD_LAZY); + if (!u_rrd.lib_name) { + u_rrd.lib_name = "librrd.so"; + } + + u_rrd.lib = dlopen(u_rrd.lib_name, RTLD_LAZY); if (!u_rrd.lib) return -1; u_rrd.create = dlsym(u_rrd.lib, "rrd_create"); @@ -39,137 +47,140 @@ int rrdtool_init() { return -1; } - if (!u_rrd.max_ds) u_rrd.max_ds = 30; - uwsgi_log_initial("*** RRDtool library available at %p ***\n", u_rrd.lib); return 0; } -void rrdtool_post_init() { +/* - struct uwsgi_string_list *usl = u_rrd.rrd; - char **argv; - int i; + create .rrd files if needed - if (!u_rrd.lib || !u_rrd.create) return; +*/ +static void rrdtool_post_init() { + + if (!u_rrd.create) return; // do not waste time if no --rrdtool option is defiend - if (!u_rrd.rrd) return; + if (!u_rrd.directory) return; - if (uwsgi.numproc > u_rrd.max_ds) { - uwsgi_log("!!! NOT ENOUGH SLOTS IN RRDTOOL DS TO HOST WORKERS DATA (increase them with --rrdtool-max-ds) !!!\n"); - dlclose(u_rrd.lib); - return; - } - - // alloc space for DS_REQ + DS WORKER + RRA + create + filename - argv = uwsgi_malloc( sizeof(char *) * (1 + u_rrd.max_ds + 4 + 1 +1)); + if (!u_rrd.freq) u_rrd.freq = 300; + char *argv[7]; argv[0] = "create"; - argv[2] = "DS:requests:DERIVE:600:0:U"; - - // create DS for workers - for(i=0;ivalue)) { - argv[1] = usl->value; - if (u_rrd.create((1 + u_rrd.max_ds + 4 + 1 +1), argv)) { - uwsgi_error("rrd_create()"); - exit(1); + struct uwsgi_string_list *usl = NULL; + uwsgi_foreach(usl, u_rrd.directory) { + char *dir = uwsgi_expand_path(usl->value, strlen(usl->value), NULL); + if (!dir) { + uwsgi_error("rrdtool_post_init()/uwsgi_expand_path()"); + exit(1); + } + struct uwsgi_metric *um = uwsgi.metrics; + // here locking is useless, but maybe in the future we could move this part + // somewhere else + int created = 0; + uwsgi_rlock(uwsgi.metrics_lock); + while(um) { + char *filename = uwsgi_concat4(dir, "/", um->name, ".rrd"); + if (!uwsgi_file_exists(filename)) { + argv[1] = filename; + if (um->type == UWSGI_METRIC_GAUGE) { + argv[2] = "DS:metric:GAUGE:600:0:U"; + } + else { + argv[2] = "DS:metric:DERIVE:600:0:U"; + } + if (u_rrd.create(7, argv)) { + uwsgi_log("unable to create rrd file for metric \"%s\"\n", um->name); + uwsgi_error("rrd_create()"); + exit(1); + } + created++; + free(filename); } + um = um->next; } - char *new_usl_value = uwsgi_malloc(PATH_MAX+1); - if (!realpath(usl->value, new_usl_value)) { - uwsgi_error("realpath()"); - exit(1); - } - usl->value = new_usl_value; - usl = usl->next; + uwsgi_rwunlock(uwsgi.metrics_lock); + + uwsgi_log("created %d new rrd files in %s\n", created, dir); + + struct uwsgi_stats_pusher_instance *uspi = uwsgi_stats_pusher_add(u_rrd.pusher, NULL); + uspi->freq = u_rrd.freq; + uspi->data = dir; + // no need to generate the json + uspi->raw=1; } - // free DS - for(i=0;i= u_rrd.freq) { - ptr = u_rrd.update_area+1; - rlen = snprintf(ptr, 1+sizeof(UMAX64_STR), ":%llu", (unsigned long long )uwsgi.workers[0].requests); - if (rlen < 2) return; - ptr+=rlen; - for(i=0;idata) { + if (!uspi->arg) { + uwsgi_log("invalid rrdtool stats pusher syntax\n"); + exit(1); } - last_update = uwsgi.current_time; - argv[0] = "update"; - argv[2] = u_rrd.update_area; - while(usl) { - argv[1] = usl->value; - if (u_rrd.update(3, argv)) { - uwsgi_log_verbose("ERROR: rrd_update(\"%s\", \"%s\")\n", argv[1], argv[2]); - } - usl = usl->next; + uspi->data = uwsgi_expand_path(uspi->arg, strlen(uspi->arg), NULL); + if (!uspi->data) { + uwsgi_error("rrdtool_push()/uwsgi_expand_path()"); + exit(1); } + if (!u_rrd.freq) u_rrd.freq = 300; + uspi->freq = u_rrd.freq; } + + // 1k will be more than enough + char buf[1024]; + char *argv[3]; + argv[0] = "update"; + + struct uwsgi_metric *um = uwsgi.metrics; + while(um) { + uwsgi_rlock(uwsgi.metrics_lock); + int ret = snprintf(buf, 1024, "N:%lld", (long long) (um->initial_value+*um->value)); + uwsgi_rwunlock(uwsgi.metrics_lock); + if (ret < 3) { + uwsgi_log("unable to update rrdtool metric for %s\n", um->name); + goto next; + } + char *filename = uwsgi_concat4(uspi->data, "/", um->name, ".rrd"); + argv[1] = filename; + argv[2] = buf; + if (u_rrd.update(3, argv)) { + uwsgi_log_verbose("ERROR: rrd_update(\"%s\", \"%s\")\n", argv[1], argv[2]); + } + free(filename); +next: + um = um->next; + } + +} + +static void rrdtool_register() { + u_rrd.pusher = uwsgi_register_stats_pusher("rrdtool", rrdtool_push); + u_rrd.pusher->raw = 1; } struct uwsgi_plugin rrdtool_plugin = { .name = "rrdtool", - .options = rrdtool_options, - - .master_cycle = rrdtool_master_cycle, - .post_init = rrdtool_post_init, + .on_load = rrdtool_register, + + // this is the best phase to create rrd files (if needed) + .preinit_apps = rrdtool_post_init, + // here we get pointers to rrdtool functions .init = rrdtool_init, };