]> arthur.barton.de Git - netdata.git/blob - src/macos_sysctl.c
Add IPv4 bandwidth chart to macOS plugin
[netdata.git] / src / macos_sysctl.c
1 #include "common.h"
2 #include <sys/sysctl.h>
3 // NEEDED BY: do_bandwidth
4 #include <net/route.h>
5
6 #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
7
8 // MacOS calculates load averages once every 5 seconds
9 #define MIN_LOADAVG_UPDATE_EVERY 5
10
11 int getsysctl(const char *name, void *ptr, size_t len);
12
13 int do_macos_sysctl(int update_every, usec_t dt) {
14     (void)dt;
15
16     static int do_loadavg = -1, do_swap = -1, do_bandwidth = -1;
17
18     if (unlikely(do_loadavg == -1)) {
19         do_loadavg              = config_get_boolean("plugin:macos:sysctl", "enable load average", 1);
20         do_swap                 = config_get_boolean("plugin:macos:sysctl", "system swap", 1);
21         do_bandwidth            = config_get_boolean("plugin:macos:sysctl", "bandwidth", 1);
22     }
23
24     RRDSET *st;
25
26     int system_pagesize = getpagesize(); // wouldn't it be better to get value directly from hw.pagesize?
27     int i, n;
28     int common_error = 0;
29     size_t size;
30
31     // NEEDED BY: do_loadavg
32     static usec_t last_loadavg_usec = 0;
33     struct loadavg sysload;
34
35     // NEEDED BY: do_swap
36     struct xsw_usage swap_usage;
37
38     // NEEDED BY: do_bandwidth
39     int mib[6];
40     static char *ifstatdata = NULL;
41     char *lim, *next;
42     struct if_msghdr *ifm;
43     struct iftot {
44         u_long  ift_ibytes;
45         u_long  ift_obytes;
46     } iftot = {0, 0};
47
48     if (last_loadavg_usec <= dt) {
49         if (likely(do_loadavg)) {
50             if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
51                 do_loadavg = 0;
52                 error("DISABLED: system.load");
53             } else {
54
55                 st = rrdset_find_bytype("system", "load");
56                 if (unlikely(!st)) {
57                     st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE);
58                     rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
59                     rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
60                     rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
61                 }
62                 else rrdset_next(st);
63
64                 rrddim_set(st, "load1", (collected_number) ((double)sysload.ldavg[0] / sysload.fscale * 1000));
65                 rrddim_set(st, "load5", (collected_number) ((double)sysload.ldavg[1] / sysload.fscale * 1000));
66                 rrddim_set(st, "load15", (collected_number) ((double)sysload.ldavg[2] / sysload.fscale * 1000));
67                 rrdset_done(st);
68             }
69         }
70
71         last_loadavg_usec = st->update_every * USEC_PER_SEC;
72     }
73     else last_loadavg_usec -= dt;
74
75     if (likely(do_swap)) {
76         if (unlikely(GETSYSCTL("vm.swapusage", swap_usage))) {
77             do_swap = 0;
78             error("DISABLED: system.swap");
79         } else {
80             st = rrdset_find("system.swap");
81             if (unlikely(!st)) {
82                 st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
83                 st->isdetail = 1;
84
85                 rrddim_add(st, "free",    NULL, 1, 1048576, RRDDIM_ABSOLUTE);
86                 rrddim_add(st, "used",    NULL, 1, 1048576, RRDDIM_ABSOLUTE);
87             }
88             else rrdset_next(st);
89
90             rrddim_set(st, "free", swap_usage.xsu_avail);
91             rrddim_set(st, "used", swap_usage.xsu_used);
92             rrdset_done(st);
93         }
94     }
95
96     // --------------------------------------------------------------------
97
98     if (likely(do_bandwidth)) {
99         mib[0] = CTL_NET;
100         mib[1] = PF_ROUTE;
101         mib[2] = 0;
102         mib[3] = AF_INET;
103         mib[4] = NET_RT_IFLIST2;
104         mib[5] = 0;
105         if (unlikely(sysctl(mib, 6, NULL, &size, NULL, 0))) {
106             error("MACOS: sysctl(%s...) failed: %s", "net interfaces", strerror(errno));
107             do_bandwidth = 0;
108             error("DISABLED: system.ipv4");
109         } else {
110             ifstatdata = reallocz(ifstatdata, size);
111             if (unlikely(sysctl(mib, 6, ifstatdata, &size, NULL, 0) < 0)) {
112                 error("MACOS: sysctl(%s...) failed: %s", "net interfaces", strerror(errno));
113                 do_bandwidth = 0;
114                 error("DISABLED: system.ipv4");
115             } else {
116                 lim = ifstatdata + size;
117                 iftot.ift_ibytes = iftot.ift_obytes = 0;
118                 for (next = ifstatdata; next < lim; ) {
119                     ifm = (struct if_msghdr *)next;
120                     next += ifm->ifm_msglen;
121
122                     if (ifm->ifm_type == RTM_IFINFO2) {
123                         struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm;
124
125                         iftot.ift_ibytes += if2m->ifm_data.ifi_ibytes;
126                         iftot.ift_obytes += if2m->ifm_data.ifi_obytes;
127                     }
128                 }
129                 st = rrdset_find("system.ipv4");
130                 if (unlikely(!st)) {
131                     st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
132
133                     rrddim_add(st, "InOctets", "received", 8, 1024, RRDDIM_INCREMENTAL);
134                     rrddim_add(st, "OutOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
135                 }
136                 else rrdset_next(st);
137
138                 rrddim_set(st, "InOctets", iftot.ift_ibytes);
139                 rrddim_set(st, "OutOctets", iftot.ift_obytes);
140                 rrdset_done(st);
141             }
142         }
143     }
144
145     return 0;
146 }
147
148 int getsysctl(const char *name, void *ptr, size_t len)
149 {
150     size_t nlen = len;
151
152     if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
153         error("MACOS: sysctl(%s...) failed: %s", name, strerror(errno));
154         return 1;
155     }
156     if (unlikely(nlen != len)) {
157         error("MACOS: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
158         return 1;
159     }
160     return 0;
161 }