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