Exemple #1
0
static int test_variable_renames(void) {
    fprintf(stderr, "Creating chart\n");
    RRDSET *st = rrdset_create("chart", "ID", NULL, "family", "context", "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
    fprintf(stderr, "Created chart with id '%s', name '%s'\n", st->id, st->name);

    fprintf(stderr, "Creating dimension DIM1\n");
    RRDDIM *rd1 = rrddim_add(st, "DIM1", NULL, 1, 1, RRDDIM_INCREMENTAL);
    fprintf(stderr, "Created dimension with id '%s', name '%s'\n", rd1->id, rd1->name);

    fprintf(stderr, "Creating dimension DIM2\n");
    RRDDIM *rd2 = rrddim_add(st, "DIM2", NULL, 1, 1, RRDDIM_INCREMENTAL);
    fprintf(stderr, "Created dimension with id '%s', name '%s'\n", rd2->id, rd2->name);

    fprintf(stderr, "Renaming chart to CHARTNAME1\n");
    rrdset_set_name(st, "CHARTNAME1");
    fprintf(stderr, "Renamed chart with id '%s' to name '%s'\n", st->id, st->name);

    fprintf(stderr, "Renaming chart to CHARTNAME2\n");
    rrdset_set_name(st, "CHARTNAME2");
    fprintf(stderr, "Renamed chart with id '%s' to name '%s'\n", st->id, st->name);

    fprintf(stderr, "Renaming dimension DIM1 to DIM1NAME1\n");
    rrddim_set_name(st, rd1, "DIM1NAME1");
    fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd1->id, rd1->name);

    fprintf(stderr, "Renaming dimension DIM1 to DIM1NAME2\n");
    rrddim_set_name(st, rd1, "DIM1NAME2");
    fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd1->id, rd1->name);

    fprintf(stderr, "Renaming dimension DIM2 to DIM2NAME1\n");
    rrddim_set_name(st, rd2, "DIM2NAME1");
    fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd2->id, rd2->name);

    fprintf(stderr, "Renaming dimension DIM2 to DIM2NAME2\n");
    rrddim_set_name(st, rd2, "DIM2NAME2");
    fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd2->id, rd2->name);

    BUFFER *buf = buffer_create(1);
    health_api_v1_chart_variables2json(st, buf);
    fprintf(stderr, "%s", buffer_tostring(buf));
    buffer_free(buf);
    return 1;
}
Exemple #2
0
static inline void tc_device_commit(struct tc_device *d)
{
	static int enable_new_interfaces = -1;

	if(enable_new_interfaces == -1)	enable_new_interfaces = config_get_boolean("plugin:tc", "enable new interfaces detected at runtime", 1);

	// we only need to add leaf classes
	struct tc_class *c, *x;

	// set all classes
	for(c = d->classes ; c ; c = c->next) {
		c->isleaf = 1;
		c->hasparent = 0;
	}

	// mark the classes as leafs and parents
	for(c = d->classes ; c ; c = c->next) {
		if(!c->updated) continue;

		for(x = d->classes ; x ; x = x->next) {
			if(!x->updated) continue;

			if(c == x) continue;

			if(x->parentid && (
				(               c->hash      == x->parent_hash && strcmp(c->id,     x->parentid) == 0) ||
				(c->leafid   && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0))) {
				// debug(D_TC_LOOP, "TC: In device '%s', class '%s' (leafid: '%s') has as leaf class '%s' (parentid: '%s').", d->name?d->name:d->id, c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->name?x->name:x->id, x->parentid?x->parentid:x->id);
				c->isleaf = 0;
				x->hasparent = 1;
			}
		}
	}

	// debugging:
	/*
	for ( c = d->classes ; c ; c = c->next) {
		if(c->isleaf && c->hasparent) debug(D_TC_LOOP, "TC: Device %s, class %s, OK", d->name, c->id);
		else debug(D_TC_LOOP, "TC: Device %s, class %s, IGNORE (isleaf: %d, hasparent: %d, parent: %s)", d->name, c->id, c->isleaf, c->hasparent, c->parentid);
	}
	*/

	// we need at least a class
	for(c = d->classes ; c ; c = c->next) {
		// debug(D_TC_LOOP, "TC: Device '%s', class '%s', isLeaf=%d, HasParent=%d, Seen=%d", d->name?d->name:d->id, c->name?c->name:c->id, c->isleaf, c->hasparent, c->seen);
		if(!c->updated) continue;
		if(c->isleaf && c->hasparent) break;
	}
	if(!c) {
		debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name?d->name:d->id);
		tc_device_classes_cleanup(d);
		return;
	}

	char var_name[CONFIG_MAX_NAME + 1];
	snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);
	if(config_get_boolean("plugin:tc", var_name, enable_new_interfaces)) {
		RRDSET *st = rrdset_find_bytype(RRD_TYPE_TC, d->id);
		if(!st) {
			debug(D_TC_LOOP, "TC: Creating new chart for device '%s'", d->name?d->name:d->id);

			st = rrdset_create(RRD_TYPE_TC, d->id, d->name?d->name:d->id, d->family?d->family:d->id, RRD_TYPE_TC ".qos", "Class Usage", "kilobits/s", 7000, rrd_update_every, RRDSET_TYPE_STACKED);

			for(c = d->classes ; c ; c = c->next) {
				if(!c->updated) continue;

				if(c->isleaf && c->hasparent)
					rrddim_add(st, c->id, c->name?c->name:c->id, 8, 1024, RRDDIM_INCREMENTAL);
			}
		}
		else {
			debug(D_TC_LOOP, "TC: Updating chart for device '%s'", d->name?d->name:d->id);
			rrdset_next_plugins(st);

			if(d->name && strcmp(d->id, d->name) != 0) rrdset_set_name(st, d->name);
		}

		for(c = d->classes ; c ; c = c->next) {
			if(!c->updated) continue;

			if(c->isleaf && c->hasparent) {
				RRDDIM *rd = rrddim_find(st, c->id);

				if(!rd) {
					debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s'", st->id, c->id, c->name);

					// new class, we have to add it
					rd = rrddim_add(st, c->id, c->name?c->name:c->id, 8, 1024, RRDDIM_INCREMENTAL);
				}
				else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", st->id, c->id);

				rrddim_set_by_pointer(st, rd, c->bytes);

				// if it has a name, different to the id
				if(c->name) {
					// update the rrd dimension with the new name
					debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", st->id, rd->id, c->name);
					rrddim_set_name(st, rd, c->name);

					free(c->name);
					c->name = NULL;
				}
			}
		}
		rrdset_done(st);
	}

	tc_device_classes_cleanup(d);
}
Exemple #3
0
static inline void tc_device_commit(struct tc_device *d) {
    static int enable_new_interfaces = -1, enable_bytes = -1, enable_packets = -1, enable_dropped = -1, enable_tokens = -1, enable_ctokens = -1, enabled_all_classes_qdiscs = -1;

    if(unlikely(enable_new_interfaces == -1)) {
        enable_new_interfaces      = config_get_boolean_ondemand("plugin:tc", "enable new interfaces detected at runtime", CONFIG_BOOLEAN_YES);
        enable_bytes               = config_get_boolean_ondemand("plugin:tc", "enable traffic charts for all interfaces", CONFIG_BOOLEAN_AUTO);
        enable_packets             = config_get_boolean_ondemand("plugin:tc", "enable packets charts for all interfaces", CONFIG_BOOLEAN_AUTO);
        enable_dropped             = config_get_boolean_ondemand("plugin:tc", "enable dropped charts for all interfaces", CONFIG_BOOLEAN_AUTO);
        enable_tokens              = config_get_boolean_ondemand("plugin:tc", "enable tokens charts for all interfaces", CONFIG_BOOLEAN_NO);
        enable_ctokens             = config_get_boolean_ondemand("plugin:tc", "enable ctokens charts for all interfaces", CONFIG_BOOLEAN_NO);
        enabled_all_classes_qdiscs = config_get_boolean_ondemand("plugin:tc", "enable show all classes and qdiscs for all interfaces", CONFIG_BOOLEAN_NO);
    }

    if(unlikely(d->enabled == (char)-1)) {
        char var_name[CONFIG_MAX_NAME + 1];
        snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);

        d->enabled                    = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_new_interfaces);

        snprintfz(var_name, CONFIG_MAX_NAME, "traffic chart for %s", d->id);
        d->enabled_bytes              = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_bytes);

        snprintfz(var_name, CONFIG_MAX_NAME, "packets chart for %s", d->id);
        d->enabled_packets            = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_packets);

        snprintfz(var_name, CONFIG_MAX_NAME, "dropped packets chart for %s", d->id);
        d->enabled_dropped            = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_dropped);

        snprintfz(var_name, CONFIG_MAX_NAME, "tokens chart for %s", d->id);
        d->enabled_tokens             = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_tokens);

        snprintfz(var_name, CONFIG_MAX_NAME, "ctokens chart for %s", d->id);
        d->enabled_ctokens            = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_ctokens);

        snprintfz(var_name, CONFIG_MAX_NAME, "show all classes for %s", d->id);
        d->enabled_all_classes_qdiscs = (char)config_get_boolean_ondemand("plugin:tc", var_name, enabled_all_classes_qdiscs);
    }

    // we only need to add leaf classes
    struct tc_class *c, *x /*, *root = NULL */;
    unsigned long long bytes_sum = 0, packets_sum = 0, dropped_sum = 0, tokens_sum = 0, ctokens_sum = 0;
    int active_nodes = 0, updated_classes = 0, updated_qdiscs = 0;

    // prepare all classes
    // we set reasonable defaults for the rest of the code below

    for(c = d->classes ; c ; c = c->next) {
        c->render = 0;          // do not render this class

        c->isleaf = 1;          // this is a leaf class
        c->hasparent = 0;       // without a parent

        if(unlikely(!c->updated))
            c->unupdated++;     // increase its unupdated counter
        else {
            c->unupdated = 0;   // reset its unupdated counter

            // count how many of each kind
            if(c->isqdisc)
                updated_qdiscs++;
            else
                updated_classes++;
        }
    }

    if(unlikely(!d->enabled || (!updated_classes && !updated_qdiscs))) {
        debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. It is not enabled/updated.", d->name?d->name:d->id);
        tc_device_classes_cleanup(d);
        return;
    }

    if(unlikely(updated_classes && updated_qdiscs)) {
        error("TC: device '%s' has active both classes (%d) and qdiscs (%d). Will render only qdiscs.", d->id, updated_classes, updated_qdiscs);

        // set all classes to !updated
        for(c = d->classes ; c ; c = c->next)
            if(unlikely(!c->isqdisc && c->updated))
                c->updated = 0;

        updated_classes = 0;
    }

    // mark the classes as leafs and parents
    //
    // TC is hierarchical:
    //  - classes can have other classes in them
    //  - the same is true for qdiscs (i.e. qdiscs have classes, that have other qdiscs)
    //
    // we need to present a chart with leaf nodes only, so that the sum
    // of all dimensions of the chart, will be the total utilization
    // of the interface.
    //
    // here we try to find the ones we need to report
    // by default all nodes are marked with: isleaf = 1 (see above)
    //
    // so, here we remove the isleaf flag from nodes in the middle
    // and we add the hasparent flag to leaf nodes we found their parent
    if(likely(!d->enabled_all_classes_qdiscs)) {
        for(c = d->classes; c; c = c->next) {
            if(unlikely(!c->updated)) continue;

            //debug(D_TC_LOOP, "TC: In device '%s', %s '%s'  has leafid: '%s' and parentid '%s'.",
            //    d->id,
            //    c->isqdisc?"qdisc":"class",
            //    c->id,
            //    c->leafid?c->leafid:"NULL",
            //    c->parentid?c->parentid:"NULL");

            // find if c is leaf or not
            for(x = d->classes; x; x = x->next) {
                if(unlikely(!x->updated || c == x || !x->parentid)) continue;

                // classes have both parentid and leafid
                // qdiscs have only parentid
                // the following works for both (it is an OR)

                if((c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) ||
                   (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0)) {
                    // debug(D_TC_LOOP, "TC: In device '%s', %s '%s' (leafid: '%s') has as leaf %s '%s' (parentid: '%s').", d->name?d->name:d->id, c->isqdisc?"qdisc":"class", c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->isqdisc?"qdisc":"class", x->name?x->name:x->id, x->parentid?x->parentid:x->id);
                    c->isleaf = 0;
                    x->hasparent = 1;
                }
            }
        }
    }

    for(c = d->classes ; c ; c = c->next) {
        if(unlikely(!c->updated)) continue;

        // debug(D_TC_LOOP, "TC: device '%s', %s '%s' isleaf=%d, hasparent=%d", d->id, (c->isqdisc)?"qdisc":"class", c->id, c->isleaf, c->hasparent);

        if(unlikely((c->isleaf && c->hasparent) || d->enabled_all_classes_qdiscs)) {
            c->render = 1;
            active_nodes++;
            bytes_sum += c->bytes;
            packets_sum += c->packets;
            dropped_sum += c->dropped;
            tokens_sum += c->tokens;
            ctokens_sum += c->ctokens;
        }

        //if(unlikely(!c->hasparent)) {
        //    if(root) error("TC: multiple root class/qdisc for device '%s' (old: '%s', new: '%s')", d->id, root->id, c->id);
        //    root = c;
        //    debug(D_TC_LOOP, "TC: found root class/qdisc '%s'", root->id);
        //}
    }

