mirror of https://github.com/mikaku/Monitorix.git
3.0: lot of work done
This commit is contained in:
parent
f3fceffb0c
commit
14234ad789
421
ng/lib/system.pm
421
ng/lib/system.pm
|
@ -1,11 +1,11 @@
|
|||
package system;
|
||||
|
||||
use strict;
|
||||
#use strict;
|
||||
use warnings;
|
||||
use Monitorix;
|
||||
use RRDs;
|
||||
use Exporter 'import';
|
||||
our @EXPORT = qw(system_init system_update);
|
||||
our @EXPORT = qw(system_init system_update system_cgi);
|
||||
|
||||
sub system_init {
|
||||
my $myself = (caller(0))[3];
|
||||
|
@ -282,4 +282,421 @@ sub system_update {
|
|||
logger("ERROR: while updating $rrd: $err") if $err;
|
||||
}
|
||||
|
||||
sub system_cgi {
|
||||
my ($package, $config, $colors, $tf, $graph, $silent, $u) = @_;
|
||||
|
||||
my $width;
|
||||
my $height;
|
||||
my @riglim;
|
||||
my @tmp;
|
||||
my @tmpz;
|
||||
my $n;
|
||||
my $err;
|
||||
|
||||
my $rrd = $config->{base_lib} . $package . ".rrd";
|
||||
my $title = $config->{graph_title}->{$package};
|
||||
my $PNG_DIR = $config->{base_dir} . "/" . $config->{imgs_dir};
|
||||
|
||||
my $total_mem;
|
||||
|
||||
my $PNG1 = $u . $package . "1." . $tf->{when} . ".png";
|
||||
my $PNG2 = $u . $package . "2." . $tf->{when} . ".png";
|
||||
my $PNG3 = $u . $package . "3." . $tf->{when} . ".png";
|
||||
my $PNG1z = $u . $package . "1z." . $tf->{when} . ".png";
|
||||
my $PNG2z = $u . $package . "2z." . $tf->{when} . ".png";
|
||||
my $PNG3z = $u . $package . "3z." . $tf->{when} . ".png";
|
||||
|
||||
$title = !$silent ? $title : "";
|
||||
|
||||
unlink ("$PNG_DIR" . "$PNG1",
|
||||
"$PNG_DIR" . "$PNG2",
|
||||
"$PNG_DIR" . "$PNG3");
|
||||
if(lc($config->{enable_zoom}) eq "y") {
|
||||
unlink ("$PNG_DIR" . "$PNG1z",
|
||||
"$PNG_DIR" . "$PNG2z",
|
||||
"$PNG_DIR" . "$PNG3z");
|
||||
}
|
||||
|
||||
if($config->{os} eq "Linux") {
|
||||
$total_mem = `grep -w MemTotal: /proc/meminfo | awk '{print \$2}'`;
|
||||
chomp($total_mem);
|
||||
} elsif(grep {$_ eq $config->{os}} ("FreeBSD", "OpenBSD", "NetBSD")) {
|
||||
$total_mem = `/sbin/sysctl -n hw.physmem`; # in bytes
|
||||
chomp($total_mem);
|
||||
$total_mem = int($total_mem / 1024); # in KB
|
||||
}
|
||||
$total_mem = int($total_mem / 1024); # in MB
|
||||
|
||||
if(lc($config->{iface_mode}) eq "text") {
|
||||
if($title) {
|
||||
main::graph_header($title, 2);
|
||||
print(" <tr>\n");
|
||||
print(" <td bgcolor='$colors->{title_bg_color}'>\n");
|
||||
}
|
||||
my (undef, undef, undef, $data) = RRDs::fetch($rrd,
|
||||
"--start=-$tf->{nwhen}$tf->{twhen}",
|
||||
"AVERAGE",
|
||||
"-r $tf->{res}");
|
||||
$err = RRDs::error;
|
||||
print("ERROR: while fetching $rrd: $err\n") if $err;
|
||||
print(" <pre style='font-size: 12px; color: $colors->{fg_color}';>\n");
|
||||
print(" CPU load average Memory usage in MB Processes\n");
|
||||
print("Time 1min 5min 15min Used Cached Buffers Total Run\n");
|
||||
print("------------------------------------------------------------- \n");
|
||||
my $line;
|
||||
my @row;
|
||||
my $time;
|
||||
for($n = 0, $time = $tf->{tb}; $n < ($tf->{tb} * $tf->{ts}); $n++) {
|
||||
$line = @$data[$n];
|
||||
my ($load1, $load5, $load15, $nproc, $npslp, $nprun, $mtotl, $buff, $cach, $free) = @$line;
|
||||
$buff /= 1024;
|
||||
$cach /= 1024;
|
||||
$free /= 1024;
|
||||
@row = ($load1, $load5, $load15, $total_mem - $free, $cach, $buff, $nproc, $nprun);
|
||||
$time = $time - (1 / $tf->{ts});
|
||||
printf(" %2d$tf->{tc} %4.1f %4.1f %4.1f %6d %6d %6d %5d %5d \n", $time, @row);
|
||||
}
|
||||
print("\n");
|
||||
print(" system uptime: " . get_uptime($config) . "\n");
|
||||
print(" </pre>\n");
|
||||
if($title) {
|
||||
print(" </td>\n");
|
||||
print(" </tr>\n");
|
||||
main::graph_footer();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if($title) {
|
||||
main::graph_header($title, 2);
|
||||
}
|
||||
if($config->{system1_rigid} eq 1) {
|
||||
push(@riglim, "--upper-limit=$config->{system1_limit}");
|
||||
} else {
|
||||
if($config->{system1_rigid} eq 2) {
|
||||
push(@riglim, "--upper-limit=$config->{system1_limit}");
|
||||
push(@riglim, "--rigid");
|
||||
}
|
||||
}
|
||||
my $uptimeline;
|
||||
if($RRDs::VERSION > 1.2) {
|
||||
$uptimeline = "COMMENT:system uptime\\: " . get_uptime($config) . "\\c";
|
||||
} else {
|
||||
$uptimeline = "COMMENT:system uptime: " . get_uptime($config) . "\\c";
|
||||
}
|
||||
|
||||
if($title) {
|
||||
print(" <tr>\n");
|
||||
print(" <td bgcolor='$colors->{title_bg_color}'>\n");
|
||||
}
|
||||
push(@tmp, "AREA:load1#4444EE: 1 min average");
|
||||
push(@tmp, "GPRINT:load1:LAST: Current\\: %4.2lf");
|
||||
push(@tmp, "GPRINT:load1:AVERAGE: Average\\: %4.2lf");
|
||||
push(@tmp, "GPRINT:load1:MIN: Min\\: %4.2lf");
|
||||
push(@tmp, "GPRINT:load1:MAX: Max\\: %4.2lf\\n");
|
||||
push(@tmp, "LINE1:load1#0000EE");
|
||||
push(@tmp, "LINE1:load5#EEEE00: 5 min average");
|
||||
push(@tmp, "GPRINT:load5:LAST: Current\\: %4.2lf");
|
||||
push(@tmp, "GPRINT:load5:AVERAGE: Average\\: %4.2lf");
|
||||
push(@tmp, "GPRINT:load5:MIN: Min\\: %4.2lf");
|
||||
push(@tmp, "GPRINT:load5:MAX: Max\\: %4.2lf\\n");
|
||||
push(@tmp, "LINE1:load15#00EEEE:15 min average");
|
||||
push(@tmp, "GPRINT:load15:LAST: Current\\: %4.2lf");
|
||||
push(@tmp, "GPRINT:load15:AVERAGE: Average\\: %4.2lf");
|
||||
push(@tmp, "GPRINT:load15:MIN: Min\\: %4.2lf");
|
||||
push(@tmp, "GPRINT:load15:MAX: Max\\: %4.2lf\\n");
|
||||
push(@tmpz, "AREA:load1#4444EE: 1 min average");
|
||||
push(@tmpz, "LINE1:load1#0000EE");
|
||||
push(@tmpz, "LINE1:load5#EEEE00: 5 min average");
|
||||
push(@tmpz, "LINE1:load15#00EEEE:15 min average");
|
||||
if($config->{os} eq "FreeBSD") {
|
||||
push(@tmp, "COMMENT: \\n");
|
||||
}
|
||||
($width, $height) = split('x', $config->{graph_size}->{main});
|
||||
if($silent =~ /imagetag/) {
|
||||
($width, $height) = split('x', $config->{graph_size}->{remote}) if $silent eq "imagetag";
|
||||
($width, $height) = split('x', $config->{graph_size}->{main}) if $silent eq "imagetagbig";
|
||||
@tmp = @tmpz;
|
||||
push(@tmp, "COMMENT: \\n");
|
||||
}
|
||||
RRDs::graph("$PNG_DIR" . "$PNG1",
|
||||
"--title=$config->{graphs}->{_system1} ($tf->{nwhen}$tf->{twhen})",
|
||||
"--start=-$tf->{nwhen}$tf->{twhen}",
|
||||
"--imgformat=PNG",
|
||||
"--vertical-label=Load average",
|
||||
"--width=$width",
|
||||
"--height=$height",
|
||||
@riglim,
|
||||
"--lower-limit=0",
|
||||
@{$config->{version12}},
|
||||
@{$colors->{graph_colors}},
|
||||
"DEF:load1=$rrd:system_load1:AVERAGE",
|
||||
"DEF:load5=$rrd:system_load5:AVERAGE",
|
||||
"DEF:load15=$rrd:system_load15:AVERAGE",
|
||||
@tmp,
|
||||
"COMMENT: \\n",
|
||||
$uptimeline);
|
||||
$err = RRDs::error;
|
||||
print("ERROR: while graphing $PNG_DIR" . "$PNG1: $err\n") if $err;
|
||||
if(lc($config->{enable_zoom}) eq "y") {
|
||||
($width, $height) = split('x', $config->{graph_size}->{zoom});
|
||||
RRDs::graph("$PNG_DIR" . "$PNG1z",
|
||||
"--title=$config->{graphs}->{_system1} ($tf->{nwhen}$tf->{twhen})",
|
||||
"--start=-$tf->{nwhen}$tf->{twhen}",
|
||||
"--imgformat=PNG",
|
||||
"--vertical-label=Load average",
|
||||
"--width=$width",
|
||||
"--height=$height",
|
||||
@riglim,
|
||||
"--lower-limit=0",
|
||||
@{$config->{version12}},
|
||||
@{$colors->{graph_colors}},
|
||||
"DEF:load1=$rrd:system_load1:AVERAGE",
|
||||
"DEF:load5=$rrd:system_load5:AVERAGE",
|
||||
"DEF:load15=$rrd:system_load15:AVERAGE",
|
||||
@tmpz);
|
||||
$err = RRDs::error;
|
||||
print("ERROR: while graphing $PNG_DIR" . "$PNG1z: $err\n") if $err;
|
||||
}
|
||||
if($title || ($silent =~ /imagetag/ && $graph =~ /system1/)) {
|
||||
if(lc($config->{enable_zoom}) eq "y") {
|
||||
if(lc($config->{disable_javascript_void}) eq "y") {
|
||||
print(" <a href=\"" . $config->{url} . $config->{imgs_dir} . $PNG1z . "\"><img src='" . $config->{url} . $config->{imgs_dir} . $PNG1 . "' border='0'></a>\n");
|
||||
}
|
||||
else {
|
||||
print(" <a href=\"javascript:void(window.open('" . $config->{url} . $config->{imgs_dir} . $PNG1z . "','','width=" . ($width + 115) . ",height=" . ($height + 100) . ",scrollbars=0,resizable=0'))\"><img src='" . $config->{url} . $config->{imgs_dir} . $PNG1 . "' border='0'></a>\n");
|
||||
}
|
||||
} else {
|
||||
print(" <img src='" . $config->{url} . $config->{imgs_dir} . $PNG1 . "'>\n");
|
||||
}
|
||||
}
|
||||
if($title) {
|
||||
print(" </td>\n");
|
||||
print(" <td bgcolor='" . $colors->{title_bg_color} . "'>\n");
|
||||
}
|
||||
|
||||
undef(@riglim);
|
||||
if($SYSTEM2_RIGID eq 1) {
|
||||
push(@riglim, "--upper-limit=$SYSTEM2_LIMIT");
|
||||
} else {
|
||||
if($SYSTEM2_RIGID eq 2) {
|
||||
push(@riglim, "--upper-limit=$SYSTEM2_LIMIT");
|
||||
push(@riglim, "--rigid");
|
||||
}
|
||||
}
|
||||
undef(@tmp);
|
||||
undef(@tmpz);
|
||||
push(@tmp, "AREA:npslp#44AAEE:Sleeping");
|
||||
push(@tmp, "AREA:nprun#EE4444:Running");
|
||||
push(@tmp, "LINE1:nprun#EE0000");
|
||||
push(@tmp, "LINE1:npslp#00EEEE");
|
||||
push(@tmp, "LINE1:nproc#EEEE00:Processes");
|
||||
($width, $height) = split('x', $GRAPH_SIZE{small});
|
||||
if($silent =~ /imagetag/) {
|
||||
($width, $height) = split('x', $GRAPH_SIZE{remote}) if $silent eq "imagetag";
|
||||
($width, $height) = split('x', $GRAPH_SIZE{main}) if $silent eq "imagetagbig";
|
||||
push(@tmp, "COMMENT: \\n");
|
||||
push(@tmp, "COMMENT: \\n");
|
||||
}
|
||||
RRDs::graph("$PNG_DIR" . "$PNG2",
|
||||
"--title=$rgraphs{_system2} ($nwhen$twhen)",
|
||||
"--start=-$nwhen$twhen",
|
||||
"--imgformat=PNG",
|
||||
"--vertical-label=Processes",
|
||||
"--width=$width",
|
||||
"--height=$height",
|
||||
@riglim,
|
||||
"--lower-limit=0",
|
||||
@VERSION12,
|
||||
@VERSION12_small,
|
||||
@graph_colors,
|
||||
"DEF:nproc=$rrd:system_nproc:AVERAGE",
|
||||
"DEF:npslp=$rrd:system_npslp:AVERAGE",
|
||||
"DEF:nprun=$rrd:system_nprun:AVERAGE",
|
||||
@tmp,
|
||||
"COMMENT: \\n");
|
||||
$err = RRDs::error;
|
||||
print("ERROR: while graphing $PNG_DIR" . "$PNG2: $err\n") if $err;
|
||||
if(lc($config->{enable_zoom}) eq "y") {
|
||||
($width, $height) = split('x', $GRAPH_SIZE{zoom});
|
||||
RRDs::graph("$PNG_DIR" . "$PNG2z",
|
||||
"--title=$rgraphs{_system2} ($nwhen$twhen)",
|
||||
"--start=-$nwhen$twhen",
|
||||
"--imgformat=PNG",
|
||||
"--vertical-label=Processes",
|
||||
"--width=$width",
|
||||
"--height=$height",
|
||||
@riglim,
|
||||
"--lower-limit=0",
|
||||
@VERSION12,
|
||||
@VERSION12_small,
|
||||
@graph_colors,
|
||||
"DEF:nproc=$rrd:system_nproc:AVERAGE",
|
||||
"DEF:npslp=$rrd:system_npslp:AVERAGE",
|
||||
"DEF:nprun=$rrd:system_nprun:AVERAGE",
|
||||
@tmp);
|
||||
$err = RRDs::error;
|
||||
print("ERROR: while graphing $PNG_DIR" . "$PNG2z: $err\n") if $err;
|
||||
}
|
||||
if($title || ($silent =~ /imagetag/ && $graph =~ /system2/)) {
|
||||
if(lc($config->{enable_zoom}) eq "y") {
|
||||
if($DISABLE_JAVASCRIPT_VOID eq "Y") {
|
||||
print(" <a href=\"" . $URL . $IMGS_DIR . $PNG2z . "\"><img src='" . $URL . $IMGS_DIR . $PNG2 . "' border='0'></a>\n");
|
||||
}
|
||||
else {
|
||||
print(" <a href=\"javascript:void(window.open('" . $URL . $IMGS_DIR . $PNG2z . "','','width=" . ($width + 115) . ",height=" . ($height + 100) . ",scrollbars=0,resizable=0'))\"><img src='" . $URL . $IMGS_DIR . $PNG2 . "' border='0'></a>\n");
|
||||
}
|
||||
} else {
|
||||
print(" <img src='" . $URL . $IMGS_DIR . $PNG2 . "'>\n");
|
||||
}
|
||||
}
|
||||
|
||||
undef(@tmp);
|
||||
undef(@tmpz);
|
||||
if($config->{os} eq "Linux") {
|
||||
push(@tmp, "AREA:m_mused#EE4444:Used");
|
||||
push(@tmp, "AREA:m_mcach#44EE44:Cached");
|
||||
push(@tmp, "AREA:m_mbuff#CCCCCC:Buffers");
|
||||
push(@tmp, "LINE1:m_mbuff#888888");
|
||||
push(@tmp, "LINE1:m_mcach#00EE00");
|
||||
push(@tmp, "LINE1:m_mused#EE0000");
|
||||
} elsif($config->{os} eq "FreeBSD") {
|
||||
push(@tmp, "AREA:m_mused#EE4444:Used");
|
||||
push(@tmp, "AREA:m_mcach#44EE44:Cached");
|
||||
push(@tmp, "AREA:m_mbuff#CCCCCC:Buffers");
|
||||
push(@tmp, "AREA:m_macti#EEEE44:Active");
|
||||
push(@tmp, "AREA:m_minac#4444EE:Inactive");
|
||||
push(@tmp, "LINE1:m_minac#0000EE");
|
||||
push(@tmp, "LINE1:m_macti#EEEE00");
|
||||
push(@tmp, "LINE1:m_mbuff#888888");
|
||||
push(@tmp, "LINE1:m_mcach#00EE00");
|
||||
push(@tmp, "LINE1:m_mused#EE0000");
|
||||
} elsif($config->{os} eq "OpenBSD" || $config->{os} eq "NetBSD") {
|
||||
push(@tmp, "AREA:m_mused#EE4444:Used");
|
||||
push(@tmp, "AREA:m_macti#44EE44:Active");
|
||||
push(@tmp, "LINE1:m_macti#00EE00");
|
||||
push(@tmp, "LINE1:m_mused#EE0000");
|
||||
}
|
||||
($width, $height) = split('x', $GRAPH_SIZE{small});
|
||||
if($silent =~ /imagetag/) {
|
||||
($width, $height) = split('x', $GRAPH_SIZE{remote}) if $silent eq "imagetag";
|
||||
($width, $height) = split('x', $GRAPH_SIZE{main}) if $silent eq "imagetagbig";
|
||||
push(@tmp, "COMMENT: \\n");
|
||||
push(@tmp, "COMMENT: \\n");
|
||||
}
|
||||
RRDs::graph("$PNG_DIR" . "$PNG3",
|
||||
"--title=$rgraphs{_system3} (${total_mem}MB) ($nwhen$twhen)",
|
||||
"--start=-$nwhen$twhen",
|
||||
"--imgformat=PNG",
|
||||
"--vertical-label=Megabytes",
|
||||
"--width=$width",
|
||||
"--height=$height",
|
||||
"--upper-limit=$total_mem",
|
||||
"--lower-limit=0",
|
||||
"--base=1024",
|
||||
@VERSION12,
|
||||
@VERSION12_small,
|
||||
@graph_colors,
|
||||
"DEF:mtotl=$rrd:system_mtotl:AVERAGE",
|
||||
"DEF:mbuff=$rrd:system_mbuff:AVERAGE",
|
||||
"DEF:mcach=$rrd:system_mcach:AVERAGE",
|
||||
"DEF:mfree=$rrd:system_mfree:AVERAGE",
|
||||
"DEF:macti=$rrd:system_macti:AVERAGE",
|
||||
"DEF:minac=$rrd:system_minac:AVERAGE",
|
||||
"CDEF:m_mtotl=mtotl,1024,/",
|
||||
"CDEF:m_mbuff=mbuff,1024,/",
|
||||
"CDEF:m_mcach=mcach,1024,/",
|
||||
"CDEF:m_mused=m_mtotl,mfree,1024,/,-",
|
||||
"CDEF:m_macti=macti,1024,/",
|
||||
"CDEF:m_minac=minac,1024,/",
|
||||
@tmp,
|
||||
"COMMENT: \\n");
|
||||
$err = RRDs::error;
|
||||
print("ERROR: while graphing $PNG_DIR" . "$PNG3: $err\n") if $err;
|
||||
if(lc($config->{enable_zoom}) eq "y") {
|
||||
($width, $height) = split('x', $GRAPH_SIZE{zoom});
|
||||
RRDs::graph("$PNG_DIR" . "$PNG3z",
|
||||
"--title=$rgraphs{_system3} (${total_mem}MB) ($nwhen$twhen)",
|
||||
"--start=-$nwhen$twhen",
|
||||
"--imgformat=PNG",
|
||||
"--vertical-label=Megabytes",
|
||||
"--width=$width",
|
||||
"--height=$height",
|
||||
"--upper-limit=$total_mem",
|
||||
"--lower-limit=0",
|
||||
"--base=1024",
|
||||
@VERSION12,
|
||||
@VERSION12_small,
|
||||
@graph_colors,
|
||||
"DEF:mtotl=$rrd:system_mtotl:AVERAGE",
|
||||
"DEF:mbuff=$rrd:system_mbuff:AVERAGE",
|
||||
"DEF:mcach=$rrd:system_mcach:AVERAGE",
|
||||
"DEF:mfree=$rrd:system_mfree:AVERAGE",
|
||||
"DEF:macti=$rrd:system_macti:AVERAGE",
|
||||
"DEF:minac=$rrd:system_minac:AVERAGE",
|
||||
"CDEF:m_mtotl=mtotl,1024,/",
|
||||
"CDEF:m_mbuff=mbuff,1024,/",
|
||||
"CDEF:m_mcach=mcach,1024,/",
|
||||
"CDEF:m_mused=m_mtotl,mfree,1024,/,-",
|
||||
"CDEF:m_macti=macti,1024,/",
|
||||
"CDEF:m_minac=minac,1024,/",
|
||||
@tmp);
|
||||
$err = RRDs::error;
|
||||
print("ERROR: while graphing $PNG_DIR" . "$PNG3z: $err\n") if $err;
|
||||
}
|
||||
if($title || ($silent =~ /imagetag/ && $graph =~ /system3/)) {
|
||||
if(lc($config->{enable_zoom}) eq "y") {
|
||||
if($DISABLE_JAVASCRIPT_VOID eq "Y") {
|
||||
print(" <a href=\"" . $URL . $IMGS_DIR . $PNG3z . "\"><img src='" . $URL . $IMGS_DIR . $PNG3 . "' border='0'></a>\n");
|
||||
}
|
||||
else {
|
||||
print(" <a href=\"javascript:void(window.open('" . $URL . $IMGS_DIR . $PNG3z . "','','width=" . ($width + 115) . ",height=" . ($height + 100) . ",scrollbars=0,resizable=0'))\"><img src='" . $URL . $IMGS_DIR . $PNG3 . "' border='0'></a>\n");
|
||||
}
|
||||
} else {
|
||||
print(" <img src='" . $URL . $IMGS_DIR . $PNG3 . "'>\n");
|
||||
}
|
||||
}
|
||||
|
||||
if($title) {
|
||||
print(" </td>\n");
|
||||
print(" </tr>\n");
|
||||
main::graph_footer();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub get_uptime {
|
||||
my $config = shift;
|
||||
my $str;
|
||||
my $uptime;
|
||||
|
||||
if($config->{os} eq "Linux") {
|
||||
open(IN, "/proc/uptime");
|
||||
($uptime, undef) = split(' ', <IN>);
|
||||
close(IN);
|
||||
} elsif($config->{os} eq "FreeBSD") {
|
||||
open(IN, "/sbin/sysctl -n kern.boottime |");
|
||||
(undef, undef, undef, $uptime) = split(' ', <IN>);
|
||||
close(IN);
|
||||
$uptime =~ s/,//;
|
||||
$uptime = time - int($uptime);
|
||||
} elsif($config->{os} eq "OpenBSD" || $config->{os} eq "NetBSD") {
|
||||
open(IN, "/sbin/sysctl -n kern.boottime |");
|
||||
$uptime = <IN>;
|
||||
close(IN);
|
||||
chomp($uptime);
|
||||
$uptime = time - int($uptime);
|
||||
}
|
||||
|
||||
my $d = int($uptime / (60 * 60 * 24));
|
||||
my $h = int($uptime / (60 * 60)) % 24;
|
||||
my $m = int($uptime / 60) % 60;
|
||||
|
||||
my $d_string = $d ? sprintf("%d days,", $d) : "";
|
||||
my $h_string = $h ? sprintf("%d", $h) : "";
|
||||
my $m_string = $h ? sprintf("%sh %dm", $h, $m) : sprintf("%d min", $m);
|
||||
|
||||
return "$d_string $m_string";
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
Loading…
Reference in New Issue