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