#ifdef NETDATA_INTERNAL_CHECKS
    // dump all the list to see what we know

    if(unlikely(debug_flags & D_TC_LOOP)) {
        for(c = d->classes ; c ; c = c->next) {
            if(c->render) debug(D_TC_LOOP, "TC: final nodes dump for '%s': class %s, OK", d->name, c->id);
            else debug(D_TC_LOOP, "TC: final nodes dump for '%s': class %s, IGNORE (updated: %d, isleaf: %d, hasparent: %d, parent: %s)", d->name?d->name:d->id, c->id, c->updated, c->isleaf, c->hasparent, c->parentid?c->parentid:"(unset)");
        }
    }
#endif

    if(unlikely(!active_nodes)) {
        debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No useful classes/qdiscs.", d->name?d->name:d->id);
        tc_device_classes_cleanup(d);
        return;
    }

    debug(D_TC_LOOP, "TC: evaluating TC device '%s'. enabled = %d/%d (bytes: %d/%d, packets: %d/%d, dropped: %d/%d, tokens: %d/%d, ctokens: %d/%d, all_classes_qdiscs: %d/%d), classes: (bytes = %llu, packets = %llu, dropped = %llu, tokens = %llu, ctokens = %llu).",
        d->name?d->name:d->id,
        d->enabled, enable_new_interfaces,
        d->enabled_bytes, enable_bytes,
        d->enabled_packets, enable_packets,
        d->enabled_dropped, enable_dropped,
        d->enabled_tokens, enable_tokens,
        d->enabled_ctokens, enable_ctokens,
        d->enabled_all_classes_qdiscs, enabled_all_classes_qdiscs,
        bytes_sum,
        packets_sum,
        dropped_sum,
        tokens_sum,
        ctokens_sum
        );

    // --------------------------------------------------------------------
    // bytes

    if(d->enabled_bytes == CONFIG_BOOLEAN_YES || (d->enabled_bytes == CONFIG_BOOLEAN_AUTO && bytes_sum)) {
        d->enabled_bytes = CONFIG_BOOLEAN_YES;

        if(unlikely(!d->st_bytes))
            d->st_bytes = rrdset_create_localhost(
                    RRD_TYPE_TC
                    , d->id
                    , d->name ? d->name : d->id
                    , d->family ? d->family : d->id
                    , RRD_TYPE_TC ".qos"
                    , "Class Usage"
                    , "kilobits/s"
                    , PLUGIN_TC_NAME
                    , NULL
                    , NETDATA_CHART_PRIO_TC_QOS
                    , localhost->rrd_update_every
                    , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED
            );

        else {
            rrdset_next(d->st_bytes);
            if(unlikely(d->name_updated)) rrdset_set_name(d->st_bytes, d->name);

            // TODO
            // update the family
        }

        for(c = d->classes ; c ; c = c->next) {
            if(unlikely(!c->render)) continue;

            if(unlikely(!c->rd_bytes))
                c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
            else if(unlikely(c->name_updated))
                rrddim_set_name(d->st_bytes, c->rd_bytes, c->name);

            rrddim_set_by_pointer(d->st_bytes, c->rd_bytes, c->bytes);
        }
        rrdset_done(d->st_bytes);
    }

    // --------------------------------------------------------------------
    // packets

    if(d->enabled_packets == CONFIG_BOOLEAN_YES || (d->enabled_packets == CONFIG_BOOLEAN_AUTO && packets_sum)) {
        d->enabled_packets = CONFIG_BOOLEAN_YES;

        if(unlikely(!d->st_packets)) {
            char id[RRD_ID_LENGTH_MAX + 1];
            char name[RRD_ID_LENGTH_MAX + 1];
            snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", d->id);
            snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id);

            d->st_packets = rrdset_create_localhost(
                    RRD_TYPE_TC
                    , id
                    , name
                    , d->family ? d->family : d->id
                    , RRD_TYPE_TC ".qos_packets"
                    , "Class Packets"
                    , "packets/s"
                    , PLUGIN_TC_NAME
                    , NULL
                    , NETDATA_CHART_PRIO_TC_QOS_PACKETS
                    , localhost->rrd_update_every
                    , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED
            );
        }
        else {
            rrdset_next(d->st_packets);

            if(unlikely(d->name_updated)) {
                char name[RRD_ID_LENGTH_MAX + 1];
                snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id);
                rrdset_set_name(d->st_packets, name);
            }

            // TODO
            // update the family
        }

        for(c = d->classes ; c ; c = c->next) {
            if(unlikely(!c->render)) continue;

            if(unlikely(!c->rd_packets))
                c->rd_packets = rrddim_add(d->st_packets, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_INCREMENTAL);
            else if(unlikely(c->name_updated))
                rrddim_set_name(d->st_packets, c->rd_packets, c->name);

            rrddim_set_by_pointer(d->st_packets, c->rd_packets, c->packets);
        }
        rrdset_done(d->st_packets);
    }

    // --------------------------------------------------------------------
    // dropped

    if(d->enabled_dropped == CONFIG_BOOLEAN_YES || (d->enabled_dropped == CONFIG_BOOLEAN_AUTO && dropped_sum)) {
        d->enabled_dropped = CONFIG_BOOLEAN_YES;

        if(unlikely(!d->st_dropped)) {
            char id[RRD_ID_LENGTH_MAX + 1];
            char name[RRD_ID_LENGTH_MAX + 1];
            snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", d->id);
            snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id);

            d->st_dropped = rrdset_create_localhost(
                    RRD_TYPE_TC
                    , id
                    , name
                    , d->family ? d->family : d->id
                    , RRD_TYPE_TC ".qos_dropped"
                    , "Class Dropped Packets"
                    , "packets/s"
                    , PLUGIN_TC_NAME
                    , NULL
                    , NETDATA_CHART_PRIO_TC_QOS_DROPPED
                    , localhost->rrd_update_every
                    , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED
            );
        }
        else {
            rrdset_next(d->st_dropped);

            if(unlikely(d->name_updated)) {
                char name[RRD_ID_LENGTH_MAX + 1];
                snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id);
                rrdset_set_name(d->st_dropped, name);
            }

            // TODO
            // update the family
        }

        for(c = d->classes ; c ; c = c->next) {
            if(unlikely(!c->render)) continue;

            if(unlikely(!c->rd_dropped))
                c->rd_dropped = rrddim_add(d->st_dropped, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_INCREMENTAL);
            else if(unlikely(c->name_updated))
                rrddim_set_name(d->st_dropped, c->rd_dropped, c->name);

            rrddim_set_by_pointer(d->st_dropped, c->rd_dropped, c->dropped);
        }
        rrdset_done(d->st_dropped);
    }

    // --------------------------------------------------------------------
    // tokens

    if(d->enabled_tokens == CONFIG_BOOLEAN_YES || (d->enabled_tokens == CONFIG_BOOLEAN_AUTO && tokens_sum)) {
        d->enabled_tokens = CONFIG_BOOLEAN_YES;

        if(unlikely(!d->st_tokens)) {
            char id[RRD_ID_LENGTH_MAX + 1];
            char name[RRD_ID_LENGTH_MAX + 1];
            snprintfz(id, RRD_ID_LENGTH_MAX, "%s_tokens", d->id);
            snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", d->name?d->name:d->id);

            d->st_tokens = rrdset_create_localhost(
                    RRD_TYPE_TC
                    , id
                    , name
                    , d->family ? d->family : d->id
                    , RRD_TYPE_TC ".qos_tokens"
                    , "Class Tokens"
                    , "tokens"
                    , PLUGIN_TC_NAME
                    , NULL
                    , NETDATA_CHART_PRIO_TC_QOS_TOCKENS
                    , localhost->rrd_update_every
                    , RRDSET_TYPE_LINE
            );
        }
        else {
            rrdset_next(d->st_tokens);

            if(unlikely(d->name_updated)) {
                char name[RRD_ID_LENGTH_MAX + 1];
                snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", d->name?d->name:d->id);
                rrdset_set_name(d->st_tokens, name);
            }

            // TODO
            // update the family
        }

        for(c = d->classes ; c ; c = c->next) {
            if(unlikely(!c->render)) continue;

            if(unlikely(!c->rd_tokens)) {
                c->rd_tokens = rrddim_add(d->st_tokens, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_ABSOLUTE);
            }
            else if(unlikely(c->name_updated))
                rrddim_set_name(d->st_tokens, c->rd_tokens, c->name);

            rrddim_set_by_pointer(d->st_tokens, c->rd_tokens, c->tokens);
        }
        rrdset_done(d->st_tokens);
    }

    // --------------------------------------------------------------------
    // ctokens

    if(d->enabled_ctokens == CONFIG_BOOLEAN_YES || (d->enabled_ctokens == CONFIG_BOOLEAN_AUTO && ctokens_sum)) {
        d->enabled_ctokens = CONFIG_BOOLEAN_YES;

        if(unlikely(!d->st_ctokens)) {
            char id[RRD_ID_LENGTH_MAX + 1];
            char name[RRD_ID_LENGTH_MAX + 1];
            snprintfz(id, RRD_ID_LENGTH_MAX, "%s_ctokens", d->id);
            snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", d->name?d->name:d->id);

            d->st_ctokens = rrdset_create_localhost(
                    RRD_TYPE_TC
                    , id
                    , name
                    , d->family ? d->family : d->id
                    , RRD_TYPE_TC ".qos_ctokens"
                    , "Class cTokens"
                    , "ctokens"
                    , PLUGIN_TC_NAME
                    , NULL
                    , NETDATA_CHART_PRIO_TC_QOS_CTOCKENS
                    , localhost->rrd_update_every
                    , RRDSET_TYPE_LINE
            );
        }
        else {
            debug(D_TC_LOOP, "TC: Updating _ctokens chart for device '%s'", d->name?d->name:d->id);
            rrdset_next(d->st_ctokens);

            if(unlikely(d->name_updated)) {
                char name[RRD_ID_LENGTH_MAX + 1];
                snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", d->name?d->name:d->id);
                rrdset_set_name(d->st_ctokens, name);
            }

            // TODO
            // update the family
        }

        for(c = d->classes ; c ; c = c->next) {
            if(unlikely(!c->render)) continue;

            if(unlikely(!c->rd_ctokens))
                c->rd_ctokens = rrddim_add(d->st_ctokens, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_ABSOLUTE);
            else if(unlikely(c->name_updated))
                rrddim_set_name(d->st_ctokens, c->rd_ctokens, c->name);

            rrddim_set_by_pointer(d->st_ctokens, c->rd_ctokens, c->ctokens);
        }
        rrdset_done(d->st_ctokens);
    }

    tc_device_classes_cleanup(d);
}
Exemple #4
0
RRDSET *rrdset_create(const char *type, const char *id, const char *name, const char *family, const char *context, const char *title, const char *units, long priority, int update_every, int chart_type)
{
	if(!type || !type[0]) {
		fatal("Cannot create rrd stats without a type.");
		return NULL;
	}

	if(!id || !id[0]) {
		fatal("Cannot create rrd stats without an id.");
		return NULL;
	}

	char fullid[RRD_ID_LENGTH_MAX + 1];
	char fullfilename[FILENAME_MAX + 1];
	RRDSET *st = NULL;

	snprintfz(fullid, RRD_ID_LENGTH_MAX, "%s.%s", type, id);

	st = rrdset_find(fullid);
	if(st) {
		error("Cannot create rrd stats for '%s', it already exists.", fullid);
		return st;
	}

	long entries = config_get_number(fullid, "history", rrd_default_history_entries);
	if(entries < 5) entries = config_set_number(fullid, "history", 5);
	if(entries > RRD_HISTORY_ENTRIES_MAX) entries = config_set_number(fullid, "history", RRD_HISTORY_ENTRIES_MAX);

	int enabled = config_get_boolean(fullid, "enabled", 1);
	if(!enabled) entries = 5;

	unsigned long size = sizeof(RRDSET);
	char *cache_dir = rrdset_cache_dir(fullid);

	debug(D_RRD_CALLS, "Creating RRD_STATS for '%s.%s'.", type, id);

	snprintfz(fullfilename, FILENAME_MAX, "%s/main.db", cache_dir);
	if(rrd_memory_mode != RRD_MEMORY_MODE_RAM) st = (RRDSET *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 0);
	if(st) {
		if(strcmp(st->magic, RRDSET_MAGIC) != 0) {
			errno = 0;
			info("Initializing file %s.", fullfilename);
			bzero(st, size);
		}
		else if(strcmp(st->id, fullid) != 0) {
			errno = 0;
			error("File %s contents are not for chart %s. Clearing it.", fullfilename, fullid);
			// munmap(st, size);
			// st = NULL;
			bzero(st, size);
		}
		else if(st->memsize != size || st->entries != entries) {
			errno = 0;
			error("File %s does not have the desired size. Clearing it.", fullfilename);
			bzero(st, size);
		}
		else if(st->update_every != update_every) {
			errno = 0;
			error("File %s does not have the desired update frequency. Clearing it.", fullfilename);
			bzero(st, size);
		}
		else if((time(NULL) - st->last_updated.tv_sec) > update_every * entries) {
			errno = 0;
			error("File %s is too old. Clearing it.", fullfilename);
			bzero(st, size);
		}
	}

	if(st) {
		st->name = NULL;
		st->type = NULL;
		st->family = NULL;
		st->context = NULL;
		st->title = NULL;
		st->units = NULL;
		st->dimensions = NULL;
		st->next = NULL;
		st->mapped = rrd_memory_mode;
	}
	else {
		st = calloc(1, size);
		if(!st) {
			fatal("Cannot allocate memory for RRD_STATS %s.%s", type, id);
			return NULL;
		}
		st->mapped = RRD_MEMORY_MODE_RAM;
	}
	st->memsize = size;
	st->entries = entries;
	st->update_every = update_every;

	if(st->current_entry >= st->entries) st->current_entry = 0;

	strcpy(st->cache_filename, fullfilename);
	strcpy(st->magic, RRDSET_MAGIC);

	strcpy(st->id, fullid);
	st->hash = simple_hash(st->id);

	st->cache_dir = cache_dir;

	st->chart_type = rrdset_type_id(config_get(st->id, "chart type", rrdset_type_name(chart_type)));
	st->type       = config_get(st->id, "type", type);
	st->family     = config_get(st->id, "family", family?family:st->type);
	st->context    = config_get(st->id, "context", context?context:st->id);
	st->units      = config_get(st->id, "units", units?units:"");

	st->priority = config_get_number(st->id, "priority", priority);
	st->enabled = enabled;

	st->isdetail = 0;
	st->debug = 0;

	st->last_collected_time.tv_sec = 0;
	st->last_collected_time.tv_usec = 0;
	st->counter_done = 0;

	st->gap_when_lost_iterations_above = (int) (
			config_get_number(st->id, "gap when lost iterations above", RRD_DEFAULT_GAP_INTERPOLATIONS) + 2);

	avl_init_lock(&st->dimensions_index, rrddim_compare);

	pthread_rwlock_init(&st->rwlock, NULL);
	pthread_rwlock_wrlock(&rrdset_root_rwlock);

	if(name && *name) rrdset_set_name(st, name);
	else rrdset_set_name(st, id);

	{
		char varvalue[CONFIG_MAX_VALUE + 1];
		snprintfz(varvalue, CONFIG_MAX_VALUE, "%s (%s)", title?title:"", st->name);
		st->title = config_get(st->id, "title", varvalue);
	}

	st->next = rrdset_root;
	rrdset_root = st;

	rrdset_index_add(st);

	pthread_rwlock_unlock(&rrdset_root_rwlock);

	return(st);
}