From c3da0b013c80b527d0bebfcf681b1811816510b5 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sat, 30 Jan 2021 10:23:56 +1100 Subject: [PATCH 1/2] add server-log option for explict server log This allows a user to specify a logrotated file or another file that isn't discoverable from server log_error system variable or other defaults. close #504 --- mysqltuner.pl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mysqltuner.pl b/mysqltuner.pl index c62400e..3779821 100755 --- a/mysqltuner.pl +++ b/mysqltuner.pl @@ -88,6 +88,7 @@ my %opt = ( "noprocess" => 0, "dbstat" => 0, "nodbstat" => 0, + "server-log" => '', "tbstat" => 0, "notbstat" => 0, "idxstat" => 0, @@ -133,6 +134,7 @@ GetOptions( 'sysstat', 'nosysstat', 'pfstat', 'nopfstat', 'idxstat', 'noidxstat', + 'server-log=s', ) or pod2usage( -exitval => 1, @@ -1242,7 +1244,7 @@ sub get_log_file_real_path { } sub log_file_recommendations { - $myvar{'log_error'} = + $myvar{'log_error'} = $opt{'server-log'} || get_log_file_real_path( $myvar{'log_error'}, $myvar{'hostname'}, $myvar{'datadir'} ); @@ -1273,7 +1275,9 @@ sub log_file_recommendations { goodprint "Log file $myvar{'log_error'} is not empty"; } else { - badprint "Log file $myvar{'log_error'} is empty"; + infoprint +"Log file $myvar{'log_error'} is empty. Assuming log-rotation. Use --server-log={file} for explicit file"; + return; } if ( ( stat $myvar{'log_error'} )[7] < 32 * 1024 * 1024 ) { @@ -6428,6 +6432,7 @@ You must provide the remote server's total memory when connecting to other serve --mysqladmin Path to a custom mysqladmin executable --mysqlcmd Path to a custom mysql executable --defaults-file Path to a custom .my.cnf + --server-log Path to explict log file =head1 PERFORMANCE AND REPORTING OPTIONS From 938b434e413fdb186901704f0be692ce48bfc610 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sat, 30 Jan 2021 12:31:00 +1100 Subject: [PATCH 2/2] extend server-log for journal/container/pods Default to reading last 30000 lines. If reading from file estimate that average line length is 80 characters and read based that far back from the end of file. --- mysqltuner.pl | 80 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/mysqltuner.pl b/mysqltuner.pl index 3779821..06d8fb3 100755 --- a/mysqltuner.pl +++ b/mysqltuner.pl @@ -238,6 +238,9 @@ my $deb = ( $opt{nocolor} == 0 ) ? "[\e[0;31mDG\e[0m]" : "[DG]"; my $cmd = ( $opt{nocolor} == 0 ) ? "\e[1;32m[CMD]($me)" : "[CMD]($me)"; my $end = ( $opt{nocolor} == 0 ) ? "\e[0m" : ""; +# Maximum lines of log output to read from end +my $maxlines = 30000; + # Checks for supported or EOL'ed MySQL versions my ( $mysqlvermajor, $mysqlverminor, $mysqlvermicro ); @@ -1244,6 +1247,7 @@ sub get_log_file_real_path { } sub log_file_recommendations { + my $fh; $myvar{'log_error'} = $opt{'server-log'} || get_log_file_real_path( $myvar{'log_error'}, $myvar{'hostname'}, $myvar{'datadir'} ); @@ -1253,42 +1257,55 @@ sub log_file_recommendations { badprint "log_error is set to $myvar{'log_error'} MT can't read stderr"; return } - if ( -f "$myvar{'log_error'}" ) { + elsif ( $myvar{'log_error'} =~ /^(docker|podman|kubectl):(.*)/ ) { + open( $fh, '-|', "$1 logs --tail=$maxlines '$2'" ) + // die "Can't start $1 $!"; + goodprint "Log from cloud` $myvar{'log_error'} exists"; + } + elsif ($myvar{'log_error'} =~ /^systemd:(.*)/ ) { + open( $fh, '-|', "journalctl -n $maxlines -b -u '$1'" ) + // die "Can't start journalctl $!"; + goodprint "Log journal` $myvar{'log_error'} exists"; + } + elsif ( -f "$myvar{'log_error'}" ) { goodprint "Log file $myvar{'log_error'} exists"; + my $size = ( stat $myvar{'log_error'} )[7]; + infoprint "Log file: " + . $myvar{'log_error'} . "(" + . hr_bytes_rnd( $size ) . ")"; + + if ( $size > 0 ) { + goodprint "Log file $myvar{'log_error'} is not empty"; + if ( $size < 32 * 1024 * 1024 ) { + goodprint "Log file $myvar{'log_error'} is smaller than 32 Mb"; + } + else { + badprint "Log file $myvar{'log_error'} is bigger than 32 Mb"; + push @generalrec, + $myvar{'log_error'} + . " is > 32Mb, you should analyze why or implement a rotation log strategy such as logrotate!"; + } + } + else { + infoprint +"Log file $myvar{'log_error'} is empty. Assuming log-rotation. Use --server-log={file} for explicit file"; + return; + } + if ( ! open( $fh, '<', $myvar{'log_error'} ) ) { + badprint "Log file $myvar{'log_error'} isn't readable."; + return; + } + goodprint "Log file $myvar{'log_error'} is readable."; + + if ( $maxlines * 80 < $size ) { + seek( $fh, -$maxlines * 80, 2); + <$fh> ; # discard line fragment + } } else { badprint "Log file $myvar{'log_error'} doesn't exist"; return; } - infoprint "Log file: " - . $myvar{'log_error'} . "(" - . hr_bytes_rnd( ( stat $myvar{'log_error'} )[7] ) . ")"; - - if ( -r "$myvar{'log_error'}" ) { - goodprint "Log file $myvar{'log_error'} is readable."; - } - else { - badprint "Log file $myvar{'log_error'} isn't readable."; - return; - } - if ( ( stat $myvar{'log_error'} )[7] > 0 ) { - goodprint "Log file $myvar{'log_error'} is not empty"; - } - else { - infoprint -"Log file $myvar{'log_error'} is empty. Assuming log-rotation. Use --server-log={file} for explicit file"; - return; - } - - if ( ( stat $myvar{'log_error'} )[7] < 32 * 1024 * 1024 ) { - goodprint "Log file $myvar{'log_error'} is smaller than 32 Mb"; - } - else { - badprint "Log file $myvar{'log_error'} is bigger than 32 Mb"; - push @generalrec, - $myvar{'log_error'} - . " is > 32Mb, you should analyze why or implement a rotation log strategy such as logrotate!"; - } my $numLi = 0; my $nbWarnLog = 0; @@ -1296,9 +1313,6 @@ sub log_file_recommendations { my @lastShutdowns; my @lastStarts; - open( my $fh, '<', $myvar{'log_error'} ) - or die "Can't open $myvar{'log_error'} for read: $!"; - while ( my $logLi = <$fh> ) { chomp $logLi; $numLi++;