PageRenderTime 63ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/graph.php

https://github.com/580farm/ganglia-web
PHP | 1424 lines | 1030 code | 191 blank | 203 comment | 292 complexity | c37b5cdf63620934652f31ad69026b74 MD5 | raw file
Possible License(s): BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. // vim: tabstop=2:softtabstop=2:shiftwidth=2:expandtab
  3. include_once "./eval_conf.php";
  4. include_once "./get_context.php";
  5. include_once "./functions.php";
  6. ///////////////////////////////////////////////////////////////////////////////
  7. // Populate $rrdtool_graph from $config (from JSON file).
  8. ///////////////////////////////////////////////////////////////////////////////
  9. function build_rrdtool_args_from_json( &$rrdtool_graph, $graph_config ) {
  10. global $context, $hostname, $range, $rrd_dir, $size, $conf;
  11. if ($conf['strip_domainname']) {
  12. $hostname = strip_domainname($hostname);
  13. }
  14. $title = sanitize( $graph_config[ 'title' ] );
  15. $rrdtool_graph[ 'title' ] = $title;
  16. // If vertical label is empty or non-existent set it to space otherwise
  17. // rrdtool will fail
  18. if ( ! isset($graph_config[ 'vertical_label' ]) ||
  19. $graph_config[ 'vertical_label' ] == "" ) {
  20. $rrdtool_graph[ 'vertical-label' ] = " ";
  21. } else {
  22. $rrdtool_graph[ 'vertical-label' ] =
  23. sanitize( $graph_config[ 'vertical_label' ] );
  24. }
  25. $rrdtool_graph['lower-limit'] = '0';
  26. if( isset($graph_config['height_adjustment']) ) {
  27. $rrdtool_graph['height'] +=
  28. ($size == 'medium') ? $graph_config['height_adjustment'] : 0;
  29. } else {
  30. $rrdtool_graph['height'] += ($size == 'medium') ? 28 : 0;
  31. }
  32. // find longest label length, so we pad the others accordingly to get
  33. // consistent column alignment
  34. $max_label_length = 0;
  35. foreach( $graph_config[ 'series' ] as $item ) {
  36. $max_label_length = max( strlen( $item[ 'label' ] ), $max_label_length );
  37. }
  38. $series = '';
  39. $cdef = '';
  40. $graphdef = '';
  41. $stack_counter = 0;
  42. // Available line types
  43. $line_widths = array("1","2","3");
  44. $total_ids = array();
  45. // Loop through all the graph items
  46. foreach( $graph_config[ 'series' ] as $index => $item ) {
  47. // ignore item if context is not defined in json template
  48. if ( isSet($item[ 'contexts' ]) and
  49. in_array($context, $item['contexts']) == false )
  50. continue;
  51. $rrd_dir = $conf['rrds'] . "/" . $item['clustername'] . "/" . $item['hostname'];
  52. $metric = sanitize( $item[ 'metric' ] );
  53. $metric_file = $rrd_dir . "/" . $metric . ".rrd";
  54. // Make sure metric file exists. Otherwise we'll get a broken graph
  55. if ( is_file($metric_file) ) {
  56. // Need this when defining graphs that may use same metric names
  57. $unique_id = "a" . $index;
  58. $total_ids[] = $unique_id;
  59. # Pad the label with spaces
  60. $label = str_pad( sanitize( $item[ 'label' ] ), $max_label_length );
  61. // use custom DS defined in json template if it's
  62. // defined (default = 'sum')
  63. $DS = "sum";
  64. if ( isset($item[ 'ds' ]) )
  65. $DS = sanitize( $item[ 'ds' ] );
  66. $series .= " DEF:'$unique_id'='$metric_file':'$DS':AVERAGE ";
  67. if (isset($graph_config['scale'])) {
  68. $cdef .= " CDEF:'s${unique_id}'=${unique_id},${graph_config['scale']},* ";
  69. }
  70. if (isset($graph_config['percent']) && $graph_config['percent'] == '1') {
  71. $cdef .= " CDEF:'p${unique_id}'=${unique_id},total,/,100,* ";
  72. }
  73. // By default graph is a line graph
  74. isset( $item['type']) ?
  75. $item_type = $item['type'] : $item_type = "line";
  76. // TODO sanitize color
  77. switch ( $item_type ) {
  78. case "line":
  79. // Make sure it's a recognized line type
  80. isset($item['line_width']) &&
  81. in_array( $item['line_width'], $line_widths) ?
  82. $line_width = $item['line_width'] : $line_width = "1";
  83. $graphdef .= "LINE" . $line_width;
  84. if (isset($graph_config['percent']) && $graph_config['percent'] == '1') {
  85. $graphdef .= ":'p${unique_id}'#${item['color']}:'${label}' ";
  86. } else if (isset($graph_config['scale'])) {
  87. $graphdef .= ":'s${unique_id}'#${item['color']}:'${label}' ";
  88. } else {
  89. $graphdef .= ":'$unique_id'#${item['color']}:'${label}' ";
  90. }
  91. break;
  92. case "stack":
  93. case "percent":
  94. // First element in a stack has to be AREA
  95. if ( $stack_counter == 0 ) {
  96. $graphdef .= "AREA";
  97. $stack_counter++;
  98. } else {
  99. $graphdef .= "STACK";
  100. }
  101. if (isset($graph_config['percent']) && $graph_config['percent'] == '1') {
  102. $graphdef .= ":'p${unique_id}'#${item['color']}:'${label}' ";
  103. } else if (isset($graph_config['scale'])) {
  104. $graphdef .= ":'s${unique_id}'#${item['color']}:'${label}' ";
  105. } else {
  106. $graphdef .= ":'$unique_id'#${item['color']}:'${label}' ";
  107. }
  108. break;
  109. // Percentile lines
  110. case "percentile":
  111. $percentile = isset($item['percentile']) ? floatval($item['percentile']): 95;
  112. $graphdef .= "VDEF:t${unique_id}=${unique_id},${percentile},PERCENT ";
  113. isset($item['line_width']) && in_array( $item['line_width'], $line_widths) ?
  114. $line_width = $item['line_width'] : $line_width = "1";
  115. $graphdef .= "LINE" . $line_width . ":'t$unique_id'#{$item['color']}:'{$label}':dashes ";
  116. break;
  117. case "area":
  118. $graphdef .= "AREA";
  119. $graphdef .= ":'$unique_id'#${item['color']}:'${label}' ";
  120. break;
  121. } // end of switch ( $item_type )
  122. if ( $conf['graphreport_stats'] ) {
  123. if (isset($graph_config['percent']) && $graph_config['percent'] == '1') {
  124. $graphdef .= legendEntry('p' . $unique_id, $conf['graphreport_stat_items']);
  125. } else if (isset($graph_config['scale'])) {
  126. $graphdef .= legendEntry('s' . $unique_id, $conf['graphreport_stat_items']);
  127. } else {
  128. $graphdef .= legendEntry($unique_id, $conf['graphreport_stat_items']);
  129. }
  130. }
  131. } // end of if ( is_file($metric_file) ) {
  132. } // end of foreach( $graph_config[ 'series' ] as $index => $item )
  133. // Percentage calculation for cdefs, if required
  134. //if (isset($graph_config['percent']) && $graph_config['percent'] == '1') {
  135. $total = " CDEF:'total'=";
  136. if (count($total_ids) == 0) {
  137. // Handle nothing gracefully, do nothing
  138. } else if (count($total_ids) == 1) {
  139. // Concat just that id, leave it at that (100%)
  140. $total .= $total_ids[0];
  141. if (isset($graph_config['scale'])) {
  142. $total .= ",${graph_config['scale']},*";
  143. }
  144. $cdef = $total . ' ' . $cdef;
  145. } else {
  146. $total .= $total_ids[0];
  147. for ($i=1; $i<count($total_ids); $i++) {
  148. $total .= ',' . $total_ids[$i] . ',ADDNAN';
  149. }
  150. if (isset($graph_config['scale'])) {
  151. $total .= ",${graph_config['scale']},*";
  152. }
  153. // Prepend total calculation
  154. $cdef = $total . ', ' . $cdef;
  155. }
  156. //} // if graph_config['percent']
  157. if ( isset($graph_config['show_total']) && $graph_config['show_total'] == 1 ) {
  158. $cdef .= " LINE1:'total'#000000:'Total' " . legendEntry('total', $conf['graphreport_stat_items']);
  159. }
  160. // If we end up with the empty series it means that no RRD files matched.
  161. // This can happen if we are trying to create a report and metrics for
  162. // this host were not collected. If that happens we should create an
  163. // empty graph
  164. if ( $series == "" ) {
  165. $rrdtool_graph[ 'series' ] =
  166. 'HRULE:1#FFCC33:"No matching metrics detected"';
  167. } else {
  168. $rrdtool_graph[ 'series' ] = $series . ' ' . $cdef . ' ' . $graphdef;
  169. }
  170. return $rrdtool_graph;
  171. }
  172. ///////////////////////////////////////////////////////////////////////////////
  173. // Graphite graphs
  174. ///////////////////////////////////////////////////////////////////////////////
  175. function build_graphite_series( $config, $host_cluster = "" ) {
  176. global $context;
  177. $targets = array();
  178. $colors = array();
  179. // Keep track of stacked items
  180. $stacked = 0;
  181. foreach( $config[ 'series' ] as $item ) {
  182. if ( isSet($item[ 'contexts' ]) and in_array($context, $item['contexts'])==false )
  183. continue;
  184. if ( $item['type'] == "stack" )
  185. $stacked++;
  186. if ( isset($item['hostname']) && isset($item['clustername']) ) {
  187. $host_cluster = $item['clustername'] . "." . str_replace(".","_", $item['hostname']);
  188. }
  189. $targets[] = "target=". urlencode( "alias($host_cluster.${item['metric']}.sum,'${item['label']}')" );
  190. $colors[] = $item['color'];
  191. }
  192. $output = implode( $targets, '&' );
  193. $output .= "&colorList=" . implode( $colors, ',' );
  194. $output .= "&vtitle=" . urlencode( isset($config[ 'vertical_label' ]) ? $config[ 'vertical_label' ] : "" );
  195. // Do we have any stacked elements. We assume if there is only one element
  196. // that is stacked that rest of it is line graphs
  197. if ( $stacked > 0 ) {
  198. if ( $stacked > 1 )
  199. $output .= "&areaMode=stacked";
  200. else
  201. $output .= "&areaMode=first";
  202. }
  203. return $output;
  204. }
  205. function build_value_for_json( $value ) {
  206. if ( is_numeric( $value ) )
  207. $val = floatval($value);
  208. else
  209. $val = $value;
  210. return $val;
  211. }
  212. $gweb_root = dirname(__FILE__);
  213. # RFM - Added all the isset() tests to eliminate "undefined index"
  214. # messages in ssl_error_log.
  215. # Graph specific variables
  216. # ATD - No need for escapeshellcmd or rawurldecode on $size or $graph. Not used directly in rrdtool calls.
  217. $size = isset($_GET["z"]) &&
  218. in_array($_GET[ 'z' ], $conf['graph_sizes_keys']) ? $_GET["z"] : NULL;
  219. $metric_name = isset($_GET["m"]) ? sanitize ( $_GET["m"] ) : NULL;
  220. # In clusterview we may supply report as metric name so let's make sure it
  221. # doesn't treat it as a metric
  222. if ( preg_match("/_report$/", $metric_name) && !isset($_GET["g"]) ) {
  223. $graph = $metric_name;
  224. } else {
  225. # If graph arg is not specified default to metric
  226. $graph = isset($_GET["g"]) ? sanitize ( $_GET["g"] ) : "metric";
  227. }
  228. $graph_arguments = array();
  229. if ($conf['enable_pass_in_arguments_to_optional_graphs']) {
  230. $pos = strpos($graph, ",");
  231. if ($pos !== FALSE) {
  232. $graph_report = substr($graph, 0, $pos);
  233. $args = str_getcsv(substr($graph, $pos + 1), ",", "'");
  234. /*
  235. ob_start();
  236. var_dump($args);
  237. $result = ob_get_clean();
  238. error_log("args = $result");
  239. */
  240. foreach ($args as $arg) {
  241. if (is_numeric($arg)) {
  242. if (ctype_digit($arg))
  243. $graph_arguments[] = intval($arg);
  244. else
  245. $graph_arguments[] = floatval($arg);
  246. } else
  247. $graph_arguments[] = $arg;
  248. }
  249. $graph = $graph_report;
  250. }
  251. }
  252. $grid = isset($_GET["G"]) ? sanitize( $_GET["G"]) : NULL;
  253. $self = isset($_GET["me"]) ? sanitize( $_GET["me"]) : NULL;
  254. $vlabel = isset($_GET["vl"]) ? sanitize($_GET["vl"]) : NULL;
  255. $graph_scale = isset($_GET["gs"]) ? sanitize($_GET["gs"]) : NULL;
  256. $scale = isset($_GET["scale"]) ? sanitize($_GET["scale"]) : NULL;
  257. $show_total = isset($_GET["show_total"]) ? sanitize($_GET["show_total"]) : NULL;
  258. $value = isset($_GET["v"]) ? sanitize ($_GET["v"]) : NULL;
  259. # Max, min, critical and warning values
  260. $max = isset($_GET["x"]) && is_numeric($_GET["x"]) ? $_GET["x"] : NULL;
  261. $min = isset($_GET["n"]) && is_numeric($_GET["n"]) ? $_GET["n"] : NULL;
  262. $critical = isset($_GET["crit"]) && is_numeric($_GET["crit"]) ? $_GET["crit"] : NULL;
  263. $warning = isset($_GET["warn"]) && is_numeric($_GET["warn"]) ? $_GET["warn"] : NULL;
  264. $sourcetime = isset($_GET["st"]) ? clean_number(sanitize($_GET["st"])) : NULL;
  265. $load_color = isset($_GET["l"]) &&
  266. is_valid_hex_color(rawurldecode($_GET['l'])) ?
  267. sanitize($_GET["l"]) : NULL;
  268. $summary = isset($_GET["su"]) ? 1 : 0;
  269. $debug = isset($_GET['debug']) ? clean_number(sanitize($_GET["debug"])) : 0;
  270. $showEvents = isset($_GET["event"]) ? sanitize ($_GET["event"]) : "show";
  271. $user['time_shift'] = isset($_GET["ts"]) ? clean_number(sanitize($_GET["ts"])) : 0;
  272. #
  273. $user['view_name'] = isset($_GET["vn"]) ? sanitize ($_GET["vn"]) : NULL;
  274. $user['item_id'] = isset($_GET["item_id"]) ? sanitize ($_GET["item_id"]) : NULL;
  275. $command = '';
  276. $graphite_url = '';
  277. $user['json_output'] = isset($_GET["json"]) ? 1 : NULL;
  278. # Request for live dashboard
  279. if ( isset($_REQUEST['live']) ) {
  280. $user['live_dashboard'] = 1;
  281. $user['json_output'] = 1;
  282. } else {
  283. $user['live_output'] = NULL;
  284. }
  285. $user['csv_output'] = isset($_GET["csv"]) ? 1 : NULL;
  286. $user['graphlot_output'] = isset($_GET["graphlot"]) ? 1 : NULL;
  287. $user['flot_output'] = isset($_GET["flot"]) ? 1 : NULL;
  288. $user['trend_line'] = isset($_GET["trend"]) ? 1 : NULL;
  289. # How many months ahead to extend the trend e.g. 6 months
  290. $user['trend_range'] = isset($_GET["trendrange"]) && is_numeric($_GET["trendrange"]) ? $_GET["trendrange"] : 6;
  291. #
  292. $user['trend_history'] = isset($_GET["trendhistory"]) && is_numeric($_GET["trendhistory"]) ? $_GET["trendhistory"] : 6;
  293. // Get hostname
  294. $raw_host = isset($_GET["h"]) ? sanitize($_GET["h"]) : "__SummaryInfo__";
  295. // For graphite purposes we need to replace all dots with underscore. dot is
  296. // separates subtrees in graphite
  297. $host = str_replace(".","_", $raw_host);
  298. # Assumes we have a $start variable (set in get_context.php).
  299. # $conf['graph_sizes'] and $conf['graph_sizes_keys'] defined in conf.php.
  300. # Add custom sizes there.
  301. $size = in_array($size, $conf['graph_sizes_keys']) ? $size : 'default';
  302. if (isset($_GET['height']) && is_numeric($_GET['height']))
  303. $height = $_GET['height'];
  304. else
  305. $height = $conf['graph_sizes'][$size]['height'];
  306. if (isset($_GET['width']) && is_numeric($_GET['width']))
  307. $width = $_GET['width'];
  308. else
  309. $width = $conf['graph_sizes'][$size]['width'];
  310. #$height = $conf['graph_sizes'][$size]['height'];
  311. #$width = $conf['graph_sizes'][$size]['width'];
  312. $fudge_0 = $conf['graph_sizes'][$size]['fudge_0'];
  313. $fudge_1 = $conf['graph_sizes'][$size]['fudge_1'];
  314. $fudge_2 = $conf['graph_sizes'][$size]['fudge_2'];
  315. # Aliases for $user['cs'] and $user['ce'] (which are set in get_context.php).
  316. $cs = $user['cs'];
  317. $ce = $user['ce'];
  318. ///////////////////////////////////////////////////////////////////////////
  319. // Set some variables depending on the context. Context is set in
  320. // get_context.php
  321. ///////////////////////////////////////////////////////////////////////////
  322. switch ($context)
  323. {
  324. case "meta":
  325. $rrd_dir = $conf['rrds'] . "/__SummaryInfo__";
  326. $rrd_graphite_link = $conf['graphite_rrd_dir'] . "/__SummaryInfo__";
  327. $title = "$self ${conf['meta_designator']}";
  328. break;
  329. case "grid":
  330. $rrd_dir = $conf['rrds'] . "/$grid/__SummaryInfo__";
  331. $rrd_graphite_link = $conf['graphite_rrd_dir'] . "/$grid/__SummaryInfo__";
  332. if (preg_match('/grid/i', $gridname))
  333. $title = $gridname;
  334. else
  335. $title = "$gridname ${conf['meta_designator']}";
  336. break;
  337. case "cluster":
  338. $rrd_dir = $conf['rrds'] . "/$clustername/__SummaryInfo__";
  339. $rrd_graphite_link = $conf['graphite_rrd_dir'] . "/$clustername/__SummaryInfo__";
  340. if (preg_match('/cluster/i', $clustername))
  341. $title = $clustername;
  342. else
  343. $title = "$clustername Cluster";
  344. break;
  345. case "host":
  346. $rrd_dir = $conf['rrds'] . "/$clustername/$raw_host";
  347. $rrd_graphite_link = $conf['graphite_rrd_dir'] . "/" . $clustername . "/" . $host;
  348. // Add hostname to report graphs' title in host view
  349. if ($graph != 'metric')
  350. if ($conf['strip_domainname'])
  351. $title = strip_domainname($raw_host);
  352. else
  353. $title = $raw_host;
  354. break;
  355. default:
  356. break;
  357. }
  358. $resource = GangliaAcl::ALL_CLUSTERS;
  359. if( $context == "grid" ) {
  360. $resource = $grid;
  361. } else if ( $context == "cluster" || $context == "host" ) {
  362. $resource = $clustername;
  363. }
  364. if( ! checkAccess( $resource, GangliaAcl::VIEW, $conf ) ) {
  365. header( "HTTP/1.1 403 Access Denied" );
  366. header ("Content-type: image/jpg");
  367. echo file_get_contents( $gweb_root.'/img/access-denied.jpg');
  368. die();
  369. }
  370. if ($cs and (is_numeric($cs) or strtotime($cs)))
  371. $start = $cs;
  372. if ($ce and (is_numeric($ce) or strtotime($ce)))
  373. $end = $ce;
  374. # Set some standard defaults that don't need to change much
  375. $rrdtool_graph = array(
  376. 'start' => $start,
  377. 'end' => $end,
  378. 'width' => $width,
  379. 'height' => $height,
  380. );
  381. # automatically strip domainname from small graphs where it won't fit
  382. if ($size == "small") {
  383. $conf['strip_domainname'] = true;
  384. # Let load coloring work for little reports in the host list.
  385. }
  386. if (! isset($subtitle) and $load_color)
  387. $rrdtool_graph['color'] = "BACK#'$load_color'";
  388. if ($debug) {
  389. error_log("Graph [$graph] in context [$context]");
  390. }
  391. /* If we have $graph, then a specific report was requested, such as "network_report" or
  392. * "cpu_report. These graphs usually have some special logic and custom handling required,
  393. * instead of simply plotting a single metric. If $graph is not set, then we are (hopefully),
  394. * plotting a single metric, and will use the commands in the metric.php file.
  395. *
  396. * With modular graphs, we look for a "${graph}.php" file, and if it exists, we
  397. * source it, and call a pre-defined function name. The current scheme for the function
  398. * names is: 'graph_' + <name_of_report>. So a 'cpu_report' would call graph_cpu_report(),
  399. * which would be found in the cpu_report.php file.
  400. *
  401. * These functions take the $rrdtool_graph array as an argument. This variable is
  402. * PASSED BY REFERENCE, and will be modified by the various functions. Each key/value
  403. * pair represents an option/argument, as passed to the rrdtool program. Thus,
  404. * $rrdtool_graph['title'] will refer to the --title option for rrdtool, and pass the array
  405. * value accordingly.
  406. *
  407. * There are two exceptions to: the 'extras' and 'series' keys in $rrdtool_graph. These are
  408. * assigned to $extras and $series respectively, and are treated specially. $series will contain
  409. * the various DEF, CDEF, RULE, LINE, AREA, etc statements that actually plot the charts. The
  410. * rrdtool program requires that this come *last* in the argument string; we make sure that it
  411. * is put in it's proper place. The $extras variable is used for other arguemnts that may not
  412. * fit nicely for other reasons. Complicated requests for --color, or adding --ridgid, for example.
  413. * It is simply a way for the graph writer to add an arbitrary options when calling rrdtool, and to
  414. * forcibly override other settings, since rrdtool will use the last version of an option passed.
  415. * (For example, if you call 'rrdtool' with two --title statements, the second one will be used.)
  416. *
  417. * See ${conf['graphdir']}/sample.php for more documentation, and details on the
  418. * common variables passed and used.
  419. */
  420. // Calculate time range.
  421. if ($sourcetime)
  422. {
  423. $end = $sourcetime;
  424. # Get_context makes start negative.
  425. $start = $sourcetime + $start;
  426. }
  427. // Fix from Phil Radden, but step is not always 15 anymore.
  428. if ($range == "month")
  429. $rrdtool_graph['end'] = floor($rrdtool_graph['end'] / 672) * 672;
  430. ///////////////////////////////////////////////////////////////////////////////
  431. // Are we generating aggregate graphs
  432. ///////////////////////////////////////////////////////////////////////////////
  433. if ( isset( $_GET["aggregate"] ) && $_GET['aggregate'] == 1 ) {
  434. // Set start time
  435. $start = time() + $start;
  436. // If graph type is not specified default to line graph
  437. if ( isset($_GET["gtype"]) && in_array($_GET["gtype"], array("stack","line","percent") ) )
  438. $graph_type = $_GET["gtype"];
  439. else
  440. $graph_type = "line";
  441. // If line width not specified default to 2
  442. if ( isset($_GET["lw"]) && in_array($_GET["lw"], array("1","2", "3") ) )
  443. $line_width = $_GET["lw"];
  444. else
  445. $line_width = "2";
  446. if ( isset($_GET["glegend"]) && in_array($_GET["glegend"], array("show", "hide") ) )
  447. $graph_legend = $_GET["glegend"];
  448. else
  449. $graph_legend = "show";
  450. /////////////////////////////////////////////////////////////////////////////
  451. // In order to reduce the load on the machine when someone is doing host
  452. // compare we look whether host list has been supplied via hl arg.
  453. // That way we do not have get metric cache
  454. /////////////////////////////////////////////////////////////////////////////
  455. if ( isset($_GET['hl']) ) {
  456. $counter = 0;
  457. $color_count = sizeof($conf['graph_colors']);
  458. $metric_name = str_replace("$", "", str_replace("^", "", $_GET['mreg'][0]));
  459. $host_list = explode(",", $_GET['hl']);
  460. foreach ( $host_list as $index => $host_cluster ) {
  461. $color_index = $counter % $color_count;
  462. $parts = explode("|", $host_cluster);
  463. $hostname = $parts[0];
  464. $clustername = $parts[1];
  465. $series = array("hostname" => $hostname,
  466. "clustername" => $clustername,
  467. "fill" => "true",
  468. "metric" => $metric_name,
  469. "color" => $conf['graph_colors'][$color_index],
  470. "label" => $hostname,
  471. "type" => $graph_type);
  472. if ($graph_type == "line" || $graph_type == "area") {
  473. $series['line_width'] = $line_width;
  474. } else if ($graph_type == "percent") {
  475. $graph_config['percent'] = "1";
  476. } else {
  477. $series['stack'] = "1";
  478. }
  479. $graph_config['series'][] = $series;
  480. $counter++;
  481. } // end of foreach ( $host_list as
  482. } else {
  483. $exclude_host_from_legend_label =
  484. (array_key_exists('lgnd_xh', $_GET) &&
  485. $_GET['lgnd_xh'] == "true") ? TRUE : FALSE;
  486. $graph_config = build_aggregate_graph_config ($graph_type,
  487. $line_width,
  488. $_GET['hreg'],
  489. $_GET['mreg'],
  490. $graph_legend,
  491. $exclude_host_from_legend_label);
  492. }
  493. // Set up
  494. $graph_config["report_type"] = "standard";
  495. $graph_config["vertical_label"] = $vlabel;
  496. $graph_config["graph_scale"] = $graph_scale;
  497. $graph_config["scale"] = $scale;
  498. $graph_config["show_total"] = $show_total;
  499. // Reset graph title
  500. if ( isset($_GET['title']) && $_GET['title'] != "") {
  501. $title = "";
  502. $graph_config["title"] = sanitize($_GET['title']);
  503. } else {
  504. $title = "Aggregate";
  505. }
  506. }
  507. ///////////////////////////////////////////////////////////////////////////
  508. // Composite graphs/reports specified in a view
  509. ///////////////////////////////////////////////////////////////////////////
  510. if ( $user['view_name'] and $user['item_id'] ) {
  511. $available_views = get_available_views();
  512. foreach ( $available_views as $id => $view ) {
  513. # Find view settings
  514. if ( $user['view_name'] == $view['view_name'] )
  515. break;
  516. }
  517. unset($available_views);
  518. foreach ( $view['items'] as $index => $graph_config ) {
  519. if ( $user['item_id'] == $graph_config['item_id'] )
  520. break;
  521. }
  522. unset($view);
  523. $title = "";
  524. build_rrdtool_args_from_json ( $rrdtool_graph, $graph_config );
  525. }
  526. //////////////////////////////////////////////////////////////////////////////
  527. // Check what graph engine we are using
  528. //////////////////////////////////////////////////////////////////////////////
  529. switch ( $conf['graph_engine'] ) {
  530. case "flot":
  531. case "rrdtool":
  532. if ( ! isset($graph_config) ) {
  533. if ( ($graph == "metric") &&
  534. isset($_GET['title']) &&
  535. $_GET['title'] !== '')
  536. $metrictitle = sanitize($_GET['title']);
  537. $php_report_file = $conf['graphdir'] . "/" . $graph . ".php";
  538. $json_report_file = $conf['graphdir'] . "/" . $graph . ".json";
  539. if( is_file( $php_report_file ) ) {
  540. # Check for path traversal issues by making sure real path is actually in graphdir
  541. if ( dirname(realpath($php_report_file)) != $conf['graphdir'] ) {
  542. $rrdtool_graph[ 'series' ] = 'HRULE:1#FFCC33:"Check \$conf[graphdir] should not be relative path"';
  543. } else {
  544. include_once $php_report_file;
  545. $graph_function = "graph_${graph}";
  546. if ($conf['enable_pass_in_arguments_to_optional_graphs'] &&
  547. count($graph_arguments)) {
  548. $rrdtool_graph['arguments'] = $graph_arguments;
  549. // Pass by reference call, $rrdtool_graph modified inplace
  550. $graph_function($rrdtool_graph);
  551. unset($rrdtool_graph['arguments']);
  552. } else {
  553. $graph_function($rrdtool_graph);
  554. }
  555. }
  556. } else if ( is_file( $json_report_file ) ) {
  557. if ( dirname(realpath($json_report_file)) != $conf['graphdir'] ) {
  558. $rrdtool_graph[ 'series' ] = 'HRULE:1#FFCC33:"Check \$conf[graphdir] should not be relative path"';
  559. } else {
  560. $graph_config = json_decode( file_get_contents( $json_report_file ), TRUE );
  561. # We need to add hostname and clustername if it's not specified
  562. foreach ( $graph_config['series'] as $index => $item ) {
  563. if ( ! isset($graph_config['series'][$index]['hostname'])) {
  564. $graph_config['series'][$index]['hostname'] = $raw_host;
  565. if (isset($grid))
  566. $graph_config['series'][$index]['clustername'] = $grid;
  567. else
  568. $graph_config['series'][$index]['clustername'] = $clustername;
  569. }
  570. }
  571. build_rrdtool_args_from_json ( $rrdtool_graph, $graph_config );
  572. }
  573. }
  574. } else {
  575. build_rrdtool_args_from_json ( $rrdtool_graph, $graph_config );
  576. }
  577. // We must have a 'series' value, or this is all for naught
  578. if (!array_key_exists('series', $rrdtool_graph) ||
  579. !strlen($rrdtool_graph['series']) ) {
  580. $rrdtool_graph[ 'series' ] =
  581. 'HRULE:1#FFCC33:"Empty RRDtool command. Likely bad graph config"';
  582. }
  583. # Make small graphs (host list) cleaner by removing the too-big
  584. # legend: it is displayed above on larger cluster summary graphs.
  585. if (($size == "small" and ! isset($subtitle)) || ($graph_config["glegend"] == "hide"))
  586. $rrdtool_graph['extras'] = isset($rrdtool_graph['extras']) ? $rrdtool_graph['extras'] . " -g" : " -g" ;
  587. # add slope-mode if rrdtool_slope_mode is set
  588. if (isset($conf['rrdtool_slope_mode']) &&
  589. $conf['rrdtool_slope_mode'] == True)
  590. $rrdtool_graph['slope-mode'] = '';
  591. if (isset($rrdtool_graph['title']) && isset($title)) {
  592. if ($conf['decorated_graph_title'])
  593. $rrdtool_graph['title'] = $title . " " .
  594. $rrdtool_graph['title'] .
  595. " last $range";
  596. else
  597. $rrdtool_graph['title'] = $rrdtool_graph['title'];
  598. }
  599. $command = $conf['rrdtool'] . " graph - $rrd_options ";
  600. // Look ahead six months
  601. if ( $user['trend_line'] ) {
  602. // We may only want to use last x months of data since for example
  603. // if we are trending disk we may have added a disk recently which will
  604. // skew a trend line. By default we'll use 6 months however we'll let
  605. // user define this if they want to.
  606. $rrdtool_graph['start'] = "-" . $user['trend_history'] * 2592000 . "s";
  607. // Project the trend line this many months ahead
  608. $rrdtool_graph['end'] = "+" . $user["trend_range"] * 2592000 . "s";
  609. }
  610. if ( $max ) {
  611. $rrdtool_graph['upper-limit'] = $max;
  612. }
  613. if ( $min )
  614. $rrdtool_graph['lower-limit'] = $min;
  615. if ( isset($graph_config['percent']) && $graph_config['percent'] == '1' ) {
  616. $rrdtool_graph['upper-limit'] = 100;
  617. $rrdtool_graph['lower-limit'] = 0;
  618. }
  619. if ( $max || $min || ( isset($graph_config['percent']) && $graph_config['percent'] == '1' ) )
  620. $rrdtool_graph['extras'] = isset($rrdtool_graph['extras']) ? $rrdtool_graph['extras'] . " --rigid" : " --rigid" ;
  621. if ( isset($graph_config['graph_scale']) ) {
  622. // Log scale support
  623. if ( $graph_config['graph_scale'] == 'log' ) {
  624. $rrdtool_graph['extras'] = isset($rrdtool_graph['extras']) ? $rrdtool_graph['extras'] . " --logarithm --units=si" : " --logarithm --units=si" ;
  625. if (!isset($rrdtool_graph['lower-limit']) || $rrdtool_graph['lower-limit'] < 1) {
  626. // With log scale, the lower limit *has* to be 1 or greater.
  627. $rrdtool_graph['lower-limit'] = 1;
  628. }
  629. }
  630. }
  631. if ( $conf['rrdtool_base_1024'] and in_array($vlabel, array('bytes', 'Bytes', 'bytes/s', 'Bytes/s', 'kB', 'MB', 'GB', 'bits', 'Bits', 'bits/s', 'Bits/s')) ) {
  632. // Set graph base value to 1024
  633. $rrdtool_graph['extras'] = isset($rrdtool_graph['extras']) ? $rrdtool_graph['extras'] . " --base=1024" : " --base=1024" ;
  634. }
  635. // The order of the other arguments isn't important, except for the
  636. // 'extras' and 'series' values. These two require special handling.
  637. // Otherwise, we just loop over them later, and tack $extras and
  638. // $series onto the end of the command.
  639. foreach (array_keys ($rrdtool_graph) as $key) {
  640. if (preg_match('/extras|series/', $key))
  641. continue;
  642. $value = $rrdtool_graph[$key];
  643. if (preg_match('/\W/', $value)) {
  644. //more than alphanumerics in value, so quote it
  645. $value = "'$value'";
  646. }
  647. $command .= " --$key $value";
  648. }
  649. // And finish up with the two variables that need special handling.
  650. // See above for how these are created
  651. $command .= array_key_exists('extras', $rrdtool_graph) ? ' '.$rrdtool_graph['extras'].' ' : '';
  652. $command .= " $rrdtool_graph[series]";
  653. break;
  654. /////////////////////////////////////////////////////////////////////////////
  655. // USING Graphite
  656. /////////////////////////////////////////////////////////////////////////////
  657. case "graphite":
  658. // Check whether the link exists from Ganglia RRD tree to the graphite
  659. // storage/rrd_dir area
  660. if ( ! is_link($rrd_graphite_link) ) {
  661. // Does the directory exist for the cluster. If not create it
  662. if ( ! is_dir ($conf['graphite_rrd_dir'] . "/" . str_replace(" ", "_", $clustername)) )
  663. mkdir ( $conf['graphite_rrd_dir'] . "/" . str_replace(" ", "_", $clustername ));
  664. symlink($rrd_dir, str_replace(" ", "_", $rrd_graphite_link));
  665. }
  666. // Generate host cluster string
  667. if ( isset($clustername) ) {
  668. $host_cluster = str_replace(" ", "_", $clustername) . "." . $host;
  669. } else {
  670. $host_cluster = $host;
  671. }
  672. $height += 70;
  673. if ($size == "small") {
  674. $width += 20;
  675. }
  676. // $title = urlencode($rrdtool_graph["title"]);
  677. // If graph_config is already set we can use it immediately
  678. if ( isset($graph_config) ) {
  679. $target = build_graphite_series( $graph_config, "" );
  680. } else {
  681. if ( isset($_GET['g'])) {
  682. // if it's a report increase the height for additional 30 pixels
  683. $height += 40;
  684. $report_name = sanitize($_GET['g']);
  685. $report_definition_file = $conf['gweb_root'] . "/graph.d/" . $report_name . ".json";
  686. // Check whether report is defined in graph.d directory
  687. if ( is_file($report_definition_file) ) {
  688. $graph_config = json_decode(file_get_contents($report_definition_file), TRUE);
  689. } else {
  690. error_log("There is JSON config file specifying $report_name.");
  691. exit(1);
  692. }
  693. if ( isset($graph_config) ) {
  694. switch ( $graph_config["report_type"] ) {
  695. case "template":
  696. $target = str_replace("HOST_CLUSTER", $conf['graphite_prefix'] . $host_cluster, $graph_config["graphite"]);
  697. break;
  698. case "standard":
  699. $target = build_graphite_series( $graph_config, $conf['graphite_prefix'] . $host_cluster );
  700. break;
  701. default:
  702. error_log("No valid report_type specified in the " .
  703. $report_name .
  704. " definition.");
  705. break;
  706. }
  707. $title = $graph_config['title'];
  708. } else {
  709. error_log("Configuration file to $report_name exists however it doesn't appear it's a valid JSON file");
  710. exit(1);
  711. }
  712. } else {
  713. // It's a simple metric graph
  714. $target = "target=" . $conf['graphite_prefix'] . "$host_cluster.$metric_name.sum&hideLegend=true&vtitle=" . urlencode($vlabel) . "&areaMode=all&colorList=". $conf['default_metric_color'];
  715. $title = " ";
  716. }
  717. } // end of if ( ! isset($graph_config) ) {
  718. if ($cs) $start = date("H:i_Ymd",strtotime($cs));
  719. if ($ce) $end = date("H:i_Ymd",strtotime($ce));
  720. if ($max == 0) $max = "";
  721. $graphite_url = $conf['graphite_url_base'] . "?width=$width&height=$height&" . $target . "&from=" . $start . "&until=" . $end . "&yMin=" . $min . "&yMax=" . $max . "&bgcolor=FFFFFF&fgcolor=000000&title=" . urlencode($title . " last " . $range);
  722. break;
  723. } // end of switch ( $conf['graph_engine'])
  724. // Output to JSON
  725. if ( $user['json_output'] ||
  726. $user['csv_output'] ||
  727. $user['flot_output'] ||
  728. $user['graphlot_output'] ) {
  729. if ($conf['graph_engine'] == "graphite") {
  730. if ( $user['json_output'] == 1 ) { $output_format = "json"; }
  731. elseif ( $user['csv_output'] == 1 ) { $output_format = "csv"; }
  732. echo file_get_contents($graphite_url . "&format=" . $output_format);
  733. } else {
  734. $rrdtool_graph_args = "";
  735. // First find RRDtool DEFs by parsing $rrdtool_graph['series']
  736. preg_match_all("/([^V]DEF|CDEF):(.*)(:AVERAGE|\s)/",
  737. " " . $rrdtool_graph['series'],
  738. $matches);
  739. foreach ( $matches[0] as $key => $value ) {
  740. $rrdtool_graph_args .= $value . " ";
  741. }
  742. preg_match_all("/(LINE[0-9]*|AREA|STACK):\'[^']*\'[^']*\'[^']*\'[^ ]* /",
  743. " " . $rrdtool_graph['series'],
  744. $matches);
  745. foreach ( $matches[0] as $key => $value ) {
  746. if ( preg_match("/(LINE[0-9]*:\'|AREA:\'|STACK:\')([^']*)(\')([^']*)(\')([^']*)(')/", $value, $out ) ) {
  747. $ds_name = $out[2];
  748. $cluster_name = "";
  749. $host_name = "";
  750. $metric_type = "line";
  751. if (preg_match("/(STACK:|AREA:)/", $value, $ignore)) {
  752. $metric_type = "stack";
  753. }
  754. $metric_name = $out[6];
  755. $ds_attr = array( "ds_name" => $ds_name,
  756. "cluster_name" => $cluster_name,
  757. "graph_type" => $metric_type,
  758. "host_name" => $host_name,
  759. "metric_name" => $metric_name );
  760. // Add color if it exists
  761. $pos_hash = strpos($out[4], '#');
  762. if ($pos_hash !== FALSE) {
  763. $pos_colon = strpos($out[4], ':');
  764. if ($pos_colon !== FALSE)
  765. $ds_attr['color'] = substr($out[4],
  766. $pos_hash,
  767. $pos_colon - $pos_hash);
  768. else
  769. $ds_attr['color'] = substr($out[4], $pos_hash);
  770. }
  771. $output_array[] = $ds_attr;
  772. $rrdtool_graph_args .= " " . "XPORT:'" . $ds_name . "':'" . $metric_name . "' ";
  773. }
  774. }
  775. // This command will export values for the specified format in XML
  776. $command = $conf['rrdtool'] . " xport --start '" . $rrdtool_graph['start'] . "' --end '" . $rrdtool_graph['end'] . "' "
  777. // Allow a custom step, if it was specified by the user. Also, we need to
  778. // specify a --maxrows in case the number of rows with $user['step'] end up
  779. // being higher than rrdxport's default (in which case the step is changed
  780. // to fit inside the default --maxrows), but we also need to guard against
  781. // "underflow" because rrdxport craps out when --maxrows is less than 10.
  782. . ( $user['step'] ?
  783. " --step '" . $user['step'] . "' --maxrows '"
  784. . max( 10, round(($rrdtool_graph['end'] - $rrdtool_graph['start'])/$user['step']) ) . "' " :
  785. "" )
  786. . $rrd_options . " " . $rrdtool_graph_args;
  787. // Read in the XML
  788. $string = "";
  789. if (strlen($command) < 100000) {
  790. $fp = popen($command,"r");
  791. while (!feof($fp)) {
  792. $buffer = fgets($fp, 4096);
  793. $string .= $buffer;
  794. }
  795. } else {
  796. $tempfile = tempnam("/tmp", "ganglia-graph-json");
  797. file_put_contents($tempfile, $command);
  798. $tempstring = exec("/bin/bash $tempfile", $tempout);
  799. foreach( $tempout as $line ) {
  800. $string .= $line;
  801. }
  802. unlink($tempfile);
  803. }
  804. // Parse it
  805. $xml = simplexml_load_string($string);
  806. # If there are multiple metrics columns will be > 1
  807. $num_of_metrics = $xml->meta->columns;
  808. //
  809. $metric_values = array();
  810. // Build the metric_values array
  811. foreach ( $xml->data->row as $key => $objects ) {
  812. $values = get_object_vars($objects);
  813. // If $values["v"] is an array we have multiple data sources/metrics and
  814. // we need to iterate over those
  815. if ( is_array($values["v"]) ) {
  816. foreach ( $values["v"] as $key => $value ) {
  817. $output_array[$key]["datapoints"][] =
  818. array(build_value_for_json($value), intval($values['t']));
  819. }
  820. } else {
  821. $output_array[0]["datapoints"][] =
  822. array(build_value_for_json($values["v"]), intval($values['t']));
  823. }
  824. }
  825. // If JSON output request simple encode the array as JSON
  826. if ( $user['json_output'] ) {
  827. // First let's check if JSON output is requested for Live Dashboard and
  828. // we are outputting aggregate graph. If so we need to add up all the values
  829. if ( $user['live_dashboard'] && sizeof($output_array) > 1 ) {
  830. $summed_output = array();
  831. foreach ( $output_array[0]['datapoints'] as $index => $datapoint ) {
  832. // Data point is an array with value and UNIX time stamp. Initialize
  833. // summed output as 0
  834. $summed_output[$index] = array( 0, $datapoint[1] );
  835. for ( $i = 0 ; $i < sizeof($output_array) ; $i++ ) {
  836. $summed_output[$index][0] += $output_array[$i]['datapoints'][$index][0];
  837. }
  838. }
  839. unset($output_array);
  840. $output_array[0]['datapoints'] = $summed_output;
  841. }
  842. header("Content-type: application/json");
  843. header("Content-Disposition: inline; filename=\"ganglia-metrics.json\"");
  844. print json_encode($output_array);
  845. }
  846. // If Flot output massage the data JSON
  847. if ( $user['flot_output'] ) {
  848. foreach ( $output_array as $key => $metric_array ) {
  849. foreach ( $metric_array['datapoints'] as $key => $values ) {
  850. $data_array[] = array ($values[1]*1000, $values[0]);
  851. }
  852. $gdata = array('label' => strip_domainname($metric_array['host_name']) .
  853. " " .
  854. $metric_array['metric_name'],
  855. 'data' => $data_array);
  856. if (array_key_exists('color', $metric_array))
  857. $gdata['color'] = $metric_array['color'];
  858. if ($metric_array['graph_type'] == "stack")
  859. $gdata['stack'] = '1';
  860. $gdata['graph_title'] = $rrdtool_graph['title'];
  861. $flot_array[] = $gdata;
  862. unset($data_array);
  863. }
  864. header("Content-type: application/json");
  865. print json_encode($flot_array);
  866. }
  867. if ( $user['csv_output'] ) {
  868. header("Content-Type: application/csv");
  869. header("Content-Disposition: inline; filename=\"ganglia-metrics.csv\"");
  870. print "Timestamp";
  871. // Print out headers
  872. for ( $i = 0 ; $i < sizeof($output_array) ; $i++ ) {
  873. print "," . $output_array[$i]["metric_name"];
  874. }
  875. print "\n";
  876. foreach ( $output_array[0]['datapoints'] as $key => $row ) {
  877. print date("c", $row[1]);
  878. for ( $j = 0 ; $j < $num_of_metrics ; $j++ ) {
  879. print "," . $output_array[$j]["datapoints"][$key][0];
  880. }
  881. print "\n";
  882. }
  883. }
  884. // Implement Graphite style Raw Data
  885. if ( $user['graphlot_output'] ) {
  886. header("Content-Type: application/json");
  887. $last_index = sizeof($output_array[0]["datapoints"]) - 1;
  888. $output_vals['step'] = $output_array[0]["datapoints"][1][1] - $output_array[0]["datapoints"][0][1];
  889. $output_vals['name'] = "stats." . $output_array[0]["metric_name"];
  890. $output_vals['start'] = $output_array[0]["datapoints"][0][1];
  891. $output_vals['end'] = $output_array[0]["datapoints"][$last_index][1];
  892. foreach ( $output_array[0]["datapoints"] as $index => $array ) {
  893. $output_vals['data'][] = $array[0];
  894. }
  895. print json_encode(array($output_vals, $output_vals));
  896. }
  897. }
  898. exit(0);
  899. }
  900. //////////////////////////////////////////////////////////////////////////////
  901. // Nagios event integration support
  902. //////////////////////////////////////////////////////////////////////////////
  903. $nagios_events = array();
  904. if ( $showEvents == "show" &&
  905. $conf['overlay_nagios_events'] &&
  906. ! in_array($range, $conf['overlay_events_exclude_ranges']) ) {
  907. $nagios_pull_url =
  908. $conf['overlay_nagios_base_url'] .
  909. '/cgi-bin/api.cgi?action=host.gangliaevents&host=' . urlencode($raw_host) .
  910. '&start=' . urlencode($start) .
  911. '&end=' . urlencode($end);
  912. $raw_nagios_events =
  913. @file_get_contents(
  914. $nagios_pull_url,
  915. 0,
  916. stream_context_create(
  917. array('http' => array('timeout' => 5),
  918. 'https' => array('timeout' => 5))));
  919. if (strlen($raw_nagios_events) > 3) {
  920. $nagios_events = json_decode( $raw_nagios_events, TRUE );
  921. // Handle any "ERROR" formatted messages and wipe resulting array.
  922. if (isset($nagios_events['response_type']) &&
  923. $nagios_events['response_type'] == 'ERROR') {
  924. $nagios_events = array();
  925. }
  926. }
  927. }
  928. //////////////////////////////////////////////////////////////////////////////
  929. // Check whether user wants to overlay events on graphs
  930. //////////////////////////////////////////////////////////////////////////////
  931. if ( $showEvents == "show" &&
  932. $conf['overlay_events'] &&
  933. $conf['graph_engine'] == "rrdtool" &&
  934. ! in_array($range, $conf['overlay_events_exclude_ranges']) && ! $user['trend_line'] ) {
  935. $color_count = sizeof($conf['graph_colors']);
  936. $counter = 0;
  937. $color_counter = 0;
  938. // In order not to pollute the command line with all the possible VRULEs
  939. // we need to find the time range for the graph
  940. if ( $rrdtool_graph['end'] == "-now" or $rrdtool_graph['end'] == "now") {
  941. $end = time();
  942. } else if ( is_numeric($rrdtool_graph['end']) ) {
  943. $end = $rrdtool_graph['end'];
  944. }
  945. if ( preg_match("/\-([0-9]*)(s)/", $rrdtool_graph['start'] , $out ) ) {
  946. $start = time() - $out[1];
  947. } else if ( is_numeric($rrdtool_graph['start']) ) {
  948. $start = $rrdtool_graph['start'];
  949. } else {
  950. // If it's not
  951. $start = time() - 157680000;
  952. }
  953. // Get array of events for time range
  954. $events_array = ganglia_events_get($start, $end);
  955. if (!empty($events_array)) {
  956. $event_color_json =
  957. file_get_contents($conf['overlay_events_color_map_file']);
  958. if ($debug)
  959. error_log("$event_color_json");
  960. $event_color_array = json_decode($event_color_json, TRUE);
  961. $initial_event_color_count = count($event_color_array);
  962. $event_color_map = array();
  963. foreach ($event_color_array as $event_color_entry) {
  964. $event_color_map[$event_color_entry['summary']] =
  965. $event_color_entry['color'];
  966. if ($debug)
  967. error_log("Adding event color to map: " .
  968. $event_color_entry['summary'] .
  969. ' ' .
  970. $event_color_entry['color']);
  971. }
  972. $color_count = sizeof($conf['graph_colors']);
  973. $counter = 0;
  974. // In order not to pollute the command line with all the possible VRULEs
  975. // we need to find the time range for the graph
  976. if ( $rrdtool_graph['end'] == "-now" or $rrdtool_graph['end'] == "now")
  977. $end = time();
  978. else if ( is_numeric($rrdtool_graph['end']) )
  979. $end = $rrdtool_graph['end'];
  980. else
  981. error_log("Graph does not have a specified end time");
  982. if ( preg_match("/\-([0-9]*)(s)/", $rrdtool_graph['start'] , $out ) ) {
  983. $start = time() - $out[1];
  984. } else if ( is_numeric($rrdtool_graph['start']) )
  985. $start = $rrdtool_graph['start'];
  986. else
  987. // If it's not
  988. $start = time() - 157680000;
  989. // Preserve original rrdtool command. That's the one we'll run regex checks
  990. // against
  991. $original_command = $command;
  992. // Combine the nagios_events array, if it exists
  993. if (count($nagios_events) > 0) {
  994. // World's dumbest array merge:
  995. foreach ($nagios_events AS $ne) {
  996. $events_array[] = $ne;
  997. }
  998. }
  999. foreach ($events_array as $key => $row) {
  1000. $start_time[$key] = $row['start_time'];
  1001. }
  1002. // Sort events in reverse chronological order
  1003. array_multisort($start_time, SORT_DESC, $events_array);
  1004. // Default to dashed line unless events_line_type is set to solid
  1005. if ( $conf['overlay_events_line_type'] == "solid" )
  1006. $overlay_events_line_type = "";
  1007. else
  1008. $overlay_events_line_type = ":dashes";
  1009. // Loop through all the events
  1010. $legend_items = array();
  1011. foreach ( $events_array as $id => $event) {
  1012. $evt_start = $event['start_time'];
  1013. // Make sure it's a number
  1014. if ( ! is_numeric($evt_start) ) {
  1015. continue;
  1016. }
  1017. unset($evt_end);
  1018. if (array_key_exists('end_time', $event) &&
  1019. is_numeric($event['end_time']) ) {
  1020. $evt_end = $event['end_time'];
  1021. }
  1022. // If event start is less than start bail out of the loop since
  1023. // there is nothing more to do since events are sorted in reverse
  1024. // chronological order and these events are not gonna show up in
  1025. // the graph
  1026. $in_graph = (($evt_start >= $start) && ($evt_start <= $end)) ||
  1027. (isset($evt_end) &&
  1028. ($evt_end >= $start) &&
  1029. ($evt_start <= $end));
  1030. if (!$in_graph) {
  1031. if ($debug)
  1032. error_log("Event [$evt_start] does not overlap with graph [$start, $end]");
  1033. continue;
  1034. }
  1035. // Compute the part of the event to be displayed
  1036. $evt_start_in_graph_range = TRUE;
  1037. if ($evt_start < $start) {
  1038. $evt_start = $start;
  1039. $evt_start_in_graph_range = FALSE;
  1040. }
  1041. $evt_end_in_graph_range = TRUE;
  1042. if (isset($evt_end)) {
  1043. if ($evt_end > $end) {
  1044. $evt_end = $end;
  1045. $evt_end_in_graph_range = FALSE;
  1046. }
  1047. } else
  1048. $evt_end_in_graph_range = FALSE;
  1049. if ( preg_match("/" . $event["host_regex"] . "/", $original_command)) {
  1050. if ( $evt_start >= $start ) {
  1051. // Do we have the end timestamp.
  1052. if ( !isset($end) || ( $evt_start < $end ) || 'N' == $end ) {
  1053. // This is a potential vector since this gets added to the
  1054. // command line_width TODO: Look over sanitize
  1055. $summary =
  1056. isset($event['summary']) ? sanitize($event['summary']) : "";
  1057. // We need to keep track of summaries so that if we have identical
  1058. // summaries e.g. Deploy we can use the same color
  1059. if ( array_key_exists($summary, $event_color_map) ) {
  1060. $color = $event_color_map[$summary];
  1061. if ($debug)
  1062. error_log("Found existing color: $summary $color");
  1063. // Reset summary to empty string if it is already present in
  1064. // the legend
  1065. if (array_key_exists($summary, $legend_items))
  1066. $summary = "";
  1067. else
  1068. $legend_items[$summary] = TRUE;
  1069. } else {
  1070. // Haven't seen this summary before. Assign it a color
  1071. $color_index = count($event_color_map) % $color_count;
  1072. $color = $conf['graph_colors'][$color_index];
  1073. $event_color_map[$summary] = $color;
  1074. $event_color_array[] = array('summary' => $summary,
  1075. 'color' => $color);
  1076. if ($debug)
  1077. error_log("Adding new event color: $summary $color");
  1078. }
  1079. if (isset($evt_end)) {
  1080. # Attempt to draw a shaded area between start and end points.
  1081. # Force solid line for ranges
  1082. $overlay_events_line_type = "";
  1083. $start_vrule = '';
  1084. if ($evt_start_in_graph_range)
  1085. $start_vrule = " VRULE:" . $evt_start .
  1086. "#$color" . $conf['overlay_events_tick_alpha'] .
  1087. ":\"" . $summary . "\"" . $overlay_events_line_type;
  1088. $end_vrule = '';
  1089. if ($evt_end_in_graph_range)
  1090. $end_vrule = " VRULE:" . $evt_end .
  1091. "#$color" . $conf['overlay_events_tick_alpha'] .
  1092. ':""' . $overlay_events_line_type;
  1093. # We need a dummpy DEF statement, because RRDtool is too stupid
  1094. # to plot graphs without a DEF statement.
  1095. # We can't count on a static name, so we have to "find" one.
  1096. if (preg_match("/DEF:['\"]?(\w+)['\"]?=/", $command, $matches)) {
  1097. # stupid rrdtool limitation.
  1098. $area_cdef =
  1099. " CDEF:area_$counter=$matches[1],POP," .
  1100. "TIME,$evt_start,GT,1,UNKN,IF,TIME,$evt_end,LT,1,UNKN,IF,+";
  1101. $area_shade = $color . $conf['overlay_events_shade_alpha'];
  1102. $area = " TICK:area_$counter#$area_shade:1";
  1103. if (!$evt_start_in_graph_range)
  1104. $area .= ':"' . $summary . '"';
  1105. $command .= "$area_cdef $area $start_vrule $end_vrule";
  1106. } else {
  1107. error_log("No DEF statements found in \$command?!");
  1108. }
  1109. } else {
  1110. $command .= " VRULE:" . $evt_start . "#" . $color .
  1111. ":\"" . $summary . "\"" . $overlay_events_line_type;
  1112. }
  1113. $counter++;
  1114. } else {
  1115. if ($debug)
  1116. error_log("Event start [$evt_start] >= graph end [$end]");
  1117. }
  1118. } else {
  1119. if ($debug)
  1120. error_log("Event start [$evt_start] < graph start [$start]");
  1121. }
  1122. } // end of if ( preg_match ...
  1123. else {
  1124. //error_log("Doesn't match host_regex");
  1125. }
  1126. } // end of foreach ( $events_array ...
  1127. unset($events_array);
  1128. if (count($event_color_array) > $initial_event_color_count) {
  1129. $event_color_json = json_encode($event_color_array);
  1130. file_put_contents($conf['overlay_events_color_map_file'],
  1131. $event_color_json);
  1132. }
  1133. } //End check for array
  1134. }
  1135. ////////////////////////////////////////////////////////////////////////////////
  1136. // Add a trend line
  1137. ////////////////////////////////////////////////////////////////////////////////
  1138. if ( $user['trend_line'] ) {
  1139. $command .= " VDEF:D2=sum,LSLSLOPE VDEF:H2=sum,LSLINT CDEF:avg2=sum,POP,D2,COUNT,*,H2,+";
  1140. $command .= " 'LINE3…

Large files files are truncated, but you can click here to view the full file