コード例 #1
0
ファイル: rrd.c プロジェクト: 4224657/netdata
collected_number rrddim_set(RRDSET *st, const char *id, collected_number value)
{
	RRDDIM *rd = rrddim_find(st, id);
	if(unlikely(!rd)) {
		error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
		return 0;
	}

	return rrddim_set_by_pointer(st, rd, value);
}
コード例 #2
0
ファイル: rrd.c プロジェクト: 4224657/netdata
int rrddim_unhide(RRDSET *st, const char *id)
{
	debug(D_RRD_CALLS, "rrddim_unhide() for chart %s, dimension %s", st->name, id);

	RRDDIM *rd = rrddim_find(st, id);
	if(unlikely(!rd)) {
		error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
		return 1;
	}

	if(rd->flags & RRDDIM_FLAG_HIDDEN) rd->flags ^= RRDDIM_FLAG_HIDDEN;
	return 0;
}
コード例 #3
0
ファイル: plugin_nfacct.c プロジェクト: 0-T-0/netdata
void *nfacct_main(void *ptr) {
	if(ptr) { ; }

	info("NFACCT thread created with task id %d", gettid());

	if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
		error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");

	if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
		error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");

	char buf[MNL_SOCKET_BUFFER_SIZE];
	struct mnl_socket *nl = NULL;
	struct nlmsghdr *nlh = NULL;
	unsigned int seq = 0, portid = 0;

	seq = time(NULL) - 1;

	nl  = mnl_socket_open(NETLINK_NETFILTER);
	if(!nl) {
		error("nfacct.plugin: mnl_socket_open() failed");
		pthread_exit(NULL);
		return NULL;
	}

	if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
		mnl_socket_close(nl);
		error("nfacct.plugin: mnl_socket_bind() failed");
		pthread_exit(NULL);
		return NULL;
	}
	portid = mnl_socket_get_portid(nl);

	// ------------------------------------------------------------------------

	struct timeval last, now;
	unsigned long long usec = 0, susec = 0;
	RRDSET *st = NULL;

	gettimeofday(&last, NULL);

	// ------------------------------------------------------------------------

	while(1) {
		if(unlikely(netdata_exit)) break;

		seq++;

		nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, seq);
		if(!nlh) {
			mnl_socket_close(nl);
			error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
			pthread_exit(NULL);
			return NULL;
		}

		if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
			error("nfacct.plugin: mnl_socket_send");
			pthread_exit(NULL);
			return NULL;
		}

		if(nfacct_list) nfacct_list->len = 0;

		int ret;
		while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
			if((ret = mnl_cb_run(buf, ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
		}

		if (ret == -1) {
			error("nfacct.plugin: error communicating with kernel.");
			pthread_exit(NULL);
			return NULL;
		}

		// --------------------------------------------------------------------

		gettimeofday(&now, NULL);
		usec = usecdiff(&now, &last) - susec;
		debug(D_NFACCT_LOOP, "nfacct.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).", usec + susec, usec, susec);

		if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
		else susec = rrd_update_every * 1000000ULL / 2ULL;


		// --------------------------------------------------------------------

		if(nfacct_list && nfacct_list->len) {
			int i;

			st = rrdset_find_bytype("netfilter", "nfacct_packets");
			if(!st) {
				st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 1006, rrd_update_every, RRDSET_TYPE_STACKED);

				for(i = 0; i < nfacct_list->len ; i++)
					rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
			}
			else rrdset_next(st);

			for(i = 0; i < nfacct_list->len ; i++) {
				RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);

				if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
				if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].pkts);
			}

			rrdset_done(st);

			// ----------------------------------------------------------------

			st = rrdset_find_bytype("netfilter", "nfacct_bytes");
			if(!st) {
				st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);

				for(i = 0; i < nfacct_list->len ; i++)
					rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
			}
			else rrdset_next(st);

			for(i = 0; i < nfacct_list->len ; i++) {
				RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);

				if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
				if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].bytes);
			}

			rrdset_done(st);
		}

		// --------------------------------------------------------------------

		usleep(susec);

		// copy current to last
		bcopy(&now, &last, sizeof(struct timeval));
	}

	mnl_socket_close(nl);
	pthread_exit(NULL);
	return NULL;
}
コード例 #4
0
ファイル: proc_interrupts.c プロジェクト: acecommerce/netdata
int do_proc_interrupts(int update_every, usec_t dt) {
    (void)dt;
    static procfile *ff = NULL;
    static int cpus = -1, do_per_core = -1;
    struct interrupt *irrs = NULL;

    if(unlikely(do_per_core == -1))
        do_per_core = config_get_boolean("plugin:proc:/proc/interrupts", "interrupts per core", 1);

    if(unlikely(!ff)) {
        char filename[FILENAME_MAX + 1];
        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/interrupts");
        ff = procfile_open(config_get("plugin:proc:/proc/interrupts", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
    }
    if(unlikely(!ff))
        return 1;

    ff = procfile_readall(ff);
    if(unlikely(!ff))
        return 0; // we return 0, so that we will retry to open it next time

    uint32_t lines = procfile_lines(ff), l;
    uint32_t words = procfile_linewords(ff, 0);

    if(unlikely(!lines)) {
        error("Cannot read /proc/interrupts, zero lines reported.");
        return 1;
    }

    // find how many CPUs are there
    if(unlikely(cpus == -1)) {
        uint32_t w;
        cpus = 0;
        for(w = 0; w < words ; w++) {
            if(likely(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0))
                cpus++;
        }
    }

    if(unlikely(!cpus)) {
        error("PLUGIN: PROC_INTERRUPTS: Cannot find the number of CPUs in /proc/interrupts");
        return 1;
    }

    // allocate the size we need;
    irrs = get_interrupts_array(lines, cpus);
    irrs[0].used = 0;

    // loop through all lines
    for(l = 1; l < lines ;l++) {
        struct interrupt *irr = irrindex(irrs, l, cpus);
        irr->used = 0;
        irr->total = 0;

        words = procfile_linewords(ff, l);
        if(unlikely(!words)) continue;

        irr->id = procfile_lineword(ff, l, 0);
        if(unlikely(!irr->id || !irr->id[0])) continue;

        int idlen = strlen(irr->id);
        if(unlikely(irr->id[idlen - 1] == ':'))
            irr->id[idlen - 1] = '\0';

        int c;
        for(c = 0; c < cpus ;c++) {
            if(likely((c + 1) < (int)words))
                irr->cpu[c].value = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
            else
                irr->cpu[c].value = 0;

            irr->total += irr->cpu[c].value;
        }

        if(unlikely(isdigit(irr->id[0]) && (uint32_t)(cpus + 2) < words)) {
            strncpyz(irr->name, procfile_lineword(ff, l, words - 1), MAX_INTERRUPT_NAME);
            int nlen = strlen(irr->name);
            int idlen = strlen(irr->id);
            if(likely(nlen + 1 + idlen <= MAX_INTERRUPT_NAME)) {
                irr->name[nlen] = '_';
                strncpyz(&irr->name[nlen + 1], irr->id, MAX_INTERRUPT_NAME - nlen - 1);
            }
            else {
                irr->name[MAX_INTERRUPT_NAME - idlen - 1] = '_';
                strncpyz(&irr->name[MAX_INTERRUPT_NAME - idlen], irr->id, idlen);
            }
        }
        else {
            strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME);
        }

        irr->used = 1;
    }

    RRDSET *st;

    // --------------------------------------------------------------------

    st = rrdset_find_bytype("system", "interrupts");
    if(unlikely(!st)) st = rrdset_create("system", "interrupts", NULL, "interrupts", NULL, "System interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_STACKED);
    else rrdset_next(st);

    for(l = 0; l < lines ;l++) {
        struct interrupt *irr = irrindex(irrs, l, cpus);
        if(unlikely(!irr->used)) continue;
        // some interrupt may have changed without changing the total number of lines
        // if the same number of interrupts have been added and removed between two
        // calls of this function.
        if(unlikely(!irr->rd || strncmp(irr->rd->name, irr->name, MAX_INTERRUPT_NAME) != 0)) {
            irr->rd = rrddim_find(st, irr->id);
            if(unlikely(!irr->rd))
                irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
            else
                rrddim_set_name(st, irr->rd, irr->name);

            // also reset per cpu RRDDIMs to avoid repeating strncmp() in the per core loop
            if(likely(do_per_core)) {
                int c;
                for (c = 0; c < cpus ;c++)
                    irr->cpu[c].rd = NULL;
            }
        }
        rrddim_set_by_pointer(st, irr->rd, irr->total);
    }
    rrdset_done(st);

    if(likely(do_per_core)) {
        int c;

        for(c = 0; c < cpus ;c++) {
            char id[50+1];
            snprintfz(id, 50, "cpu%d_interrupts", c);

            st = rrdset_find_bytype("cpu", id);
            if(unlikely(!st)) {
                char title[100+1];
                snprintfz(title, 100, "CPU%d Interrupts", c);
                st = rrdset_create("cpu", id, NULL, "interrupts", "cpu.interrupts", title, "interrupts/s", 1100 + c, update_every, RRDSET_TYPE_STACKED);
            }
            else rrdset_next(st);

            for(l = 0; l < lines ;l++) {
                struct interrupt *irr = irrindex(irrs, l, cpus);
                if(unlikely(!irr->used)) continue;
                if(unlikely(!irr->cpu[c].rd)) {
                    irr->cpu[c].rd = rrddim_find(st, irr->id);
                    if(unlikely(!irr->cpu[c].rd))
                        irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
                    else
                        rrddim_set_name(st, irr->cpu[c].rd, irr->name);
                }
                rrddim_set_by_pointer(st, irr->cpu[c].rd, irr->cpu[c].value);
            }
            rrdset_done(st);
        }
    }

    return 0;
}
コード例 #5
0
ファイル: plugin_tc.c プロジェクト: Brainiarc7/netdata
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);
}
コード例 #6
0
ファイル: plugins_d.c プロジェクト: SanskritFritz/netdata
void *pluginsd_worker_thread(void *arg)
{
	struct plugind *cd = (struct plugind *)arg;
	char line[PLUGINSD_LINE_MAX + 1];

#ifdef DETACH_PLUGINS_FROM_NETDATA
	unsigned long long usec = 0, susec = 0;
	struct timeval last = {0, 0} , now = {0, 0};
#endif

	char *words[MAX_WORDS] = { NULL };
	uint32_t SET_HASH = simple_hash("SET");
	uint32_t BEGIN_HASH = simple_hash("BEGIN");
	uint32_t END_HASH = simple_hash("END");
	uint32_t FLUSH_HASH = simple_hash("FLUSH");
	uint32_t CHART_HASH = simple_hash("CHART");
	uint32_t DIMENSION_HASH = simple_hash("DIMENSION");
	uint32_t DISABLE_HASH = simple_hash("DISABLE");
#ifdef DETACH_PLUGINS_FROM_NETDATA
	uint32_t MYPID_HASH = simple_hash("MYPID");
	uint32_t STOPPING_WAKE_ME_UP_PLEASE_HASH = simple_hash("STOPPING_WAKE_ME_UP_PLEASE");
#endif

	while(likely(1)) {
		if(unlikely(netdata_exit)) break;

		FILE *fp = mypopen(cd->cmd, &cd->pid);
		if(unlikely(!fp)) {
			error("Cannot popen(\"%s\", \"r\").", cd->cmd);
			break;
		}

		info("PLUGINSD: '%s' running on pid %d", cd->fullfilename, cd->pid);

		RRDSET *st = NULL;
		unsigned long long count = 0;
		char *s;
		uint32_t hash;

		while(likely(fgets(line, PLUGINSD_LINE_MAX, fp) != NULL)) {
			if(unlikely(netdata_exit)) break;

			line[PLUGINSD_LINE_MAX] = '\0';

			// debug(D_PLUGINSD, "PLUGINSD: %s: %s", cd->filename, line);

			int w = pluginsd_split_words(line, words, MAX_WORDS);
			s = words[0];
			if(unlikely(!s || !*s || !w)) {
				// debug(D_PLUGINSD, "PLUGINSD: empty line");
				continue;
			}

			// debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);

			hash = simple_hash(s);

			if(likely(hash == SET_HASH && !strcmp(s, "SET"))) {
				char *dimension = words[1];
				char *value = words[2];

				if(unlikely(!dimension || !*dimension)) {
					error("PLUGINSD: '%s' is requesting a SET on chart '%s', without a dimension. Disabling it.", cd->fullfilename, st->id);
					cd->enabled = 0;
					killpid(cd->pid, SIGTERM);
					break;
				}

				if(unlikely(!value || !*value)) value = NULL;

				if(unlikely(!st)) {
					error("PLUGINSD: '%s' is requesting a SET on dimension %s with value %s, without a BEGIN. Disabling it.", cd->fullfilename, dimension, value?value:"<nothing>");
					cd->enabled = 0;
					killpid(cd->pid, SIGTERM);
					break;
				}

				if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is setting dimension %s/%s to %s", cd->fullfilename, st->id, dimension, value?value:"<nothing>");

				if(value) rrddim_set(st, dimension, atoll(value));

				count++;
			}
			else if(likely(hash == BEGIN_HASH && !strcmp(s, "BEGIN"))) {
				char *id = words[1];
				char *microseconds_txt = words[2];

				if(unlikely(!id)) {
					error("PLUGINSD: '%s' is requesting a BEGIN without a chart id. Disabling it.", cd->fullfilename);
					cd->enabled = 0;
					killpid(cd->pid, SIGTERM);
					break;
				}

				st = rrdset_find(id);
				if(unlikely(!st)) {
					error("PLUGINSD: '%s' is requesting a BEGIN on chart '%s', which does not exist. Disabling it.", cd->fullfilename, id);
					cd->enabled = 0;
					killpid(cd->pid, SIGTERM);
					break;
				}

				if(likely(st->counter_done)) {
					unsigned long long microseconds = 0;
					if(microseconds_txt && *microseconds_txt) microseconds = strtoull(microseconds_txt, NULL, 10);
					if(microseconds) rrdset_next_usec(st, microseconds);
					else rrdset_next_plugins(st);
				}
			}
			else if(likely(hash == END_HASH && !strcmp(s, "END"))) {
				if(unlikely(!st)) {
					error("PLUGINSD: '%s' is requesting an END, without a BEGIN. Disabling it.", cd->fullfilename);
					cd->enabled = 0;
					killpid(cd->pid, SIGTERM);
					break;
				}

				if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a END on chart %s", cd->fullfilename, st->id);

				rrdset_done(st);
				st = NULL;
			}
			else if(likely(hash == FLUSH_HASH && !strcmp(s, "FLUSH"))) {
				debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename);
				st = NULL;
			}
			else if(likely(hash == CHART_HASH && !strcmp(s, "CHART"))) {
				st = NULL;

				char *type = words[1];
				char *id = NULL;
				if(likely(type)) {
					id = strchr(type, '.');
					if(likely(id)) { *id = '\0'; id++; }
				}
				char *name = words[2];
				char *title = words[3];
				char *units = words[4];
				char *family = words[5];
				char *category = words[6];
				char *chart = words[7];
				char *priority_s = words[8];
				char *update_every_s = words[9];

				if(unlikely(!type || !*type || !id || !*id)) {
					error("PLUGINSD: '%s' is requesting a CHART, without a type.id. Disabling it.", cd->fullfilename);
					cd->enabled = 0;
					killpid(cd->pid, SIGTERM);
					break;
				}

				int priority = 1000;
				if(likely(priority_s)) priority = atoi(priority_s);

				int update_every = cd->update_every;
				if(likely(update_every_s)) update_every = atoi(update_every_s);
				if(unlikely(!update_every)) update_every = cd->update_every;

				int chart_type = RRDSET_TYPE_LINE;
				if(unlikely(chart)) chart_type = rrdset_type_id(chart);

				if(unlikely(!name || !*name)) name = NULL;
				if(unlikely(!family || !*family)) family = id;
				if(unlikely(!category || !*category)) category = type;

				st = rrdset_find_bytype(type, id);
				if(unlikely(!st)) {
					debug(D_PLUGINSD, "PLUGINSD: Creating chart type='%s', id='%s', name='%s', family='%s', category='%s', chart='%s', priority=%d, update_every=%d"
						, type, id
						, name?name:""
						, family?family:""
						, category?category:""
						, rrdset_type_name(chart_type)
						, priority
						, update_every
						);

					st = rrdset_create(type, id, name, family, title, units, priority, update_every, chart_type);
					cd->update_every = update_every;

					if(unlikely(strcmp(category, "none") == 0)) st->isdetail = 1;
				}
				else debug(D_PLUGINSD, "PLUGINSD: Chart '%s' already exists. Not adding it again.", st->id);
			}
			else if(likely(hash == DIMENSION_HASH && !strcmp(s, "DIMENSION"))) {
				char *id = words[1];
				char *name = words[2];
				char *algorithm = words[3];
				char *multiplier_s = words[4];
				char *divisor_s = words[5];
				char *options = words[6];

				if(unlikely(!id || !*id)) {
					error("PLUGINSD: '%s' is requesting a DIMENSION, without an id. Disabling it.", cd->fullfilename);
					cd->enabled = 0;
					killpid(cd->pid, SIGTERM);
					break;
				}

				if(unlikely(!st)) {
					error("PLUGINSD: '%s' is requesting a DIMENSION, without a CHART. Disabling it.", cd->fullfilename);
					cd->enabled = 0;
					killpid(cd->pid, SIGTERM);
					break;
				}

				long multiplier = 1;
				if(multiplier_s && *multiplier_s) multiplier = atol(multiplier_s);
				if(unlikely(!multiplier)) multiplier = 1;

				long divisor = 1;
				if(likely(divisor_s && *divisor_s)) divisor = atol(divisor_s);
				if(unlikely(!divisor)) divisor = 1;

				if(unlikely(!algorithm || !*algorithm)) algorithm = "absolute";

				if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: Creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'"
					, st->id
					, id
					, name?name:""
					, rrddim_algorithm_name(rrddim_algorithm_id(algorithm))
					, multiplier
					, divisor
					, options?options:""
					);

				RRDDIM *rd = rrddim_find(st, id);
				if(unlikely(!rd)) {
					rd = rrddim_add(st, id, name, multiplier, divisor, rrddim_algorithm_id(algorithm));
					rd->flags = 0x00000000;
					if(options && *options) {
						if(strstr(options, "hidden") != NULL) rd->flags |= RRDDIM_FLAG_HIDDEN;
						if(strstr(options, "noreset") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
						if(strstr(options, "nooverflow") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
					}
				}
				else if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: dimension %s/%s already exists. Not adding it again.", st->id, id);
			}
			else if(unlikely(hash == DISABLE_HASH && !strcmp(s, "DISABLE"))) {
				error("PLUGINSD: '%s' called DISABLE. Disabling it.", cd->fullfilename);
				cd->enabled = 0;
				killpid(cd->pid, SIGTERM);
				break;
			}
#ifdef DETACH_PLUGINS_FROM_NETDATA
			else if(likely(hash == MYPID_HASH && !strcmp(s, "MYPID"))) {
				char *pid_s = words[1];
				pid_t pid = atol(pid_s);

				if(likely(pid)) cd->pid = pid;
				debug(D_PLUGINSD, "PLUGINSD: %s is on pid %d", cd->id, cd->pid);
			}
			else if(likely(hash == STOPPING_WAKE_ME_UP_PLEASE_HASH && !strcmp(s, "STOPPING_WAKE_ME_UP_PLEASE"))) {
				error("PLUGINSD: '%s' (pid %d) called STOPPING_WAKE_ME_UP_PLEASE.", cd->fullfilename, cd->pid);

				gettimeofday(&now, NULL);
				if(unlikely(!usec && !susec)) {
					// our first run
					susec = cd->rrd_update_every * 1000000ULL;
				}
				else {
					// second+ run
					usec = usecdiff(&now, &last) - susec;
					error("PLUGINSD: %s last loop took %llu usec (worked for %llu, sleeped for %llu).\n", cd->fullfilename, usec + susec, usec, susec);
					if(unlikely(usec < (rrd_update_every * 1000000ULL / 2ULL))) susec = (rrd_update_every * 1000000ULL) - usec;
					else susec = rrd_update_every * 1000000ULL / 2ULL;
				}

				error("PLUGINSD: %s sleeping for %llu. Will kill with SIGCONT pid %d to wake it up.\n", cd->fullfilename, susec, cd->pid);
				usleep(susec);
				killpid(cd->pid, SIGCONT);
				bcopy(&now, &last, sizeof(struct timeval));
				break;
			}
#endif
			else {
				error("PLUGINSD: '%s' is sending command '%s' which is not known by netdata. Disabling it.", cd->fullfilename, s);
				cd->enabled = 0;
				killpid(cd->pid, SIGTERM);
				break;
			}
		}

		info("PLUGINSD: '%s' on pid %d stopped.", cd->fullfilename, cd->pid);

		// fgets() failed or loop broke
		int code = mypclose(fp, cd->pid);
		if(code == 1 || code == 127) {
			// 1 = DISABLE
			// 127 = cannot even run it
			error("PLUGINSD: '%s' (pid %d) exited with code %d. Disabling it.", cd->fullfilename, cd->pid, code);
			cd->enabled = 0;
		}

		if(netdata_exit) {
			cd->pid = 0;
			cd->enabled = 0;
			cd->obsolete = 1;
			return NULL;
		}

		if(unlikely(!count && cd->enabled)) {
			error("PLUGINSD: '%s' (pid %d) does not generate usefull output. Waiting a bit before starting it again.", cd->fullfilename, cd->pid);
			sleep((unsigned int) (cd->update_every * 10));
		}

		cd->pid = 0;
		if(likely(cd->enabled)) sleep((unsigned int) cd->update_every);
		else break;
	}

	cd->obsolete = 1;
	return NULL;
}
コード例 #7
0
int do_proc_softirqs(int update_every, usec_t dt) {
    (void)dt;
    static procfile *ff = NULL;
    static int cpus = -1, do_per_core = -1;
    struct interrupt *irrs = NULL;

    if(unlikely(do_per_core == -1)) do_per_core = config_get_boolean("plugin:proc:/proc/softirqs", "interrupts per core", 1);

    if(unlikely(!ff)) {
        char filename[FILENAME_MAX + 1];
        snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/softirqs");
        ff = procfile_open(config_get("plugin:proc:/proc/softirqs", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
        if(unlikely(!ff)) return 1;
    }

    ff = procfile_readall(ff);
    if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time

    size_t lines = procfile_lines(ff), l;
    size_t words = procfile_linewords(ff, 0);

    if(unlikely(!lines)) {
        error("Cannot read /proc/softirqs, zero lines reported.");
        return 1;
    }

    // find how many CPUs are there
    if(unlikely(cpus == -1)) {
        uint32_t w;
        cpus = 0;
        for(w = 0; w < words ; w++) {
            if(likely(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0))
                cpus++;
        }
    }

    if(unlikely(!cpus)) {
        error("PLUGIN: PROC_SOFTIRQS: Cannot find the number of CPUs in /proc/softirqs");
        return 1;
    }

    // allocate the size we need;
    irrs = get_interrupts_array(lines, cpus);
    irrs[0].used = 0;

    // loop through all lines
    for(l = 1; l < lines ;l++) {
        struct interrupt *irr = irrindex(irrs, l, cpus);
        irr->used = 0;
        irr->total = 0;

        words = procfile_linewords(ff, l);
        if(unlikely(!words)) continue;

        irr->id = procfile_lineword(ff, l, 0);
        if(unlikely(!irr->id || !irr->id[0])) continue;

        int c;
        for(c = 0; c < cpus ;c++) {
            if(likely((c + 1) < (int)words))
                irr->cpu[c].value = str2ull(procfile_lineword(ff, l, (uint32_t)(c + 1)));
            else
                irr->cpu[c].value = 0;

            irr->total += irr->cpu[c].value;
        }

        strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME);

        irr->used = 1;
    }

    // --------------------------------------------------------------------

    static RRDSET *st_system_softirqs = NULL;
    if(unlikely(!st_system_softirqs))
        st_system_softirqs = rrdset_create_localhost(
                "system"
                , "softirqs"
                , NULL
                , "softirqs"
                , NULL
                , "System softirqs"
                , "softirqs/s"
                , PLUGIN_PROC_NAME
                , PLUGIN_PROC_MODULE_SOFTIRQS_NAME
                , NETDATA_CHART_PRIO_SYSTEM_SOFTIRQS
                , update_every
                , RRDSET_TYPE_STACKED
        );
    else
        rrdset_next(st_system_softirqs);

    for(l = 0; l < lines ;l++) {
        struct interrupt *irr = irrindex(irrs, l, cpus);

        if(unlikely(!irr->used)) continue;

        // some interrupt may have changed without changing the total number of lines
        // if the same number of interrupts have been added and removed between two
        // calls of this function.
        if(unlikely(!irr->rd || strncmp(irr->name, irr->rd->name, MAX_INTERRUPT_NAME) != 0)) {
            irr->rd = rrddim_find(st_system_softirqs, irr->id);

            if(unlikely(!irr->rd))
                irr->rd = rrddim_add(st_system_softirqs, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
            else
                rrddim_set_name(st_system_softirqs, irr->rd, irr->name);

            // also reset per cpu RRDDIMs to avoid repeating strncmp() in the per core loop
            if(likely(do_per_core)) {
                int c;
                for (c = 0; c < cpus ;c++) irr->cpu[c].rd = NULL;
            }
        }

        rrddim_set_by_pointer(st_system_softirqs, irr->rd, irr->total);
    }

    rrdset_done(st_system_softirqs);

    // --------------------------------------------------------------------

    if(do_per_core) {
        static RRDSET **core_st = NULL;
        static int old_cpus = 0;

        if(old_cpus < cpus) {
            core_st = reallocz(core_st, sizeof(RRDSET *) * cpus);
            memset(&core_st[old_cpus], 0, sizeof(RRDSET *) * (cpus - old_cpus));
            old_cpus = cpus;
        }

        int c;

        for(c = 0; c < cpus ; c++) {
            if(unlikely(!core_st[c])) {
                // find if everything is just zero
                unsigned long long core_sum = 0;

                for (l = 0; l < lines; l++) {
                    struct interrupt *irr = irrindex(irrs, l, cpus);
                    if (unlikely(!irr->used)) continue;
                    core_sum += irr->cpu[c].value;
                }

                if (unlikely(core_sum == 0)) continue; // try next core

                char id[50 + 1];
                snprintfz(id, 50, "cpu%d_softirqs", c);

                char title[100 + 1];
                snprintfz(title, 100, "CPU%d softirqs", c);

                core_st[c] = rrdset_create_localhost(
                        "cpu"
                        , id
                        , NULL
                        , "softirqs"
                        , "cpu.softirqs"
                        , title
                        , "softirqs/s"
                        , PLUGIN_PROC_NAME
                        , PLUGIN_PROC_MODULE_SOFTIRQS_NAME
                        , NETDATA_CHART_PRIO_SOFTIRQS_PER_CORE + c
                        , update_every
                        , RRDSET_TYPE_STACKED
                );
            }
            else
                rrdset_next(core_st[c]);

            for(l = 0; l < lines ;l++) {
                struct interrupt *irr = irrindex(irrs, l, cpus);

                if(unlikely(!irr->used)) continue;

                if(unlikely(!irr->cpu[c].rd)) {
                    irr->cpu[c].rd = rrddim_find(core_st[c], irr->id);

                    if(unlikely(!irr->cpu[c].rd))
                        irr->cpu[c].rd = rrddim_add(core_st[c], irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
                    else
                        rrddim_set_name(core_st[c], irr->cpu[c].rd, irr->name);
                }

                rrddim_set_by_pointer(core_st[c], irr->cpu[c].rd, irr->cpu[c].value);
            }

            rrdset_done(core_st[c]);
        }
    }

    return 0;
}