1: | <?php |
2: | declare(strict_types=1); |
3: | |
4: | |
5: | |
6: | |
7: | |
8: | |
9: | |
10: | |
11: | |
12: | |
13: | |
14: | |
15: | use Daphnie\Collector; |
16: | use Daphnie\Metrics\Memory as MemoryMetric; |
17: | use Opcenter\System\Memory; |
18: | |
19: | |
20: | |
21: | |
22: | |
23: | |
24: | class Stats_Module extends Module_Skeleton |
25: | { |
26: | |
27: | |
28: | |
29: | |
30: | |
31: | public function __construct() |
32: | { |
33: | parent::__construct(); |
34: | $this->exportedFunctions = array( |
35: | '*' => PRIVILEGE_ALL |
36: | ); |
37: | } |
38: | |
39: | |
40: | |
41: | |
42: | |
43: | |
44: | public function release(): array |
45: | { |
46: | $contents = file('/etc/os-release', FILE_SKIP_EMPTY_LINES|FILE_IGNORE_NEW_LINES); |
47: | $vars = array_build($contents, function ($index, $line) { |
48: | [$k,$v] = explode('=', $line); |
49: | return [ |
50: | strtolower($k), |
51: | \Util_Conf::inferType(trim($v, '"\'')) |
52: | ]; |
53: | }); |
54: | $vars['id_like'] = explode(' ', $vars['id_like']); |
55: | |
56: | return $vars; |
57: | } |
58: | |
59: | |
60: | |
61: | |
62: | |
63: | |
64: | public function get_partition_information() |
65: | { |
66: | $fsoptions = array(); |
67: | |
68: | $buffer = file('/proc/mounts', FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); |
69: | |
70: | $results = []; |
71: | $knownMounts = []; |
72: | foreach ($buffer as $line) { |
73: | if (0 !== strncmp($line, '/dev/', 5)) { |
74: | continue; |
75: | } |
76: | |
77: | [$dev, $mpoint, $type, $options, $fsck, $_] = explode(' ', $line); |
78: | |
79: | if (isset($knownMounts[$dev])) { |
80: | continue; |
81: | } |
82: | |
83: | $knownMounts[$dev] = 1; |
84: | |
85: | $total = disk_total_space($mpoint)/1024; |
86: | if (!$total) { |
87: | |
88: | continue; |
89: | } |
90: | $free = disk_free_space($mpoint)/1024; |
91: | |
92: | $results[] = [ |
93: | 'disk' => $dev, |
94: | 'size' => (int)$total, |
95: | 'used' => (int)($total-$free), |
96: | 'free' => (int)$free, |
97: | 'percent' => round(($total - $free)/$total * 100) . '%', |
98: | 'mount' => $mpoint, |
99: | 'fstype' => $type, |
100: | 'options' => $options |
101: | ]; |
102: | } |
103: | |
104: | return $results; |
105: | } |
106: | |
107: | public function get_spamassassin_stats() |
108: | { |
109: | $sastats = array(); |
110: | if (!file_exists('/tmp/sa-stats')) { |
111: | return $sastats; |
112: | } |
113: | $fp = fopen('/tmp/sa-stats', 'r'); |
114: | while (false !== ($line = fgets($fp))) { |
115: | $buffer = ' '; |
116: | if (false !== strpos($line, 'Period Beginning')) { |
117: | $data = explode(':', $line); |
118: | $sastats['begin_date'] = trim(implode(':', array_slice($data, 1))); |
119: | } else if (false !== strpos($line, 'Period Ending')) { |
120: | $data = explode(':', $line); |
121: | $sastats['end_date'] = trim(implode(':', array_slice($data, 1))); |
122: | } else { |
123: | if (false !== strpos($line, 'Reporting Period')) { |
124: | |
125: | $line = fgets($fp); |
126: | fgets($fp); |
127: | while (false !== ($line = fgets($fp))) { |
128: | if ($buffer[strlen($buffer) - 2] == "\n" && $buffer[strlen($buffer) - 1] == "\n" && $line == "\n") { |
129: | break; |
130: | } |
131: | $buffer .= $line; |
132: | } |
133: | $sastats['reporting_information'] = trim($buffer); |
134: | } else { |
135: | if (false !== strpos($line, 'Statistics by Hour')) { |
136: | $line = fgets($fp); |
137: | while (false !== ($line = fgets($fp))) { |
138: | |
139: | if ($buffer[strlen($buffer) - 2] == "\n" && $buffer[strlen($buffer) - 1] == "\n" && $line == "\n") { |
140: | break; |
141: | } |
142: | $buffer .= $line; |
143: | } |
144: | $sastats['stats_by_hour'] = trim($buffer); |
145: | } else { |
146: | if (false !== strpos($line, 'Done. Report generated')) { |
147: | while (false !== ($line = fgets($fp))) { |
148: | |
149: | |
150: | |
151: | |
152: | if (false !== strpos($line, 'TOP')) { |
153: | $bufftmp = $buffer; |
154: | $buffer = $line; |
155: | while (false !== ($line = fgets($fp))) { |
156: | $buffer .= $line; |
157: | } |
158: | $sastats['rule_information'] = trim($buffer); |
159: | $buffer = $bufftmp; |
160: | break; |
161: | } |
162: | $buffer .= $line; |
163: | } |
164: | $sastats['reporting_information'] .= "\n\n" . trim($buffer); |
165: | } else { |
166: | if (false !== strpos($line, 'TOP')) { |
167: | |
168: | } |
169: | } |
170: | } |
171: | } |
172: | } |
173: | } |
174: | fclose($fp); |
175: | |
176: | return $sastats; |
177: | } |
178: | |
179: | |
180: | |
181: | |
182: | |
183: | |
184: | public function get_memory_information() |
185: | { |
186: | if (false === ($fd = fopen('/proc/meminfo', 'r'))) { |
187: | return new FileError('/proc/meminfo does not exist'); |
188: | } |
189: | |
190: | $stats = Memory::stats(); |
191: | $results['swap'] = array( |
192: | 'total' => 0, |
193: | 'used' => 0, |
194: | 'percent' => 0 |
195: | ); |
196: | $results['devswap'] = array(); |
197: | |
198: | $results['ram'] = array_combine( |
199: | ['total', 't_free', 'cached', 'buffers', 'available'], |
200: | array_only($stats, ['memtotal', 'memfree', 'cached', 'buffers', 'memavailable']) |
201: | ); |
202: | |
203: | if (!empty($stats['swaptotal'])) { |
204: | $results['swap'] = array_combine( |
205: | ['total', 'free'], |
206: | array_only($stats, ['swaptotal', 'swapfree']) |
207: | ); |
208: | } |
209: | |
210: | $results['ram']['t_used'] = $results['ram']['total'] - $results['ram']['t_free']; |
211: | $results['ram']['percent'] = round(($results['ram']['t_used'] * 100) / $results['ram']['total']); |
212: | $results['swap']['used'] = $results['swap']['total'] - $results['swap']['free']; |
213: | if ($results['swap']['total'] > 0) { |
214: | $results['swap']['percent'] = round(($results['swap']['used'] * 100) / $results['swap']['total']); |
215: | } |
216: | |
217: | |
218: | if (isset($results['ram']['cached']) && isset($results['ram']['buffers'])) { |
219: | $results['ram']['app'] = $results['ram']['t_used'] - $results['ram']['cached'] - $results['ram']['buffers']; |
220: | $results['ram']['app_percent'] = round(($results['ram']['app'] * 100) / $results['ram']['total']); |
221: | $results['ram']['buffers_percent'] = round(($results['ram']['buffers'] * 100) / $results['ram']['total']); |
222: | $results['ram']['cached_percent'] = round(($results['ram']['cached'] * 100) / $results['ram']['total']); |
223: | } |
224: | |
225: | $swaps = file('/proc/swaps'); |
226: | for ($i = 1, $n = count($swaps); $i < $n; $i++) { |
227: | $ar_buf = preg_split('/\s+/', $swaps[$i], 6); |
228: | $results['devswap'][$ar_buf[0]] = array(); |
229: | $results['devswap'][$ar_buf[0]]['total'] = $ar_buf[2]; |
230: | $results['devswap'][$ar_buf[0]]['used'] = $ar_buf[3]; |
231: | $results['devswap'][$ar_buf[0]]['free'] = ($results['devswap'][$ar_buf[0]]['total'] - $results['devswap'][$ar_buf[0]]['used']); |
232: | $results['devswap'][$ar_buf[0]]['percent'] = round(($ar_buf[3] * 100) / $ar_buf[2]); |
233: | } |
234: | |
235: | return $results; |
236: | } |
237: | |
238: | |
239: | |
240: | |
241: | |
242: | |
243: | public function vmstat(): array { |
244: | $stat = file('/proc/stat', FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); |
245: | $ts = microtime(true); |
246: | $fields = preg_split('/\s+/', $stat[0]); |
247: | |
248: | $labels = [ |
249: | 'user', |
250: | 'nice', |
251: | 'system', |
252: | 'idle', |
253: | 'iowait', |
254: | 'irq', |
255: | 'softirq', |
256: | 'steal', |
257: | 'guest', |
258: | 'guest_nice' |
259: | ]; |
260: | array_shift($fields); |
261: | $values = array_combine($labels, array_map(static function ($v) { |
262: | return (int)$v; |
263: | }, $fields) |
264: | ); |
265: | $values['ts'] = $ts; |
266: | |
267: | |
268: | return $values; |
269: | } |
270: | |
271: | |
272: | |
273: | |
274: | |
275: | |
276: | |
277: | public function get_network_device_information() |
278: | { |
279: | $results = array(); |
280: | |
281: | if (false === ($fd = fopen('/proc/net/dev', 'r'))) { |
282: | return new IOError('/proc/net/dev does not exist'); |
283: | } |
284: | |
285: | while ($buf = fgets($fd, 4096)) { |
286: | if (preg_match('/:/', $buf)) { |
287: | list($dev_name, $stats_list) = explode(":", $buf, 2); |
288: | $stats = preg_split('/\s+/', trim($stats_list)); |
289: | $results[$dev_name] = array(); |
290: | |
291: | $results[$dev_name]['rx_bytes'] = $stats[0]; |
292: | $results[$dev_name]['rx_packets'] = $stats[1]; |
293: | $results[$dev_name]['rx_errs'] = $stats[2]; |
294: | $results[$dev_name]['rx_drop'] = $stats[3]; |
295: | |
296: | $results[$dev_name]['tx_bytes'] = $stats[8]; |
297: | $results[$dev_name]['tx_packets'] = $stats[9]; |
298: | $results[$dev_name]['tx_errs'] = $stats[10]; |
299: | $results[$dev_name]['tx_drop'] = $stats[11]; |
300: | |
301: | $results[$dev_name]['errs'] = $stats[2] + $stats[10]; |
302: | $results[$dev_name]['drop'] = $stats[3] + $stats[11]; |
303: | } |
304: | } |
305: | |
306: | return $results; |
307: | |
308: | } |
309: | |
310: | public function _cron(Cronus $c) |
311: | { |
312: | if (!TELEMETRY_ENABLED) { |
313: | return; |
314: | } |
315: | $collector = new Collector(PostgreSQL::pdo()); |
316: | $status = Memory::stats(); |
317: | foreach (MemoryMetric::getAttributeMap() as $attr => $metric) { |
318: | $val = $status[$metric]; |
319: | |
320: | if ($val instanceof Closure) { |
321: | $val = $val($status); |
322: | } |
323: | $collector->add("memory-${attr}", null, $val); |
324: | } |
325: | } |
326: | } |
327: | |