1#
2# Monitorix - A lightweight system monitoring tool.
3#
4# Copyright (C) 2005-2017 by Jordi Sanfeliu <jordi@fibranet.cat>
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program; if not, write to the Free Software Foundation, Inc.,
18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19#
20
21package mysql;
22
23use strict;
24use warnings;
25use Monitorix;
26use RRDs;
27use DBI;
28use Exporter 'import';
29our @EXPORT = qw(mysql_init mysql_update mysql_cgi);
30
31sub mysql_init {
32	my $myself = (caller(0))[3];
33	my ($package, $config, $debug) = @_;
34	my $rrd = $config->{base_lib} . $package . ".rrd";
35	my $mysql = $config->{mysql};
36
37	my $info;
38	my @ds;
39	my @rra;
40	my @tmp;
41	my $n;
42
43	my @average;
44	my @min;
45	my @max;
46	my @last;
47
48	if(!grep {$_ eq lc($mysql->{conn_type})} ("host", "socket")) {
49		logger("$myself: ERROR: invalid value in 'conn_type' option.");
50		return;
51	}
52
53	if(-e $rrd) {
54		$info = RRDs::info($rrd);
55		for my $key (keys %$info) {
56			if(index($key, 'ds[') == 0) {
57				if(index($key, '.type') != -1) {
58					push(@ds, substr($key, 3, index($key, ']') - 3));
59				}
60			}
61			if(index($key, 'rra[') == 0) {
62				if(index($key, '.rows') != -1) {
63					push(@rra, substr($key, 4, index($key, ']') - 4));
64				}
65			}
66		}
67		if(scalar(@ds) / 38 != scalar(my @ml = split(',', $mysql->{list}))) {
68			logger("$myself: Detected size mismatch between 'list' (" . scalar(my @ml = split(',', $mysql->{list})) . ") and $rrd (" . scalar(@ds) / 38 . "). Resizing it accordingly. All historical data will be lost. Backup file created.");
69			rename($rrd, "$rrd.bak");
70		}
71		if(scalar(@rra) < 12 + (4 * $config->{max_historic_years})) {
72			logger("$myself: Detected size mismatch between 'max_historic_years' (" . $config->{max_historic_years} . ") and $rrd (" . ((scalar(@rra) -12) / 4) . "). Resizing it accordingly. All historical data will be lost. Backup file created.");
73			rename($rrd, "$rrd.bak");
74		}
75	}
76
77	if(!(-e $rrd)) {
78		logger("Creating '$rrd' file.");
79		for($n = 1; $n <= $config->{max_historic_years}; $n++) {
80			push(@average, "RRA:AVERAGE:0.5:1440:" . (365 * $n));
81			push(@min, "RRA:MIN:0.5:1440:" . (365 * $n));
82			push(@max, "RRA:MAX:0.5:1440:" . (365 * $n));
83			push(@last, "RRA:LAST:0.5:1440:" . (365 * $n));
84		}
85		for($n = 0; $n < scalar(my @ml = split(',', $mysql->{list})); $n++) {
86			push(@tmp, "DS:mysql" . $n . "_queries:GAUGE:120:0:U");
87			push(@tmp, "DS:mysql" . $n . "_sq:GAUGE:120:0:U");
88			push(@tmp, "DS:mysql" . $n . "_tchr:GAUGE:120:0:100");
89			push(@tmp, "DS:mysql" . $n . "_qcu:GAUGE:120:0:100");
90			push(@tmp, "DS:mysql" . $n . "_ot:GAUGE:120:0:U");
91			push(@tmp, "DS:mysql" . $n . "_conns_u:GAUGE:120:0:100");
92			push(@tmp, "DS:mysql" . $n . "_conns:GAUGE:120:0:U");
93			push(@tmp, "DS:mysql" . $n . "_tlw:GAUGE:120:0:U");
94			push(@tmp, "DS:mysql" . $n . "_kbu:GAUGE:120:0:100");
95			push(@tmp, "DS:mysql" . $n . "_innbu:GAUGE:120:0:100");
96			push(@tmp, "DS:mysql" . $n . "_csel:GAUGE:120:0:U");
97			push(@tmp, "DS:mysql" . $n . "_ccom:GAUGE:120:0:U");
98			push(@tmp, "DS:mysql" . $n . "_cdel:GAUGE:120:0:U");
99			push(@tmp, "DS:mysql" . $n . "_cins:GAUGE:120:0:U");
100			push(@tmp, "DS:mysql" . $n . "_cinss:GAUGE:120:0:U");
101			push(@tmp, "DS:mysql" . $n . "_cupd:GAUGE:120:0:U");
102			push(@tmp, "DS:mysql" . $n . "_crep:GAUGE:120:0:U");
103			push(@tmp, "DS:mysql" . $n . "_creps:GAUGE:120:0:U");
104			push(@tmp, "DS:mysql" . $n . "_crol:GAUGE:120:0:U");
105			push(@tmp, "DS:mysql" . $n . "_acli:GAUGE:120:0:U");
106			push(@tmp, "DS:mysql" . $n . "_acon:GAUGE:120:0:U");
107			push(@tmp, "DS:mysql" . $n . "_brecv:GAUGE:120:0:U");
108			push(@tmp, "DS:mysql" . $n . "_bsent:GAUGE:120:0:U");
109			push(@tmp, "DS:mysql" . $n . "_qchr:GAUGE:120:0:100");
110			push(@tmp, "DS:mysql" . $n . "_cstmtex:GAUGE:120:0:U");
111			push(@tmp, "DS:mysql" . $n . "_tttd:GAUGE:120:0:100");
112			push(@tmp, "DS:mysql" . $n . "_val04:GAUGE:120:0:U");
113			push(@tmp, "DS:mysql" . $n . "_val05:GAUGE:120:0:U");
114			push(@tmp, "DS:mysql" . $n . "_val06:GAUGE:120:0:U");
115			push(@tmp, "DS:mysql" . $n . "_val07:GAUGE:120:0:U");
116			push(@tmp, "DS:mysql" . $n . "_val08:GAUGE:120:0:U");
117			push(@tmp, "DS:mysql" . $n . "_val09:GAUGE:120:0:U");
118			push(@tmp, "DS:mysql" . $n . "_val10:GAUGE:120:0:U");
119			push(@tmp, "DS:mysql" . $n . "_val11:GAUGE:120:0:U");
120			push(@tmp, "DS:mysql" . $n . "_val12:GAUGE:120:0:U");
121			push(@tmp, "DS:mysql" . $n . "_val13:GAUGE:120:0:U");
122			push(@tmp, "DS:mysql" . $n . "_val14:GAUGE:120:0:U");
123			push(@tmp, "DS:mysql" . $n . "_val15:GAUGE:120:0:U");
124		}
125		eval {
126			RRDs::create($rrd,
127				"--step=60",
128				@tmp,
129				"RRA:AVERAGE:0.5:1:1440",
130				"RRA:AVERAGE:0.5:30:336",
131				"RRA:AVERAGE:0.5:60:744",
132				@average,
133				"RRA:MIN:0.5:1:1440",
134				"RRA:MIN:0.5:30:336",
135				"RRA:MIN:0.5:60:744",
136				@min,
137				"RRA:MAX:0.5:1:1440",
138				"RRA:MAX:0.5:30:336",
139				"RRA:MAX:0.5:60:744",
140				@max,
141				"RRA:LAST:0.5:1:1440",
142				"RRA:LAST:0.5:30:336",
143				"RRA:LAST:0.5:60:744",
144				@last,
145			);
146		};
147		my $err = RRDs::error;
148		if($@ || $err) {
149			logger("$@") unless !$@;
150			if($err) {
151				logger("ERROR: while creating $rrd: $err");
152				if($err eq "RRDs::error") {
153					logger("... is the RRDtool Perl package installed?");
154				}
155			}
156			return;
157		}
158	}
159
160	# Since 3.0.0 the new values are used (Query_cache_hit_rate, Com_stmt_execute)
161	for($n = 0; $n < scalar(my @ml = split(',', $mysql->{list})); $n++) {
162		RRDs::tune($rrd,
163			"--data-source-rename=mysql" . $n . "_val01:mysql" . $n . "_qchr",
164			"--data-source-rename=mysql" . $n . "_val02:mysql" . $n . "_cstmtex",
165			"--data-source-rename=mysql" . $n . "_val03:mysql" . $n . "_tttd",
166			"--maximum=mysql" . $n . "_qchr:100",
167			"--maximum=mysql" . $n . "_tttd:100",
168		);
169	}
170
171	$config->{mysql_hist} = ();
172	push(@{$config->{func_update}}, $package);
173	logger("$myself: Ok") if $debug;
174}
175
176sub mysql_update {
177	my $myself = (caller(0))[3];
178	my ($package, $config, $debug) = @_;
179	my $rrd = $config->{base_lib} . $package . ".rrd";
180	my $mysql = $config->{mysql};
181
182	my $str;
183	my $n = 0;
184	my $rrdata = "N";
185
186	my $print_error = 0;
187	$print_error = 1 if $debug;
188
189	for($n = 0; $n < scalar(my @ml = split(',', $mysql->{list})); $n++) {
190		$ml[$n] = trim($ml[$n]);
191		my $host = $ml[$n];
192		my $sock = $ml[$n];
193		my $port = trim((split(',', $mysql->{desc}->{$ml[$n]}))[0]);
194		my $user = trim((split(',', $mysql->{desc}->{$ml[$n]}))[1]);
195		my $pass = trim((split(',', $mysql->{desc}->{$ml[$n]}))[2]);
196		my $dbh;
197		if(lc($mysql->{conn_type}) eq "host") {
198			unless ($host && $port && $user && $pass) {
199				logger("$myself: ERROR: undefined configuration in 'host' connection.");
200				next;
201			}
202			$dbh = DBI->connect(
203				"DBI:mysql:host=$host;port=$port",
204				$user,
205				$pass,
206				{ PrintError => $print_error, }
207			) or logger("$myself: Cannot connect to MySQL '$host:$port'.") and next;
208		}
209		if(lc($mysql->{conn_type}) eq "socket") {
210			unless ($sock) {
211				logger("$myself: ERROR: undefined configuration in 'socket' connection");
212				next;
213			}
214			$dbh = DBI->connect(
215				"DBI:mysql:mysql_socket=$sock",
216				$user,
217				$pass,
218				{ PrintError => $print_error, }
219			) or logger("$myself: Cannot connect to MySQL '$sock'.") and next;
220		}
221
222		# SHOW GLOBAL STATUS
223		my $aborted_clients = 0;
224		my $aborted_connects = 0;
225		my $connections = 0;
226		my $connections_real = 0;
227		my $innodb_buffer_pool_pages_free = 0;
228		my $innodb_buffer_pool_pages_total = 0;
229		my $key_blocks_used = 0;
230		my $key_blocks_unused = 0;
231		my $max_used_connections = 0;
232		my $qcache_free_memory = 0;
233		my $qcache_hits = 0;
234		my $qcache_inserts = 0;
235		my $queries = 0;
236		my $opened_tables = 0;
237		my $slow_queries = 0;
238		my $table_locks_waited = 0;
239		my $threads_created = 0;
240		my $created_tmp_disk_tables = 0;
241		my $created_tmp_tables = 0;
242
243		my $bytes_received = 0;
244		my $bytes_sent = 0;
245		my $com_commit = 0;
246		my $com_delete = 0;
247		my $com_insert = 0;
248		my $com_insert_s = 0;
249		my $com_replace = 0;
250		my $com_replace_s = 0;
251		my $com_rollback = 0;
252		my $Com_select = 0;
253		my $com_select = 0;
254		my $com_update = 0;
255		my $com_stmtex = 0;
256		my $sql = "show global status";
257		my $sth = $dbh->prepare($sql);
258		$sth->execute;
259		while(my ($name, $value) = $sth->fetchrow_array) {
260			if($name eq "Aborted_clients") {
261				$str = $n . "aborted_clients";
262				$aborted_clients = $value - ($config->{mysql_hist}->{$str} || 0);
263				$aborted_clients = 0 unless $aborted_clients != $value;
264				$aborted_clients /= 60;
265				$config->{mysql_hist}->{$str} = $value;
266			}
267			if($name eq "Aborted_connects") {
268				$str = $n . "aborted_connects";
269				$aborted_connects = $value - ($config->{mysql_hist}->{$str} || 0);
270				$aborted_connects = 0 unless $aborted_connects != $value;
271				$aborted_connects /= 60;
272				$config->{mysql_hist}->{$str} = $value;
273			}
274			if($name eq "Connections") {
275				$str = $n . "connections";
276				$connections_real = int($value);
277				$connections = $value - ($config->{mysql_hist}->{$str} || 0);
278				$connections = 0 unless $connections != $value;
279				$connections /= 60;
280				$config->{mysql_hist}->{$str} = $value;
281			}
282			if($name eq "Innodb_buffer_pool_pages_free") {
283				$innodb_buffer_pool_pages_free = int($value);
284			}
285			if($name eq "Innodb_buffer_pool_pages_total") {
286				$innodb_buffer_pool_pages_total = int($value);
287			}
288			if($name eq "Key_blocks_unused") {
289				$key_blocks_unused = int($value);
290			}
291			if($name eq "Key_blocks_used") {
292				$key_blocks_used = int($value);
293			}
294			if($name eq "Max_used_connections") {
295				$max_used_connections = int($value);
296			}
297			if($name eq "Opened_tables") {
298				$str = $n . "opened_tables";
299				$opened_tables = $value - ($config->{mysql_hist}->{$str} || 0);
300				$opened_tables = 0 unless $opened_tables != $value;
301#				$opened_tables /= 60;
302				$config->{mysql_hist}->{$str} = $value;
303			}
304			if($name eq "Qcache_free_memory") {
305				$qcache_free_memory = int($value);
306			}
307			if($name eq "Qcache_hits") {
308				$qcache_hits = int($value);
309			}
310			if($name eq "Qcache_inserts") {
311				$qcache_inserts = int($value);
312			}
313			if($name eq "Queries") {
314				$str = $n . "queries";
315				$queries = $value - ($config->{mysql_hist}->{$str} || 0);
316				$queries = 0 unless $queries != $value;
317				$queries /= 60;
318				$config->{mysql_hist}->{$str} = $value;
319			}
320			if($name eq "Slow_queries") {
321				$str = $n . "slow_queries";
322				$slow_queries = $value - ($config->{mysql_hist}->{$str} || 0);
323				$slow_queries = 0 unless $slow_queries != $value;
324				$slow_queries /= 60;
325				$config->{mysql_hist}->{$str} = $value;
326			}
327			if($name eq "Table_locks_waited") {
328				$str = $n . "table_locks_waited";
329				$table_locks_waited = $value - ($config->{mysql_hist}->{$str} || 0);
330				$table_locks_waited = 0 unless $table_locks_waited != $value;
331#				$table_locks_waited /= 60;
332				$config->{mysql_hist}->{$str} = $value;
333			}
334			if($name eq "Threads_created") {
335				$threads_created = int($value);
336			}
337			if($name eq "Created_tmp_disk_tables") {
338				$created_tmp_disk_tables = int($value);
339			}
340			if($name eq "Created_tmp_tables") {
341				$created_tmp_tables = int($value);
342			}
343
344			if($name eq "Bytes_received") {
345				$str = $n . "bytes_received";
346				$bytes_received = $value - ($config->{mysql_hist}->{$str} || 0);
347				$bytes_received = 0 unless $bytes_received != $value;
348				$bytes_received /= 60;
349				$config->{mysql_hist}->{$str} = $value;
350			}
351			if($name eq "Bytes_sent") {
352				$str = $n . "bytes_sent";
353				$bytes_sent = $value - ($config->{mysql_hist}->{$str} || 0);
354				$bytes_sent = 0 unless $bytes_sent != $value;
355				$bytes_sent /= 60;
356				$config->{mysql_hist}->{$str} = $value;
357			}
358			if($name eq "Com_commit") {
359				$str = $n . "com_commit";
360				$com_commit = $value - ($config->{mysql_hist}->{$str} || 0);
361				$com_commit = 0 unless $com_commit != $value;
362				$com_commit /= 60;
363				$config->{mysql_hist}->{$str} = $value;
364			}
365			if($name eq "Com_delete") {
366				$str = $n . "com_delete";
367				$com_delete = $value - ($config->{mysql_hist}->{$str} || 0);
368				$com_delete = 0 unless $com_delete != $value;
369				$com_delete /= 60;
370				$config->{mysql_hist}->{$str} = $value;
371			}
372			if($name eq "Com_insert") {
373				$str = $n . "com_insert";
374				$com_insert = $value - ($config->{mysql_hist}->{$str} || 0);
375				$com_insert = 0 unless $com_insert != $value;
376				$com_insert /= 60;
377				$config->{mysql_hist}->{$str} = $value;
378			}
379			if($name eq "Com_insert_select") {
380				$str = $n . "com_insert_s";
381				$com_insert_s = $value - ($config->{mysql_hist}->{$str} || 0);
382				$com_insert_s = 0 unless $com_insert_s != $value;
383				$com_insert_s /= 60;
384				$config->{mysql_hist}->{$str} = $value;
385			}
386			if($name eq "Com_replace") {
387				$str = $n . "com_replace";
388				$com_replace = $value - ($config->{mysql_hist}->{$str} || 0);
389				$com_replace = 0 unless $com_replace != $value;
390				$com_replace /= 60;
391				$config->{mysql_hist}->{$str} = $value;
392			}
393			if($name eq "Com_replace_select") {
394				$str = $n . "com_replace_s";
395				$com_replace_s = $value - ($config->{mysql_hist}->{$str} || 0);
396				$com_replace_s = 0 unless $com_replace_s != $value;
397				$com_replace_s /= 60;
398				$config->{mysql_hist}->{$str} = $value;
399			}
400			if($name eq "Com_rollback") {
401				$str = $n . "com_rollback";
402				$com_rollback = $value - ($config->{mysql_hist}->{$str} || 0);
403				$com_rollback = 0 unless $com_rollback != $value;
404				$com_rollback /= 60;
405				$config->{mysql_hist}->{$str} = $value;
406			}
407			if($name eq "Com_select") {
408				$str = $n . "com_select";
409				$Com_select = $value;
410				$value += $qcache_hits;
411				$com_select = $value - ($config->{mysql_hist}->{$str} || 0);
412				$com_select = 0 unless $com_select != $value;
413				$com_select /= 60;
414				$config->{mysql_hist}->{$str} = $value;
415			}
416			if($name eq "Com_update") {
417				$str = $n . "com_update";
418				$com_update = $value - ($config->{mysql_hist}->{$str} || 0);
419				$com_update = 0 unless $com_update != $value;
420				$com_update /= 60;
421				$config->{mysql_hist}->{$str} = $value;
422			}
423			if($name eq "Com_stmt_execute") {
424				$str = $n . "com_stmtex";
425				$com_stmtex = $value - ($config->{mysql_hist}->{$str} || 0);
426				$com_stmtex = 0 unless $com_stmtex != $value;
427				$com_stmtex /= 60;
428				$config->{mysql_hist}->{$str} = $value;
429			}
430		}
431		$sth->finish;
432
433		# SHOW VARIABLES
434		my $query_cache_size = 0;
435		my $max_connections = 0;
436		$sql = "show variables";
437		$sth = $dbh->prepare($sql);
438		$sth->execute;
439		while(my ($name, $value) = $sth->fetchrow_array) {
440			if($name eq "max_connections") {
441				$max_connections = int($value);
442			}
443			if($name eq "query_cache_size") {
444				$query_cache_size = int($value);
445			}
446		}
447		$sth->finish;
448		$dbh->disconnect;
449
450		my $tcache_hit_rate = 0;
451		my $qcache_usage = 0;
452		my $connections_usage = 0;
453		my $key_buffer_usage = 0;
454		my $innodb_buffer_pool_usage = 0;
455		my $qcache_hit_rate = 0;
456		my $temp_tables_to_disk = 0;
457
458		$tcache_hit_rate = (1 - ($threads_created / $connections_real)) * 100
459			unless !$connections_real;
460		$qcache_usage = (1 - ($qcache_free_memory / $query_cache_size)) * 100
461			unless !$query_cache_size;
462		$connections_usage = ($max_used_connections / $max_connections) * 100
463			unless !$max_connections;
464		$key_buffer_usage = ($key_blocks_used / ($key_blocks_used + $key_blocks_unused)) * 100
465			unless !($key_blocks_used + $key_blocks_unused);
466		$innodb_buffer_pool_usage = (1 - ($innodb_buffer_pool_pages_free / $innodb_buffer_pool_pages_total)) * 100
467			unless !$innodb_buffer_pool_pages_total;
468
469		$connections_usage = $connections_usage > 100 ? 100 : $connections_usage;
470		if($qcache_hits + $Com_select == 0) {
471			$qcache_hit_rate = 0;
472		} else {
473			$qcache_hit_rate = $qcache_hits / ($qcache_hits + $Com_select) * 100;
474		}
475		$temp_tables_to_disk = $created_tmp_disk_tables / ($created_tmp_disk_tables + $created_tmp_tables) * 100;
476
477		$rrdata .= ":$queries:$slow_queries:$tcache_hit_rate:$qcache_usage:$opened_tables:$connections_usage:$connections:$table_locks_waited:$key_buffer_usage:$innodb_buffer_pool_usage:$com_select:$com_commit:$com_delete:$com_insert:$com_insert_s:$com_update:$com_replace:$com_replace_s:$com_rollback:$aborted_clients:$aborted_connects:$bytes_received:$bytes_sent:$qcache_hit_rate:$com_stmtex:$temp_tables_to_disk:0:0:0:0:0:0:0:0:0:0:0:0";
478	}
479
480	RRDs::update($rrd, $rrdata);
481	logger("$myself: $rrdata") if $debug;
482	my $err = RRDs::error;
483	logger("ERROR: while updating $rrd: $err") if $err;
484}
485
486sub mysql_cgi {
487	my ($package, $config, $cgi) = @_;
488	my @output;
489
490	my $mysql = $config->{mysql};
491	my @rigid = split(',', ($mysql->{rigid} || ""));
492	my @limit = split(',', ($mysql->{limit} || ""));
493	my $tf = $cgi->{tf};
494	my $colors = $cgi->{colors};
495	my $graph = $cgi->{graph};
496	my $silent = $cgi->{silent};
497	my $zoom = "--zoom=" . $config->{global_zoom};
498	my %rrd = (
499		'new' => \&RRDs::graphv,
500		'old' => \&RRDs::graph,
501	);
502	my $version = "new";
503	my $pic;
504	my $picz;
505	my $picz_width;
506	my $picz_height;
507
508	my $u = "";
509	my $width;
510	my $height;
511	my @riglim;
512	my @IMG;
513	my @IMGz;
514	my @tmp;
515	my @tmpz;
516	my @CDEF;
517	my $T = "B";
518	my $vlabel = "bytes/s";
519	my $e;
520	my $e2;
521	my $n;
522	my $n2;
523	my $err;
524
525	$version = "old" if $RRDs::VERSION < 1.3;
526	my $rrd = $config->{base_lib} . $package . ".rrd";
527	my $title = $config->{graph_title}->{$package};
528	my $IMG_DIR = $config->{base_dir} . "/" . $config->{imgs_dir};
529	my $imgfmt_uc = uc($config->{image_format});
530	my $imgfmt_lc = lc($config->{image_format});
531
532	$title = !$silent ? $title : "";
533
534	if(lc($config->{netstats_in_bps}) eq "y") {
535		$T = "b";
536		$vlabel = "bits/s";
537	}
538
539
540	# text mode
541	#
542	if(lc($config->{iface_mode}) eq "text") {
543		if($title) {
544			push(@output, main::graph_header($title, 2));
545			push(@output, "    <tr>\n");
546			push(@output, "    <td bgcolor='$colors->{title_bg_color}'>\n");
547		}
548		my (undef, undef, undef, $data) = RRDs::fetch("$rrd",
549			"--start=-$tf->{nwhen}$tf->{twhen}",
550			"AVERAGE",
551			"-r $tf->{res}");
552		$err = RRDs::error;
553		push(@output, "ERROR: while fetching $rrd: $err\n") if $err;
554		my $line1;
555		my $line2;
556		my $line3;
557		push(@output, "    <pre style='font-size: 12px; color: $colors->{fg_color}';>\n");
558		push(@output, "    ");
559		for($n = 0; $n < scalar(my @ml = split(',', $mysql->{list})); $n++) {
560			$line1 = "                                                                                                                                                                                                                          ";
561			$line2 .= "   Select  Commit  Delete  Insert  Insert_S  Update  Replace  Replace_S  Rollback  TCacheHit  QCache_U  Conns_U  KeyBuf_U  InnoDB_U  OpenedTbl  TLocks_W  Queries  SlowQrs  Conns  AbrtCli  AbrtConn  BytesRecv  BytesSent QCacheHitR StmtExec TmpTbToDsk";
562			$line3 .= "---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
563			if($line1) {
564				my $i = length($line1);
565				if(lc($mysql->{conn_type}) eq "host") {
566					push(@output, sprintf(sprintf("%${i}s", sprintf("%s:%s", $ml[$n], trim((split(',', $mysql->{desc}->{$ml[$n]}))[0])))));
567				}
568				if(lc($mysql->{conn_type}) eq "socket") {
569					push(@output, sprintf(sprintf("%${i}s", sprintf("socket: %s", $ml[$n]))));
570				}
571			}
572		}
573		push(@output, "\n");
574		push(@output, "Time$line2\n");
575		push(@output, "----$line3 \n");
576		my $line;
577		my @row;
578		my $time;
579		my $n2;
580		my $from;
581		my $to;
582		for($n = 0, $time = $tf->{tb}; $n < ($tf->{tb} * $tf->{ts}); $n++) {
583			$line = @$data[$n];
584			$time = $time - (1 / $tf->{ts});
585			push(@output, sprintf(" %2d$tf->{tc}", $time));
586			for($n2 = 0; $n2 < scalar(my @ml = split(',', $mysql->{list})); $n2++) {
587				undef(@row);
588				$from = $n2 * 38;
589				$to = $from + 38;
590				push(@row, @$line[$from..$to]);
591				push(@output, sprintf("   %6d  %6d  %6d  %6d  %8d  %6d  %7d   %8d  %8d        %2d%%       %2d%%      %2d%%       %2d%%       %2d%%     %6d    %6d   %6d   %6d %6d   %6d    %6d  %9d  %9d        %2d%%   %6d        %2d%%", @row));
592			}
593			push(@output, "\n");
594		}
595		push(@output, "    </pre>\n");
596		if($title) {
597			push(@output, "    </td>\n");
598			push(@output, "    </tr>\n");
599			push(@output, main::graph_footer());
600		}
601		push(@output, "  <br>\n");
602		return @output;
603	}
604
605
606	# graph mode
607	#
608	if($silent eq "yes" || $silent eq "imagetag") {
609		$colors->{fg_color} = "#000000";  # visible color for text mode
610		$u = "_";
611	}
612	if($silent eq "imagetagbig") {
613		$colors->{fg_color} = "#000000";  # visible color for text mode
614		$u = "";
615	}
616
617	for($n = 0; $n < scalar(my @ml = split(',', $mysql->{list})); $n++) {
618		for($n2 = 1; $n2 <= 6; $n2++) {
619			my $str = $u . $package . $n . $n2 . "." . $tf->{when} . ".$imgfmt_lc";
620			push(@IMG, $str);
621			unlink("$IMG_DIR" . $str);
622			if(lc($config->{enable_zoom}) eq "y") {
623				$str = $u . $package . $n . $n2 . "z." . $tf->{when} . ".$imgfmt_lc";
624				push(@IMGz, $str);
625				unlink("$IMG_DIR" . $str);
626			}
627		}
628	}
629
630	$e = 0;
631	foreach (my @ml = split(',', $mysql->{list})) {
632		my $uri;
633		if(lc($mysql->{conn_type}) eq "host") {
634	        	$uri = $_ . ":" . trim((split(',', $mysql->{desc}->{$_}))[0]);
635		}
636		if(lc($mysql->{conn_type}) eq "socket") {
637	        	$uri = "socket: " . $_;
638		}
639
640		if($e) {
641			push(@output, "  <br>\n");
642		}
643		if($title) {
644			push(@output, main::graph_header($title, 2));
645		}
646		@riglim = @{setup_riglim($rigid[0], $limit[0])};
647		if($title) {
648			push(@output, "    <tr>\n");
649			push(@output, "    <td valign='top' bgcolor='$colors->{title_bg_color}'>\n");
650		}
651		undef(@tmp);
652		undef(@tmpz);
653		undef(@CDEF);
654		push(@tmp, "LINE2:com_select#FFA500:Select");
655		push(@tmp, "GPRINT:com_select:LAST:         Cur\\: %6.1lf");
656		push(@tmp, "GPRINT:com_select:AVERAGE:    Avg\\: %6.1lf");
657		push(@tmp, "GPRINT:com_select:MIN:    Min\\: %6.1lf");
658		push(@tmp, "GPRINT:com_select:MAX:    Max\\: %6.1lf\\n");
659		push(@tmp, "LINE2:com_commit#EEEE44:Commit");
660		push(@tmp, "GPRINT:com_commit:LAST:         Cur\\: %6.1lf");
661		push(@tmp, "GPRINT:com_commit:AVERAGE:    Avg\\: %6.1lf");
662		push(@tmp, "GPRINT:com_commit:MIN:    Min\\: %6.1lf");
663		push(@tmp, "GPRINT:com_commit:MAX:    Max\\: %6.1lf\\n");
664		push(@tmp, "LINE2:com_delete#EE4444:Delete");
665		push(@tmp, "GPRINT:com_delete:LAST:         Cur\\: %6.1lf");
666		push(@tmp, "GPRINT:com_delete:AVERAGE:    Avg\\: %6.1lf");
667		push(@tmp, "GPRINT:com_delete:MIN:    Min\\: %6.1lf");
668		push(@tmp, "GPRINT:com_delete:MAX:    Max\\: %6.1lf\\n");
669		push(@tmp, "LINE2:com_insert#44EE44:Insert");
670		push(@tmp, "GPRINT:com_insert:LAST:         Cur\\: %6.1lf");
671		push(@tmp, "GPRINT:com_insert:AVERAGE:    Avg\\: %6.1lf");
672		push(@tmp, "GPRINT:com_insert:MIN:    Min\\: %6.1lf");
673		push(@tmp, "GPRINT:com_insert:MAX:    Max\\: %6.1lf\\n");
674		push(@tmp, "LINE2:com_insert_s#448844:Insert Select");
675		push(@tmp, "GPRINT:com_insert_s:LAST:  Cur\\: %6.1lf");
676		push(@tmp, "GPRINT:com_insert_s:AVERAGE:    Avg\\: %6.1lf");
677		push(@tmp, "GPRINT:com_insert_s:MIN:    Min\\: %6.1lf");
678		push(@tmp, "GPRINT:com_insert_s:MAX:    Max\\: %6.1lf\\n");
679		push(@tmp, "LINE2:com_update#EE44EE:Update");
680		push(@tmp, "GPRINT:com_update:LAST:         Cur\\: %6.1lf");
681		push(@tmp, "GPRINT:com_update:AVERAGE:    Avg\\: %6.1lf");
682		push(@tmp, "GPRINT:com_update:MIN:    Min\\: %6.1lf");
683		push(@tmp, "GPRINT:com_update:MAX:    Max\\: %6.1lf\\n");
684		push(@tmp, "LINE2:com_replace#44EEEE:Replace");
685		push(@tmp, "GPRINT:com_replace:LAST:        Cur\\: %6.1lf");
686		push(@tmp, "GPRINT:com_replace:AVERAGE:    Avg\\: %6.1lf");
687		push(@tmp, "GPRINT:com_replace:MIN:    Min\\: %6.1lf");
688		push(@tmp, "GPRINT:com_replace:MAX:    Max\\: %6.1lf\\n");
689		push(@tmp, "LINE2:com_replace_s#4444EE:Replace Select");
690		push(@tmp, "GPRINT:com_replace_s:LAST: Cur\\: %6.1lf");
691		push(@tmp, "GPRINT:com_replace_s:AVERAGE:    Avg\\: %6.1lf");
692		push(@tmp, "GPRINT:com_replace_s:MIN:    Min\\: %6.1lf");
693		push(@tmp, "GPRINT:com_replace_s:MAX:    Max\\: %6.1lf\\n");
694		push(@tmp, "LINE2:com_rollback#444444:Rollback");
695		push(@tmp, "GPRINT:com_rollback:LAST:       Cur\\: %6.1lf");
696		push(@tmp, "GPRINT:com_rollback:AVERAGE:    Avg\\: %6.1lf");
697		push(@tmp, "GPRINT:com_rollback:MIN:    Min\\: %6.1lf");
698		push(@tmp, "GPRINT:com_rollback:MAX:    Max\\: %6.1lf\\n");
699		push(@tmp, "LINE2:com_stmtex#888888:Prep.Stmt.Exec");
700		push(@tmp, "GPRINT:com_stmtex:LAST: Cur\\: %6.1lf");
701		push(@tmp, "GPRINT:com_stmtex:AVERAGE:    Avg\\: %6.1lf");
702		push(@tmp, "GPRINT:com_stmtex:MIN:    Min\\: %6.1lf");
703		push(@tmp, "GPRINT:com_stmtex:MAX:    Max\\: %6.1lf\\n");
704		push(@tmpz, "LINE2:com_select#FFA500:Select");
705		push(@tmpz, "LINE2:com_commit#EEEE44:Commit");
706		push(@tmpz, "LINE2:com_delete#EE4444:Delete");
707		push(@tmpz, "LINE2:com_insert#44EE44:Insert");
708		push(@tmpz, "LINE2:com_insert_s#448844:Insert Sel");
709		push(@tmpz, "LINE2:com_update#EE44EE:Update");
710		push(@tmpz, "LINE2:com_replace#44EEEE:Replace");
711		push(@tmpz, "LINE2:com_replace_s#4444EE:Replace Sel");
712		push(@tmpz, "LINE2:com_rollback#444444:Rollback");
713		push(@tmpz, "LINE2:com_stmtex#888888:Prep.Stmt.Exec");
714		if(lc($config->{show_gaps}) eq "y") {
715			push(@tmp, "AREA:wrongdata#$colors->{gap}:");
716			push(@tmpz, "AREA:wrongdata#$colors->{gap}:");
717			push(@CDEF, "CDEF:wrongdata=allvalues,UN,INF,UNKN,IF");
718		}
719		($width, $height) = split('x', $config->{graph_size}->{main});
720		if($silent =~ /imagetag/) {
721			($width, $height) = split('x', $config->{graph_size}->{remote}) if $silent eq "imagetag";
722			($width, $height) = split('x', $config->{graph_size}->{main}) if $silent eq "imagetagbig";
723			@tmp = @tmpz;
724			push(@tmp, "COMMENT: \\n");
725			push(@tmp, "COMMENT: \\n");
726		}
727		$pic = $rrd{$version}->("$IMG_DIR" . "$IMG[$e * 6]",
728			"--title=$config->{graphs}->{_mysql1}  ($tf->{nwhen}$tf->{twhen})",
729			"--start=-$tf->{nwhen}$tf->{twhen}",
730			"--imgformat=$imgfmt_uc",
731			"--vertical-label=Queries/s",
732			"--width=$width",
733			"--height=$height",
734			@riglim,
735			$zoom,
736			@{$cgi->{version12}},
737			@{$colors->{graph_colors}},
738			"DEF:com_select=$rrd:mysql" . $e . "_csel:AVERAGE",
739			"DEF:com_commit=$rrd:mysql" . $e . "_ccom:AVERAGE",
740			"DEF:com_delete=$rrd:mysql" . $e . "_cdel:AVERAGE",
741			"DEF:com_insert=$rrd:mysql" . $e . "_cins:AVERAGE",
742			"DEF:com_insert_s=$rrd:mysql" . $e . "_cinss:AVERAGE",
743			"DEF:com_update=$rrd:mysql" . $e . "_cupd:AVERAGE",
744			"DEF:com_replace=$rrd:mysql" . $e . "_crep:AVERAGE",
745			"DEF:com_replace_s=$rrd:mysql" . $e . "_creps:AVERAGE",
746			"DEF:com_rollback=$rrd:mysql" . $e . "_crol:AVERAGE",
747			"DEF:com_stmtex=$rrd:mysql" . $e . "_cstmtex:AVERAGE",
748			"CDEF:allvalues=com_select,com_commit,com_delete,com_insert,com_insert_s,com_update,com_replace,com_replace_s,com_rollback,com_stmtex,+,+,+,+,+,+,+,+,+",
749			@CDEF,
750			@tmp);
751		$err = RRDs::error;
752		push(@output, "ERROR: while graphing $IMG_DIR" . "$IMG[$e * 6]: $err\n") if $err;
753		if(lc($config->{enable_zoom}) eq "y") {
754			($width, $height) = split('x', $config->{graph_size}->{zoom});
755			$picz = $rrd{$version}->("$IMG_DIR" . "$IMGz[$e * 6]",
756				"--title=$config->{graphs}->{_mysql1}  ($tf->{nwhen}$tf->{twhen})",
757				"--start=-$tf->{nwhen}$tf->{twhen}",
758				"--imgformat=$imgfmt_uc",
759				"--vertical-label=Queries/s",
760				"--width=$width",
761				"--height=$height",
762				@riglim,
763				$zoom,
764				@{$cgi->{version12}},
765				@{$colors->{graph_colors}},
766				"DEF:com_select=$rrd:mysql" . $e . "_csel:AVERAGE",
767				"DEF:com_commit=$rrd:mysql" . $e . "_ccom:AVERAGE",
768				"DEF:com_delete=$rrd:mysql" . $e . "_cdel:AVERAGE",
769				"DEF:com_insert=$rrd:mysql" . $e . "_cins:AVERAGE",
770				"DEF:com_insert_s=$rrd:mysql" . $e . "_cinss:AVERAGE",
771				"DEF:com_update=$rrd:mysql" . $e . "_cupd:AVERAGE",
772				"DEF:com_replace=$rrd:mysql" . $e . "_crep:AVERAGE",
773				"DEF:com_replace_s=$rrd:mysql" . $e . "_creps:AVERAGE",
774				"DEF:com_rollback=$rrd:mysql" . $e . "_crol:AVERAGE",
775				"DEF:com_stmtex=$rrd:mysql" . $e . "_cstmtex:AVERAGE",
776				"CDEF:allvalues=com_select,com_commit,com_delete,com_insert,com_insert_s,com_update,com_replace,com_replace_s,com_rollback,com_stmtex,+,+,+,+,+,+,+,+,+",
777				@CDEF,
778				@tmpz);
779			$err = RRDs::error;
780			push(@output, "ERROR: while graphing $IMG_DIR" . "$IMGz[$e * 6]: $err\n") if $err;
781		}
782		$e2 = $e + 1;
783		if($title || ($silent =~ /imagetag/ && $graph =~ /mysql$e2/)) {
784			if(lc($config->{enable_zoom}) eq "y") {
785				if(lc($config->{disable_javascript_void}) eq "y") {
786					push(@output, "      <a href=\"" . $config->{url} . "/" . $config->{imgs_dir} . $IMGz[$e * 6] . "\"><img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6] . "' border='0'></a>\n");
787				} else {
788					if($version eq "new") {
789						$picz_width = $picz->{image_width} * $config->{global_zoom};
790						$picz_height = $picz->{image_height} * $config->{global_zoom};
791					} else {
792						$picz_width = $width + 115;
793						$picz_height = $height + 100;
794					}
795					push(@output, "      <a href=\"javascript:void(window.open('" . $config->{url} . "/" . $config->{imgs_dir} . $IMGz[$e * 6] . "','','width=" . $picz_width . ",height=" . $picz_height . ",scrollbars=0,resizable=0'))\"><img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6] . "' border='0'></a>\n");
796				}
797			} else {
798				push(@output, "      <img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6] . "'>\n");
799			}
800		}
801
802		@riglim = @{setup_riglim($rigid[1], $limit[1])};
803		undef(@tmp);
804		undef(@tmpz);
805		undef(@CDEF);
806		push(@tmp, "LINE2:tcache_hit_r#FFA500:Thread Cache Hit Rate");
807		push(@tmp, "GPRINT:tcache_hit_r:LAST:  Cur\\: %4.1lf%%");
808		push(@tmp, "GPRINT:tcache_hit_r:AVERAGE:  Avg\\: %4.1lf%%");
809		push(@tmp, "GPRINT:tcache_hit_r:MIN:  Min\\: %4.1lf%%");
810		push(@tmp, "GPRINT:tcache_hit_r:MAX:  Max\\: %4.1lf%%\\n");
811		push(@tmp, "LINE2:qcache_hitr#4444EE:Query Cache Hit Rate");
812		push(@tmp, "GPRINT:qcache_hitr:LAST:   Cur\\: %4.1lf%%");
813		push(@tmp, "GPRINT:qcache_hitr:AVERAGE:  Avg\\: %4.1lf%%");
814		push(@tmp, "GPRINT:qcache_hitr:MIN:  Min\\: %4.1lf%%");
815		push(@tmp, "GPRINT:qcache_hitr:MAX:  Max\\: %4.1lf%%\\n");
816		push(@tmp, "LINE2:qcache_usage#44EEEE:Query Cache Usage");
817		push(@tmp, "GPRINT:qcache_usage:LAST:      Cur\\: %4.1lf%%");
818		push(@tmp, "GPRINT:qcache_usage:AVERAGE:  Avg\\: %4.1lf%%");
819		push(@tmp, "GPRINT:qcache_usage:MIN:  Min\\: %4.1lf%%");
820		push(@tmp, "GPRINT:qcache_usage:MAX:  Max\\: %4.1lf%%\\n");
821		push(@tmp, "LINE2:conns_u#44EE44:Connections Usage");
822		push(@tmp, "GPRINT:conns_u:LAST:      Cur\\: %4.1lf%%");
823		push(@tmp, "GPRINT:conns_u:AVERAGE:  Avg\\: %4.1lf%%");
824		push(@tmp, "GPRINT:conns_u:MIN:  Min\\: %4.1lf%%");
825		push(@tmp, "GPRINT:conns_u:MAX:  Max\\: %4.1lf%%\\n");
826		push(@tmp, "LINE2:key_buf_u#EE4444:Key Buffer Usage");
827		push(@tmp, "GPRINT:key_buf_u:LAST:       Cur\\: %4.1lf%%");
828		push(@tmp, "GPRINT:key_buf_u:AVERAGE:  Avg\\: %4.1lf%%");
829		push(@tmp, "GPRINT:key_buf_u:MIN:  Min\\: %4.1lf%%");
830		push(@tmp, "GPRINT:key_buf_u:MAX:  Max\\: %4.1lf%%\\n");
831		push(@tmp, "LINE2:innodb_buf_u#EE44EE:InnoDB Buffer P. Usage");
832		push(@tmp, "GPRINT:innodb_buf_u:LAST: Cur\\: %4.1lf%%");
833		push(@tmp, "GPRINT:innodb_buf_u:AVERAGE:  Avg\\: %4.1lf%%");
834		push(@tmp, "GPRINT:innodb_buf_u:MIN:  Min\\: %4.1lf%%");
835		push(@tmp, "GPRINT:innodb_buf_u:MAX:  Max\\: %4.1lf%%\\n");
836		push(@tmp, "LINE2:tmptbltodsk#888888:Temp. Tables to Disk");
837		push(@tmp, "GPRINT:tmptbltodsk:LAST:   Cur\\: %4.1lf%%");
838		push(@tmp, "GPRINT:tmptbltodsk:AVERAGE:  Avg\\: %4.1lf%%");
839		push(@tmp, "GPRINT:tmptbltodsk:MIN:  Min\\: %4.1lf%%");
840		push(@tmp, "GPRINT:tmptbltodsk:MAX:  Max\\: %4.1lf%%\\n");
841		push(@tmpz, "LINE2:tcache_hit_r#FFA500:Thread Cache Hit Rate");
842		push(@tmpz, "LINE2:qcache_hitr#4444EE:Query Cache Hit Rate");
843		push(@tmpz, "LINE2:qcache_usage#44EEEE:Query Cache Usage");
844		push(@tmpz, "LINE2:conns_u#44EE44:Connections Usage");
845		push(@tmpz, "LINE2:key_buf_u#EE4444:Key Buffer Usage");
846		push(@tmpz, "LINE2:innodb_buf_u#EE44EE:Innodb Buffer P. Usage");
847		push(@tmpz, "LINE2:tmptbltodsk#888888:Temp. Tables to Disk");
848		if(lc($config->{show_gaps}) eq "y") {
849			push(@tmp, "AREA:wrongdata#$colors->{gap}:");
850			push(@tmpz, "AREA:wrongdata#$colors->{gap}:");
851			push(@CDEF, "CDEF:wrongdata=allvalues,UN,INF,UNKN,IF");
852		}
853		($width, $height) = split('x', $config->{graph_size}->{main});
854		if($silent =~ /imagetag/) {
855			($width, $height) = split('x', $config->{graph_size}->{remote}) if $silent eq "imagetag";
856			($width, $height) = split('x', $config->{graph_size}->{main}) if $silent eq "imagetagbig";
857			@tmp = @tmpz;
858			push(@tmp, "COMMENT: \\n");
859			push(@tmp, "COMMENT: \\n");
860		}
861		$pic = $rrd{$version}->("$IMG_DIR" . "$IMG[$e * 6 + 1]",
862			"--title=$config->{graphs}->{_mysql2}  ($tf->{nwhen}$tf->{twhen})",
863			"--start=-$tf->{nwhen}$tf->{twhen}",
864			"--imgformat=$imgfmt_uc",
865			"--vertical-label=Percent (%)",
866			"--width=$width",
867			"--height=$height",
868			@riglim,
869			$zoom,
870			@{$cgi->{version12}},
871			@{$colors->{graph_colors}},
872			"DEF:tcache_hit_r=$rrd:mysql" . $e . "_tchr:AVERAGE",
873			"DEF:qcache_hitr=$rrd:mysql" . $e . "_qchr:AVERAGE",
874			"DEF:qcache_usage=$rrd:mysql" . $e . "_qcu:AVERAGE",
875			"DEF:conns_u=$rrd:mysql" . $e . "_conns_u:AVERAGE",
876			"DEF:key_buf_u=$rrd:mysql" . $e . "_kbu:AVERAGE",
877			"DEF:innodb_buf_u=$rrd:mysql" . $e . "_innbu:AVERAGE",
878			"DEF:tmptbltodsk=$rrd:mysql" . $e . "_tttd:AVERAGE",
879			"CDEF:allvalues=tcache_hit_r,qcache_hitr,qcache_usage,conns_u,key_buf_u,innodb_buf_u,tmptbltodsk,+,+,+,+,+,+",
880			@CDEF,
881			@tmp);
882		$err = RRDs::error;
883		push(@output, "ERROR: while graphing $IMG_DIR" . "$IMG[$e * 6 + 1]: $err\n") if $err;
884		if(lc($config->{enable_zoom}) eq "y") {
885			($width, $height) = split('x', $config->{graph_size}->{zoom});
886			$picz = $rrd{$version}->("$IMG_DIR" . "$IMGz[$e * 6 + 1]",
887				"--title=$config->{graphs}->{_mysql2}  ($tf->{nwhen}$tf->{twhen})",
888				"--start=-$tf->{nwhen}$tf->{twhen}",
889				"--imgformat=$imgfmt_uc",
890				"--vertical-label=Percent (%)",
891				"--width=$width",
892				"--height=$height",
893				@riglim,
894				$zoom,
895				@{$cgi->{version12}},
896				@{$colors->{graph_colors}},
897				"DEF:tcache_hit_r=$rrd:mysql" . $e . "_tchr:AVERAGE",
898				"DEF:qcache_hitr=$rrd:mysql" . $e . "_qchr:AVERAGE",
899				"DEF:qcache_usage=$rrd:mysql" . $e . "_qcu:AVERAGE",
900				"DEF:conns_u=$rrd:mysql" . $e . "_conns_u:AVERAGE",
901				"DEF:key_buf_u=$rrd:mysql" . $e . "_kbu:AVERAGE",
902				"DEF:innodb_buf_u=$rrd:mysql" . $e . "_innbu:AVERAGE",
903				"DEF:tmptbltodsk=$rrd:mysql" . $e . "_tttd:AVERAGE",
904				"CDEF:allvalues=tcache_hit_r,qcache_hitr,qcache_usage,conns_u,key_buf_u,innodb_buf_u,tmptbltodsk,+,+,+,+,+,+",
905				@CDEF,
906				@tmpz);
907			$err = RRDs::error;
908			push(@output, "ERROR: while graphing $IMG_DIR" . "$IMGz[$e * 6 + 1]: $err\n") if $err;
909		}
910		$e2 = $e + 2;
911		if($title || ($silent =~ /imagetag/ && $graph =~ /mysql$e2/)) {
912			if(lc($config->{enable_zoom}) eq "y") {
913				if(lc($config->{disable_javascript_void}) eq "y") {
914					push(@output, "      <a href=\"" . $config->{url} . "/" . $config->{imgs_dir} . $IMGz[$e * 6 + 1] . "\"><img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 1] . "' border='0'></a>\n");
915				} else {
916					if($version eq "new") {
917						$picz_width = $picz->{image_width} * $config->{global_zoom};
918						$picz_height = $picz->{image_height} * $config->{global_zoom};
919					} else {
920						$picz_width = $width + 115;
921						$picz_height = $height + 100;
922					}
923					push(@output, "      <a href=\"javascript:void(window.open('" . $config->{url} . "/" . $config->{imgs_dir} . $IMGz[$e * 6 + 1] . "','','width=" . $picz_width . ",height=" . $picz_height . ",scrollbars=0,resizable=0'))\"><img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 1] . "' border='0'></a>\n");
924				}
925			} else {
926				push(@output, "      <img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 1] . "'>\n");
927			}
928		}
929
930		if($title) {
931			push(@output, "    </td>\n");
932			push(@output, "    <td valign='top' bgcolor='" . $colors->{title_bg_color} . "'>\n");
933		}
934		@riglim = @{setup_riglim($rigid[2], $limit[2])};
935		undef(@tmp);
936		undef(@tmpz);
937		undef(@CDEF);
938		push(@tmp, "AREA:opened_tbl#44EEEE:Opened Tables");
939		push(@tmp, "GPRINT:opened_tbl:LAST:        Current\\: %7.1lf\\n");
940		push(@tmp, "AREA:tlocks_w#4444EE:Table Locks Waited");
941		push(@tmp, "GPRINT:tlocks_w:LAST:   Current\\: %7.1lf\\n");
942		push(@tmp, "COMMENT: \\n");
943		push(@tmp, "LINE1:opened_tbl#00EEEE");
944		push(@tmp, "LINE1:tlocks_w#0000EE");
945		push(@tmpz, "AREA:opened_tbl#44EEEE:Opened Tables");
946		push(@tmpz, "AREA:tlocks_w#4444EE:Table Locks Waited");
947		push(@tmpz, "LINE1:opened_tbl#00EEEE");
948		push(@tmpz, "LINE1:tlocks_w#0000EE");
949		if(lc($config->{show_gaps}) eq "y") {
950			push(@tmp, "AREA:wrongdata#$colors->{gap}:");
951			push(@tmpz, "AREA:wrongdata#$colors->{gap}:");
952			push(@CDEF, "CDEF:wrongdata=allvalues,UN,INF,UNKN,IF");
953		}
954		($width, $height) = split('x', $config->{graph_size}->{small});
955		if($silent =~ /imagetag/) {
956			($width, $height) = split('x', $config->{graph_size}->{remote}) if $silent eq "imagetag";
957			($width, $height) = split('x', $config->{graph_size}->{main}) if $silent eq "imagetagbig";
958			@tmp = @tmpz;
959			push(@tmp, "COMMENT: \\n");
960			push(@tmp, "COMMENT: \\n");
961			push(@tmp, "COMMENT: \\n");
962		}
963		$pic = $rrd{$version}->("$IMG_DIR" . "$IMG[$e * 6 + 2]",
964			"--title=$config->{graphs}->{_mysql3}  ($tf->{nwhen}$tf->{twhen})",
965			"--start=-$tf->{nwhen}$tf->{twhen}",
966			"--imgformat=$imgfmt_uc",
967			"--vertical-label=Open & Locks/min",
968			"--width=$width",
969			"--height=$height",
970			@riglim,
971			$zoom,
972			@{$cgi->{version12}},
973			@{$cgi->{version12_small}},
974			@{$colors->{graph_colors}},
975			"DEF:opened_tbl=$rrd:mysql" . $e . "_ot:AVERAGE",
976			"DEF:tlocks_w=$rrd:mysql" . $e . "_tlw:AVERAGE",
977			"CDEF:allvalues=opened_tbl,tlocks_w,+",
978			@CDEF,
979			@tmp);
980		$err = RRDs::error;
981		push(@output, "ERROR: while graphing $IMG_DIR" . "$IMG[$e * 6 + 2]: $err\n") if $err;
982		if(lc($config->{enable_zoom}) eq "y") {
983			($width, $height) = split('x', $config->{graph_size}->{zoom});
984			$picz = $rrd{$version}->("$IMG_DIR" . "$IMGz[$e * 6 + 2]",
985				"--title=$config->{graphs}->{_mysql3}  ($tf->{nwhen}$tf->{twhen})",
986				"--start=-$tf->{nwhen}$tf->{twhen}",
987				"--imgformat=$imgfmt_uc",
988				"--vertical-label=Open & Locks/min",
989				"--width=$width",
990				"--height=$height",
991				@riglim,
992				$zoom,
993				@{$cgi->{version12}},
994				@{$cgi->{version12_small}},
995				@{$colors->{graph_colors}},
996				"DEF:opened_tbl=$rrd:mysql" . $e . "_ot:AVERAGE",
997				"DEF:tlocks_w=$rrd:mysql" . $e . "_tlw:AVERAGE",
998				"CDEF:allvalues=opened_tbl,tlocks_w,+",
999				@CDEF,
1000				@tmpz);
1001			$err = RRDs::error;
1002			push(@output, "ERROR: while graphing $IMG_DIR" . "$IMGz[$e * 6 + 2]: $err\n") if $err;
1003		}
1004		$e2 = $e + 3;
1005		if($title || ($silent =~ /imagetag/ && $graph =~ /mysql$e2/)) {
1006			if(lc($config->{enable_zoom}) eq "y") {
1007				if(lc($config->{disable_javascript_void}) eq "y") {
1008					push(@output, "      <a href=\"" . $config->{url} . "/" . $config->{imgs_dir} . $IMGz[$e * 6 + 2] . "\"><img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 2] . "' border='0'></a>\n");
1009				} else {
1010					if($version eq "new") {
1011						$picz_width = $picz->{image_width} * $config->{global_zoom};
1012						$picz_height = $picz->{image_height} * $config->{global_zoom};
1013					} else {
1014						$picz_width = $width + 115;
1015						$picz_height = $height + 100;
1016					}
1017					push(@output, "      <a href=\"javascript:void(window.open('" . $config->{url} . "/" . $config->{imgs_dir} . $IMGz[$e * 6 + 2] . "','','width=" . $picz_width . ",height=" . $picz_height . ",scrollbars=0,resizable=0'))\"><img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 2] . "' border='0'></a>\n");
1018				}
1019			} else {
1020				push(@output, "      <img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 2] . "'>\n");
1021			}
1022		}
1023
1024		@riglim = @{setup_riglim($rigid[3], $limit[3])};
1025		undef(@tmp);
1026		undef(@tmpz);
1027		undef(@CDEF);
1028		push(@tmp, "AREA:qrs#44EEEE:Queries");
1029		push(@tmp, "GPRINT:qrs:LAST:              Current\\: %7.1lf\\n");
1030		push(@tmp, "AREA:sqrs#4444EE:Slow Queries");
1031		push(@tmp, "GPRINT:sqrs:LAST:         Current\\: %7.1lf\\n");
1032		push(@tmp, "LINE1:qrs#00EEEE");
1033		push(@tmp, "LINE1:sqrs#0000EE");
1034		push(@tmp, "COMMENT: \\n");
1035		push(@tmpz, "AREA:qrs#44EEEE:Queries");
1036		push(@tmpz, "AREA:sqrs#4444EE:Slow Queries");
1037		push(@tmpz, "LINE1:qrs#00EEEE");
1038		push(@tmpz, "LINE1:sqrs#0000EE");
1039		if(lc($config->{show_gaps}) eq "y") {
1040			push(@tmp, "AREA:wrongdata#$colors->{gap}:");
1041			push(@tmpz, "AREA:wrongdata#$colors->{gap}:");
1042			push(@CDEF, "CDEF:wrongdata=allvalues,UN,INF,UNKN,IF");
1043		}
1044		($width, $height) = split('x', $config->{graph_size}->{small});
1045		if($silent =~ /imagetag/) {
1046			($width, $height) = split('x', $config->{graph_size}->{remote}) if $silent eq "imagetag";
1047			($width, $height) = split('x', $config->{graph_size}->{main}) if $silent eq "imagetagbig";
1048			@tmp = @tmpz;
1049			push(@tmp, "COMMENT: \\n");
1050			push(@tmp, "COMMENT: \\n");
1051			push(@tmp, "COMMENT: \\n");
1052		}
1053		$pic = $rrd{$version}->("$IMG_DIR" . "$IMG[$e * 6 + 3]",
1054			"--title=$config->{graphs}->{_mysql4}  ($tf->{nwhen}$tf->{twhen})",
1055			"--start=-$tf->{nwhen}$tf->{twhen}",
1056			"--imgformat=$imgfmt_uc",
1057			"--vertical-label=Queries/s",
1058			"--width=$width",
1059			"--height=$height",
1060			@riglim,
1061			$zoom,
1062			@{$cgi->{version12}},
1063			@{$cgi->{version12_small}},
1064			@{$colors->{graph_colors}},
1065			"DEF:qrs=$rrd:mysql" . $e . "_queries:AVERAGE",
1066			"DEF:sqrs=$rrd:mysql" . $e . "_sq:AVERAGE",
1067			"CDEF:allvalues=qrs,sqrs,+",
1068			@CDEF,
1069			@tmp);
1070		$err = RRDs::error;
1071		push(@output, "ERROR: while graphing $IMG_DIR" . "$IMG[$e * 6 + 3]: $err\n") if $err;
1072		if(lc($config->{enable_zoom}) eq "y") {
1073			($width, $height) = split('x', $config->{graph_size}->{zoom});
1074			$picz = $rrd{$version}->("$IMG_DIR" . "$IMGz[$e * 6 + 3]",
1075				"--title=$config->{graphs}->{_mysql4}  ($tf->{nwhen}$tf->{twhen})",
1076				"--start=-$tf->{nwhen}$tf->{twhen}",
1077				"--imgformat=$imgfmt_uc",
1078				"--vertical-label=Queries/s",
1079				"--width=$width",
1080				"--height=$height",
1081				@riglim,
1082				$zoom,
1083				@{$cgi->{version12}},
1084				@{$cgi->{version12_small}},
1085				@{$colors->{graph_colors}},
1086				"DEF:qrs=$rrd:mysql" . $e . "_queries:AVERAGE",
1087				"DEF:sqrs=$rrd:mysql" . $e . "_sq:AVERAGE",
1088				"CDEF:allvalues=qrs,sqrs,+",
1089				@CDEF,
1090				@tmpz);
1091			$err = RRDs::error;
1092			push(@output, "ERROR: while graphing $IMG_DIR" . "$IMGz[$e * 6 + 3]: $err\n") if $err;
1093		}
1094		$e2 = $e + 4;
1095		if($title || ($silent =~ /imagetag/ && $graph =~ /mysql$e2/)) {
1096			if(lc($config->{enable_zoom}) eq "y") {
1097				if(lc($config->{disable_javascript_void}) eq "y") {
1098					push(@output, "      <a href=\"" . $config->{url} . "/" . $config->{imgs_dir} . $IMGz[$e * 6 + 3] . "\"><img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 3] . "' border='0'></a>\n");
1099				} else {
1100					if($version eq "new") {
1101						$picz_width = $picz->{image_width} * $config->{global_zoom};
1102						$picz_height = $picz->{image_height} * $config->{global_zoom};
1103					} else {
1104						$picz_width = $width + 115;
1105						$picz_height = $height + 100;
1106					}
1107					push(@output, "      <a href=\"javascript:void(window.open('" . $config->{url} . "/" . $config->{imgs_dir} . $IMGz[$e * 6 + 3] . "','','width=" . $picz_width . ",height=" . $picz_height . ",scrollbars=0,resizable=0'))\"><img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 3] . "' border='0'></a>\n");
1108				}
1109			} else {
1110				push(@output, "      <img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 3] . "'>\n");
1111			}
1112		}
1113
1114		@riglim = @{setup_riglim($rigid[4], $limit[4])};
1115		undef(@tmp);
1116		undef(@tmpz);
1117		undef(@CDEF);
1118		push(@tmp, "AREA:conns#44EEEE:Connections");
1119		push(@tmp, "GPRINT:conns:LAST:          Current\\: %7.1lf\\n");
1120		push(@tmp, "AREA:acli#EEEE44:Aborted Clients");
1121		push(@tmp, "GPRINT:acli:LAST:      Current\\: %7.1lf\\n");
1122		push(@tmp, "AREA:acon#EE4444:Aborted Connects");
1123		push(@tmp, "GPRINT:acon:LAST:     Current\\: %7.1lf\\n");
1124		push(@tmp, "LINE1:conns#00EEEE");
1125		push(@tmp, "LINE1:acli#EEEE00");
1126		push(@tmp, "LINE1:acon#EE0000");
1127		push(@tmp, "COMMENT: \\n");
1128		push(@tmpz, "AREA:conns#44EEEE:Connections");
1129		push(@tmpz, "AREA:acli#EEEE44:Aborted Clients");
1130		push(@tmpz, "AREA:acon#EE4444:Aborted Connects");
1131		push(@tmpz, "LINE1:conns#00EEEE");
1132		push(@tmpz, "LINE1:acli#EEEE00");
1133		push(@tmpz, "LINE1:acon#EE0000");
1134		if(lc($config->{show_gaps}) eq "y") {
1135			push(@tmp, "AREA:wrongdata#$colors->{gap}:");
1136			push(@tmpz, "AREA:wrongdata#$colors->{gap}:");
1137			push(@CDEF, "CDEF:wrongdata=allvalues,UN,INF,UNKN,IF");
1138		}
1139		($width, $height) = split('x', $config->{graph_size}->{small});
1140		if($silent =~ /imagetag/) {
1141			($width, $height) = split('x', $config->{graph_size}->{remote}) if $silent eq "imagetag";
1142			($width, $height) = split('x', $config->{graph_size}->{main}) if $silent eq "imagetagbig";
1143			@tmp = @tmpz;
1144			push(@tmp, "COMMENT: \\n");
1145			push(@tmp, "COMMENT: \\n");
1146			push(@tmp, "COMMENT: \\n");
1147		}
1148		$pic = $rrd{$version}->("$IMG_DIR" . "$IMG[$e * 6 + 4]",
1149			"--title=$config->{graphs}->{_mysql5}  ($tf->{nwhen}$tf->{twhen})",
1150			"--start=-$tf->{nwhen}$tf->{twhen}",
1151			"--imgformat=$imgfmt_uc",
1152			"--vertical-label=Connectionss/s",
1153			"--width=$width",
1154			"--height=$height",
1155			@riglim,
1156			$zoom,
1157			@{$cgi->{version12}},
1158			@{$cgi->{version12_small}},
1159			@{$colors->{graph_colors}},
1160			"DEF:conns=$rrd:mysql" . $e . "_conns:AVERAGE",
1161			"DEF:acli=$rrd:mysql" . $e . "_acli:AVERAGE",
1162			"DEF:acon=$rrd:mysql" . $e . "_acon:AVERAGE",
1163			"CDEF:allvalues=conns,acli,acon,+,+",
1164			@CDEF,
1165			@tmp);
1166		$err = RRDs::error;
1167		push(@output, "ERROR: while graphing $IMG_DIR" . "$IMG[$e * 6 + 4]: $err\n") if $err;
1168		if(lc($config->{enable_zoom}) eq "y") {
1169			($width, $height) = split('x', $config->{graph_size}->{zoom});
1170			$picz = $rrd{$version}->("$IMG_DIR" . "$IMGz[$e * 6 + 4]",
1171				"--title=$config->{graphs}->{_mysql5}  ($tf->{nwhen}$tf->{twhen})",
1172				"--start=-$tf->{nwhen}$tf->{twhen}",
1173				"--imgformat=$imgfmt_uc",
1174				"--vertical-label=Connectionss/s",
1175				"--width=$width",
1176				"--height=$height",
1177				@riglim,
1178				$zoom,
1179				@{$cgi->{version12}},
1180				@{$cgi->{version12_small}},
1181				@{$colors->{graph_colors}},
1182				"DEF:conns=$rrd:mysql" . $e . "_conns:AVERAGE",
1183				"DEF:acli=$rrd:mysql" . $e . "_acli:AVERAGE",
1184				"DEF:acon=$rrd:mysql" . $e . "_acon:AVERAGE",
1185				"CDEF:allvalues=conns,acli,acon,+,+",
1186				@CDEF,
1187				@tmpz);
1188			$err = RRDs::error;
1189			push(@output, "ERROR: while graphing $IMG_DIR" . "$IMGz[$e * 6 + 4]: $err\n") if $err;
1190		}
1191		$e2 = $e + 5;
1192		if($title || ($silent =~ /imagetag/ && $graph =~ /mysql$e2/)) {
1193			if(lc($config->{enable_zoom}) eq "y") {
1194				if(lc($config->{disable_javascript_void}) eq "y") {
1195					push(@output, "      <a href=\"" . $config->{url} . "/" . $config->{imgs_dir} . $IMGz[$e * 6 + 4] . "\"><img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 4] . "' border='0'></a>\n");
1196				} else {
1197					if($version eq "new") {
1198						$picz_width = $picz->{image_width} * $config->{global_zoom};
1199						$picz_height = $picz->{image_height} * $config->{global_zoom};
1200					} else {
1201						$picz_width = $width + 115;
1202						$picz_height = $height + 100;
1203					}
1204					push(@output, "      <a href=\"javascript:void(window.open('" . $config->{url} . "/" . $config->{imgs_dir} . $IMGz[$e * 6 + 4] . "','','width=" . $picz_width . ",height=" . $picz_height . ",scrollbars=0,resizable=0'))\"><img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 4] . "' border='0'></a>\n");
1205				}
1206			} else {
1207				push(@output, "      <img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 4] . "'>\n");
1208			}
1209		}
1210
1211		@riglim = @{setup_riglim($rigid[5], $limit[5])};
1212		undef(@tmp);
1213		undef(@tmpz);
1214		undef(@CDEF);
1215		push(@tmp, "AREA:B_in#44EE44:Input");
1216		push(@tmp, "AREA:B_out#4444EE:Output");
1217		push(@tmp, "AREA:B_out#4444EE:");
1218		push(@tmp, "AREA:B_in#44EE44:");
1219		push(@tmp, "LINE1:B_out#0000EE");
1220		push(@tmp, "LINE1:B_in#00EE00");
1221		push(@tmpz, "AREA:B_in#44EE44:Input");
1222		push(@tmpz, "AREA:B_out#4444EE:Output");
1223		push(@tmpz, "AREA:B_out#4444EE:");
1224		push(@tmpz, "AREA:B_in#44EE44:");
1225		push(@tmpz, "LINE1:B_out#0000EE");
1226		push(@tmpz, "LINE1:B_in#00EE00");
1227		if(lc($config->{netstats_in_bps}) eq "y") {
1228			push(@CDEF, "CDEF:B_in=in,8,*");
1229			push(@CDEF, "CDEF:B_out=out,8,*");
1230		} else {
1231			push(@CDEF, "CDEF:B_in=in");
1232			push(@CDEF, "CDEF:B_out=out");
1233		}
1234		if(lc($config->{show_gaps}) eq "y") {
1235			push(@tmp, "AREA:wrongdata#$colors->{gap}:");
1236			push(@tmpz, "AREA:wrongdata#$colors->{gap}:");
1237			push(@CDEF, "CDEF:wrongdata=allvalues,UN,INF,UNKN,IF");
1238		}
1239		($width, $height) = split('x', $config->{graph_size}->{small});
1240		if($silent =~ /imagetag/) {
1241			($width, $height) = split('x', $config->{graph_size}->{remote}) if $silent eq "imagetag";
1242			($width, $height) = split('x', $config->{graph_size}->{main}) if $silent eq "imagetagbig";
1243			@tmp = @tmpz;
1244			push(@tmp, "COMMENT: \\n");
1245			push(@tmp, "COMMENT: \\n");
1246			push(@tmp, "COMMENT: \\n");
1247		}
1248		$pic = $rrd{$version}->("$IMG_DIR" . "$IMG[$e * 6 + 5]",
1249			"--title=$config->{graphs}->{_mysql6}  ($tf->{nwhen}$tf->{twhen})",
1250			"--start=-$tf->{nwhen}$tf->{twhen}",
1251			"--imgformat=$imgfmt_uc",
1252			"--vertical-label=$vlabel",
1253			"--width=$width",
1254			"--height=$height",
1255			@riglim,
1256			$zoom,
1257			@{$cgi->{version12}},
1258			@{$cgi->{version12_small}},
1259			@{$colors->{graph_colors}},
1260			"DEF:in=$rrd:mysql" . $e . "_brecv:AVERAGE",
1261			"DEF:out=$rrd:mysql" . $e . "_bsent:AVERAGE",
1262			"CDEF:allvalues=in,out,+",
1263			@CDEF,
1264			@tmp);
1265		$err = RRDs::error;
1266		push(@output, "ERROR: while graphing $IMG_DIR" . "$IMG[$e * 6 + 5]: $err\n") if $err;
1267		if(lc($config->{enable_zoom}) eq "y") {
1268			($width, $height) = split('x', $config->{graph_size}->{zoom});
1269			$picz = $rrd{$version}->("$IMG_DIR" . "$IMGz[$e * 6 + 5]",
1270				"--title=$config->{graphs}->{_mysql6}  ($tf->{nwhen}$tf->{twhen})",
1271				"--start=-$tf->{nwhen}$tf->{twhen}",
1272				"--imgformat=$imgfmt_uc",
1273				"--vertical-label=$vlabel",
1274				"--width=$width",
1275				"--height=$height",
1276				@riglim,
1277				$zoom,
1278				@{$cgi->{version12}},
1279				@{$cgi->{version12_small}},
1280				@{$colors->{graph_colors}},
1281				"DEF:in=$rrd:mysql" . $e . "_brecv:AVERAGE",
1282				"DEF:out=$rrd:mysql" . $e . "_bsent:AVERAGE",
1283				"CDEF:allvalues=in,out,+",
1284				@CDEF,
1285				@tmpz);
1286			$err = RRDs::error;
1287			push(@output, "ERROR: while graphing $IMG_DIR" . "$IMGz[$e * 6 + 5]: $err\n") if $err;
1288		}
1289		$e2 = $e + 6;
1290		if($title || ($silent =~ /imagetag/ && $graph =~ /mysql$e2/)) {
1291			if(lc($config->{enable_zoom}) eq "y") {
1292				if(lc($config->{disable_javascript_void}) eq "y") {
1293					push(@output, "      <a href=\"" . $config->{url} . "/" . $config->{imgs_dir} . $IMGz[$e * 6 + 5] . "\"><img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 5] . "' border='0'></a>\n");
1294				} else {
1295					if($version eq "new") {
1296						$picz_width = $picz->{image_width} * $config->{global_zoom};
1297						$picz_height = $picz->{image_height} * $config->{global_zoom};
1298					} else {
1299						$picz_width = $width + 115;
1300						$picz_height = $height + 100;
1301					}
1302					push(@output, "      <a href=\"javascript:void(window.open('" . $config->{url} . "/" . $config->{imgs_dir} . $IMGz[$e * 6 + 5] . "','','width=" . $picz_width . ",height=" . $picz_height . ",scrollbars=0,resizable=0'))\"><img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 5] . "' border='0'></a>\n");
1303				}
1304			} else {
1305				push(@output, "      <img src='" . $config->{url} . "/" . $config->{imgs_dir} . $IMG[$e * 6 + 5] . "'>\n");
1306			}
1307		}
1308
1309		if($title) {
1310			push(@output, "    </td>\n");
1311			push(@output, "    </tr>\n");
1312
1313			push(@output, "    <tr>\n");
1314			push(@output, "      <td bgcolor='$colors->{title_bg_color}' colspan='2'>\n");
1315			push(@output, "       <font face='Verdana, sans-serif' color='$colors->{title_fg_color}'>\n");
1316			push(@output, "       <font size='-1'>\n");
1317			push(@output, "        <b style='{color: " . $colors->{title_fg_color} . "}'>&nbsp;&nbsp;$uri</b>\n");
1318			push(@output, "       </font></font>\n");
1319			push(@output, "      </td>\n");
1320			push(@output, "    </tr>\n");
1321			push(@output, main::graph_footer());
1322		}
1323		$e++;
1324	}
1325	push(@output, "  <br>\n");
1326	return @output;
1327}
1328
13291;
1330