xenstat_plugin.c 39 KB

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