xenstat_plugin.c 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "../../libnetdata/libnetdata.h"
  3. #define PLUGIN_XENSTAT_NAME "xenstat.plugin"
  4. #define NETDATA_CHART_PRIO_XENSTAT_NODE_CPUS 30001
  5. #define NETDATA_CHART_PRIO_XENSTAT_NODE_CPU_FREQ 30002
  6. #define NETDATA_CHART_PRIO_XENSTAT_NODE_MEM 30003
  7. #define NETDATA_CHART_PRIO_XENSTAT_NODE_TMEM 30004
  8. #define NETDATA_CHART_PRIO_XENSTAT_NODE_DOMAINS 30005
  9. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_STATES 30101
  10. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_CPU 30102
  11. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VCPU 30103
  12. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_MEM 30104
  13. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_TMEM_PAGES 30104
  14. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_TMEM_OPERATIONS 30105
  15. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_OO_REQ 30200
  16. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_REQUESTS 30300
  17. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_SECTORS 30400
  18. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_BYTES 30500
  19. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_PACKETS 30600
  20. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_ERRORS 30700
  21. #define NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_DROPS 30800
  22. #define TYPE_LENGTH_MAX 200
  23. #define CHART_IS_OBSOLETE 1
  24. #define CHART_IS_NOT_OBSOLETE 0
  25. // callback required by fatal()
  26. void netdata_cleanup_and_exit(int ret) {
  27. exit(ret);
  28. }
  29. void send_statistics( const char *action, const char *action_result, const char *action_data) {
  30. (void) action;
  31. (void) action_result;
  32. (void) action_data;
  33. return;
  34. }
  35. // callbacks required by popen()
  36. void signals_block(void) {};
  37. void signals_unblock(void) {};
  38. void signals_reset(void) {};
  39. // callback required by eval()
  40. int health_variable_lookup(const char *variable, uint32_t hash, struct rrdcalc *rc, calculated_number *result) {
  41. (void)variable;
  42. (void)hash;
  43. (void)rc;
  44. (void)result;
  45. return 0;
  46. };
  47. // required by get_system_cpus()
  48. char *netdata_configured_host_prefix = "";
  49. // Variables
  50. static int debug = 0;
  51. static int netdata_update_every = 1;
  52. #ifdef HAVE_LIBXENSTAT
  53. #include <xenstat.h>
  54. #include <libxl.h>
  55. struct vcpu_metrics {
  56. unsigned int id;
  57. unsigned int online;
  58. unsigned long long ns;
  59. int chart_generated;
  60. int updated;
  61. struct vcpu_metrics *next;
  62. };
  63. struct vbd_metrics {
  64. unsigned int id;
  65. unsigned int error;
  66. unsigned long long oo_reqs;
  67. unsigned long long rd_reqs;
  68. unsigned long long wr_reqs;
  69. unsigned long long rd_sects;
  70. unsigned long long wr_sects;
  71. int oo_req_chart_generated;
  72. int requests_chart_generated;
  73. int sectors_chart_generated;
  74. int updated;
  75. struct vbd_metrics *next;
  76. };
  77. struct network_metrics {
  78. unsigned int id;
  79. unsigned long long rbytes;
  80. unsigned long long rpackets;
  81. unsigned long long rerrs;
  82. unsigned long long rdrops;
  83. unsigned long long tbytes;
  84. unsigned long long tpackets;
  85. unsigned long long terrs;
  86. unsigned long long tdrops;
  87. int bytes_chart_generated;
  88. int packets_chart_generated;
  89. int errors_chart_generated;
  90. int drops_chart_generated;
  91. int updated;
  92. struct network_metrics *next;
  93. };
  94. struct domain_metrics {
  95. char *uuid;
  96. uint32_t hash;
  97. unsigned int id;
  98. char *name;
  99. // states
  100. unsigned int running;
  101. unsigned int blocked;
  102. unsigned int paused;
  103. unsigned int shutdown;
  104. unsigned int crashed;
  105. unsigned int dying;
  106. unsigned long long cpu_ns;
  107. unsigned long long cur_mem;
  108. unsigned long long max_mem;
  109. struct vcpu_metrics *vcpu_root;
  110. struct vbd_metrics *vbd_root;
  111. struct network_metrics *network_root;
  112. int states_chart_generated;
  113. int cpu_chart_generated;
  114. int vcpu_chart_generated;
  115. int num_vcpus_changed;
  116. int mem_chart_generated;
  117. int updated;
  118. struct domain_metrics *next;
  119. };
  120. struct node_metrics{
  121. unsigned long long tot_mem;
  122. unsigned long long free_mem;
  123. int num_domains;
  124. unsigned int num_cpus;
  125. unsigned long long node_cpu_hz;
  126. struct domain_metrics *domain_root;
  127. };
  128. static struct node_metrics node_metrics = {
  129. .domain_root = NULL
  130. };
  131. static inline struct domain_metrics *domain_metrics_get(const char *uuid, uint32_t hash) {
  132. struct domain_metrics *d = NULL, *last = NULL;
  133. for(d = node_metrics.domain_root; d ; last = d, d = d->next) {
  134. if(unlikely(d->hash == hash && !strcmp(d->uuid, uuid)))
  135. return d;
  136. }
  137. if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: allocating memory for domain with uuid %s\n", uuid);
  138. d = callocz(1, sizeof(struct domain_metrics));
  139. d->uuid = strdupz(uuid);
  140. d->hash = hash;
  141. if(unlikely(!last)) {
  142. d->next = node_metrics.domain_root;
  143. node_metrics.domain_root = d;
  144. }
  145. else {
  146. d->next = last->next;
  147. last->next = d;
  148. }
  149. return d;
  150. }
  151. static struct domain_metrics *domain_metrics_free(struct domain_metrics *d) {
  152. struct domain_metrics *cur = NULL, *last = NULL;
  153. struct vcpu_metrics *vcpu, *vcpu_f;
  154. struct vbd_metrics *vbd, *vbd_f;
  155. struct network_metrics *network, *network_f;
  156. if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: freeing memory for domain '%s' id %d, uuid %s\n", d->name, d->id, d->uuid);
  157. for(cur = node_metrics.domain_root; cur ; last = cur, cur = cur->next) {
  158. if(unlikely(cur->hash == d->hash && !strcmp(cur->uuid, d->uuid))) break;
  159. }
  160. if(unlikely(!cur)) {
  161. error("XENSTAT: failed to free domain metrics.");
  162. return NULL;
  163. }
  164. if(likely(last))
  165. last->next = cur->next;
  166. else
  167. node_metrics.domain_root = NULL;
  168. freez(cur->uuid);
  169. freez(cur->name);
  170. vcpu = cur->vcpu_root;
  171. while(vcpu) {
  172. vcpu_f = vcpu;
  173. vcpu = vcpu->next;
  174. freez(vcpu_f);
  175. }
  176. vbd = cur->vbd_root;
  177. while(vbd) {
  178. vbd_f = vbd;
  179. vbd = vbd->next;
  180. freez(vbd_f);
  181. }
  182. network = cur->network_root;
  183. while(network) {
  184. network_f = network;
  185. network = network->next;
  186. freez(network_f);
  187. }
  188. freez(cur);
  189. return last ? last : NULL;
  190. }
  191. static int vcpu_metrics_collect(struct domain_metrics *d, xenstat_domain *domain) {
  192. static unsigned int last_num_vcpus = 0;
  193. unsigned int num_vcpus = 0;
  194. xenstat_vcpu *vcpu = NULL;
  195. struct vcpu_metrics *vcpu_m = NULL, *last_vcpu_m = NULL;
  196. num_vcpus = xenstat_domain_num_vcpus(domain);
  197. if(unlikely(num_vcpus != last_num_vcpus)) {
  198. d->num_vcpus_changed = 1;
  199. last_num_vcpus = num_vcpus;
  200. }
  201. for(vcpu_m = d->vcpu_root; vcpu_m ; vcpu_m = vcpu_m->next)
  202. vcpu_m->updated = 0;
  203. vcpu_m = d->vcpu_root;
  204. unsigned int i;
  205. for(i = 0; i < num_vcpus; i++) {
  206. if(unlikely(!vcpu_m)) {
  207. vcpu_m = callocz(1, sizeof(struct vcpu_metrics));
  208. if(unlikely(i == 0)) d->vcpu_root = vcpu_m;
  209. else last_vcpu_m->next = vcpu_m;
  210. }
  211. vcpu_m->id = i;
  212. vcpu = xenstat_domain_vcpu(domain, i);
  213. if(unlikely(!vcpu)) {
  214. error("XENSTAT: cannot get VCPU statistics.");
  215. return 1;
  216. }
  217. vcpu_m->online = xenstat_vcpu_online(vcpu);
  218. vcpu_m->ns = xenstat_vcpu_ns(vcpu);
  219. vcpu_m->updated = 1;
  220. last_vcpu_m = vcpu_m;
  221. vcpu_m = vcpu_m->next;
  222. }
  223. return 0;
  224. }
  225. static int vbd_metrics_collect(struct domain_metrics *d, xenstat_domain *domain) {
  226. unsigned int num_vbds = xenstat_domain_num_vbds(domain);
  227. xenstat_vbd *vbd = NULL;
  228. struct vbd_metrics *vbd_m = NULL, *last_vbd_m = NULL;
  229. for(vbd_m = d->vbd_root; vbd_m ; vbd_m = vbd_m->next)
  230. vbd_m->updated = 0;
  231. vbd_m = d->vbd_root;
  232. unsigned int i;
  233. for(i = 0; i < num_vbds; i++) {
  234. if(unlikely(!vbd_m)) {
  235. vbd_m = callocz(1, sizeof(struct vbd_metrics));
  236. if(unlikely(i == 0)) d->vbd_root = vbd_m;
  237. else last_vbd_m->next = vbd_m;
  238. }
  239. vbd_m->id = i;
  240. vbd = xenstat_domain_vbd(domain, i);
  241. if(unlikely(!vbd)) {
  242. error("XENSTAT: cannot get VBD statistics.");
  243. return 1;
  244. }
  245. #ifdef HAVE_XENSTAT_VBD_ERROR
  246. vbd_m->error = xenstat_vbd_error(vbd);
  247. #else
  248. vbd_m->error = 0;
  249. #endif
  250. vbd_m->oo_reqs = xenstat_vbd_oo_reqs(vbd);
  251. vbd_m->rd_reqs = xenstat_vbd_rd_reqs(vbd);
  252. vbd_m->wr_reqs = xenstat_vbd_wr_reqs(vbd);
  253. vbd_m->rd_sects = xenstat_vbd_rd_sects(vbd);
  254. vbd_m->wr_sects = xenstat_vbd_wr_sects(vbd);
  255. vbd_m->updated = 1;
  256. last_vbd_m = vbd_m;
  257. vbd_m = vbd_m->next;
  258. }
  259. return 0;
  260. }
  261. static int network_metrics_collect(struct domain_metrics *d, xenstat_domain *domain) {
  262. unsigned int num_networks = xenstat_domain_num_networks(domain);
  263. xenstat_network *network = NULL;
  264. struct network_metrics *network_m = NULL, *last_network_m = NULL;
  265. for(network_m = d->network_root; network_m ; network_m = network_m->next)
  266. network_m->updated = 0;
  267. network_m = d->network_root;
  268. unsigned int i;
  269. for(i = 0; i < num_networks; i++) {
  270. if(unlikely(!network_m)) {
  271. network_m = callocz(1, sizeof(struct network_metrics));
  272. if(unlikely(i == 0)) d->network_root = network_m;
  273. else last_network_m->next = network_m;
  274. }
  275. network_m->id = i;
  276. network = xenstat_domain_network(domain, i);
  277. if(unlikely(!network)) {
  278. error("XENSTAT: cannot get network statistics.");
  279. return 1;
  280. }
  281. network_m->rbytes = xenstat_network_rbytes(network);
  282. network_m->rpackets = xenstat_network_rpackets(network);
  283. network_m->rerrs = xenstat_network_rerrs(network);
  284. network_m->rdrops = xenstat_network_rdrop(network);
  285. network_m->tbytes = xenstat_network_tbytes(network);
  286. network_m->tpackets = xenstat_network_tpackets(network);
  287. network_m->terrs = xenstat_network_terrs(network);
  288. network_m->tdrops = xenstat_network_tdrop(network);
  289. network_m->updated = 1;
  290. last_network_m = network_m;
  291. network_m = network_m->next;
  292. }
  293. return 0;
  294. }
  295. static int xenstat_collect(xenstat_handle *xhandle, libxl_ctx *ctx, libxl_dominfo *info) {
  296. // mark all old metrics as not-updated
  297. struct domain_metrics *d;
  298. for(d = node_metrics.domain_root; d ; d = d->next)
  299. d->updated = 0;
  300. xenstat_node *node = xenstat_get_node(xhandle, XENSTAT_ALL);
  301. if (unlikely(!node)) {
  302. error("XENSTAT: failed to retrieve statistics from libxenstat.");
  303. return 1;
  304. }
  305. node_metrics.tot_mem = xenstat_node_tot_mem(node);
  306. node_metrics.free_mem = xenstat_node_free_mem(node);
  307. node_metrics.num_domains = xenstat_node_num_domains(node);
  308. node_metrics.num_cpus = xenstat_node_num_cpus(node);
  309. node_metrics.node_cpu_hz = xenstat_node_cpu_hz(node);
  310. int i;
  311. for(i = 0; i < node_metrics.num_domains; i++) {
  312. xenstat_domain *domain = NULL;
  313. char uuid[LIBXL_UUID_FMTLEN + 1];
  314. domain = xenstat_node_domain_by_index(node, i);
  315. // get domain UUID
  316. unsigned int id = xenstat_domain_id(domain);
  317. if(unlikely(libxl_domain_info(ctx, info, id))) {
  318. error("XENSTAT: cannot get domain info.");
  319. }
  320. else {
  321. snprintfz(uuid, LIBXL_UUID_FMTLEN, LIBXL_UUID_FMT "\n", LIBXL_UUID_BYTES(info->uuid));
  322. }
  323. uint32_t hash = simple_hash(uuid);
  324. d = domain_metrics_get(uuid, hash);
  325. d->id = id;
  326. if(unlikely(!d->name)) {
  327. d->name = strdupz(xenstat_domain_name(domain));
  328. netdata_fix_chart_id(d->name);
  329. if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: domain id %d, uuid %s has name '%s'\n", d->id, d->uuid, d->name);
  330. }
  331. d->running = xenstat_domain_running(domain);
  332. d->blocked = xenstat_domain_blocked(domain);
  333. d->paused = xenstat_domain_paused(domain);
  334. d->shutdown = xenstat_domain_shutdown(domain);
  335. d->crashed = xenstat_domain_crashed(domain);
  336. d->dying = xenstat_domain_dying(domain);
  337. d->cpu_ns = xenstat_domain_cpu_ns(domain);
  338. d->cur_mem = xenstat_domain_cur_mem(domain);
  339. d->max_mem = xenstat_domain_max_mem(domain);
  340. if(unlikely(vcpu_metrics_collect(d, domain) || vbd_metrics_collect(d, domain) || network_metrics_collect(d, domain))) {
  341. xenstat_free_node(node);
  342. return 1;
  343. }
  344. d->updated = 1;
  345. }
  346. xenstat_free_node(node);
  347. return 0;
  348. }
  349. static void xenstat_send_node_metrics() {
  350. static int mem_chart_generated = 0, domains_chart_generated = 0, cpus_chart_generated = 0, cpu_freq_chart_generated = 0;
  351. // ----------------------------------------------------------------
  352. if(unlikely(!mem_chart_generated)) {
  353. printf("CHART xenstat.mem '' 'Memory Usage' 'MiB' 'memory' '' stacked %d %d '' %s\n"
  354. , NETDATA_CHART_PRIO_XENSTAT_NODE_MEM
  355. , netdata_update_every
  356. , PLUGIN_XENSTAT_NAME
  357. );
  358. printf("DIMENSION %s '' absolute 1 %d\n", "free", netdata_update_every * 1024 * 1024);
  359. printf("DIMENSION %s '' absolute 1 %d\n", "used", netdata_update_every * 1024 * 1024);
  360. mem_chart_generated = 1;
  361. }
  362. printf(
  363. "BEGIN xenstat.mem\n"
  364. "SET free = %lld\n"
  365. "SET used = %lld\n"
  366. "END\n"
  367. , (collected_number) node_metrics.free_mem
  368. , (collected_number) (node_metrics.tot_mem - node_metrics.free_mem)
  369. );
  370. // ----------------------------------------------------------------
  371. if(unlikely(!domains_chart_generated)) {
  372. printf("CHART xenstat.domains '' 'Number of Domains' 'domains' 'domains' '' line %d %d '' %s\n"
  373. , NETDATA_CHART_PRIO_XENSTAT_NODE_DOMAINS
  374. , netdata_update_every
  375. , PLUGIN_XENSTAT_NAME
  376. );
  377. printf("DIMENSION %s '' absolute 1 %d\n", "domains", netdata_update_every);
  378. domains_chart_generated = 1;
  379. }
  380. printf(
  381. "BEGIN xenstat.domains\n"
  382. "SET domains = %lld\n"
  383. "END\n"
  384. , (collected_number) node_metrics.num_domains
  385. );
  386. // ----------------------------------------------------------------
  387. if(unlikely(!cpus_chart_generated)) {
  388. printf("CHART xenstat.cpus '' 'Number of CPUs' 'cpus' 'cpu' '' line %d %d '' %s\n"
  389. , NETDATA_CHART_PRIO_XENSTAT_NODE_CPUS
  390. , netdata_update_every
  391. , PLUGIN_XENSTAT_NAME
  392. );
  393. printf("DIMENSION %s '' absolute 1 %d\n", "cpus", netdata_update_every);
  394. cpus_chart_generated = 1;
  395. }
  396. printf(
  397. "BEGIN xenstat.cpus\n"
  398. "SET cpus = %lld\n"
  399. "END\n"
  400. , (collected_number) node_metrics.num_cpus
  401. );
  402. // ----------------------------------------------------------------
  403. if(unlikely(!cpu_freq_chart_generated)) {
  404. printf("CHART xenstat.cpu_freq '' 'CPU Frequency' 'MHz' 'cpu' '' line %d %d '' %s\n"
  405. , NETDATA_CHART_PRIO_XENSTAT_NODE_CPU_FREQ
  406. , netdata_update_every
  407. , PLUGIN_XENSTAT_NAME
  408. );
  409. printf("DIMENSION %s '' absolute 1 %d\n", "frequency", netdata_update_every * 1024 * 1024);
  410. cpu_freq_chart_generated = 1;
  411. }
  412. printf(
  413. "BEGIN xenstat.cpu_freq\n"
  414. "SET frequency = %lld\n"
  415. "END\n"
  416. , (collected_number) node_metrics.node_cpu_hz
  417. );
  418. }
  419. static void print_domain_states_chart_definition(char *type, int obsolete_flag) {
  420. printf("CHART %s.states '' 'Domain States' 'boolean' 'states' 'xendomain.states' line %d %d %s %s\n"
  421. , type
  422. , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_STATES
  423. , netdata_update_every
  424. , obsolete_flag ? "obsolete": "''"
  425. , PLUGIN_XENSTAT_NAME
  426. );
  427. printf("DIMENSION running '' absolute 1 %d\n", netdata_update_every);
  428. printf("DIMENSION blocked '' absolute 1 %d\n", netdata_update_every);
  429. printf("DIMENSION paused '' absolute 1 %d\n", netdata_update_every);
  430. printf("DIMENSION shutdown '' absolute 1 %d\n", netdata_update_every);
  431. printf("DIMENSION crashed '' absolute 1 %d\n", netdata_update_every);
  432. printf("DIMENSION dying '' absolute 1 %d\n", netdata_update_every);
  433. }
  434. static void print_domain_cpu_chart_definition(char *type, int obsolete_flag) {
  435. printf("CHART %s.cpu '' 'CPU Usage (100%% = 1 core)' 'percentage' 'cpu' 'xendomain.cpu' line %d %d %s %s\n"
  436. , type
  437. , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_CPU
  438. , netdata_update_every
  439. , obsolete_flag ? "obsolete": "''"
  440. , PLUGIN_XENSTAT_NAME
  441. );
  442. printf("DIMENSION used '' incremental 100 %d\n", netdata_update_every * 1000000000);
  443. }
  444. static void print_domain_mem_chart_definition(char *type, int obsolete_flag) {
  445. printf("CHART %s.mem '' 'Memory Reservation' 'MiB' 'memory' 'xendomain.mem' line %d %d %s %s\n"
  446. , type
  447. , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_MEM
  448. , netdata_update_every
  449. , obsolete_flag ? "obsolete": "''"
  450. , PLUGIN_XENSTAT_NAME
  451. );
  452. printf("DIMENSION maximum '' absolute 1 %d\n", netdata_update_every * 1024 * 1024);
  453. printf("DIMENSION current '' absolute 1 %d\n", netdata_update_every * 1024 * 1024);
  454. }
  455. static void print_domain_vcpu_chart_definition(char *type, struct domain_metrics *d, int obsolete_flag) {
  456. struct vcpu_metrics *vcpu_m;
  457. printf("CHART %s.vcpu '' 'CPU Usage per VCPU' 'percentage' 'cpu' 'xendomain.vcpu' line %d %d %s %s\n"
  458. , type
  459. , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VCPU
  460. , netdata_update_every
  461. , obsolete_flag ? "obsolete": "''"
  462. , PLUGIN_XENSTAT_NAME
  463. );
  464. for(vcpu_m = d->vcpu_root; vcpu_m; vcpu_m = vcpu_m->next) {
  465. if(likely(vcpu_m->updated && vcpu_m->online)) {
  466. printf("DIMENSION vcpu%u '' incremental 100 %d\n", vcpu_m->id, netdata_update_every * 1000000000);
  467. }
  468. }
  469. }
  470. static void print_domain_vbd_oo_chart_definition(char *type, unsigned int vbd, int obsolete_flag) {
  471. 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"
  472. , type
  473. , vbd
  474. , vbd
  475. , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_OO_REQ + vbd
  476. , netdata_update_every
  477. , obsolete_flag ? "obsolete": "''"
  478. , PLUGIN_XENSTAT_NAME
  479. );
  480. printf("DIMENSION requests '' incremental 1 %d\n", netdata_update_every);
  481. }
  482. static void print_domain_vbd_requests_chart_definition(char *type, unsigned int vbd, int obsolete_flag) {
  483. printf("CHART %s.requests_vbd%u '' 'VBD%u Requests' 'requests/s' 'vbd' 'xendomain.requests_vbd' line %d %d %s %s\n"
  484. , type
  485. , vbd
  486. , vbd
  487. , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_REQUESTS + vbd
  488. , netdata_update_every
  489. , obsolete_flag ? "obsolete": "''"
  490. , PLUGIN_XENSTAT_NAME
  491. );
  492. printf("DIMENSION read '' incremental 1 %d\n", netdata_update_every);
  493. printf("DIMENSION write '' incremental -1 %d\n", netdata_update_every);
  494. }
  495. static void print_domain_vbd_sectors_chart_definition(char *type, unsigned int vbd, int obsolete_flag) {
  496. printf("CHART %s.sectors_vbd%u '' 'VBD%u Read/Written Sectors' 'sectors/s' 'vbd' 'xendomain.sectors_vbd' line %d %d %s %s\n"
  497. , type
  498. , vbd
  499. , vbd
  500. , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_VBD_SECTORS + vbd
  501. , netdata_update_every
  502. , obsolete_flag ? "obsolete": "''"
  503. , PLUGIN_XENSTAT_NAME
  504. );
  505. printf("DIMENSION read '' incremental 1 %d\n", netdata_update_every);
  506. printf("DIMENSION write '' incremental -1 %d\n", netdata_update_every);
  507. }
  508. static void print_domain_network_bytes_chart_definition(char *type, unsigned int network, int obsolete_flag) {
  509. printf("CHART %s.bytes_network%u '' 'Network%u Received/Sent Bytes' 'kilobits/s' 'network' 'xendomain.bytes_network' line %d %d %s %s\n"
  510. , type
  511. , network
  512. , network
  513. , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_BYTES + network
  514. , netdata_update_every
  515. , obsolete_flag ? "obsolete": "''"
  516. , PLUGIN_XENSTAT_NAME
  517. );
  518. printf("DIMENSION received '' incremental 8 %d\n", netdata_update_every * 1000);
  519. printf("DIMENSION sent '' incremental -8 %d\n", netdata_update_every * 1000);
  520. }
  521. static void print_domain_network_packets_chart_definition(char *type, unsigned int network, int obsolete_flag) {
  522. printf("CHART %s.packets_network%u '' 'Network%u Recieved/Sent Packets' 'packets/s' 'network' 'xendomain.packets_network' line %d %d %s %s\n"
  523. , type
  524. , network
  525. , network
  526. , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_PACKETS + network
  527. , netdata_update_every
  528. , obsolete_flag ? "obsolete": "''"
  529. , PLUGIN_XENSTAT_NAME
  530. );
  531. printf("DIMENSION received '' incremental 1 %d\n", netdata_update_every);
  532. printf("DIMENSION sent '' incremental -1 %d\n", netdata_update_every);
  533. }
  534. static void print_domain_network_errors_chart_definition(char *type, unsigned int network, int obsolete_flag) {
  535. printf("CHART %s.errors_network%u '' 'Network%u Receive/Transmit Errors' 'errors/s' 'network' 'xendomain.errors_network' line %d %d %s %s\n"
  536. , type
  537. , network
  538. , network
  539. , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_PACKETS + network
  540. , netdata_update_every
  541. , obsolete_flag ? "obsolete": "''"
  542. , PLUGIN_XENSTAT_NAME
  543. );
  544. printf("DIMENSION received '' incremental 1 %d\n", netdata_update_every);
  545. printf("DIMENSION sent '' incremental -1 %d\n", netdata_update_every);
  546. }
  547. static void print_domain_network_drops_chart_definition(char *type, unsigned int network, int obsolete_flag) {
  548. printf("CHART %s.drops_network%u '' 'Network%u Recieve/Transmit Drops' 'drops/s' 'network' 'xendomain.drops_network' line %d %d %s %s\n"
  549. , type
  550. , network
  551. , network
  552. , NETDATA_CHART_PRIO_XENSTAT_DOMAIN_NET_PACKETS + network
  553. , netdata_update_every
  554. , obsolete_flag ? "obsolete": "''"
  555. , PLUGIN_XENSTAT_NAME
  556. );
  557. printf("DIMENSION received '' incremental 1 %d\n", netdata_update_every);
  558. printf("DIMENSION sent '' incremental -1 %d\n", netdata_update_every);
  559. }
  560. static void xenstat_send_domain_metrics() {
  561. if(unlikely(!node_metrics.domain_root)) return;
  562. struct domain_metrics *d;
  563. for(d = node_metrics.domain_root; d; d = d->next) {
  564. char type[TYPE_LENGTH_MAX + 1];
  565. snprintfz(type, TYPE_LENGTH_MAX, "xendomain_%s_%s", d->name, d->uuid);
  566. if(likely(d->updated)) {
  567. // ----------------------------------------------------------------
  568. if(unlikely(!d->states_chart_generated)) {
  569. print_domain_states_chart_definition(type, CHART_IS_NOT_OBSOLETE);
  570. d->states_chart_generated = 1;
  571. }
  572. printf(
  573. "BEGIN %s.states\n"
  574. "SET running = %lld\n"
  575. "SET blocked = %lld\n"
  576. "SET paused = %lld\n"
  577. "SET shutdown = %lld\n"
  578. "SET crashed = %lld\n"
  579. "SET dying = %lld\n"
  580. "END\n"
  581. , type
  582. , (collected_number)d->running
  583. , (collected_number)d->blocked
  584. , (collected_number)d->paused
  585. , (collected_number)d->shutdown
  586. , (collected_number)d->crashed
  587. , (collected_number)d->dying
  588. );
  589. // ----------------------------------------------------------------
  590. if(unlikely(!d->cpu_chart_generated)) {
  591. print_domain_cpu_chart_definition(type, CHART_IS_NOT_OBSOLETE);
  592. d->cpu_chart_generated = 1;
  593. }
  594. printf(
  595. "BEGIN %s.cpu\n"
  596. "SET used = %lld\n"
  597. "END\n"
  598. , type
  599. , (collected_number)d->cpu_ns
  600. );
  601. // ----------------------------------------------------------------
  602. struct vcpu_metrics *vcpu_m;
  603. if(unlikely(!d->vcpu_chart_generated || d->num_vcpus_changed)) {
  604. print_domain_vcpu_chart_definition(type, d, CHART_IS_NOT_OBSOLETE);
  605. d->num_vcpus_changed = 0;
  606. d->vcpu_chart_generated = 1;
  607. }
  608. printf("BEGIN %s.vcpu\n", type);
  609. for(vcpu_m = d->vcpu_root; vcpu_m; vcpu_m = vcpu_m->next) {
  610. if(likely(vcpu_m->updated && vcpu_m->online)) {
  611. printf(
  612. "SET vcpu%u = %lld\n"
  613. , vcpu_m->id
  614. , (collected_number)vcpu_m->ns
  615. );
  616. }
  617. }
  618. printf("END\n");
  619. // ----------------------------------------------------------------
  620. if(unlikely(!d->mem_chart_generated)) {
  621. print_domain_mem_chart_definition(type, CHART_IS_NOT_OBSOLETE);
  622. d->mem_chart_generated = 1;
  623. }
  624. printf(
  625. "BEGIN %s.mem\n"
  626. "SET maximum = %lld\n"
  627. "SET current = %lld\n"
  628. "END\n"
  629. , type
  630. , (collected_number)d->max_mem
  631. , (collected_number)d->cur_mem
  632. );
  633. // ----------------------------------------------------------------
  634. struct vbd_metrics *vbd_m;
  635. for(vbd_m = d->vbd_root; vbd_m; vbd_m = vbd_m->next) {
  636. if(likely(vbd_m->updated && !vbd_m->error)) {
  637. if(unlikely(!vbd_m->oo_req_chart_generated)) {
  638. print_domain_vbd_oo_chart_definition(type, vbd_m->id, CHART_IS_NOT_OBSOLETE);
  639. vbd_m->oo_req_chart_generated = 1;
  640. }
  641. printf(
  642. "BEGIN %s.oo_req_vbd%u\n"
  643. "SET requests = %lld\n"
  644. "END\n"
  645. , type
  646. , vbd_m->id
  647. , (collected_number)vbd_m->oo_reqs
  648. );
  649. // ----------------------------------------------------------------
  650. if(unlikely(!vbd_m->requests_chart_generated)) {
  651. print_domain_vbd_requests_chart_definition(type, vbd_m->id, CHART_IS_NOT_OBSOLETE);
  652. vbd_m->requests_chart_generated = 1;
  653. }
  654. printf(
  655. "BEGIN %s.requests_vbd%u\n"
  656. "SET read = %lld\n"
  657. "SET write = %lld\n"
  658. "END\n"
  659. , type
  660. , vbd_m->id
  661. , (collected_number)vbd_m->rd_reqs
  662. , (collected_number)vbd_m->wr_reqs
  663. );
  664. // ----------------------------------------------------------------
  665. if(unlikely(!vbd_m->sectors_chart_generated)) {
  666. print_domain_vbd_sectors_chart_definition(type, vbd_m->id, CHART_IS_NOT_OBSOLETE);
  667. vbd_m->sectors_chart_generated = 1;
  668. }
  669. printf(
  670. "BEGIN %s.sectors_vbd%u\n"
  671. "SET read = %lld\n"
  672. "SET write = %lld\n"
  673. "END\n"
  674. , type
  675. , vbd_m->id
  676. , (collected_number)vbd_m->rd_sects
  677. , (collected_number)vbd_m->wr_sects
  678. );
  679. }
  680. else {
  681. if(unlikely(vbd_m->oo_req_chart_generated
  682. || vbd_m->requests_chart_generated
  683. || vbd_m->sectors_chart_generated)) {
  684. 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);
  685. print_domain_vbd_oo_chart_definition(type, vbd_m->id, CHART_IS_OBSOLETE);
  686. print_domain_vbd_requests_chart_definition(type, vbd_m->id, CHART_IS_OBSOLETE);
  687. print_domain_vbd_sectors_chart_definition(type, vbd_m->id, CHART_IS_OBSOLETE);
  688. vbd_m->oo_req_chart_generated = 0;
  689. vbd_m->requests_chart_generated = 0;
  690. vbd_m->sectors_chart_generated = 0;
  691. }
  692. }
  693. }
  694. // ----------------------------------------------------------------
  695. struct network_metrics *network_m;
  696. for(network_m = d->network_root; network_m; network_m = network_m->next) {
  697. if(likely(network_m->updated)) {
  698. if(unlikely(!network_m->bytes_chart_generated)) {
  699. print_domain_network_bytes_chart_definition(type, network_m->id, CHART_IS_NOT_OBSOLETE);
  700. network_m->bytes_chart_generated = 1;
  701. }
  702. printf(
  703. "BEGIN %s.bytes_network%u\n"
  704. "SET recieved = %lld\n"
  705. "SET sent = %lld\n"
  706. "END\n"
  707. , type
  708. , network_m->id
  709. , (collected_number)network_m->rbytes
  710. , (collected_number)network_m->tbytes
  711. );
  712. // ----------------------------------------------------------------
  713. if(unlikely(!network_m->packets_chart_generated)) {
  714. print_domain_network_packets_chart_definition(type, network_m->id, CHART_IS_NOT_OBSOLETE);
  715. network_m->packets_chart_generated = 1;
  716. }
  717. printf(
  718. "BEGIN %s.packets_network%u\n"
  719. "SET recieved = %lld\n"
  720. "SET sent = %lld\n"
  721. "END\n"
  722. , type
  723. , network_m->id
  724. , (collected_number)network_m->rpackets
  725. , (collected_number)network_m->tpackets
  726. );
  727. // ----------------------------------------------------------------
  728. if(unlikely(!network_m->errors_chart_generated)) {
  729. print_domain_network_errors_chart_definition(type, network_m->id, CHART_IS_NOT_OBSOLETE);
  730. network_m->errors_chart_generated = 1;
  731. }
  732. printf(
  733. "BEGIN %s.errors_network%u\n"
  734. "SET recieved = %lld\n"
  735. "SET sent = %lld\n"
  736. "END\n"
  737. , type
  738. , network_m->id
  739. , (collected_number)network_m->rerrs
  740. , (collected_number)network_m->terrs
  741. );
  742. // ----------------------------------------------------------------
  743. if(unlikely(!network_m->drops_chart_generated)) {
  744. print_domain_network_drops_chart_definition(type, network_m->id, CHART_IS_NOT_OBSOLETE);
  745. network_m->drops_chart_generated = 1;
  746. }
  747. printf(
  748. "BEGIN %s.drops_network%u\n"
  749. "SET recieved = %lld\n"
  750. "SET sent = %lld\n"
  751. "END\n"
  752. , type
  753. , network_m->id
  754. , (collected_number)network_m->rdrops
  755. , (collected_number)network_m->tdrops
  756. );
  757. }
  758. else {
  759. if(unlikely(network_m->bytes_chart_generated
  760. || network_m->packets_chart_generated
  761. || network_m->errors_chart_generated
  762. || network_m->drops_chart_generated))
  763. 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);
  764. print_domain_network_bytes_chart_definition(type, network_m->id, CHART_IS_OBSOLETE);
  765. print_domain_network_packets_chart_definition(type, network_m->id, CHART_IS_OBSOLETE);
  766. print_domain_network_errors_chart_definition(type, network_m->id, CHART_IS_OBSOLETE);
  767. print_domain_network_drops_chart_definition(type, network_m->id, CHART_IS_OBSOLETE);
  768. network_m->bytes_chart_generated = 0;
  769. network_m->packets_chart_generated = 0;
  770. network_m->errors_chart_generated = 0;
  771. network_m->drops_chart_generated = 0;
  772. }
  773. }
  774. }
  775. else{
  776. 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);
  777. print_domain_states_chart_definition(type, CHART_IS_OBSOLETE);
  778. print_domain_cpu_chart_definition(type, CHART_IS_OBSOLETE);
  779. print_domain_vcpu_chart_definition(type, d, CHART_IS_OBSOLETE);
  780. print_domain_mem_chart_definition(type, CHART_IS_OBSOLETE);
  781. d = domain_metrics_free(d);
  782. }
  783. }
  784. }
  785. int main(int argc, char **argv) {
  786. // ------------------------------------------------------------------------
  787. // initialization of netdata plugin
  788. program_name = "xenstat.plugin";
  789. // disable syslog
  790. error_log_syslog = 0;
  791. // set errors flood protection to 100 logs per hour
  792. error_log_errors_per_period = 100;
  793. error_log_throttle_period = 3600;
  794. // ------------------------------------------------------------------------
  795. // parse command line parameters
  796. int i, freq = 0;
  797. for(i = 1; i < argc ; i++) {
  798. if(isdigit(*argv[i]) && !freq) {
  799. int n = str2i(argv[i]);
  800. if(n > 0 && n < 86400) {
  801. freq = n;
  802. continue;
  803. }
  804. }
  805. 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) {
  806. printf("xenstat.plugin %s\n", VERSION);
  807. exit(0);
  808. }
  809. else if(strcmp("debug", argv[i]) == 0) {
  810. debug = 1;
  811. continue;
  812. }
  813. else if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
  814. fprintf(stderr,
  815. "\n"
  816. " netdata xenstat.plugin %s\n"
  817. " Copyright (C) 2019 Netdata Inc.\n"
  818. " Released under GNU General Public License v3 or later.\n"
  819. " All rights reserved.\n"
  820. "\n"
  821. " This program is a data collector plugin for netdata.\n"
  822. "\n"
  823. " Available command line options:\n"
  824. "\n"
  825. " COLLECTION_FREQUENCY data collection frequency in seconds\n"
  826. " minimum: %d\n"
  827. "\n"
  828. " debug enable verbose output\n"
  829. " default: disabled\n"
  830. "\n"
  831. " -v\n"
  832. " -V\n"
  833. " --version print version and exit\n"
  834. "\n"
  835. " -h\n"
  836. " --help print this message and exit\n"
  837. "\n"
  838. " For more information:\n"
  839. " https://github.com/netdata/netdata/tree/master/collectors/xenstat.plugin\n"
  840. "\n"
  841. , VERSION
  842. , netdata_update_every
  843. );
  844. exit(1);
  845. }
  846. error("xenstat.plugin: ignoring parameter '%s'", argv[i]);
  847. }
  848. errno = 0;
  849. if(freq >= netdata_update_every)
  850. netdata_update_every = freq;
  851. else if(freq)
  852. error("update frequency %d seconds is too small for XENSTAT. Using %d.", freq, netdata_update_every);
  853. // ------------------------------------------------------------------------
  854. // initialize xen API handles
  855. xenstat_handle *xhandle = NULL;
  856. libxl_ctx *ctx = NULL;
  857. libxl_dominfo info;
  858. if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling xenstat_init()\n");
  859. xhandle = xenstat_init();
  860. if (xhandle == NULL)
  861. error("XENSTAT: failed to initialize xenstat library.");
  862. if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling libxl_ctx_alloc()\n");
  863. if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, NULL)) {
  864. error("XENSTAT: failed to initialize xl context.");
  865. }
  866. libxl_dominfo_init(&info);
  867. // ------------------------------------------------------------------------
  868. // the main loop
  869. if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: starting data collection\n");
  870. time_t started_t = now_monotonic_sec();
  871. size_t iteration;
  872. usec_t step = netdata_update_every * USEC_PER_SEC;
  873. heartbeat_t hb;
  874. heartbeat_init(&hb);
  875. for(iteration = 0; 1; iteration++) {
  876. usec_t dt = heartbeat_next(&hb, step);
  877. if(unlikely(netdata_exit)) break;
  878. if(unlikely(debug && iteration))
  879. fprintf(stderr, "xenstat.plugin: iteration %zu, dt %llu usec\n"
  880. , iteration
  881. , dt
  882. );
  883. if(likely(xhandle)) {
  884. if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling xenstat_collect()\n");
  885. int ret = xenstat_collect(xhandle, ctx, &info);
  886. if(likely(!ret)) {
  887. if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling xenstat_send_node_metrics()\n");
  888. xenstat_send_node_metrics();
  889. if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: calling xenstat_send_domain_metrics()\n");
  890. xenstat_send_domain_metrics();
  891. }
  892. else {
  893. if(unlikely(debug)) fprintf(stderr, "xenstat.plugin: can't collect data\n");
  894. }
  895. }
  896. fflush(stdout);
  897. // restart check (14400 seconds)
  898. if(unlikely(now_monotonic_sec() - started_t > 14400)) break;
  899. }
  900. libxl_ctx_free(ctx);
  901. xenstat_uninit(xhandle);
  902. info("XENSTAT process exiting");
  903. }
  904. #else // !HAVE_LIBXENSTAT
  905. int main(int argc, char **argv) {
  906. (void)argc;
  907. (void)argv;
  908. fatal("xenstat.plugin is not compiled.");
  909. }
  910. #endif // !HAVE_LIBXENSTAT