1 <?php // vim:fenc=utf-8:filetype=php:ts=4
2 /*
3 * Copyright (C) 2009 Bruno Prémont <bonbons AT linux-vserver.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation; only version 2 of the License is applicable.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12 * details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
19 error_reporting(E_ALL | E_NOTICE | E_WARNING);
21 require('config.php');
22 require('functions.php');
24 /**
25 * Send back new list content
26 * @items Array of options values to return to browser
27 * @method Name of Javascript method that will be called to process data
28 */
29 function dhtml_response_list(&$items, $method) {
30 header("Content-Type: text/xml");
32 print('<?xml version="1.0" encoding="utf-8" ?>'."\n");
33 print("<response>\n");
34 printf(" <method>%s</method>\n", htmlspecialchars($method));
35 print(" <result>\n");
36 foreach ($items as &$item)
37 printf(' <option>%s</option>'."\n", htmlspecialchars($item));
38 print(" </result>\n");
39 print("</response>");
40 }
42 function dhtml_response_graphs(&$graphs, $method) {
43 header("Content-Type: text/xml");
45 print('<?xml version="1.0" encoding="utf-8" ?>'."\n");
46 print("<response>\n");
47 printf(" <method>%s</method>\n", htmlspecialchars($method));
48 print(" <result>\n");
49 foreach ($graphs as &$graph)
50 printf(' <graph host="%s" plugin="%s" plugin_instance="%s" type="%s" type_instance="%s" timespan="%s" logarithmic="%d" tinyLegend="%d" />'."\n",
51 htmlspecialchars($graph['host']), htmlspecialchars($graph['plugin']), htmlspecialchars($graph['pinst']),
52 htmlspecialchars($graph['type']), htmlspecialchars($graph['tinst']), htmlspecialchars($graph['timespan']),
53 htmlspecialchars($graph['logarithmic']), htmlspecialchars($graph['tinyLegend']));
54 print(" </result>\n");
55 print("</response>");
56 }
58 /**
59 * Product page body with selection fields
60 */
61 function build_page() {
62 global $config;
64 if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/compatible; MSIE [0-9]+.[0-9];/', $_SERVER['HTTP_USER_AGENT'])) {
65 // Internet Explorer does not support XHTML
66 header("Content-Type: text/html");
68 print('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">');
69 print('<html lang="en">'."\n");
70 } else {
71 header("Content-Type: application/xhtml+xml");
73 print('<?xml version="1.0" encoding="utf-8" ?>'."\n");
74 print('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'."\n");
75 print('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">'."\n");
76 }
77 $url_base = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/';
78 ?>
79 <head>
80 <title>Collectd graph viewer</title>
81 <link rel="icon" href="favicon.png" type="image/png" />
82 <style type="text/css">
83 body, html { background-color: #EEEEEE; color: #000000; }
84 h1 { text-align: center; }
85 div.body { margin: auto; width: <?php echo isset($config['rrd_width']) ? 110+(int)$config['rrd_width'] : 600; ?>px; background: #FFFFFF; border: 1px solid #DDDDDD; }
86 p.error { color: #CC0000; margin: 0em; }
87 div.selector { margin: 0.5em 2em; }
88 div.selectorbox { padding: 5px; border: 1px solid #CCCCCC; background-color: #F8F8F8; }
89 div.selectorbox table { border: none; }
90 div.selectorbox table td.s1 { border-bottom: 1px dashed #F0F0F0; padding-right: 1em; vertical-align: middle; }
91 div.selectorbox table td.s2 { border-bottom: 1px dashed #F0F0F0; vertical-align: middle; }
92 div.selectorbox table td.s3 { vertical-align: middle; }
93 div.selectorbox table td.sc { padding: 0.5em 2em; text-align: center; }
94 a img { border: none; }
95 div.graphs { border-top: 1px solid #DDDDDD; padding: 5px; overflow: auto; }
96 div.graphs_t { position: relative; }
97 div.graph { text-align: right; }
98 div.selector select { width: 100%; }
99 table.toolbox { border: 1px solid #5500dd; padding: 0px; margin: 0px; background: #ffffff;}
100 table.toolbox td.c1 { vertical-align: middle; text-align: left; padding-left: 0.3em; padding-right: 1em; border-right: 1px solid #5500dd; }
101 table.toolbox td.c2 { vertical-align: middle; text-align: center; padding-left: 5px; padding-right: 5px; }
102 </style>
103 <script type="text/javascript">// <![CDATA[
104 var dhtml_url = '<?php echo addslashes($url_base.basename($_SERVER['PHP_SELF'])); ?>';
105 var graph_url = '<?php echo addslashes($url_base.'graph.php'); ?>';
106 // ]]></script>
107 <script type="text/javascript" src="<?php echo htmlspecialchars($url_base.'browser.js'); ?>"></script>
108 </head>
110 <body onload="ListRefreshHost(); GraphListRefresh(); "><div class="body">
111 <h1><img src="collectd-logo.png" align="bottom" alt="" /> Collectd browser for system statistics graphs</h1>
112 <div class="selector"><a href="javascript:toggleDiv('selector')"><span id="selector_sw">Hide</span> graph selection tool</a><div id="selector" class="selectorbox">
113 <table>
114 <tr>
115 <td class="s1">Host:</td>
116 <td class="s2"><select id="host_list" name="host" disabled="disabled" onchange="ListRefreshPlugin()">
117 </select></td>
118 <td class="s3"><a href="javascript:ListRefreshHost()"><img src="refresh.png" width="16" height="16" alt="R" title="Refresh host list" /></a></td>
119 </tr>
120 <tr>
121 <td class="s1">Plugin:</td>
122 <td class="s2"><select id="plugin_list" name="plugin" disabled="disabled" onchange="ListRefreshPluginInstance()">
123 </select></td>
124 <td class="s3"><a href="javascript:ListRefreshPlugin()"><img src="refresh.png" width="16" height="16" alt="R" title="Refresh plugin list" /></a></td>
125 </tr>
126 <tr>
127 <td class="s1">Plugin instance:</td>
128 <td class="s2"><select id="pinst_list" name="pinst" disabled="disabled" onchange="ListRefreshType()">
129 </select></td>
130 <td class="s3"><a href="javascript:ListRefreshPluginInstance()"><img src="refresh.png" width="16" height="16" alt="R" title="Refresh plugin instance list" /></a></td>
131 </tr>
132 <tr>
133 <td class="s1">Type:</td>
134 <td class="s2"><select id="type_list" name="type" disabled="disabled" onchange="ListRefreshTypeInstance()">
135 </select></td>
136 <td class="s3"><a href="javascript:ListRefreshType()"><img src="refresh.png" width="16" height="16" alt="R" title="Refresh type list" /></a></td>
137 </tr>
138 <tr>
139 <td class="s1">Type instance:</td>
140 <td class="s2"><select id="tinst_list" name="tinst" disabled="disabled" onchange="RefreshButtons()">
141 </select></td>
142 <td class="s3"><a href="javascript:ListRefreshTypeInstance()"><img src="refresh.png" width="16" height="16" alt="R" title="Refresh type instance list" /></a></td>
143 </tr>
144 <tr>
145 <td class="s1">Graph settings:</td>
146 <td class="s2"><select id="timespan" name="timespan">
147 <?php foreach ($config['timespan'] as &$timespan)
148 printf("\t\t\t\t\t\t<option value=\"%s\">%s</option>\n", htmlspecialchars($timespan['name']), htmlspecialchars($timespan['label']));
149 ?> </select>
150 <br /><label><input id="logarithmic" name="logarithmic" type="checkbox" value="1" /> Logarithmic scale</label>
151 <br /><label><input id="tinylegend" name="tinylegend" type="checkbox" value="1" /> Minimal legend</label></td>
152 <td class="s3"></td>
153 </tr>
154 <tr>
155 <td class="sc" colspan="3"><input id="btnAdd" name="btnAdd" type="button" disabled="disabled" onclick="GraphAppend()" value="Add graph" />
156 <input id="btnClear" name="btnClear" type="button" disabled="disabled" onclick="GraphDropAll()" value="Remove all graphs" />
157 <input id="btnRefresh" name="btnRefresh" type="button" disabled="disabled" onclick="GraphRefreshAll()" value="Refresh all graphs" /></td>
158 </tr>
159 <tr>
160 <td class="s1" rowspan="2">Graph list favorites:</td>
161 <td class="s3"><input type="text" style="width: 100%" maxlength="30" id="GraphListName" name="GraphListName" value="default" onchange="GraphListCheckName(false)" /></td>
162 <td class="s3"><a href="javascript:GraphSave()"><img src="save.png" width="16" height="16" alt="S" title="Save graph list to cookie" /></a></td>
163 </tr>
164 <tr>
165 <td class="s2"><select id="GraphList" name="GraphList" onfocus="GraphListRefresh()">
166 <option value="default">default</option>
167 </select></td>
168 <td class="s3"><a href="javascript:GraphLoad()"><img src="load.png" width="16" height="16" alt="L" title="Load graph list from cookie" /></a><a href="javascript:GraphDrop()"><img src="delete.png" width="16" height="16" alt="D" title="Delete graph list from cookie" /></a></td>
169 </tr>
170 </table>
171 </div></div>
172 <div class="graphs"><div id="graphs" class="graphs_t">
173 <div id="nograph">Please use above graph selection tool to add graphs to this area.<?php
174 // Config checking
175 if (!isset($config['datadirs']))
176 echo '<p class="error">Config error: $config["datadirs"] is not set</p>';
177 else if (!is_array($config['datadirs']))
178 echo '<p class="error">Config error: $config["datadirs"] is not an array</p>';
179 else if (count($config['datadirs']) == 0)
180 echo '<p class="error">Config error: $config["datadirs"] is empty</p>';
181 else foreach ($config['datadirs'] as $datadir)
182 if (!is_dir($datadir))
183 echo '<p class="error">Config error: $config["datadirs"], '.htmlspecialchars($datadir).' does not exist</p>';
184 if (!isset($config['rrd_width']))
185 echo '<p class="error">Config error: $config["rrd_width"] is not set</p>';
186 else if (10 > (int)$config['rrd_width'])
187 echo '<p class="error">Config error: $config["rrd_width"] is invalid. Integer >= 10 expected</p>';
188 if (!isset($config['rrd_height']))
189 echo '<p class="error">Config error: $config["rrd_height"] is not set</p>';
190 else if (10 > (int)$config['rrd_height'])
191 echo '<p class="error">Config error: $config["rrd_height"] is invalid. Integer >= 10 expected</p>';
192 if (!isset($config['rrd_opts']))
193 echo '<p class="error">Config error: $config["rrd_opts"] is not set</p>';
194 else if (!is_array($config['rrd_opts']))
195 echo '<p class="error">Config error: $config["rrd_opts"] is not an array</p>';
196 if (!isset($config['timespan']))
197 echo '<p class="error">Config error: $config["timespan"] is not set</p>';
198 else if (!is_array($config['timespan']))
199 echo '<p class="error">Config error: $config["timespan"] is not an array</p>';
200 else if (count($config['timespan']) == 0)
201 echo '<p class="error">Config error: $config["timespan"] is empty</p>';
202 else foreach ($config['timespan'] as &$timespan)
203 if (!is_array($timespan) || !isset($timespan['name']) || !isset($timespan['label']) || !isset($timespan['seconds']) || 10 > (int)$timespan['seconds'])
204 echo '<p class="error">Config error: $config["timespan"], invalid entry found</p>';
205 if (!is_null($config['collectd_sock']) && strncmp('unix://', $config['collectd_sock'], 7) != 0)
206 echo '<p class="error">Config error: $config["collectd_sock"] is not valid</p>';
207 if (!defined('RRDTOOL'))
208 echo '<p class="error">Config error: RRDTOOL is not defined</p>';
209 else if (!is_executable(RRDTOOL))
210 echo '<p class="error">Config error: RRDTOOL ('.htmlspecialchars(RRDTOOL).') is not executable</p>';
211 ?></div>
212 </div></div>
213 <input type="hidden" name="ge_graphid" id="ge_graphid" value="" />
214 <table id="ge" class="toolbox" style="position: absolute; display: none; " cellspacing="1" cellpadding="0">
215 <tr>
216 <td class="c1" rowspan="3"><select id="ge_timespan" name="ge_timespan" onchange="GraphAdjust(null)"><?php
217 foreach ($config['timespan'] as &$timespan)
218 printf("\t\t\t\t\t\t<option value=\"%s\">%s</option>\n", htmlspecialchars($timespan['name']), htmlspecialchars($timespan['label']));
219 ?></select><br />
220 <label><input id="ge_logarithmic" name="ge_logarithmic" type="checkbox" value="1" onchange="GraphAdjust(null)" /> Logarithmic scale</label><br />
221 <label><input id="ge_tinylegend" name="ge_tinylegend" type="checkbox" value="1" onchange="GraphAdjust(null)" /> Minimal legend</label></td>
222 <td class="c2"><a href="javascript:GraphMoveUp(null)"><img src="move-up.png" alt="UP" title="Move graph up"/></a></td>
223 </tr>
224 <tr>
225 <td class="c2"><a href="javascript:GraphRefresh(null)"><img src="refresh.png" alt="R" title="Refresh graph"/></a> <a href="javascript:GraphRemove(null)"><img src="delete.png" alt="RM" title="Remove graph"/></a></td>
226 </tr>
227 <tr>
228 <td class="c2"><a href="javascript:GraphMoveDown(null)"><img src="move-down.png" alt="DN" title="Move graph down"/></a></td>
229 </tr>
230 </table>
231 </div></body>
232 </html><?php
233 }
236 /*
237 * Select action based on user input
238 */
239 $action = read_var('action', $_POST, 'overview');
240 switch ($action) {
241 case 'list_hosts':
242 // Generate a list of hosts
243 $hosts = collectd_list_hosts();
244 if (count($hosts) > 1)
245 array_unshift($hosts, '@all');
246 return dhtml_response_list($hosts, 'ListOfHost');
248 case 'list_plugins':
249 // Generate list of plugins for selected hosts
250 $arg_hosts = read_var('host', $_POST, '');
251 if (is_array($arg_hosts))
252 $arg_hosts = reset($arg_hosts);
253 $plugins = collectd_list_plugins($arg_hosts);
254 if (count($plugins) > 1)
255 array_unshift($plugins, '@all');
256 return dhtml_response_list($plugins, 'ListOfPlugin');
258 case 'list_pinsts':
259 // Generate list of plugin_instances for selected hosts and plugin
260 $arg_hosts = read_var('host', $_POST, '');
261 if (is_array($arg_hosts))
262 $arg_hosts = reset($arg_hosts);
263 $arg_plugin = read_var('plugin', $_POST, '');
264 $pinsts = collectd_list_plugins($arg_hosts, $arg_plugin);
265 if (count($pinsts) > 1)
266 array_unshift($pinsts, '@all' /* , '@merge_sum', '@merge_avg', '@merge_stack', '@merge_line' */);
267 return dhtml_response_list($pinsts, 'ListOfPluginInstance');
269 case 'list_types':
270 // Generate list of types for selected hosts, plugin and plugin-instance
271 $arg_hosts = read_var('host', $_POST, '');
272 if (is_array($arg_hosts))
273 $arg_hosts = reset($arg_hosts);
274 $arg_plugin = read_var('plugin', $_POST, '');
275 $arg_pinst = read_var('plugin_instance', $_POST, '');
276 $types = collectd_list_types($arg_hosts, $arg_plugin, $arg_pinst);
277 if (count($types) > 1)
278 array_unshift($types, '@all');
279 return dhtml_response_list($types, 'ListOfType');
281 case 'list_tinsts':
282 // Generate list of types for selected hosts, plugin and plugin-instance
283 $arg_hosts = read_var('host', $_POST, '');
284 if (is_array($arg_hosts))
285 $arg_hosts = reset($arg_hosts);
286 $arg_plugin = read_var('plugin', $_POST, '');
287 $arg_pinst = read_var('plugin_instance', $_POST, '');
288 $arg_type = read_var('type', $_POST, '');
289 $tinsts = collectd_list_types($arg_hosts, $arg_plugin, $arg_pinst, $arg_type);
290 if (count($tinsts))
291 if ($arg_type != '@all') {
292 require('definitions.php');
293 load_graph_definitions();
294 if (isset($MetaGraphDefs[$arg_type]))
295 array_unshift($tinsts, '@merge');
296 if (count($tinsts) > 1)
297 array_unshift($tinsts, '@all');
298 } else {
299 array_unshift($tinsts, /* '@merge_sum', '@merge_avg', '@merge_stack', '@merge_line', */ '@merge');
300 if (count($tinsts) > 1)
301 array_unshift($tinsts, '@all');
302 }
303 return dhtml_response_list($tinsts, 'ListOfTypeInstance');
305 case 'list_graphs':
306 // Generate list of types for selected hosts, plugin and plugin-instance
307 $arg_hosts = read_var('host', $_POST, '');
308 if (is_array($arg_hosts))
309 $arg_hosts = reset($arg_hosts);
310 $arg_plugin = read_var('plugin', $_POST, '');
311 $arg_pinst = read_var('plugin_instance', $_POST, '');
312 $arg_type = read_var('type', $_POST, '');
313 $arg_tinst = read_var('type_instance', $_POST, '');
314 $arg_log = (int)read_var('logarithmic', $_POST, '0');
315 $arg_legend = (int)read_var('tinyLegend', $_POST, '0');
316 $arg_period = read_var('timespan', $_POST, '');
317 $graphs = collectd_list_graphs($arg_hosts, $arg_plugin, $arg_pinst, $arg_type, $arg_tinst);
318 foreach ($graphs as &$graph) {
319 $graph['logarithmic'] = $arg_log;
320 $graph['tinyLegend'] = $arg_legend;
321 $graph['timespan'] = $arg_period;
322 }
323 return dhtml_response_graphs($graphs, 'ListOfGraph');
325 case 'overview':
326 default:
327 return build_page();
328 break;
329 }
330 ?>