netdata-functions.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. <?php
  2. function netdataSettngsArray()
  3. {
  4. $array = array(
  5. 'name' => 'Netdata',
  6. 'enabled' => true,
  7. 'image' => 'plugins/images/tabs/netdata.png',
  8. 'category' => 'Monitor',
  9. 'settings' => array(
  10. 'Enable' => array(
  11. array(
  12. 'type' => 'switch',
  13. 'name' => 'homepageNetdataEnabled',
  14. 'label' => 'Enable',
  15. 'value' => $GLOBALS['homepageNetdataEnabled']
  16. ),
  17. array(
  18. 'type' => 'select',
  19. 'name' => 'homepageNetdataAuth',
  20. 'label' => 'Minimum Authentication',
  21. 'value' => $GLOBALS['homepageNetdataAuth'],
  22. 'options' => groupSelect()
  23. )
  24. ),
  25. 'Connection' => array(
  26. array(
  27. 'type' => 'html',
  28. 'override' => 12,
  29. 'label' => 'Info',
  30. 'html' => 'The URL needs to be on the same domain as your Organizr, and be proxied by subdomain. E.g. If Organizr is accessed at: https://domain.com, then your URL for netdata should be: https://netdata.domain.com'
  31. ),
  32. array(
  33. 'type' => 'input',
  34. 'name' => 'netdataURL',
  35. 'label' => 'URL',
  36. 'value' => $GLOBALS['netdataURL'],
  37. 'help' => 'Please enter the local IP:PORT of your netdata instance'
  38. ),
  39. array(
  40. 'type' => 'blank',
  41. 'label' => ''
  42. ),
  43. ),
  44. )
  45. );
  46. for($i = 1; $i <= 7; $i++) {
  47. $array['settings']['Chart '.$i] = array(
  48. array(
  49. 'type' => 'switch',
  50. 'name' => 'netdata'.$i.'Enabled',
  51. 'label' => 'Enable',
  52. 'value' => $GLOBALS['netdata'.$i.'Enabled']
  53. ),
  54. array(
  55. 'type' => 'blank',
  56. 'label' => ''
  57. ),
  58. array(
  59. 'type' => 'input',
  60. 'name' => 'netdata'.$i.'Title',
  61. 'label' => 'Title',
  62. 'value' => $GLOBALS['netdata'.$i.'Title'],
  63. 'help' => 'Title for the netdata graph'
  64. ),
  65. array(
  66. 'type' => 'select',
  67. 'name' => 'netdata'.$i.'Data',
  68. 'label' => 'Data',
  69. 'value' => $GLOBALS['netdata'.$i.'Data'],
  70. 'options' => netdataOptions(),
  71. ),
  72. array(
  73. 'type' => 'select',
  74. 'name' => 'netdata'.$i.'Chart',
  75. 'label' => 'Chart',
  76. 'value' => $GLOBALS['netdata'.$i.'Chart'],
  77. 'options' => netdataChartOptions(),
  78. ),
  79. array(
  80. 'type' => 'select',
  81. 'name' => 'netdata'.$i.'Colour',
  82. 'label' => 'Colour',
  83. 'value' => $GLOBALS['netdata'.$i.'Colour'],
  84. 'options' => netdataColourOptions(),
  85. ),
  86. array(
  87. 'type' => 'select',
  88. 'name' => 'netdata'.$i.'Size',
  89. 'label' => 'Size',
  90. 'value' => $GLOBALS['netdata'.$i.'Size'],
  91. 'options' => netdataSizeOptions(),
  92. ),
  93. array(
  94. 'type' => 'blank',
  95. 'label' => ''
  96. ),
  97. array(
  98. 'type' => 'switch',
  99. 'name' => 'netdata'.$i.'lg',
  100. 'label' => 'Show on large screens',
  101. 'value' => $GLOBALS['netdata'.$i.'lg']
  102. ),
  103. array(
  104. 'type' => 'switch',
  105. 'name' => 'netdata'.$i.'md',
  106. 'label' => 'Show on medium screens',
  107. 'value' => $GLOBALS['netdata'.$i.'md']
  108. ),
  109. array(
  110. 'type' => 'switch',
  111. 'name' => 'netdata'.$i.'sm',
  112. 'label' => 'Show on small screens',
  113. 'value' => $GLOBALS['netdata'.$i.'sm']
  114. ),
  115. );
  116. }
  117. $array['settings']['Custom data'] = [
  118. [
  119. 'type' => 'html',
  120. 'label' => '',
  121. 'override' => 12,
  122. 'html' => <<<HTML
  123. <div>
  124. <p>This is where you can define custom data sources for your netdata charts. To use a custom source, you need to select 'Custom' in the data field for the chart.</p>
  125. <p>To define a custom data source, you need to add an entry to the JSON below, where the key is the chart number you want the custom data to be used for. Here is an example to set chart 1's custom data source to RAM percentage:</p>
  126. <pre>{
  127. "1": {
  128. "url": "/api/v1/data?chart=system.ram&format=array&points=540&group=average&gtime=0&options=absolute|percentage|jsonwrap|nonzero&after=-540&dimensions=used|buffers|active|wired",
  129. "value": "result,0",
  130. "units": "%",
  131. "max": 100
  132. }
  133. }</pre>
  134. <p>The URL is appended to your netdata URL and returns JSON formatted data. The value field tells Organizr how to return the value you want from the netdata API. This should be formatted as comma-separated keys to access the desired value. So the value field here will access data from an array like this:</p>
  135. <pre>[
  136. 'result': [
  137. VALUE,
  138. // more values...
  139. ]
  140. ]</pre>
  141. </div>
  142. HTML
  143. ],
  144. [
  145. 'type' => 'textbox',
  146. 'name' => 'netdataCustom',
  147. 'class' => 'javaTextarea',
  148. 'label' => 'Custom definitions',
  149. 'override' => 12,
  150. 'value' => $GLOBALS['netdataCustom'],
  151. 'attr' => 'rows="10"',
  152. ]
  153. ];
  154. $array['settings']['Options'] = array(
  155. array(
  156. 'type' => 'select',
  157. 'name' => 'homepageNetdataRefresh',
  158. 'label' => 'Refresh Seconds',
  159. 'value' => $GLOBALS['homepageNetdataRefresh'],
  160. 'options' => optionTime()
  161. ),
  162. );
  163. return $array;
  164. }
  165. function disk($dimension, $url)
  166. {
  167. $data = [];
  168. // Get Data
  169. $dataUrl = $url . '/api/v1/data?chart=system.io&dimensions='.$dimension.'&format=array&points=540&group=average&gtime=0&options=absolute|jsonwrap|nonzero&after=-540';
  170. try {
  171. $response = Requests::get($dataUrl);
  172. if ($response->success) {
  173. $json = json_decode($response->body, true);
  174. $data['value'] = $json['latest_values'][0] / 1000;
  175. $data['percent'] = getPercent($json['latest_values'][0], $json['max']);
  176. $data['units'] = 'MiB/s';
  177. $data['max'] = $json['max'];
  178. }
  179. } catch (Requests_Exception $e) {
  180. writeLog('error', 'Netdata Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  181. };
  182. return $data;
  183. }
  184. function diskSpace($dimension, $url)
  185. {
  186. $data = [];
  187. // Get Data
  188. $dataUrl = $url . '/api/v1/data?chart=disk_space._&format=json&points=509&group=average&gtime=0&options=ms|jsonwrap|nonzero&after=-540&dimension='.$dimension;
  189. try {
  190. $response = Requests::get($dataUrl);
  191. if ($response->success) {
  192. $json = json_decode($response->body, true);
  193. $data['value'] = $json['result']['data'][0][1];
  194. $data['percent'] = $data['value'];
  195. $data['units'] = '%';
  196. $data['max'] = 100;
  197. }
  198. } catch (Requests_Exception $e) {
  199. writeLog('error', 'Netdata Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  200. };
  201. return $data;
  202. }
  203. function net($dimension, $url)
  204. {
  205. $data = [];
  206. // Get Data
  207. $dataUrl = $url . '/api/v1/data?chart=system.net&dimensions='.$dimension.'&format=array&points=540&group=average&gtime=0&options=absolute|jsonwrap|nonzero&after=-540';
  208. try {
  209. $response = Requests::get($dataUrl);
  210. if ($response->success) {
  211. $json = json_decode($response->body, true);
  212. $data['value'] = $json['latest_values'][0] / 1000;
  213. $data['percent'] = getPercent($json['latest_values'][0], $json['max']);
  214. $data['units'] = 'Mbit/s';
  215. $data['max'] = $json['max'];
  216. }
  217. } catch (Requests_Exception $e) {
  218. writeLog('error', 'Netdata Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  219. };
  220. return $data;
  221. }
  222. function cpu($url)
  223. {
  224. $data = [];
  225. $dataUrl = $url . '/api/v1/data?chart=system.cpu&format=array';
  226. try {
  227. $response = Requests::get($dataUrl);
  228. if ($response->success) {
  229. $json = json_decode($response->body, true);
  230. $data['value'] = $json[0];
  231. $data['percent'] = $data['value'];
  232. $data['max'] = 100;
  233. $data['units'] = '%';
  234. }
  235. } catch (Requests_Exception $e) {
  236. writeLog('error', 'Netdata Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  237. };
  238. return $data;
  239. }
  240. function ram($url)
  241. {
  242. $data = [];
  243. $dataUrl = $url . '/api/v1/data?chart=system.ram&format=array&points=540&group=average&gtime=0&options=absolute|percentage|jsonwrap|nonzero&after=-540&dimensions=used|buffers|active|wired';
  244. try {
  245. $response = Requests::get($dataUrl);
  246. if ($response->success) {
  247. $json = json_decode($response->body, true);
  248. $data['value'] = $json['result'][0];
  249. $data['percent'] = $data['value'];
  250. $data['max'] = 100;
  251. $data['units'] = '%';
  252. }
  253. } catch (Requests_Exception $e) {
  254. writeLog('error', 'Netdata Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  255. };
  256. return $data;
  257. }
  258. function swap($url)
  259. {
  260. $data = [];
  261. $dataUrl = $url . '/api/v1/data?chart=system.swap&format=array&points=540&group=average&gtime=0&options=absolute|percentage|jsonwrap|nonzero&after=-540&dimensions=used';
  262. try {
  263. $response = Requests::get($dataUrl);
  264. if ($response->success) {
  265. $json = json_decode($response->body, true);
  266. $data['value'] = $json['result'][0];
  267. $data['percent'] = $data['value'];
  268. $data['max'] = 100;
  269. $data['units'] = '%';
  270. }
  271. } catch (Requests_Exception $e) {
  272. writeLog('error', 'Netdata Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  273. };
  274. return $data;
  275. }
  276. function ipmiTemp($url, $unit)
  277. {
  278. $data = [];
  279. $dataUrl = $url . '/api/v1/data?chart=ipmi.temperatures_c&format=array&points=540&group=average&gtime=0&options=absolute|jsonwrap|nonzero&after=-540';
  280. try {
  281. $response = Requests::get($dataUrl);
  282. if ($response->success) {
  283. $json = json_decode($response->body, true);
  284. $data['value'] = $json['result'][0];
  285. if($unit == 'c') {
  286. $data['percent'] = ($data['value'] / 50) * 100;
  287. $data['max'] = 50;
  288. } else if($unit == 'f') {
  289. $data['value'] = ($data['value'] * 9/5) + 32;
  290. $data['percent'] = ($data['value'] / 122) * 100;
  291. $data['max'] = 122;
  292. }
  293. $data['units'] = '°'.strtoupper($unit);
  294. }
  295. } catch (Requests_Exception $e) {
  296. writeLog('error', 'Netdata Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  297. };
  298. return $data;
  299. }
  300. function getPercent($val, $max)
  301. {
  302. if($max == 0) {
  303. return 0;
  304. } else {
  305. return ( $val / $max ) * 100;
  306. }
  307. }
  308. function cpuTemp($url, $unit)
  309. {
  310. $data = [];
  311. $dataUrl = $url . '/api/v1/data?chart=sensors.coretemp-isa-0000_temperature&format=json&points=509&group=average&gtime=0&options=ms|flip|jsonwrap|nonzero&after=-540';
  312. try {
  313. $response = Requests::get($dataUrl);
  314. if ($response->success) {
  315. $json = json_decode($response->body, true);
  316. $vals = $json['latest_values'];
  317. $vals = array_filter($vals);
  318. if(count($vals) > 0) {
  319. $data['value'] = array_sum($vals) / count($vals);
  320. } else {
  321. $data['value'] = 0;
  322. }
  323. if($unit == 'c') {
  324. $data['percent'] = ($data['value'] / 50) * 100;
  325. $data['max'] = 50;
  326. } else if($unit == 'f') {
  327. $data['value'] = ($data['value'] * 9/5) + 32;
  328. $data['percent'] = ($data['value'] / 122) * 100;
  329. $data['max'] = 122;
  330. }
  331. $data['units'] = '°'.strtoupper($unit);
  332. }
  333. } catch (Requests_Exception $e) {
  334. writeLog('error', 'Netdata Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  335. };
  336. return $data;
  337. }
  338. function customNetdata($url, $id)
  339. {
  340. try {
  341. $customs = json_decode($GLOBALS['netdataCustom'], true, 512, JSON_THROW_ON_ERROR);
  342. } catch(Exception $e) {
  343. $customs = false;
  344. }
  345. if($customs == false) {
  346. return [
  347. 'error' => 'unable to parse custom JSON'
  348. ];
  349. } else if(!isset($customs[$id])) {
  350. return [
  351. 'error' => 'custom definition not found'
  352. ];
  353. } else {
  354. $data = [];
  355. $custom = $customs[$id];
  356. if(isset($custom['url']) && isset($custom['value']) && isset($custom['max']) && isset($custom['units'])) {
  357. $dataUrl = $url . '/' . $custom['url'];
  358. try {
  359. $response = Requests::get($dataUrl);
  360. if ($response->success) {
  361. $json = json_decode($response->body, true);
  362. $data['max'] = $custom['max'];
  363. $data['units'] = $custom['units'];
  364. $selectors = explode(',', $custom['value']);
  365. foreach($selectors as $selector) {
  366. if(is_numeric($selector)) {
  367. $selector = (int) $selector;
  368. }
  369. if(!isset($data['value'])) {
  370. $data['value'] = $json[$selector];
  371. } else {
  372. $data['value'] = $data['value'][$selector];
  373. }
  374. }
  375. if($data['max'] == 0) {
  376. $data['percent'] = 0;
  377. } else {
  378. $data['percent'] = ( $data['value'] / $data['max'] ) * 100;
  379. }
  380. }
  381. } catch (Requests_Exception $e) {
  382. writeLog('error', 'Netdata Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  383. };
  384. } else {
  385. $data['error'] = 'custom definition incomplete';
  386. }
  387. return $data;
  388. }
  389. }