// SPDX-License-Identifier: GPL-3.0-or-later #include "../../libnetdata/libnetdata.h" #include #include #define PLUGIN_XENSTAT_NAME "xenstat.plugin" #define NETDATA_CHART_PRIO_XENSTAT_NODE_CPUS 30001 #define NETDATA_CHART_PRIO_XENSTAT_NODE_CPU_FREQ 30002 #define NETDATA_CHART_PRIO_XENSTAT_NODE_MEM 30003 #define NETDATA_CHART_PRIO_XENSTAT_NODE_TMEM 30004 #define NETDATA_CHART_PRIO_XENSTAT_NODE_DOMAINS 30005 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_STATES 30101 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_CPU 30102 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VCPU 30103 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_MEM 30104 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_TMEM_PAGES 30104 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_TMEM_OPERATIONS 30105 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_OO_REQ 30200 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_REQUESTS 30300 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_SECTORS 30400 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_BYTES 30500 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_PACKETS 30600 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_ERRORS 30700 #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_DROPS 30800 #define TYPE_LENGTH_MAX 200 #define CHART_IS_OBSOLETE 1 #define CHART_IS_NOT_OBSOLETE 0 // callback required by fatal() void netdata_cleanup_and_exit(int ret) { exit(ret); } void send_statistics( const char *action, const char *action_result, const char *action_data) { (void) action; (void) action_result; (void) action_data; return; } // callbacks required by popen() void signals_block(void) {}; void signals_unblock(void) {}; void signals_reset(void) {}; // callback required by eval() int health_variable_lookup(const char *variable, uint32_t hash, struct rrdcalc *rc, calculated_number *result) { (void)variable; (void)hash; (void)rc; (void)result; return 0; }; // required by get_system_cpus() char *netdata_configured_host_prefix = ""; // Variables static int debug = 0; static int netdata_update_every = 1; struct vcpu_metrics { unsigned int id; unsigned int online; unsigned long long ns; int chart_generated; int updated; struct vcpu_metrics *next; }; struct vbd_metrics { unsigned int id; unsigned int error; unsigned long long oo_reqs; unsigned long long rd_reqs; unsigned long long wr_reqs; unsigned long long rd_sects; unsigned long long wr_sects; int oo_req_chart_generated; int requests_chart_generated; int sectors_chart_generated; int updated; struct vbd_metrics *next; }; struct network_metrics { unsigned int id; unsigned long long rbytes; unsigned long long rpackets; unsigned long long rerrs; unsigned long long rdrops; unsigned long long tbytes; unsigned long long tpackets; unsigned long long terrs; unsigned long long tdrops; int bytes_chart_generated; int packets_chart_generated; int errors_chart_generated; int drops_chart_generated; int updated; struct network_metrics *next; }; struct domain_metrics { char *uuid; uint32_t hash; unsigned int id; char *name; // states unsigned int running; unsigned int blocked; unsigned int paused; unsigned int shutdown; unsigned int crashed; unsigned int dying; unsigned int cur_vcpus; unsigned long long cpu_ns; unsigned long long cur_mem; unsigned long long max_mem; struct vcpu_metrics *vcpu_root; struct vbd_metrics *vbd_root; struct network_metrics *network_root; int states_chart_generated; int cpu_chart_generated; int vcpu_chart_generated; int num_vcpus_changed; int mem_chart_generated; int updated; struct domain_metrics *next; }; struct node_metrics{ unsigned long long tot_mem; unsigned long long free_mem; int num_domains; unsigned int num_cpus; unsigned long long node_cpu_hz; struct domain_metrics *domain_root; }; static struct node_metrics node_metrics = { .domain_root = NULL }; static inline struct domain_metrics *domain_metrics_get(const char *uuid, uint32_t hash) { struct domain_metrics *d = NULL, *last = NULL; for(d = node_metrics.domain_root; d ; last = d, d = d->next) { if(unlikely(d->hash == hash && !strcmp(d->uuid, uuid))) return d; } if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: allocating memory for domain with uuid %s\n", uuid); d = callocz(1, sizeof(struct domain_metrics)); d->uuid = strdupz(uuid); d->hash = hash; if(unlikely(!last)) { d->next = node_metrics.domain_root; node_metrics.domain_root = d; } else { d->next = last->next; last->next = d; } return d; } static struct domain_metrics *domain_metrics_free(struct domain_metrics *d) { struct domain_metrics *cur = NULL, *last = NULL; struct vcpu_metrics *vcpu, *vcpu_f; struct vbd_metrics *vbd, *vbd_f; struct network_metrics *network, *network_f; if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: freeing memory for domain '%s' id %d, uuid %s\n", d->name, d->id, d->uuid); for(cur = node_metrics.domain_root; cur ; last = cur, cur = cur->next) { if(unlikely(cur->hash == d->hash && !strcmp(cur->uuid, d->uuid))) break; } if(unlikely(!cur)) { error("XENSTAT: failed to free domain metrics."); return NULL; } if(likely(last)) last->next = cur->next; else node_metrics.domain_root = NULL; freez(cur->uuid); freez(cur->name); vcpu = cur->vcpu_root; while(vcpu) { vcpu_f = vcpu; vcpu = vcpu->next; freez(vcpu_f); } vbd = cur->vbd_root; while(vbd) { vbd_f = vbd; vbd = vbd->next; freez(vbd_f); } network = cur->network_root; while(network) { network_f = network; network = network->next; freez(network_f); } freez(cur); return last ? last : NULL; } static int vcpu_metrics_collect(struct domain_metrics *d, xenstat_domain *domain) { unsigned int num_vcpus = 0; xenstat_vcpu *vcpu = NULL; struct vcpu_metrics *vcpu_m = NULL, *last_vcpu_m = NULL; num_vcpus = xenstat_domain_num_vcpus(domain); for(vcpu_m = d->vcpu_root; vcpu_m ; vcpu_m = vcpu_m->next) vcpu_m->updated = 0; vcpu_m = d->vcpu_root; unsigned int i, num_online_vcpus=0; for(i = 0; i < num_vcpus; i++) { if(unlikely(!vcpu_m)) { vcpu_m = callocz(1, sizeof(struct vcpu_metrics)); if(unlikely(i == 0)) d->vcpu_root = vcpu_m; else last_vcpu_m->next = vcpu_m; } vcpu_m->id = i; vcpu = xenstat_domain_vcpu(domain, i); if(unlikely(!vcpu)) { error("XENSTAT: cannot get VCPU statistics."); return 1; } vcpu_m->online = xenstat_vcpu_online(vcpu); if(likely(vcpu_m->online)) { num_online_vcpus++; } vcpu_m->ns = xenstat_vcpu_ns(vcpu); vcpu_m->updated = 1; last_vcpu_m = vcpu_m; vcpu_m = vcpu_m->next; } if(unlikely(num_online_vcpus != d->cur_vcpus)) { d->num_vcpus_changed = 1; d->cur_vcpus = num_online_vcpus; } return 0; } static int vbd_metrics_collect(struct domain_metrics *d, xenstat_domain *domain) { unsigned int num_vbds = xenstat_domain_num_vbds(domain); xenstat_vbd *vbd = NULL; struct vbd_metrics *vbd_m = NULL, *last_vbd_m = NULL; for(vbd_m = d->vbd_root; vbd_m ; vbd_m = vbd_m->next) vbd_m->updated = 0; vbd_m = d->vbd_root; unsigned int i; for(i = 0; i < num_vbds; i++) { if(unlikely(!vbd_m)) { vbd_m = callocz(1, sizeof(struct vbd_metrics)); if(unlikely(i == 0)) d->vbd_root = vbd_m; else last_vbd_m->next = vbd_m; } vbd_m->id = i; vbd = xenstat_domain_vbd(domain, i); if(unlikely(!vbd)) { error("XENSTAT: cannot get VBD statistics."); return 1; } #ifdef HAVE_XENSTAT_VBD_ERROR vbd_m->error = xenstat_vbd_error(vbd); #else vbd_m->error = 0; #endif vbd_m->oo_reqs = xenstat_vbd_oo_reqs(vbd); vbd_m->rd_reqs = xenstat_vbd_rd_reqs(vbd); vbd_m->wr_reqs = xenstat_vbd_wr_reqs(vbd); vbd_m->rd_sects = xenstat_vbd_rd_sects(vbd); vbd_m->wr_sects = xenstat_vbd_wr_sects(vbd); vbd_m->updated = 1; last_vbd_m = vbd_m; vbd_m = vbd_m->next; } return 0; } static int network_metrics_collect(struct domain_metrics *d, xenstat_domain *domain) { unsigned int num_networks = xenstat_domain_num_networks(domain); xenstat_network *network = NULL; struct network_metrics *network_m = NULL, *last_network_m = NULL; for(network_m = d->network_root; network_m ; network_m = network_m->next) network_m->updated = 0; network_m = d->network_root; unsigned int i; for(i = 0; i < num_networks; i++) { if(unlikely(!network_m)) { network_m = callocz(1, sizeof(struct network_metrics)); if(unlikely(i == 0)) d->network_root = network_m; else last_network_m->next = network_m; } network_m->id = i; network = xenstat_domain_network(domain, i); if(unlikely(!network)) { error("XENSTAT: cannot get network statistics."); return 1; } network_m->rbytes = xenstat_network_rbytes(network); network_m->rpackets = xenstat_network_rpackets(network); network_m->rerrs = xenstat_network_rerrs(network); network_m->rdrops = xenstat_network_rdrop(network); network_m->tbytes = xenstat_network_tbytes(network); network_m->tpackets = xenstat_network_tpackets(network); network_m->terrs = xenstat_network_terrs(network); network_m->tdrops = xenstat_network_tdrop(network); network_m->updated = 1; last_network_m = network_m; network_m = network_m->next; } return 0; } static int xenstat_collect(xenstat_handle *xhandle, libxl_ctx *ctx, libxl_dominfo *info) { // mark all old metrics as not-updated struct domain_metrics *d; for(d = node_metrics.domain_root; d ; d = d->next) d->updated = 0; xenstat_node *node = xenstat_get_node(xhandle, XENSTAT_ALL); if (unlikely(!node)) { error("XENSTAT: failed to retrieve statistics from libxenstat."); return 1; } node_metrics.tot_mem = xenstat_node_tot_mem(node); node_metrics.free_mem = xenstat_node_free_mem(node); node_metrics.num_domains = xenstat_node_num_domains(node); node_metrics.num_cpus = xenstat_node_num_cpus(node); node_metrics.node_cpu_hz = xenstat_node_cpu_hz(node); int i; for(i = 0; i < node_metrics.num_domains; i++) { xenstat_domain *domain = NULL; char uuid[LIBXL_UUID_FMTLEN + 1]; domain = xenstat_node_domain_by_index(node, i); // get domain UUID unsigned int id = xenstat_domain_id(domain); if(unlikely(libxl_domain_info(ctx, info, id))) { error("XENSTAT: cannot get domain info."); } else { snprintfz(uuid, LIBXL_UUID_FMTLEN, LIBXL_UUID_FMT "\n", LIBXL_UUID_BYTES(info->uuid)); } uint32_t hash = simple_hash(uuid); d = domain_metrics_get(uuid, hash); d->id = id; if(unlikely(!d->name)) { d->name = strdupz(xenstat_domain_name(domain)); netdata_fix_chart_id(d->name); if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: domain id %d, uuid %s has name '%s'\n", d->id, d->uuid, d->name); } d->running = xenstat_domain_running(domain); d->blocked = xenstat_domain_blocked(domain); d->paused = xenstat_domain_paused(domain); d->shutdown = xenstat_domain_shutdown(domain); d->crashed = xenstat_domain_crashed(domain); d->dying = xenstat_domain_dying(domain); d->cpu_ns = xenstat_domain_cpu_ns(domain); d->cur_mem = xenstat_domain_cur_mem(domain); d->max_mem = xenstat_domain_max_mem(domain); if(unlikely(vcpu_metrics_collect(d, domain) || vbd_metrics_collect(d, domain) || network_metrics_collect(d, domain))) { xenstat_free_node(node); return 1; } d->updated = 1; } xenstat_free_node(node); return 0; } static void xenstat_send_node_metrics() { static int mem_chart_generated = 0, domains_chart_generated = 0, cpus_chart_generated = 0, cpu_freq_chart_generated = 0; // ---------------------------------------------------------------- if(unlikely(!mem_chart_generated)) { printf("CHART xenstat.mem '' 'Memory Usage' 'MiB' 'memory' '' stacked %d %d '' %s\n" , NETDATA_CHART_PRIO_XENSTAT_NODE_MEM , netdata_update_every , PLUGIN_XENSTAT_NAME ); printf("DIMENSION %s '' absolute 1 %d\n", "free", netdata_update_every * 1024 * 1024); printf("DIMENSION %s '' absolute 1 %d\n", "used", netdata_update_every * 1024 * 1024); mem_chart_generated = 1; } printf( "BEGIN xenstat.mem\n" "SET free = %lld\n" "SET used = %lld\n" "END\n" , (collected_number) node_metrics.free_mem , (collected_number) (node_metrics.tot_mem - node_metrics.free_mem) ); // ---------------------------------------------------------------- if(unlikely(!domains_chart_generated)) { printf("CHART xenstat.domains '' 'Number of Domains' 'domains' 'domains' '' line %d %d '' %s\n" , NETDATA_CHART_PRIO_XENSTAT_NODE_DOMAINS , netdata_update_every , PLUGIN_XENSTAT_NAME ); printf("DIMENSION %s '' absolute 1 %d\n", "domains", netdata_update_every); domains_chart_generated = 1; } printf( "BEGIN xenstat.domains\n" "SET domains = %lld\n" "END\n" , (collected_number) node_metrics.num_domains ); // ---------------------------------------------------------------- if(unlikely(!cpus_chart_generated)) { printf("CHART xenstat.cpus '' 'Number of CPUs' 'cpus' 'cpu' '' line %d %d '' %s\n" , NETDATA_CHART_PRIO_XENSTAT_NODE_CPUS , netdata_update_every , PLUGIN_XENSTAT_NAME ); printf("DIMENSION %s '' absolute 1 %d\n", "cpus", netdata_update_every); cpus_chart_generated = 1; } printf( "BEGIN xenstat.cpus\n" "SET cpus = %lld\n" "END\n" , (collected_number) node_metrics.num_cpus ); // ---------------------------------------------------------------- if(unlikely(!cpu_freq_chart_generated)) { printf("CHART xenstat.cpu_freq '' 'CPU Frequency' 'MHz' 'cpu' '' line %d %d '' %s\n" , NETDATA_CHART_PRIO_XENSTAT_NODE_CPU_FREQ , netdata_update_every , PLUGIN_XENSTAT_NAME ); printf("DIMENSION %s '' absolute 1 %d\n", "frequency", netdata_update_every * 1024 * 1024); cpu_freq_chart_generated = 1; } printf( "BEGIN xenstat.cpu_freq\n" "SET frequency = %lld\n" "END\n" , (collected_number) node_metrics.node_cpu_hz ); } static void print_domain_states_chart_definition(char *type, int obsolete_flag) { printf("CHART %s.states '' 'Domain States' 'boolean' 'states' 'xendomain.states' line %d %d %s %s\n" , type , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_STATES , netdata_update_every , obsolete_flag ? "obsolete": "''" , PLUGIN_XENSTAT_NAME ); printf("DIMENSION running '' absolute 1 %d\n", netdata_update_every); printf("DIMENSION blocked '' absolute 1 %d\n", netdata_update_every); printf("DIMENSION paused '' absolute 1 %d\n", netdata_update_every); printf("DIMENSION shutdown '' absolute 1 %d\n", netdata_update_every); printf("DIMENSION crashed '' absolute 1 %d\n", netdata_update_every); printf("DIMENSION dying '' absolute 1 %d\n", netdata_update_every); } static void print_domain_cpu_chart_definition(char *type, int obsolete_flag) { printf("CHART %s.cpu '' 'CPU Usage (100%% = 1 core)' 'percentage' 'cpu' 'xendomain.cpu' line %d %d %s %s\n" , type , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_CPU , netdata_update_every , obsolete_flag ? "obsolete": "''" , PLUGIN_XENSTAT_NAME ); printf("DIMENSION used '' incremental 100 %d\n", netdata_update_every * 1000000000); } static void print_domain_mem_chart_definition(char *type, int obsolete_flag) { printf("CHART %s.mem '' 'Memory Reservation' 'MiB' 'memory' 'xendomain.mem' line %d %d %s %s\n" , type , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_MEM , netdata_update_every , obsolete_flag ? "obsolete": "''" , PLUGIN_XENSTAT_NAME ); printf("DIMENSION maximum '' absolute 1 %d\n", netdata_update_every * 1024 * 1024); printf("DIMENSION current '' absolute 1 %d\n", netdata_update_every * 1024 * 1024); } static void print_domain_vcpu_chart_definition(char *type, struct domain_metrics *d, int obsolete_flag) { struct vcpu_metrics *vcpu_m; printf("CHART %s.vcpu '' 'CPU Usage per VCPU' 'percentage' 'cpu' 'xendomain.vcpu' line %d %d %s %s\n" , type , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VCPU , netdata_update_every , obsolete_flag ? "obsolete": "''" , PLUGIN_XENSTAT_NAME ); for(vcpu_m = d->vcpu_root; vcpu_m; vcpu_m = vcpu_m->next) { if(likely(vcpu_m->updated && vcpu_m->online)) { printf("DIMENSION vcpu%u '' incremental 100 %d\n", vcpu_m->id, netdata_update_every * 1000000000); } } } static void print_domain_vbd_oo_chart_definition(char *type, unsigned int vbd, int obsolete_flag) { printf("CHART %s.oo_req_vbd%u '' 'VBD%u \"Out Of\" Requests' 'requests/s' 'vbd' 'xendomain.oo_req_vbd' line %d %d %s %s\n" , type , vbd , vbd , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_OO_REQ + vbd , netdata_update_every , obsolete_flag ? "obsolete": "''" , PLUGIN_XENSTAT_NAME ); printf("DIMENSION requests '' incremental 1 %d\n", netdata_update_every); } static void print_domain_vbd_requests_chart_definition(char *type, unsigned int vbd, int obsolete_flag) { printf("CHART %s.requests_vbd%u '' 'VBD%u Requests' 'requests/s' 'vbd' 'xendomain.requests_vbd' line %d %d %s %s\n" , type , vbd , vbd , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_REQUESTS + vbd , netdata_update_every , obsolete_flag ? "obsolete": "''" , PLUGIN_XENSTAT_NAME ); printf("DIMENSION read '' incremental 1 %d\n", netdata_update_every); printf("DIMENSION write '' incremental -1 %d\n", netdata_update_every); } static void print_domain_vbd_sectors_chart_definition(char *type, unsigned int vbd, int obsolete_flag) { printf("CHART %s.sectors_vbd%u '' 'VBD%u Read/Written Sectors' 'sectors/s' 'vbd' 'xendomain.sectors_vbd' line %d %d %s %s\n" , type , vbd , vbd , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_SECTORS + vbd , netdata_update_every , obsolete_flag ? "obsolete": "''" , PLUGIN_XENSTAT_NAME ); printf("DIMENSION read '' incremental 1 %d\n", netdata_update_every); printf("DIMENSION write '' incremental -1 %d\n", netdata_update_every); } static void print_domain_network_bytes_chart_definition(char *type, unsigned int network, int obsolete_flag) { printf("CHART %s.bytes_network%u '' 'Network%u Received/Sent Bytes' 'kilobits/s' 'network' 'xendomain.bytes_network' line %d %d %s %s\n" , type , network , network , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_BYTES + network , netdata_update_every , obsolete_flag ? "obsolete": "''" , PLUGIN_XENSTAT_NAME ); printf("DIMENSION received '' incremental 8 %d\n", netdata_update_every * 1000); printf("DIMENSION sent '' incremental -8 %d\n", netdata_update_every * 1000); } static void print_domain_network_packets_chart_definition(char *type, unsigned int network, int obsolete_flag) { printf("CHART %s.packets_network%u '' 'Network%u Received/Sent Packets' 'packets/s' 'network' 'xendomain.packets_network' line %d %d %s %s\n" , type , network , network , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_PACKETS + network , netdata_update_every , obsolete_flag ? "obsolete": "''" , PLUGIN_XENSTAT_NAME ); printf("DIMENSION received '' incremental 1 %d\n", netdata_update_every); printf("DIMENSION sent '' incremental -1 %d\n", netdata_update_every); } static void print_domain_network_errors_chart_definition(char *type, unsigned int network, int obsolete_flag) { printf("CHART %s.errors_network%u '' 'Network%u Receive/Transmit Errors' 'errors/s' 'network' 'xendomain.errors_network' line %d %d %s %s\n" , type , network , network , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_PACKETS + network , netdata_update_every , obsolete_flag ? "obsolete": "''" , PLUGIN_XENSTAT_NAME ); printf("DIMENSION received '' incremental 1 %d\n", netdata_update_every); printf("DIMENSION sent '' incremental -1 %d\n", netdata_update_every); } static void print_domain_network_drops_chart_definition(char *type, unsigned int network, int obsolete_flag) { printf("CHART %s.drops_network%u '' 'Network%u Receive/Transmit Drops' 'drops/s' 'network' 'xendomain.drops_network' line %d %d %s %s\n" , type , network , network , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_PACKETS + network , netdata_update_every , obsolete_flag ? "obsolete": "''" , PLUGIN_XENSTAT_NAME ); printf("DIMENSION received '' incremental 1 %d\n", netdata_update_every); printf("DIMENSION sent '' incremental -1 %d\n", netdata_update_every); } static void xenstat_send_domain_metrics() { if(unlikely(!node_metrics.domain_root)) return; struct domain_metrics *d; for(d = node_metrics.domain_root; d; d = d->next) { char type[TYPE_LENGTH_MAX + 1]; snprintfz(type, TYPE_LENGTH_MAX, "xendomain_%s_%s", d->name, d->uuid); if(likely(d->updated)) { // ---------------------------------------------------------------- if(unlikely(!d->states_chart_generated)) { print_domain_states_chart_definition(type, CHART_IS_NOT_OBSOLETE); d->states_chart_generated = 1; } printf( "BEGIN %s.states\n" "SET running = %lld\n" "SET blocked = %lld\n" "SET paused = %lld\n" "SET shutdown = %lld\n" "SET crashed = %lld\n" "SET dying = %lld\n" "END\n" , type , (collected_number)d->running , (collected_number)d->blocked , (collected_number)d->paused , (collected_number)d->shutdown , (collected_number)d->crashed , (collected_number)d->dying ); // ---------------------------------------------------------------- if(unlikely(!d->cpu_chart_generated)) { print_domain_cpu_chart_definition(type, CHART_IS_NOT_OBSOLETE); d->cpu_chart_generated = 1; } printf( "BEGIN %s.cpu\n" "SET used = %lld\n" "END\n" , type , (collected_number)d->cpu_ns ); // ---------------------------------------------------------------- struct vcpu_metrics *vcpu_m; if(unlikely(!d->vcpu_chart_generated || d->num_vcpus_changed)) { print_domain_vcpu_chart_definition(type, d, CHART_IS_NOT_OBSOLETE); d->num_vcpus_changed = 0; d->vcpu_chart_generated = 1; } printf("BEGIN %s.vcpu\n", type); for(vcpu_m = d->vcpu_root; vcpu_m; vcpu_m = vcpu_m->next) { if(likely(vcpu_m->updated && vcpu_m->online)) { printf( "SET vcpu%u = %lld\n" , vcpu_m->id , (collected_number)vcpu_m->ns ); } } printf("END\n"); // ---------------------------------------------------------------- if(unlikely(!d->mem_chart_generated)) { print_domain_mem_chart_definition(type, CHART_IS_NOT_OBSOLETE); d->mem_chart_generated = 1; } printf( "BEGIN %s.mem\n" "SET maximum = %lld\n" "SET current = %lld\n" "END\n" , type , (collected_number)d->max_mem , (collected_number)d->cur_mem ); // ---------------------------------------------------------------- struct vbd_metrics *vbd_m; for(vbd_m = d->vbd_root; vbd_m; vbd_m = vbd_m->next) { if(likely(vbd_m->updated && !vbd_m->error)) { if(unlikely(!vbd_m->oo_req_chart_generated)) { print_domain_vbd_oo_chart_definition(type, vbd_m->id, CHART_IS_NOT_OBSOLETE); vbd_m->oo_req_chart_generated = 1; } printf( "BEGIN %s.oo_req_vbd%u\n" "SET requests = %lld\n" "END\n" , type , vbd_m->id , (collected_number)vbd_m->oo_reqs ); // ---------------------------------------------------------------- if(unlikely(!vbd_m->requests_chart_generated)) { print_domain_vbd_requests_chart_definition(type, vbd_m->id, CHART_IS_NOT_OBSOLETE); vbd_m->requests_chart_generated = 1; } printf( "BEGIN %s.requests_vbd%u\n" "SET read = %lld\n" "SET write = %lld\n" "END\n" , type , vbd_m->id , (collected_number)vbd_m->rd_reqs , (collected_number)vbd_m->wr_reqs ); // ---------------------------------------------------------------- if(unlikely(!vbd_m->sectors_chart_generated)) { print_domain_vbd_sectors_chart_definition(type, vbd_m->id, CHART_IS_NOT_OBSOLETE); vbd_m->sectors_chart_generated = 1; } printf( "BEGIN %s.sectors_vbd%u\n" "SET read = %lld\n" "SET write = %lld\n" "END\n" , type , vbd_m->id , (collected_number)vbd_m->rd_sects , (collected_number)vbd_m->wr_sects ); } else { if(unlikely(vbd_m->oo_req_chart_generated || vbd_m->requests_chart_generated || vbd_m->sectors_chart_generated)) { if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: mark charts as obsolete for vbd %d, domain '%s', id %d, uuid %s\n", vbd_m->id, d->name, d->id, d->uuid); print_domain_vbd_oo_chart_definition(type, vbd_m->id, CHART_IS_OBSOLETE); print_domain_vbd_requests_chart_definition(type, vbd_m->id, CHART_IS_OBSOLETE); print_domain_vbd_sectors_chart_definition(type, vbd_m->id, CHART_IS_OBSOLETE); vbd_m->oo_req_chart_generated = 0; vbd_m->requests_chart_generated = 0; vbd_m->sectors_chart_generated = 0; } } } // ---------------------------------------------------------------- struct network_metrics *network_m; for(network_m = d->network_root; network_m; network_m = network_m->next) { if(likely(network_m->updated)) { if(unlikely(!network_m->bytes_chart_generated)) { print_domain_network_bytes_chart_definition(type, network_m->id, CHART_IS_NOT_OBSOLETE); network_m->bytes_chart_generated = 1; } printf( "BEGIN %s.bytes_network%u\n" "SET received = %lld\n" "SET sent = %lld\n" "END\n" , type , network_m->id , (collected_number)network_m->rbytes , (collected_number)network_m->tbytes ); // ---------------------------------------------------------------- if(unlikely(!network_m->packets_chart_generated)) { print_domain_network_packets_chart_definition(type, network_m->id, CHART_IS_NOT_OBSOLETE); network_m->packets_chart_generated = 1; } printf( "BEGIN %s.packets_network%u\n" "SET received = %lld\n" "SET sent = %lld\n" "END\n" , type , network_m->id , (collected_number)network_m->rpackets , (collected_number)network_m->tpackets ); // ---------------------------------------------------------------- if(unlikely(!network_m->errors_chart_generated)) { print_domain_network_errors_chart_definition(type, network_m->id, CHART_IS_NOT_OBSOLETE); network_m->errors_chart_generated = 1; } printf( "BEGIN %s.errors_network%u\n" "SET received = %lld\n" "SET sent = %lld\n" "END\n" , type , network_m->id , (collected_number)network_m->rerrs , (collected_number)network_m->terrs ); // ---------------------------------------------------------------- if(unlikely(!network_m->drops_chart_generated)) { print_domain_network_drops_chart_definition(type, network_m->id, CHART_IS_NOT_OBSOLETE); network_m->drops_chart_generated = 1; } printf( "BEGIN %s.drops_network%u\n" "SET received = %lld\n" "SET sent = %lld\n" "END\n" , type , network_m->id , (collected_number)network_m->rdrops , (collected_number)network_m->tdrops ); } else { if(unlikely(network_m->bytes_chart_generated || network_m->packets_chart_generated || network_m->errors_chart_generated || network_m->drops_chart_generated)) if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: mark charts as obsolete for network %d, domain '%s', id %d, uuid %s\n", network_m->id, d->name, d->id, d->uuid); print_domain_network_bytes_chart_definition(type, network_m->id, CHART_IS_OBSOLETE); print_domain_network_packets_chart_definition(type, network_m->id, CHART_IS_OBSOLETE); print_domain_network_errors_chart_definition(type, network_m->id, CHART_IS_OBSOLETE); print_domain_network_drops_chart_definition(type, network_m->id, CHART_IS_OBSOLETE); network_m->bytes_chart_generated = 0; network_m->packets_chart_generated = 0; network_m->errors_chart_generated = 0; network_m->drops_chart_generated = 0; } } } else{ if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: mark charts as obsolete for domain '%s', id %d, uuid %s\n", d->name, d->id, d->uuid); print_domain_states_chart_definition(type, CHART_IS_OBSOLETE); print_domain_cpu_chart_definition(type, CHART_IS_OBSOLETE); print_domain_vcpu_chart_definition(type, d, CHART_IS_OBSOLETE); print_domain_mem_chart_definition(type, CHART_IS_OBSOLETE); d = domain_metrics_free(d); } } } int main(int argc, char **argv) { // ------------------------------------------------------------------------ // initialization of netdata plugin program_name = "xenstat.plugin"; // disable syslog error_log_syslog = 0; // set errors flood protection to 100 logs per hour error_log_errors_per_period = 100; error_log_throttle_period = 3600; // ------------------------------------------------------------------------ // parse command line parameters int i, freq = 0; for(i = 1; i < argc ; i++) { if(isdigit(*argv[i]) && !freq) { int n = str2i(argv[i]); if(n > 0 && n < 86400) { freq = n; continue; } } else if(strcmp("version", argv[i]) == 0 || strcmp("-version", argv[i]) == 0 || strcmp("--version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) { printf("xenstat.plugin %s\n", VERSION); exit(0); } else if(strcmp("debug", argv[i]) == 0) { debug = 1; continue; } else if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) { fprintf(stderr, "\n" " netdata xenstat.plugin %s\n" " Copyright (C) 2019 Netdata Inc.\n" " Released under GNU General Public License v3 or later.\n" " All rights reserved.\n" "\n" " This program is a data collector plugin for netdata.\n" "\n" " Available command line options:\n" "\n" " COLLECTION_FREQUENCY data collection frequency in seconds\n" " minimum: %d\n" "\n" " debug enable verbose output\n" " default: disabled\n" "\n" " -v\n" " -V\n" " --version print version and exit\n" "\n" " -h\n" " --help print this message and exit\n" "\n" " For more information:\n" " https://github.com/netdata/netdata/tree/master/collectors/xenstat.plugin\n" "\n" , VERSION , netdata_update_every ); exit(1); } error("xenstat.plugin: ignoring parameter '%s'", argv[i]); } errno = 0; if(freq >= netdata_update_every) netdata_update_every = freq; else if(freq) error("update frequency %d seconds is too small for XENSTAT. Using %d.", freq, netdata_update_every); // ------------------------------------------------------------------------ // initialize xen API handles xenstat_handle *xhandle = NULL; libxl_ctx *ctx = NULL; libxl_dominfo info; if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling xenstat_init()\n"); xhandle = xenstat_init(); if (xhandle == NULL) error("XENSTAT: failed to initialize xenstat library."); if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling libxl_ctx_alloc()\n"); if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, NULL)) { error("XENSTAT: failed to initialize xl context."); } libxl_dominfo_init(&info); // ------------------------------------------------------------------------ // the main loop if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: starting data collection\n"); time_t started_t = now_monotonic_sec(); size_t iteration; usec_t step = netdata_update_every * USEC_PER_SEC; heartbeat_t hb; heartbeat_init(&hb); for(iteration = 0; 1; iteration++) { usec_t dt = heartbeat_next(&hb, step); if(unlikely(netdata_exit)) break; if(unlikely(debug && iteration)) fprintf(stderr, "xenstat.plugin: iteration %zu, dt %llu usec\n" , iteration , dt ); if(likely(xhandle)) { if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling xenstat_collect()\n"); int ret = xenstat_collect(xhandle, ctx, &info); if(likely(!ret)) { if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling xenstat_send_node_metrics()\n"); xenstat_send_node_metrics(); if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling xenstat_send_domain_metrics()\n"); xenstat_send_domain_metrics(); } else { if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: can't collect data\n"); } } fflush(stdout); // restart check (14400 seconds) if(unlikely(now_monotonic_sec() - started_t > 14400)) break; } libxl_ctx_free(ctx); xenstat_uninit(xhandle); info("XENSTAT process exiting"); }