summaryrefslogtreecommitdiffstats
path: root/collectors/xenstat.plugin
diff options
context:
space:
mode:
Diffstat (limited to 'collectors/xenstat.plugin')
-rw-r--r--collectors/xenstat.plugin/Makefile.am8
l---------collectors/xenstat.plugin/README.md1
-rw-r--r--collectors/xenstat.plugin/integrations/xen_xcp-ng.md176
-rw-r--r--collectors/xenstat.plugin/metadata.yaml195
-rw-r--r--collectors/xenstat.plugin/xenstat_plugin.c1066
5 files changed, 1446 insertions, 0 deletions
diff --git a/collectors/xenstat.plugin/Makefile.am b/collectors/xenstat.plugin/Makefile.am
new file mode 100644
index 00000000..161784b8
--- /dev/null
+++ b/collectors/xenstat.plugin/Makefile.am
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
diff --git a/collectors/xenstat.plugin/README.md b/collectors/xenstat.plugin/README.md
new file mode 120000
index 00000000..32fe4d21
--- /dev/null
+++ b/collectors/xenstat.plugin/README.md
@@ -0,0 +1 @@
+integrations/xen_xcp-ng.md \ No newline at end of file
diff --git a/collectors/xenstat.plugin/integrations/xen_xcp-ng.md b/collectors/xenstat.plugin/integrations/xen_xcp-ng.md
new file mode 100644
index 00000000..17dc8d78
--- /dev/null
+++ b/collectors/xenstat.plugin/integrations/xen_xcp-ng.md
@@ -0,0 +1,176 @@
+<!--startmeta
+custom_edit_url: "https://github.com/netdata/netdata/edit/master/collectors/xenstat.plugin/README.md"
+meta_yaml: "https://github.com/netdata/netdata/edit/master/collectors/xenstat.plugin/metadata.yaml"
+sidebar_label: "Xen XCP-ng"
+learn_status: "Published"
+learn_rel_path: "Data Collection/Containers and VMs"
+most_popular: False
+message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE"
+endmeta-->
+
+# Xen XCP-ng
+
+
+<img src="https://netdata.cloud/img/xen.png" width="150"/>
+
+
+Plugin: xenstat.plugin
+Module: xenstat.plugin
+
+<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" />
+
+## Overview
+
+This collector monitors XenServer and XCP-ng host and domains statistics.
+
+
+
+This collector is supported on all platforms.
+
+This collector supports collecting metrics from multiple instances of this integration, including remote instances.
+
+The plugin needs setuid.
+
+### Default Behavior
+
+#### Auto-Detection
+
+This plugin requires the `xen-dom0-libs-devel` and `yajl-devel` libraries to be installed.
+
+#### Limits
+
+The default configuration for this integration does not impose any limits on data collection.
+
+#### Performance Impact
+
+The default configuration for this integration is not expected to impose a significant performance impact on the system.
+
+
+## Metrics
+
+Metrics grouped by *scope*.
+
+The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels.
+
+
+
+### Per Xen XCP-ng instance
+
+These metrics refer to the entire monitored application.
+
+This scope has no labels.
+
+Metrics:
+
+| Metric | Dimensions | Unit |
+|:------|:----------|:----|
+| xenstat.mem | free, used | MiB |
+| xenstat.domains | domains | domains |
+| xenstat.cpus | cpus | cpus |
+| xenstat.cpu_freq | frequency | MHz |
+
+### Per xendomain
+
+Metrics related to Xen domains. Each domain provides its own set of the following metrics.
+
+This scope has no labels.
+
+Metrics:
+
+| Metric | Dimensions | Unit |
+|:------|:----------|:----|
+| xendomain.states | running, blocked, paused, shutdown, crashed, dying | boolean |
+| xendomain.cpu | used | percentage |
+| xendomain.mem | maximum, current | MiB |
+| xendomain.vcpu | a dimension per vcpu | percentage |
+
+### Per xendomain vbd
+
+Metrics related to Xen domain Virtual Block Device. Each VBD provides its own set of the following metrics.
+
+This scope has no labels.
+
+Metrics:
+
+| Metric | Dimensions | Unit |
+|:------|:----------|:----|
+| xendomain.oo_req_vbd | requests | requests/s |
+| xendomain.requests_vbd | read, write | requests/s |
+| xendomain.sectors_vbd | read, write | sectors/s |
+
+### Per xendomain network
+
+Metrics related to Xen domain network interfaces. Each network interface provides its own set of the following metrics.
+
+This scope has no labels.
+
+Metrics:
+
+| Metric | Dimensions | Unit |
+|:------|:----------|:----|
+| xendomain.bytes_network | received, sent | kilobits/s |
+| xendomain.packets_network | received, sent | packets/s |
+| xendomain.errors_network | received, sent | errors/s |
+| xendomain.drops_network | received, sent | drops/s |
+
+
+
+## Alerts
+
+There are no alerts configured by default for this integration.
+
+
+## Setup
+
+### Prerequisites
+
+#### Libraries
+
+1. Install `xen-dom0-libs-devel` and `yajl-devel` using the package manager of your system.
+
+ Note: On Cent-OS systems you will need `centos-release-xen` repository and the required package for xen is `xen-devel`
+
+2. Re-install Netdata from source. The installer will detect that the required libraries are now available and will also build xenstat.plugin.
+
+
+
+### Configuration
+
+#### File
+
+The configuration file name for this integration is `netdata.conf`.
+Configuration for this specific integration is located in the `[plugin:xenstat]` section within that file.
+
+The file format is a modified INI syntax. The general structure is:
+
+```ini
+[section1]
+ option1 = some value
+ option2 = some other value
+
+[section2]
+ option3 = some third value
+```
+You can edit the configuration file using the `edit-config` script from the
+Netdata [config directory](https://github.com/netdata/netdata/blob/master/docs/configure/nodes.md#the-netdata-config-directory).
+
+```bash
+cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata
+sudo ./edit-config netdata.conf
+```
+#### Options
+
+
+
+<details><summary>Config options</summary>
+
+| Name | Description | Default | Required |
+|:----|:-----------|:-------|:--------:|
+| update every | Data collection frequency. | 1 | no |
+
+</details>
+
+#### Examples
+There are no configuration examples.
+
+
diff --git a/collectors/xenstat.plugin/metadata.yaml b/collectors/xenstat.plugin/metadata.yaml
new file mode 100644
index 00000000..e5527dbb
--- /dev/null
+++ b/collectors/xenstat.plugin/metadata.yaml
@@ -0,0 +1,195 @@
+plugin_name: xenstat.plugin
+modules:
+ - meta:
+ plugin_name: xenstat.plugin
+ module_name: xenstat.plugin
+ monitored_instance:
+ name: Xen XCP-ng
+ link: "https://xenproject.org/"
+ categories:
+ - data-collection.containers-and-vms
+ icon_filename: "xen.png"
+ related_resources:
+ integrations:
+ list: []
+ info_provided_to_referring_integrations:
+ description: ""
+ keywords: []
+ most_popular: false
+ overview:
+ data_collection:
+ metrics_description: "This collector monitors XenServer and XCP-ng host and domains statistics."
+ method_description: ""
+ supported_platforms:
+ include: []
+ exclude: []
+ multi_instance: true
+ additional_permissions:
+ description: "The plugin needs setuid."
+ default_behavior:
+ auto_detection:
+ description: "This plugin requires the `xen-dom0-libs-devel` and `yajl-devel` libraries to be installed."
+ limits:
+ description: ""
+ performance_impact:
+ description: ""
+ setup:
+ prerequisites:
+ list:
+ - title: Libraries
+ description: |
+ 1. Install `xen-dom0-libs-devel` and `yajl-devel` using the package manager of your system.
+
+ Note: On Cent-OS systems you will need `centos-release-xen` repository and the required package for xen is `xen-devel`
+
+ 2. Re-install Netdata from source. The installer will detect that the required libraries are now available and will also build xenstat.plugin.
+ configuration:
+ file:
+ name: "netdata.conf"
+ section_name: "[plugin:xenstat]"
+ description: "The netdata main configuration file."
+ options:
+ description: ""
+ folding:
+ title: "Config options"
+ enabled: true
+ list:
+ - name: update every
+ description: Data collection frequency.
+ default_value: 1
+ required: false
+ examples:
+ folding:
+ enabled: true
+ title: ""
+ list: []
+ troubleshooting:
+ problems:
+ list: []
+ alerts: []
+ metrics:
+ folding:
+ title: Metrics
+ enabled: false
+ description: ""
+ availability: []
+ scopes:
+ - name: global
+ description: "These metrics refer to the entire monitored application."
+ labels: []
+ metrics:
+ - name: xenstat.mem
+ description: Memory Usage
+ unit: "MiB"
+ chart_type: stacked
+ dimensions:
+ - name: free
+ - name: used
+ - name: xenstat.domains
+ description: Number of Domains
+ unit: "domains"
+ chart_type: line
+ dimensions:
+ - name: domains
+ - name: xenstat.cpus
+ description: Number of CPUs
+ unit: "cpus"
+ chart_type: line
+ dimensions:
+ - name: cpus
+ - name: xenstat.cpu_freq
+ description: CPU Frequency
+ unit: "MHz"
+ chart_type: line
+ dimensions:
+ - name: frequency
+ - name: xendomain
+ description: "Metrics related to Xen domains. Each domain provides its own set of the following metrics."
+ labels: []
+ metrics:
+ - name: xendomain.states
+ description: Domain States
+ unit: "boolean"
+ chart_type: line
+ dimensions:
+ - name: running
+ - name: blocked
+ - name: paused
+ - name: shutdown
+ - name: crashed
+ - name: dying
+ - name: xendomain.cpu
+ description: CPU Usage (100% = 1 core)
+ unit: "percentage"
+ chart_type: line
+ dimensions:
+ - name: used
+ - name: xendomain.mem
+ description: Memory Reservation
+ unit: "MiB"
+ chart_type: line
+ dimensions:
+ - name: maximum
+ - name: current
+ - name: xendomain.vcpu
+ description: CPU Usage per VCPU
+ unit: "percentage"
+ chart_type: line
+ dimensions:
+ - name: a dimension per vcpu
+ - name: xendomain vbd
+ description: "Metrics related to Xen domain Virtual Block Device. Each VBD provides its own set of the following metrics."
+ labels: []
+ metrics:
+ - name: xendomain.oo_req_vbd
+ description: VBD{%u} Out Of Requests
+ unit: "requests/s"
+ chart_type: line
+ dimensions:
+ - name: requests
+ - name: xendomain.requests_vbd
+ description: VBD{%u} Requests
+ unit: "requests/s"
+ chart_type: line
+ dimensions:
+ - name: read
+ - name: write
+ - name: xendomain.sectors_vbd
+ description: VBD{%u} Read/Written Sectors
+ unit: "sectors/s"
+ chart_type: line
+ dimensions:
+ - name: read
+ - name: write
+ - name: xendomain network
+ description: "Metrics related to Xen domain network interfaces. Each network interface provides its own set of the following metrics."
+ labels: []
+ metrics:
+ - name: xendomain.bytes_network
+ description: Network{%u} Received/Sent Bytes
+ unit: "kilobits/s"
+ chart_type: line
+ dimensions:
+ - name: received
+ - name: sent
+ - name: xendomain.packets_network
+ description: Network{%u} Received/Sent Packets
+ unit: "packets/s"
+ chart_type: line
+ dimensions:
+ - name: received
+ - name: sent
+ - name: xendomain.errors_network
+ description: Network{%u} Receive/Transmit Errors
+ unit: "errors/s"
+ chart_type: line
+ dimensions:
+ - name: received
+ - name: sent
+ - name: xendomain.drops_network
+ description: Network{%u} Receive/Transmit Drops
+ unit: "drops/s"
+ chart_type: line
+ dimensions:
+ - name: received
+ - name: sent
diff --git a/collectors/xenstat.plugin/xenstat_plugin.c b/collectors/xenstat.plugin/xenstat_plugin.c
new file mode 100644
index 00000000..319396d4
--- /dev/null
+++ b/collectors/xenstat.plugin/xenstat_plugin.c
@@ -0,0 +1,1066 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "libnetdata/libnetdata.h"
+#include "libnetdata/required_dummies.h"
+
+#include <xenstat.h>
+#include <libxl.h>
+
+#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
+
+// 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 %u, 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)) {
+ netdata_log_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)) {
+ netdata_log_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)) {
+ netdata_log_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)) {
+ netdata_log_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)) {
+ netdata_log_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))) {
+ netdata_log_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 %u, 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 %u %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 %u %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 %u %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 %u %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 %u %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 %u %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 %u %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 %u, domain '%s', id %u, 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 %u, domain '%s', id %u, 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 %u, 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) {
+ clocks_init();
+
+ // ------------------------------------------------------------------------
+ // initialization of netdata plugin
+
+ program_name = PLUGIN_XENSTAT_NAME;
+
+ nd_log_initialize_for_external_plugins(PLUGIN_XENSTAT_NAME);
+
+ // ------------------------------------------------------------------------
+ // 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);
+ }
+
+ netdata_log_error("xenstat.plugin: ignoring parameter '%s'", argv[i]);
+ }
+
+ errno = 0;
+
+ if(freq >= netdata_update_every)
+ netdata_update_every = freq;
+ else if(freq)
+ netdata_log_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) {
+ netdata_log_error("XENSTAT: failed to initialize xenstat library.");
+ return 1;
+ }
+
+ if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling libxl_ctx_alloc()\n");
+ if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, NULL)) {
+ netdata_log_error("XENSTAT: failed to initialize xl context.");
+ xenstat_uninit(xhandle);
+ return 1;
+ }
+ 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);
+ netdata_log_info("XENSTAT process exiting");
+
+ return 0;
+}