1 <?php // vim:fenc=utf-8:filetype=php:ts=4
3 * Copyright (C) 2009 Bruno Prémont <bonbons AT linux-vserver.org>
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.
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
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.
19 error_reporting(E_ALL | E_NOTICE | E_WARNING);
21 require('config.php');
22 require('functions.php');
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
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));
36 foreach ($items as &$item)
37 printf(' <option>%s</option>'."\n", htmlspecialchars($item));
38 print(" </result>\n");
43 * Product page body with selection fields
45 function build_page() {
48 if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/compatible; MSIE [0-9]+.[0-9];/', $_SERVER['HTTP_USER_AGENT'])) {
49 // Internet Explorer does not support XHTML
50 header("Content-Type: text/html");
52 print('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">');
53 print('<html lang="en">'."\n");
55 header("Content-Type: application/xhtml+xml");
57 print('<?xml version="1.0" encoding="utf-8" ?>'."\n");
58 print('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'."\n");
59 print('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">'."\n");
61 $url_base = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/';
64 <title>Collectd graph viewer</title>
65 <link rel="icon" href="favicon.png" type="image/png" />
66 <style type="text/css">
67 body, html { background-color: #EEEEEE; color: #000000; }
68 h1 { text-align: center; }
69 div.body { margin: auto; width: <?php echo isset($config['rrd_width']) ? 125+(int)$config['rrd_width'] : 600; ?>px; background: #FFFFFF; border: 1px solid #DDDDDD; }
70 p.error { color: #CC0000; margin: 0em; }
71 div.selector { margin: 0.5em 2em; }
72 div.selectorbox { padding: 5px; border: 1px solid #CCCCCC; background-color: #F8F8F8; }
73 div.selectorbox table { border: none; }
74 div.selectorbox table td.s1 { border-bottom: 1px dashed #F0F0F0; padding-right: 1em; vertical-align: middle; }
75 div.selectorbox table td.s2 { border-bottom: 1px dashed #F0F0F0; vertical-align: middle; }
76 div.selectorbox table td.s3 { vertical-align: middle; }
77 div.selectorbox table td.sc { padding: 0.5em 2em; text-align: center; }
78 a img { border: none; }
79 div.graphs { border-top: 1px solid #DDDDDD; padding: 5px; overflow: auto; }
80 div.graphs_t { display: table; }
81 div.graph { display: table-row; }
82 div.graph_img { display: table-cell; vertical-align: middle; text-align: right; }
83 div.graph_opts { display: table-cell; vertical-align: middle; text-align: center; line-height: 2em; }
84 select { width: 100%; }
86 <script type="text/javascript">// <![CDATA[
87 var dhtml_url = '<?php echo addslashes($url_base.basename($_SERVER['PHP_SELF'])); ?>';
88 var graph_url = '<?php echo addslashes($url_base.'graph.php'); ?>';
90 <script type="text/javascript" src="<?php echo htmlspecialchars($url_base.'browser.js'); ?>"></script>
93 <body onload="ListRefreshHost()"><div class="body">
94 <h1><img src="collectd-logo.png" align="bottom" alt="" /> Collectd browser for system statistics graphs</h1>
95 <div class="selector"><a href="javascript:toggleDiv('selector')"><span id="selector_sw">Hide</span> graph selection tool</a><div id="selector" class="selectorbox">
98 <td class="s1">Host:</td>
99 <td class="s2"><select id="host_list" name="host" disabled="disabled" onchange="ListRefreshPlugin()">
101 <td class="s3"><a href="javascript:ListRefreshHost()"><img src="refresh.png" width="16" height="16" alt="R" title="Refresh host list" /></a></td>
104 <td class="s1">Plugin:</td>
105 <td class="s2"><select id="plugin_list" name="plugin" disabled="disabled" onchange="ListRefreshPluginInstance()">
107 <td class="s3"><a href="javascript:ListRefreshPlugin()"><img src="refresh.png" width="16" height="16" alt="R" title="Refresh plugin list" /></a></td>
110 <td class="s1">Plugin instance:</td>
111 <td class="s2"><select id="pinst_list" name="pinst" disabled="disabled" onchange="ListRefreshType()">
113 <td class="s3"><a href="javascript:ListRefreshPluginInstance()"><img src="refresh.png" width="16" height="16" alt="R" title="Refresh plugin instance list" /></a></td>
116 <td class="s1">Type:</td>
117 <td class="s2"><select id="type_list" name="type" disabled="disabled" onchange="ListRefreshTypeInstance()">
119 <td class="s3"><a href="javascript:ListRefreshType()"><img src="refresh.png" width="16" height="16" alt="R" title="Refresh type list" /></a></td>
122 <td class="s1">Type instance:</td>
123 <td class="s2"><select id="tinst_list" name="tinst" disabled="disabled" onchange="RefreshButtons()">
125 <td class="s3"><a href="javascript:ListRefreshTypeInstance()"><img src="refresh.png" width="16" height="16" alt="R" title="Refresh type instance list" /></a></td>
128 <td class="s1">Graph settings:</td>
129 <td class="s2"><select id="timespan" name="timespan">
130 <?php foreach ($config['timespan'] as &$timespan)
131 printf("\t\t\t\t\t\t<option value=\"%s\">%s</option>\n", htmlspecialchars($timespan['name']), htmlspecialchars($timespan['label']));
133 <br /><label><input id="logarithmic" name="logarithmic" type="checkbox" value="1" /> Logarithmic scale</label>
134 <br /><label><input id="tinylegend" name="tinylegend" type="checkbox" value="1" /> Minimal legend</label></td>
138 <td class="sc" colspan="3"><input id="btnAdd" name="btnAdd" type="button" disabled="disabled" onclick="GraphAppend()" value="Add graph" />
139 <input id="btnClear" name="btnClear" type="button" disabled="disabled" onclick="GraphDropAll()" value="Remove all graphs" />
140 <input id="btnRefresh" name="btnRefresh" type="button" disabled="disabled" onclick="GraphRefresh(null)" value="Refresh all graphs" />
141 <input id="btnSave" name="btnSave" type="button" onclick="GraphSave()" value="Save" title="Save graph list to cookie" />
142 <input id="btnLoad" name="btnLoad" type="button" onclick="GraphLoad()" value="Load" title="Load graph list from cookie" /></td>
146 <div class="graphs"><div id="graphs" class="graphs_t">
147 <div id="nograph">Please use above graph selection tool to add graphs to this area.<?php
149 if (!isset($config['datadirs']))
150 echo '<p class="error">Config error: $config["datadirs"] is not set</p>';
151 else if (!is_array($config['datadirs']))
152 echo '<p class="error">Config error: $config["datadirs"] is not an array</p>';
153 else if (count($config['datadirs']) == 0)
154 echo '<p class="error">Config error: $config["datadirs"] is empty</p>';
155 else foreach ($config['datadirs'] as $datadir)
156 if (!is_dir($datadir))
157 echo '<p class="error">Config error: $config["datadirs"], '.htmlspecialchars($datadir).' does not exist</p>';
158 if (!isset($config['rrd_width']))
159 echo '<p class="error">Config error: $config["rrd_width"] is not set</p>';
160 else if (10 > (int)$config['rrd_width'])
161 echo '<p class="error">Config error: $config["rrd_width"] is invalid. Integer >= 10 expected</p>';
162 if (!isset($config['rrd_height']))
163 echo '<p class="error">Config error: $config["rrd_height"] is not set</p>';
164 else if (10 > (int)$config['rrd_height'])
165 echo '<p class="error">Config error: $config["rrd_height"] is invalid. Integer >= 10 expected</p>';
166 if (!isset($config['rrd_opts']))
167 echo '<p class="error">Config error: $config["rrd_opts"] is not set</p>';
168 else if (!is_array($config['rrd_opts']))
169 echo '<p class="error">Config error: $config["rrd_opts"] is not an array</p>';
170 if (!isset($config['timespan']))
171 echo '<p class="error">Config error: $config["timespan"] is not set</p>';
172 else if (!is_array($config['timespan']))
173 echo '<p class="error">Config error: $config["timespan"] is not an array</p>';
174 else if (count($config['timespan']) == 0)
175 echo '<p class="error">Config error: $config["timespan"] is empty</p>';
176 else foreach ($config['timespan'] as &$timespan)
177 if (!is_array($timespan) || !isset($timespan['name']) || !isset($timespan['label']) || !isset($timespan['seconds']) || 10 > (int)$timespan['seconds'])
178 echo '<p class="error">Config error: $config["timespan"], invalid entry found</p>';
179 if (!is_null($config['collectd_sock']) && strncmp('unix://', $config['collectd_sock'], 7) != 0)
180 echo '<p class="error">Config error: $config["collectd_sock"] is not valid</p>';
181 if (!defined('RRDTOOL'))
182 echo '<p class="error">Config error: RRDTOOL is not defined</p>';
183 else if (!is_executable(RRDTOOL))
184 echo '<p class="error">Config error: RRDTOOL ('.htmlspecialchars(RRDTOOL).') is not executable</p>';
193 * Select action based on user input
195 $action = read_var('action', $_POST, 'overview');
198 // Generate a list of hosts
199 $hosts = collectd_list_hosts();
200 return dhtml_response_list($hosts, 'ListOfHost');
203 // Generate list of plugins for selected hosts
204 $arg_hosts = read_var('host', $_POST, array());
205 if (!is_array($arg_hosts))
206 $arg_hosts = array($arg_hosts);
207 $plugins = collectd_list_plugins(reset($arg_hosts));
208 return dhtml_response_list($plugins, 'ListOfPlugin');
211 // Generate list of plugin_instances for selected hosts and plugin
212 $arg_hosts = read_var('host', $_POST, array());
213 if (!is_array($arg_hosts))
214 $arg_hosts = array($arg_hosts);
215 $arg_plugin = read_var('plugin', $_POST, '');
216 $pinsts = collectd_list_pinsts(reset($arg_hosts), $arg_plugin);
217 return dhtml_response_list($pinsts, 'ListOfPluginInstance');
220 // Generate list of types for selected hosts, plugin and plugin-instance
221 $arg_hosts = read_var('host', $_POST, array());
222 if (!is_array($arg_hosts))
223 $arg_hosts = array($arg_hosts);
224 $arg_plugin = read_var('plugin', $_POST, '');
225 $arg_pinst = read_var('plugin_instance', $_POST, '');
226 $types = collectd_list_types(reset($arg_hosts), $arg_plugin, $arg_pinst);
227 return dhtml_response_list($types, 'ListOfType');
230 // Generate list of types for selected hosts, plugin and plugin-instance
231 $arg_hosts = read_var('host', $_POST, array());
232 if (!is_array($arg_hosts))
233 $arg_hosts = array($arg_hosts);
234 $arg_plugin = read_var('plugin', $_POST, '');
235 $arg_pinst = read_var('plugin_instance', $_POST, '');
236 $arg_type = read_var('type', $_POST, '');
237 $tinsts = collectd_list_tinsts(reset($arg_hosts), $arg_plugin, $arg_pinst, $arg_type);
238 if (count($tinsts)) {
239 require('definitions.php');
240 load_graph_definitions();
241 if (isset($MetaGraphDefs[$arg_type])) {
242 $meta_tinsts = array('@');
243 return dhtml_response_list($meta_tinsts, 'ListOfTypeInstance');
246 return dhtml_response_list($tinsts, 'ListOfTypeInstance');