#!/usr/bin/perl # AUTHOR: cbirchinger@netswarm.net # VERSION: 0.4 (Sep 18 2013) use strict; use DBI; use Getopt::Long qw(:config posix_default no_ignore_case); use Term::ReadKey; my @dbcfgs = ( "$ENV{HOME}/.my-root.cnf", "$ENV{HOME}/.my.cnf", "/etc/mysql/my.cnf", "/etc/my.cnf" ); my $dbuser; # leave empty to use the config file my $dbpass; # leave empty to use the config file my $dbhost; # leave empty to use the config file my %ansi = ( id => "\e[38;5;227m", user => "\e[38;5;99m", host => "\e[38;5;159m", db => "\e[38;5;208m", command => "\e[38;5;34m", time => "\e[38;5;118m", state => "\e[38;5;68m", info => "\e[38;5;250m", change => "\e[38;5;196m", add => "\e[38;5;118m", read => "\e[38;5;230m", sleep => "\e[38;5;244m", reset => "\e[1;0m", titlebg => "\e[48;5;238m", ); my $db='information_schema'; my $dbquery="SELECT ID,USER,HOST,IFNULL(DB, '') as DB,COMMAND,TIME,STATE,IFNULL(INFO, '') as INFO FROM information_schema.processlist ORDER BY ID"; my %opts; GetOptions(\%opts, 'host|h=s', 'user|u=s', 'password|p=s', 'config|c=s', 'nocolor|n', 'help', ) || printhelp(); printhelp() if ($opts{'help'}); $dbhost = $ARGV[0] if ($ARGV[0]); $dbhost = $opts{'host'} if ($opts{'host'}); $dbuser = $opts{'user'} if ($opts{'user'}); $dbpass = $opts{'password'} if ($opts{'password'}); my $dbcfg; if ($opts{'config'}) { $dbcfg = $opts{'config'}; print STDERR "Warning: Can't open file $dbcfg\n" if (! -r $dbcfg); } else { foreach (@dbcfgs) { if (-r $_) { $dbcfg = $_; last; } } } my $dbsrvstr; $dbsrvstr = ";host=${dbhost}" if ($dbhost); my $dbh = DBI->connect ( "DBI:mysql:database=${db}${dbsrvstr}" . ";mysql_read_default_file=${dbcfg}", $dbuser, $dbpass, { RaiseError => 0, PrintError => 0 } ) or abort("Couldn't connect to database: $DBI::errstr"); my $sql = $dbh->prepare($dbquery); $sql->execute; abort("SQL Error. return code: " . $sql->err . " error msg: " . $sql->errstr) if ($sql->err); my @labels = qw(id user host db command time state info); my %max = map { $_ => 15; } @labels; # Strip colors if ($opts{'nocolor'}) { %max = map { $_ => 3; } @labels; %ansi = map { $_ => ''; } @labels; } my @result; my $sleep = 0; while ( my $ref = $sql->fetchrow_arrayref() ) { my %data; @data{'id', 'user', 'host', 'db', 'command', 'time', 'state', 'info'} = @$ref; next if ( $data{'info'} =~ /information_schema.processlist/ ); if ( $data{'command'} eq 'Sleep' ) { $sleep++; next; } my %colordata; foreach (@labels) { $colordata{$_} = $ansi{$_} . $data{$_}; } foreach (keys(%colordata)) { if ( length($colordata{$_}) > $max{$_} ) { $max{$_} = length($colordata{$_}) } } push(@result, \%colordata); } $sql->finish(); my @colorlabels; foreach (@labels) { push (@colorlabels, "$ansi{$_}" . ucfirst($_)); } (my $wchar) = GetTerminalSize(); my $ttext = sprintf("$ansi{'titlebg'}%-$max{'id'}s %-$max{'user'}s %-$max{'host'}s %-$max{'db'}s %-$max{'command'}s %-$max{'time'}s %s", @colorlabels); my $ttpad = $wchar - vislength($ttext); print ${ttext} . ' ' x $ttpad . $ansi{'reset'} . "\n"; foreach (@result) { my %data = %{ $_ }; printf("%-$max{'id'}s %-$max{'user'}s %-$max{'host'}s %-$max{'db'}s %-$max{'command'}s %-$max{'time'}s %s\n", $data{'id'}, $data{'user'}, $data{'host'}, $data{'db'}, $data{'command'}, $data{'time'}, $data{'state'}); if ( length($data{'info'}) > length($ansi{'info'}) ) { $data{'info'} =~ s/^\s*\e?\[[\d;]*m?\s*(select|show)(\s.*)/$ansi{'read'}${1}$ansi{'info'}${2}/i || $data{'info'} =~ s/^\s*\e?\[[\d;]*m?\s*(delete|update|alter|drop|set)(\s.*)/$ansi{'change'}${1}$ansi{'info'}${2}/i || $data{'info'} =~ s/^\s*\e?\[[\d;]*m?\s*(insert|load|create)(\s.*)/$ansi{'add'}${1}$ansi{'info'}${2}/i; print "$ansi{'sleep'}↳ $data{'info'}\n"; } } my $ftext = "$ansi{'sleep'}$ansi{'titlebg'} Sleeping: ${sleep}"; my $ftpad = $wchar - vislength($ftext); print ${ftext} . ' ' x $ftpad . $ansi{'reset'} . "\n"; sub vislength { my ($str) = @_; $str =~ s/\e\[\d+(?>(;\d+)*)m//g; return length($str); } sub abort { my ($errstr) = @_; $errstr = "ERROR: Unknown error\n" if ! $errstr; print STDERR $errstr . "\n"; exit 1; } sub printhelp { (my $basename = $0) =~ s/.*\///; print "Usage: $basename [OPTION]... [HOST]\n"; print "\n"; print " --help Display this help screen\n"; print " -n, --nocolor No ANSI color sequences\n"; print " -c, --config=CONFIG Read my.cnf config file. Use [client] section credentials and host\n"; print " -u, --user=USER MySQL user name\n"; print " -p, --password=PASSWORD MySQL password\n"; print " -h, --host=HOST MySQL server host\n"; print " HOST MySQL server host\n"; print "\n"; print "Default options are read from the following files in the given order:\n" . join(' ', @dbcfgs) . "\n"; print "\n"; exit 0; }