mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-02 02:34:19 +00:00
2816 lines
91 KiB
Bash
Executable File
2816 lines
91 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# This program is part of Percona Toolkit: http://www.percona.com/software/
|
|
# See "COPYRIGHT, LICENSE, AND WARRANTY" at the end of this file for legal
|
|
# notices and disclaimers.
|
|
|
|
set -u
|
|
|
|
# ########################################################################
|
|
# Globals, settings, helper functions
|
|
# ########################################################################
|
|
TOOL="pt-summary"
|
|
POSIXLY_CORRECT=1
|
|
export POSIXLY_CORRECT
|
|
|
|
# ###########################################################################
|
|
# log_warn_die package
|
|
# This package is a copy without comments from the original. The original
|
|
# with comments and its test file can be found in the GitHub repository at,
|
|
# lib/bash/log_warn_die.sh
|
|
# t/lib/bash/log_warn_die.sh
|
|
# See https://github.com/percona/percona-toolkit for more information.
|
|
# ###########################################################################
|
|
|
|
|
|
set -u
|
|
|
|
PTFUNCNAME=""
|
|
PTDEBUG="${PTDEBUG:-""}"
|
|
EXIT_STATUS=0
|
|
|
|
ts() {
|
|
TS=$(date +%F-%T | tr ':-' '_')
|
|
echo "$TS $*"
|
|
}
|
|
|
|
info() {
|
|
[ ${OPT_VERBOSE:-3} -ge 3 ] && ts "$*"
|
|
}
|
|
|
|
log() {
|
|
[ ${OPT_VERBOSE:-3} -ge 2 ] && ts "$*"
|
|
}
|
|
|
|
warn() {
|
|
[ ${OPT_VERBOSE:-3} -ge 1 ] && ts "$*" >&2
|
|
EXIT_STATUS=1
|
|
}
|
|
|
|
die() {
|
|
ts "$*" >&2
|
|
EXIT_STATUS=1
|
|
exit 1
|
|
}
|
|
|
|
_d () {
|
|
[ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(ts "$*")" >&2
|
|
}
|
|
|
|
# ###########################################################################
|
|
# End log_warn_die package
|
|
# ###########################################################################
|
|
|
|
# ###########################################################################
|
|
# parse_options package
|
|
# This package is a copy without comments from the original. The original
|
|
# with comments and its test file can be found in the GitHub repository at,
|
|
# lib/bash/parse_options.sh
|
|
# t/lib/bash/parse_options.sh
|
|
# See https://github.com/percona/percona-toolkit for more information.
|
|
# ###########################################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
set -u
|
|
|
|
ARGV="" # Non-option args (probably input files)
|
|
EXT_ARGV="" # Everything after -- (args for an external command)
|
|
HAVE_EXT_ARGV="" # Got --, everything else is put into EXT_ARGV
|
|
OPT_ERRS=0 # How many command line option errors
|
|
OPT_VERSION="" # If --version was specified
|
|
OPT_HELP="" # If --help was specified
|
|
OPT_ASK_PASS="" # If --ask-pass was specified
|
|
PO_DIR="" # Directory with program option spec files
|
|
GLOBAL_CONFIG=0 # We ignore non-recognized options in global configs
|
|
|
|
usage() {
|
|
local file="$1"
|
|
|
|
local usage="$(grep '^Usage: ' "$file")"
|
|
echo $usage
|
|
echo
|
|
echo "For more information, 'man $TOOL' or 'perldoc $file'."
|
|
}
|
|
|
|
usage_or_errors() {
|
|
local file="$1"
|
|
local version=""
|
|
|
|
if [ "$OPT_VERSION" ]; then
|
|
version=$(grep '^pt-[^ ]\+ [0-9]' "$file")
|
|
echo "$version"
|
|
return 1
|
|
fi
|
|
|
|
if [ -z $(_which perl) ]; then
|
|
echo "Perl binary required to run this tool"
|
|
return 1
|
|
fi
|
|
|
|
if [ "$OPT_HELP" ]; then
|
|
usage "$file"
|
|
echo
|
|
echo "Command line options:"
|
|
echo
|
|
perl -e '
|
|
use strict;
|
|
use warnings FATAL => qw(all);
|
|
my $lcol = 20; # Allow this much space for option names.
|
|
my $rcol = 80 - $lcol; # The terminal is assumed to be 80 chars wide.
|
|
my $name;
|
|
while ( <> ) {
|
|
my $line = $_;
|
|
chomp $line;
|
|
if ( $line =~ s/^long:/ --/ ) {
|
|
$name = $line;
|
|
}
|
|
elsif ( $line =~ s/^desc:// ) {
|
|
$line =~ s/ +$//mg;
|
|
my @lines = grep { $_ }
|
|
$line =~ m/(.{0,$rcol})(?:\s+|\Z)/g;
|
|
if ( length($name) >= $lcol ) {
|
|
print $name, "\n", (q{ } x $lcol);
|
|
}
|
|
else {
|
|
printf "%-${lcol}s", $name;
|
|
}
|
|
print join("\n" . (q{ } x $lcol), @lines);
|
|
print "\n";
|
|
}
|
|
}
|
|
' "$PO_DIR"/*
|
|
echo
|
|
echo "Options and values after processing arguments:"
|
|
echo
|
|
(
|
|
cd "$PO_DIR"
|
|
for opt in *; do
|
|
local varname="OPT_$(echo "$opt" | tr a-z- A-Z_)"
|
|
eval local varvalue=\$$varname
|
|
if ! grep -q "type:" "$PO_DIR/$opt" >/dev/null; then
|
|
if [ "$varvalue" -a "$varvalue" = "yes" ];
|
|
then varvalue="TRUE"
|
|
else
|
|
varvalue="FALSE"
|
|
fi
|
|
fi
|
|
printf -- " --%-30s %s" "$opt" "${varvalue:-(No value)}"
|
|
echo
|
|
done
|
|
)
|
|
return 1
|
|
fi
|
|
|
|
if [ $OPT_ERRS -gt 0 ]; then
|
|
echo
|
|
usage "$file"
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
option_error() {
|
|
local err="$1"
|
|
OPT_ERRS=$(($OPT_ERRS + 1))
|
|
echo "$err" >&2
|
|
}
|
|
|
|
parse_options() {
|
|
local file="$1"
|
|
shift
|
|
|
|
ARGV=""
|
|
EXT_ARGV=""
|
|
HAVE_EXT_ARGV=""
|
|
OPT_ERRS=0
|
|
OPT_VERSION=""
|
|
OPT_HELP=""
|
|
OPT_ASK_PASS=""
|
|
PO_DIR="$PT_TMPDIR/po"
|
|
|
|
if [ ! -d "$PO_DIR" ]; then
|
|
mkdir "$PO_DIR"
|
|
if [ $? -ne 0 ]; then
|
|
echo "Cannot mkdir $PO_DIR" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
rm -rf "$PO_DIR"/*
|
|
if [ $? -ne 0 ]; then
|
|
echo "Cannot rm -rf $PO_DIR/*" >&2
|
|
exit 1
|
|
fi
|
|
|
|
_parse_pod "$file" # Parse POD into program option (po) spec files
|
|
_eval_po # Eval po into existence with default values
|
|
|
|
if [ $# -ge 2 ] && [ "$1" = "--config" ]; then
|
|
shift # --config
|
|
local user_config_files="$1"
|
|
shift # that ^
|
|
local IFS=","
|
|
for user_config_file in $user_config_files; do
|
|
_parse_config_files "$user_config_file"
|
|
done
|
|
else
|
|
GLOBAL_CONFIG=1
|
|
_parse_config_files "/etc/percona-toolkit/percona-toolkit.conf"
|
|
GLOBAL_CONFIG=0
|
|
_parse_config_files "/etc/percona-toolkit/$TOOL.conf"
|
|
if [ "${HOME:-}" ]; then
|
|
GLOBAL_CONFIG=1
|
|
_parse_config_files "$HOME/.percona-toolkit.conf"
|
|
GLOBAL_CONFIG=0
|
|
_parse_config_files "$HOME/.$TOOL.conf"
|
|
fi
|
|
fi
|
|
|
|
_parse_command_line "${@:-""}"
|
|
}
|
|
|
|
_parse_pod() {
|
|
local file="$1"
|
|
|
|
PO_FILE="$file" PO_DIR="$PO_DIR" perl -e '
|
|
$/ = "";
|
|
my $file = $ENV{PO_FILE};
|
|
open my $fh, "<", $file or die "Cannot open $file: $!";
|
|
while ( defined(my $para = <$fh>) ) {
|
|
next unless $para =~ m/^=head1 OPTIONS/;
|
|
while ( defined(my $para = <$fh>) ) {
|
|
last if $para =~ m/^=head1/;
|
|
chomp;
|
|
if ( $para =~ m/^=item --(\S+)/ ) {
|
|
my $opt = $1;
|
|
my $file = "$ENV{PO_DIR}/$opt";
|
|
open my $opt_fh, ">", $file or die "Cannot open $file: $!";
|
|
print $opt_fh "long:$opt\n";
|
|
$para = <$fh>;
|
|
chomp;
|
|
if ( $para =~ m/^[a-z ]+:/ ) {
|
|
map {
|
|
chomp;
|
|
my ($attrib, $val) = split(/: /, $_);
|
|
print $opt_fh "$attrib:$val\n";
|
|
} split(/; /, $para);
|
|
$para = <$fh>;
|
|
chomp;
|
|
}
|
|
my ($desc) = $para =~ m/^([^?.]+)/;
|
|
print $opt_fh "desc:$desc.\n";
|
|
close $opt_fh;
|
|
}
|
|
}
|
|
last;
|
|
}
|
|
'
|
|
}
|
|
|
|
_eval_po() {
|
|
local IFS=":"
|
|
for opt_spec in "$PO_DIR"/*; do
|
|
local opt=""
|
|
local default_val=""
|
|
local neg=0
|
|
local size=0
|
|
while read key val; do
|
|
case "$key" in
|
|
long)
|
|
opt=$(echo $val | sed 's/-/_/g' | tr '[:lower:]' '[:upper:]')
|
|
;;
|
|
default)
|
|
default_val="$val"
|
|
;;
|
|
"short form")
|
|
;;
|
|
type)
|
|
[ "$val" = "size" ] && size=1
|
|
;;
|
|
desc)
|
|
;;
|
|
negatable)
|
|
if [ "$val" = "yes" ]; then
|
|
neg=1
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Invalid attribute in $opt_spec: $line" >&2
|
|
exit 1
|
|
esac
|
|
done < "$opt_spec"
|
|
|
|
if [ -z "$opt" ]; then
|
|
echo "No long attribute in option spec $opt_spec" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ $neg -eq 1 ]; then
|
|
if [ -z "$default_val" ] || [ "$default_val" != "yes" ]; then
|
|
echo "Option $opt_spec is negatable but not default: yes" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ $size -eq 1 -a -n "$default_val" ]; then
|
|
default_val=$(size_to_bytes $default_val)
|
|
fi
|
|
|
|
eval "OPT_${opt}"="$default_val"
|
|
done
|
|
}
|
|
|
|
_parse_config_files() {
|
|
|
|
for config_file in "${@:-""}"; do
|
|
test -f "$config_file" || continue
|
|
|
|
while read config_opt; do
|
|
|
|
echo "$config_opt" | grep '^[ ]*[^#]' >/dev/null 2>&1 || continue
|
|
|
|
config_opt="$(echo "$config_opt" | sed -e 's/^ *//g' -e 's/ *$//g' -e 's/[ ]*=[ ]*/=/' -e 's/\s[ ]*#.*$//')"
|
|
|
|
[ "$config_opt" = "" ] && continue
|
|
|
|
echo "$config_opt" | grep -v 'version-check' >/dev/null 2>&1 || continue
|
|
|
|
if ! [ "$HAVE_EXT_ARGV" ]; then
|
|
config_opt="--$config_opt"
|
|
fi
|
|
|
|
_parse_command_line "$config_opt"
|
|
|
|
done < "$config_file"
|
|
|
|
HAVE_EXT_ARGV="" # reset for each file
|
|
|
|
done
|
|
}
|
|
|
|
_parse_command_line() {
|
|
local opt=""
|
|
local val=""
|
|
local next_opt_is_val=""
|
|
local opt_is_ok=""
|
|
local opt_is_negated=""
|
|
local real_opt=""
|
|
local required_arg=""
|
|
local spec=""
|
|
|
|
for opt in "${@:-""}"; do
|
|
if [ "$opt" = "--" -o "$opt" = "----" ]; then
|
|
HAVE_EXT_ARGV=1
|
|
continue
|
|
fi
|
|
if [ "$HAVE_EXT_ARGV" ]; then
|
|
if [ "$EXT_ARGV" ]; then
|
|
EXT_ARGV="$EXT_ARGV $opt"
|
|
else
|
|
EXT_ARGV="$opt"
|
|
fi
|
|
continue
|
|
fi
|
|
|
|
if [ "$next_opt_is_val" ]; then
|
|
next_opt_is_val=""
|
|
if [ $# -eq 0 ] || [ $(expr "$opt" : "\-") -eq 1 ]; then
|
|
option_error "$real_opt requires a $required_arg argument"
|
|
continue
|
|
fi
|
|
val="$opt"
|
|
opt_is_ok=1
|
|
else
|
|
if [ $(expr "$opt" : "\-") -eq 0 ]; then
|
|
if [ -z "$ARGV" ]; then
|
|
ARGV="$opt"
|
|
else
|
|
ARGV="$ARGV $opt"
|
|
fi
|
|
continue
|
|
fi
|
|
|
|
real_opt="$opt"
|
|
|
|
if $(echo $opt | grep '^--no[^-]' >/dev/null); then
|
|
local base_opt=$(echo $opt | sed 's/^--no//')
|
|
if [ -f "$PT_TMPDIR/po/$base_opt" ]; then
|
|
opt_is_negated=1
|
|
opt="$base_opt"
|
|
else
|
|
opt_is_negated=""
|
|
opt=$(echo $opt | sed 's/^-*//')
|
|
fi
|
|
else
|
|
if $(echo $opt | grep '^--no-' >/dev/null); then
|
|
opt_is_negated=1
|
|
opt=$(echo $opt | sed 's/^--no-//')
|
|
else
|
|
opt_is_negated=""
|
|
opt=$(echo $opt | sed 's/^-*//')
|
|
fi
|
|
fi
|
|
|
|
if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
|
|
val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')"
|
|
opt="$(echo $opt | awk -F= '{print $1}')"
|
|
fi
|
|
|
|
if [ -f "$PT_TMPDIR/po/$opt" ]; then
|
|
spec="$PT_TMPDIR/po/$opt"
|
|
else
|
|
spec=$(grep "^short form:-$opt\$" "$PT_TMPDIR"/po/* | cut -d ':' -f 1)
|
|
if [ -z "$spec" ]; then
|
|
if [ $GLOBAL_CONFIG -eq 1 ]; then
|
|
continue
|
|
else
|
|
option_error "Unknown option: $real_opt"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
required_arg=$(cat "$spec" | awk -F: '/^type:/{print $2}')
|
|
if [ "$required_arg" ]; then
|
|
if [ "$val" ]; then
|
|
opt_is_ok=1
|
|
else
|
|
next_opt_is_val=1
|
|
fi
|
|
else
|
|
if [ "$val" ]; then
|
|
option_error "Option $real_opt does not take a value"
|
|
continue
|
|
fi
|
|
if [ "$opt_is_negated" ]; then
|
|
val=""
|
|
else
|
|
val="yes"
|
|
fi
|
|
opt_is_ok=1
|
|
fi
|
|
fi
|
|
|
|
if [ "$opt_is_ok" ]; then
|
|
opt=$(cat "$spec" | grep '^long:' | cut -d':' -f2 | sed 's/-/_/g' | tr '[:lower:]' '[:upper:]')
|
|
|
|
if grep "^type:size" "$spec" >/dev/null; then
|
|
val=$(size_to_bytes $val)
|
|
fi
|
|
|
|
eval "OPT_$opt"='$val'
|
|
|
|
opt=""
|
|
val=""
|
|
next_opt_is_val=""
|
|
opt_is_ok=""
|
|
opt_is_negated=""
|
|
real_opt=""
|
|
required_arg=""
|
|
spec=""
|
|
fi
|
|
done
|
|
}
|
|
|
|
size_to_bytes() {
|
|
local size="$1"
|
|
echo $size | perl -ne '%f=(B=>1, K=>1_024, M=>1_048_576, G=>1_073_741_824, T=>1_099_511_627_776); m/^(\d+)([kMGT])?/i; print $1 * $f{uc($2 || "B")};'
|
|
}
|
|
|
|
# ###########################################################################
|
|
# End parse_options package
|
|
# ###########################################################################
|
|
|
|
# ###########################################################################
|
|
# tmpdir package
|
|
# This package is a copy without comments from the original. The original
|
|
# with comments and its test file can be found in the GitHub repository at,
|
|
# lib/bash/tmpdir.sh
|
|
# t/lib/bash/tmpdir.sh
|
|
# See https://github.com/percona/percona-toolkit for more information.
|
|
# ###########################################################################
|
|
|
|
|
|
set -u
|
|
|
|
PT_TMPDIR=""
|
|
|
|
mk_tmpdir() {
|
|
local dir="${1:-""}"
|
|
|
|
if [ -n "$dir" ]; then
|
|
if [ ! -d "$dir" ]; then
|
|
mkdir "$dir" || die "Cannot make tmpdir $dir"
|
|
fi
|
|
PT_TMPDIR="$dir"
|
|
else
|
|
local tool="${0##*/}"
|
|
local pid="$$"
|
|
PT_TMPDIR=`mktemp -d -t "${tool}.${pid}.XXXXXX"` \
|
|
|| die "Cannot make secure tmpdir"
|
|
fi
|
|
}
|
|
|
|
rm_tmpdir() {
|
|
if [ -n "$PT_TMPDIR" ] && [ -d "$PT_TMPDIR" ]; then
|
|
rm -rf "$PT_TMPDIR"
|
|
fi
|
|
PT_TMPDIR=""
|
|
}
|
|
|
|
# ###########################################################################
|
|
# End tmpdir package
|
|
# ###########################################################################
|
|
|
|
# ###########################################################################
|
|
# alt_cmds package
|
|
# This package is a copy without comments from the original. The original
|
|
# with comments and its test file can be found in the GitHub repository at,
|
|
# lib/bash/alt_cmds.sh
|
|
# t/lib/bash/alt_cmds.sh
|
|
# See https://github.com/percona/percona-toolkit for more information.
|
|
# ###########################################################################
|
|
|
|
|
|
set -u
|
|
|
|
_seq() {
|
|
local i="$1"
|
|
awk "BEGIN { for(i=1; i<=$i; i++) print i; }"
|
|
}
|
|
|
|
_pidof() {
|
|
local cmd="$1"
|
|
if ! pidof "$cmd" 2>/dev/null; then
|
|
ps -eo pid,ucomm | awk -v comm="$cmd" '$2 == comm { print $1 }'
|
|
fi
|
|
}
|
|
|
|
_lsof() {
|
|
local pid="$1"
|
|
if ! lsof -p $pid 2>/dev/null; then
|
|
/bin/ls -l /proc/$pid/fd 2>/dev/null
|
|
fi
|
|
}
|
|
|
|
|
|
|
|
_which() {
|
|
if [ -x /usr/bin/which ]; then
|
|
/usr/bin/which "$1" 2>/dev/null | awk '{print $1}'
|
|
elif which which 1>/dev/null 2>&1; then
|
|
which "$1" 2>/dev/null | awk '{print $1}'
|
|
else
|
|
echo "$1"
|
|
fi
|
|
}
|
|
|
|
# ###########################################################################
|
|
# End alt_cmds package
|
|
# ###########################################################################
|
|
|
|
# ###########################################################################
|
|
# summary_common package
|
|
# This package is a copy without comments from the original. The original
|
|
# with comments and its test file can be found in the GitHub repository at,
|
|
# lib/bash/summary_common.sh
|
|
# t/lib/bash/summary_common.sh
|
|
# See https://github.com/percona/percona-toolkit for more information.
|
|
# ###########################################################################
|
|
|
|
|
|
set -u
|
|
|
|
CMD_FILE="$( _which file 2>/dev/null )"
|
|
CMD_NM="$( _which nm 2>/dev/null )"
|
|
CMD_OBJDUMP="$( _which objdump 2>/dev/null )"
|
|
|
|
get_nice_of_pid () {
|
|
local pid="$1"
|
|
local niceness="$(ps -p $pid -o nice | awk '$1 !~ /[^0-9]/ {print $1; exit}')"
|
|
|
|
if [ -n "${niceness}" ]; then
|
|
echo $niceness
|
|
else
|
|
local tmpfile="$PT_TMPDIR/nice_through_c.tmp.c"
|
|
_d "Getting the niceness from ps failed, somehow. We are about to try this:"
|
|
cat <<EOC > "$tmpfile"
|
|
|
|
int main(void) {
|
|
int priority = getpriority(PRIO_PROCESS, $pid);
|
|
if ( priority == -1 && errno == ESRCH ) {
|
|
return 1;
|
|
}
|
|
else {
|
|
printf("%d\\n", priority);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
EOC
|
|
local c_comp=$(_which gcc)
|
|
if [ -z "${c_comp}" ]; then
|
|
c_comp=$(_which cc)
|
|
fi
|
|
_d "$tmpfile: $( cat "$tmpfile" )"
|
|
_d "$c_comp -xc \"$tmpfile\" -o \"$tmpfile\" && eval \"$tmpfile\""
|
|
$c_comp -xc "$tmpfile" -o "$tmpfile" 2>/dev/null && eval "$tmpfile" 2>/dev/null
|
|
if [ $? -ne 0 ]; then
|
|
echo "?"
|
|
_d "Failed to get a niceness value for $pid"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
get_oom_of_pid () {
|
|
local pid="$1"
|
|
local oom_adj=""
|
|
|
|
if [ -n "${pid}" -a -e /proc/cpuinfo ]; then
|
|
if [ -s "/proc/$pid/oom_score_adj" ]; then
|
|
oom_adj=$(cat "/proc/$pid/oom_score_adj" 2>/dev/null)
|
|
_d "For $pid, the oom value is $oom_adj, retrieved from oom_score_adj"
|
|
else
|
|
oom_adj=$(cat "/proc/$pid/oom_adj" 2>/dev/null)
|
|
_d "For $pid, the oom value is $oom_adj, retrieved from oom_adj"
|
|
fi
|
|
fi
|
|
|
|
if [ -n "${oom_adj}" ]; then
|
|
echo "${oom_adj}"
|
|
else
|
|
echo "?"
|
|
_d "Can't find the oom value for $pid"
|
|
fi
|
|
}
|
|
|
|
has_symbols () {
|
|
local executable="$(_which "$1")"
|
|
local has_symbols=""
|
|
|
|
if [ "${CMD_FILE}" ] \
|
|
&& [ "$($CMD_FILE "${executable}" | grep 'not stripped' )" ]; then
|
|
has_symbols=1
|
|
elif [ "${CMD_NM}" ] \
|
|
|| [ "${CMD_OBJDMP}" ]; then
|
|
if [ "${CMD_NM}" ] \
|
|
&& [ !"$("${CMD_NM}" -- "${executable}" 2>&1 | grep 'File format not recognized' )" ]; then
|
|
if [ -z "$( $CMD_NM -- "${executable}" 2>&1 | grep ': no symbols' )" ]; then
|
|
has_symbols=1
|
|
fi
|
|
elif [ -z "$("${CMD_OBJDUMP}" -t -- "${executable}" | grep '^no symbols$' )" ]; then
|
|
has_symbols=1
|
|
fi
|
|
fi
|
|
|
|
if [ "${has_symbols}" ]; then
|
|
echo "Yes"
|
|
else
|
|
echo "No"
|
|
fi
|
|
}
|
|
|
|
setup_data_dir () {
|
|
local existing_dir="$1"
|
|
local data_dir=""
|
|
if [ -z "$existing_dir" ]; then
|
|
mkdir "$PT_TMPDIR/data" || die "Cannot mkdir $PT_TMPDIR/data"
|
|
data_dir="$PT_TMPDIR/data"
|
|
else
|
|
if [ ! -d "$existing_dir" ]; then
|
|
mkdir "$existing_dir" || die "Cannot mkdir $existing_dir"
|
|
elif [ "$( ls -A "$existing_dir" )" ]; then
|
|
die "--save-samples directory isn't empty, halting."
|
|
fi
|
|
touch "$existing_dir/test" || die "Cannot write to $existing_dir"
|
|
rm "$existing_dir/test" || die "Cannot rm $existing_dir/test"
|
|
data_dir="$existing_dir"
|
|
fi
|
|
echo "$data_dir"
|
|
}
|
|
|
|
get_var () {
|
|
local varname="$1"
|
|
local file="$2"
|
|
awk -v pattern="${varname}" '$1 == pattern { if (length($2)) { len = length($1); print substr($0, len+index(substr($0, len+1), $2)) } }' "${file}"
|
|
}
|
|
|
|
# ###########################################################################
|
|
# End summary_common package
|
|
# ###########################################################################
|
|
|
|
# ###########################################################################
|
|
# report_formatting package
|
|
# This package is a copy without comments from the original. The original
|
|
# with comments and its test file can be found in the GitHub repository at,
|
|
# lib/bash/report_formatting.sh
|
|
# t/lib/bash/report_formatting.sh
|
|
# See https://github.com/percona/percona-toolkit for more information.
|
|
# ###########################################################################
|
|
|
|
|
|
set -u
|
|
|
|
POSIXLY_CORRECT=1
|
|
export POSIXLY_CORRECT
|
|
|
|
fuzzy_formula='
|
|
rounded = 0;
|
|
if (fuzzy_var <= 10 ) {
|
|
rounded = 1;
|
|
}
|
|
factor = 1;
|
|
while ( rounded == 0 ) {
|
|
if ( fuzzy_var <= 50 * factor ) {
|
|
fuzzy_var = sprintf("%.0f", fuzzy_var / (5 * factor)) * 5 * factor;
|
|
rounded = 1;
|
|
}
|
|
else if ( fuzzy_var <= 100 * factor) {
|
|
fuzzy_var = sprintf("%.0f", fuzzy_var / (10 * factor)) * 10 * factor;
|
|
rounded = 1;
|
|
}
|
|
else if ( fuzzy_var <= 250 * factor) {
|
|
fuzzy_var = sprintf("%.0f", fuzzy_var / (25 * factor)) * 25 * factor;
|
|
rounded = 1;
|
|
}
|
|
factor = factor * 10;
|
|
}'
|
|
|
|
fuzz () {
|
|
awk -v fuzzy_var="$1" "BEGIN { ${fuzzy_formula} print fuzzy_var;}"
|
|
}
|
|
|
|
fuzzy_pct () {
|
|
local pct="$(awk -v one="$1" -v two="$2" 'BEGIN{ if (two > 0) { printf "%d", one/two*100; } else {print 0} }')";
|
|
echo "$(fuzz "${pct}")%"
|
|
}
|
|
|
|
section () {
|
|
local str="$1"
|
|
awk -v var="${str} _" 'BEGIN {
|
|
line = sprintf("# %-60s", var);
|
|
i = index(line, "_");
|
|
x = substr(line, i);
|
|
gsub(/[_ \t]/, "#", x);
|
|
printf("%s%s\n", substr(line, 1, i-1), x);
|
|
}'
|
|
}
|
|
|
|
NAME_VAL_LEN=12
|
|
name_val() {
|
|
printf "%+*s | %s\n" "${NAME_VAL_LEN}" "$1" "$2"
|
|
}
|
|
|
|
shorten() {
|
|
local num="$1"
|
|
local prec="${2:-2}"
|
|
local div="${3:-1024}"
|
|
|
|
echo "$num" | awk -v prec="$prec" -v div="$div" '
|
|
{
|
|
num = $1;
|
|
unit = num >= 1125899906842624 ? "P" \
|
|
: num >= 1099511627776 ? "T" \
|
|
: num >= 1073741824 ? "G" \
|
|
: num >= 1048576 ? "M" \
|
|
: num >= 1024 ? "k" \
|
|
: "";
|
|
while ( num >= div ) {
|
|
num /= div;
|
|
}
|
|
printf "%.*f%s", prec, num, unit;
|
|
}
|
|
'
|
|
}
|
|
|
|
group_concat() {
|
|
sed -e '{H; $!d;}' -e 'x' -e 's/\n[[:space:]]*\([[:digit:]]*\)[[:space:]]*/, \1x/g' -e 's/[[:space:]][[:space:]]*/ /g' -e 's/, //' "${1}"
|
|
}
|
|
|
|
# ###########################################################################
|
|
# End report_formatting package
|
|
# ###########################################################################
|
|
|
|
# ###########################################################################
|
|
# collect_system_info package
|
|
# This package is a copy without comments from the original. The original
|
|
# with comments and its test file can be found in the GitHub repository at,
|
|
# lib/bash/collect_system_info.sh
|
|
# t/lib/bash/collect_system_info.sh
|
|
# See https://github.com/percona/percona-toolkit for more information.
|
|
# ###########################################################################
|
|
|
|
|
|
|
|
set -u
|
|
|
|
setup_commands () {
|
|
CMD_SYSCTL="$(_which sysctl 2>/dev/null )"
|
|
CMD_DMIDECODE="$(_which dmidecode 2>/dev/null )"
|
|
CMD_ZONENAME="$(_which zonename 2>/dev/null )"
|
|
CMD_DMESG="$(_which dmesg 2>/dev/null )"
|
|
CMD_FILE="$(_which file 2>/dev/null )"
|
|
CMD_LSPCI="$(_which lspci 2>/dev/null )"
|
|
CMD_PRTDIAG="$(_which prtdiag 2>/dev/null )"
|
|
CMD_SMBIOS="$(_which smbios 2>/dev/null )"
|
|
CMD_GETENFORCE="$(_which getenforce 2>/dev/null )"
|
|
CMD_PRTCONF="$(_which prtconf 2>/dev/null )"
|
|
CMD_LVS="$(_which lvs 2>/dev/null)"
|
|
CMD_VGS="$(_which vgs 2>/dev/null)"
|
|
CMD_PRSTAT="$(_which prstat 2>/dev/null)"
|
|
CMD_ISAINFO="$(_which isainfo 2>/dev/null)"
|
|
CMD_TOP="$(_which top 2>/dev/null)"
|
|
CMD_ARCCONF="$( _which arcconf 2>/dev/null )"
|
|
CMD_HPACUCLI="$( _which hpacucli 2>/dev/null )"
|
|
CMD_MEGACLI64="$( _which MegaCli64 2>/dev/null )"
|
|
CMD_VMSTAT="$(_which vmstat 2>/dev/null)"
|
|
CMD_IP="$( _which ip 2>/dev/null )"
|
|
CMD_NETSTAT="$( _which netstat 2>/dev/null )"
|
|
CMD_PSRINFO="$( _which psrinfo 2>/dev/null )"
|
|
CMD_SWAPCTL="$( _which swapctl 2>/dev/null )"
|
|
CMD_LSB_RELEASE="$( _which lsb_release 2>/dev/null )"
|
|
CMD_ETHTOOL="$( _which ethtool 2>/dev/null )"
|
|
CMD_GETCONF="$( _which getconf 2>/dev/null )"
|
|
CMD_FIO_STATUS="$( _which fio-status 2>/dev/null )"
|
|
}
|
|
|
|
collect_system_data () { local PTFUNCNAME=collect_system_data;
|
|
local data_dir="$1"
|
|
|
|
if [ -r /var/log/dmesg -a -s /var/log/dmesg ]; then
|
|
cat "/var/log/dmesg" > "$data_dir/dmesg_file"
|
|
fi
|
|
|
|
$CMD_SYSCTL -a > "$data_dir/sysctl" 2>/dev/null
|
|
|
|
if [ "${CMD_LSPCI}" ]; then
|
|
$CMD_LSPCI > "$data_dir/lspci_file" 2>/dev/null
|
|
fi
|
|
|
|
local platform="$(uname -s)"
|
|
echo "platform $platform" >> "$data_dir/summary"
|
|
echo "hostname $(uname -n)" >> "$data_dir/summary"
|
|
uptime >> "$data_dir/uptime"
|
|
|
|
processor_info "$data_dir"
|
|
find_release_and_kernel "$platform" >> "$data_dir/summary"
|
|
cpu_and_os_arch "$platform" >> "$data_dir/summary"
|
|
find_virtualization "$platform" "$data_dir/dmesg_file" "$data_dir/lspci_file" >> "$data_dir/summary"
|
|
dmidecode_system_info >> "$data_dir/summary"
|
|
|
|
if [ "${platform}" = "SunOS" -a "${CMD_ZONENAME}" ]; then
|
|
echo "zonename $($CMD_ZONENAME)" >> "$data_dir/summary"
|
|
fi
|
|
|
|
if [ -x /lib/libc.so.6 ]; then
|
|
echo "compiler $(/lib/libc.so.6 | grep 'Compiled by' | cut -c13-)" >> "$data_dir/summary"
|
|
fi
|
|
|
|
local rss=$(ps -eo rss 2>/dev/null | awk '/[0-9]/{total += $1 * 1024} END {print total}')
|
|
echo "rss ${rss}" >> "$data_dir/summary"
|
|
|
|
[ "$CMD_DMIDECODE" ] && $CMD_DMIDECODE > "$data_dir/dmidecode" 2>/dev/null
|
|
|
|
find_memory_stats "$platform" > "$data_dir/memory"
|
|
find_numa_stats > "$data_dir/numactl"
|
|
[ "$OPT_SUMMARIZE_MOUNTS" ] && mounted_fs_info "$platform" > "$data_dir/mounted_fs"
|
|
raid_controller "$data_dir/dmesg_file" "$data_dir/lspci_file" >> "$data_dir/summary"
|
|
|
|
local controller="$(get_var raid_controller "$data_dir/summary")"
|
|
proprietary_raid_controller "$data_dir/raid-controller" "$data_dir/summary" "$data_dir" "$controller"
|
|
|
|
[ "${platform}" = "Linux" ] && linux_exclusive_collection "$data_dir"
|
|
|
|
if [ "$CMD_IP" -a "$OPT_SUMMARIZE_NETWORK" ]; then
|
|
$CMD_IP -s link > "$data_dir/ip"
|
|
network_device_info "$data_dir/ip" > "$data_dir/network_devices"
|
|
fi
|
|
|
|
[ "$CMD_SWAPCTL" ] && $CMD_SWAPCTL -s > "$data_dir/swapctl"
|
|
|
|
if [ "$OPT_SUMMARIZE_PROCESSES" ]; then
|
|
top_processes > "$data_dir/processes"
|
|
notable_processes_info > "$data_dir/notable_procs"
|
|
|
|
if [ "$CMD_VMSTAT" ]; then
|
|
touch "$data_dir/vmstat"
|
|
(
|
|
$CMD_VMSTAT 1 $OPT_SLEEP > "$data_dir/vmstat"
|
|
) &
|
|
fi
|
|
fi
|
|
|
|
fio_status_minus_a "$data_dir/fusion-io_card"
|
|
|
|
cat /sys/kernel/mm/transparent_hugepage/enabled >"$data_dir/transparent_hugepage" 2>/dev/null
|
|
|
|
for file in $data_dir/*; do
|
|
[ "$file" = "vmstat" ] && continue
|
|
[ ! -s "$file" ] && rm "$file"
|
|
done
|
|
}
|
|
|
|
fio_status_minus_a () {
|
|
local file="$1"
|
|
local full_output="${file}_original_output"
|
|
[ -z "$CMD_FIO_STATUS" ] && return;
|
|
$CMD_FIO_STATUS -a > "$full_output"
|
|
|
|
cat <<'EOP' > "$PT_TMPDIR/fio_status_format.pl"
|
|
my $tmp_adapter;
|
|
while (<>) {
|
|
if ( /Fusion-io driver version:\s*(.+)/ ) {
|
|
print "driver_version $1"
|
|
}
|
|
next unless /^Adapter:(.+)/;
|
|
$tmp_adapter = $1;
|
|
last;
|
|
}
|
|
|
|
$/ = "\nAdapter: ";
|
|
$_ = $tmp_adapter . "\n" . scalar(<>);
|
|
my @adapters;
|
|
do {
|
|
my ($adapter, $adapter_general) = /\s*(.+)\s*\n\s*(.+)/m;
|
|
$adapter =~ tr/ /:/;
|
|
$adapter .= "::" . scalar(@adapters); # To differentiate two adapters with the same name
|
|
push @adapters, $adapter;
|
|
my ($connected_modules) = /Connected \S+ modules?:\s*\n(.+?\n)\n/smg;
|
|
my @connected_modules = $connected_modules =~ /\s+([^:]+):.+\n/g;
|
|
|
|
print "${adapter}_general $adapter_general";
|
|
print "${adapter}_modules @connected_modules";
|
|
|
|
for my $module (@connected_modules) {
|
|
my ($rest, $attached, $general, $firmware, $temperature, $media_status) = /(
|
|
^ \s* $module \s+ (Attached[^\n]+) \n
|
|
\s+ ([^\n]+) \n # All the second line
|
|
.+? (Firmware\s+[^\n]+) \n
|
|
.+? (Internal \s+ temperature:[^\n]+) \n
|
|
.+? ((?:Media | Reserve \s+ space) \s+ status:[^\n]+) \n
|
|
.+?(?:\n\n|\z)
|
|
)/xsm;
|
|
my ($pbw) = $rest =~ /.+?(Rated \s+ PBW:[^\n]+)/xsm;
|
|
print "${adapter}_${module}_attached_as $attached";
|
|
print "${adapter}_${module}_general $general";
|
|
print "${adapter}_${module}_firmware $firmware";
|
|
print "${adapter}_${module}_media_status $media_status";
|
|
print "${adapter}_${module}_temperature $temperature";
|
|
print "${adapter}_${module}_rated_pbw $pbw" if $pbw;
|
|
}
|
|
} while <>;
|
|
|
|
print "adapters @adapters\n";
|
|
|
|
exit;
|
|
EOP
|
|
|
|
perl -wln "$PT_TMPDIR/fio_status_format.pl" "$full_output" > "$file"
|
|
}
|
|
|
|
linux_exclusive_collection () { local PTFUNCNAME=linux_exclusive_collection;
|
|
local data_dir="$1"
|
|
|
|
echo "threading $(getconf GNU_LIBPTHREAD_VERSION)" >> "$data_dir/summary"
|
|
|
|
local getenforce=""
|
|
[ "$CMD_GETENFORCE" ] && getenforce="$($CMD_GETENFORCE 2>&1)"
|
|
echo "getenforce ${getenforce:-"No SELinux detected"}" >> "$data_dir/summary"
|
|
|
|
if [ -e "$data_dir/sysctl" ]; then
|
|
echo "swappiness $(awk '/vm.swappiness/{print $3}' "$data_dir/sysctl")" >> "$data_dir/summary"
|
|
|
|
local dirty_ratio="$(awk '/vm.dirty_ratio/{print $3}' "$data_dir/sysctl")"
|
|
local dirty_bg_ratio="$(awk '/vm.dirty_background_ratio/{print $3}' "$data_dir/sysctl")"
|
|
if [ "$dirty_ratio" -a "$dirty_bg_ratio" ]; then
|
|
echo "dirtypolicy $dirty_ratio, $dirty_bg_ratio" >> "$data_dir/summary"
|
|
fi
|
|
|
|
local dirty_bytes="$(awk '/vm.dirty_bytes/{print $3}' "$data_dir/sysctl")"
|
|
if [ "$dirty_bytes" ]; then
|
|
echo "dirtystatus $(awk '/vm.dirty_bytes/{print $3}' "$data_dir/sysctl"), $(awk '/vm.dirty_background_bytes/{print $3}' "$data_dir/sysctl")" >> "$data_dir/summary"
|
|
fi
|
|
fi
|
|
|
|
if [ -e "$data_dir/numactl" ]; then
|
|
echo "numa-available $(awk '/available/{print $2}' "$data_dir/numactl")" >> "$data_dir/summary"
|
|
echo "numa-policy $(awk '/policy/{print $2}' "$data_dir/numactl")" >> "$data_dir/summary"
|
|
echo "numa-preferred-node $(awk '/preferred node/{print $3}' "$data_dir/numactl")" >> "$data_dir/summary"
|
|
fi
|
|
|
|
schedulers_and_queue_size "$data_dir/summary" > "$data_dir/partitioning"
|
|
|
|
for file in dentry-state file-nr inode-nr; do
|
|
echo "${file} $(cat /proc/sys/fs/${file} 2>&1)" >> "$data_dir/summary"
|
|
done
|
|
|
|
[ "$CMD_LVS" -a -x "$CMD_LVS" ] && $CMD_LVS 1>"$data_dir/lvs" 2>"$data_dir/lvs.stderr"
|
|
|
|
[ "$CMD_VGS" -a -x "$CMD_VGS" ] && \
|
|
$CMD_VGS -o vg_name,vg_size,vg_free 2>/dev/null > "$data_dir/vgs"
|
|
|
|
[ "$CMD_NETSTAT" -a "$OPT_SUMMARIZE_NETWORK" ] && \
|
|
$CMD_NETSTAT -antp > "$data_dir/netstat" 2>/dev/null
|
|
}
|
|
|
|
network_device_info () {
|
|
local ip_minus_s_file="$1"
|
|
|
|
if [ "$CMD_ETHTOOL" ]; then
|
|
local tempfile="$PT_TMPDIR/ethtool_output_temp"
|
|
for device in $( awk '/^[1-9]/{ print $2 }' "$ip_minus_s_file" \
|
|
| awk -F: '{print $1}' \
|
|
| grep -v '^lo\|^in\|^gr' \
|
|
| sort -u ); do
|
|
ethtool $device > "$tempfile" 2>/dev/null
|
|
|
|
if ! grep -q 'No data available' "$tempfile"; then
|
|
cat "$tempfile"
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
find_release_and_kernel () { local PTFUNCNAME=find_release_and_kernel;
|
|
local platform="$1"
|
|
|
|
local kernel=""
|
|
local release=""
|
|
if [ "${platform}" = "Linux" ]; then
|
|
kernel="$(uname -r)"
|
|
if [ -e /etc/fedora-release ]; then
|
|
release=$(cat /etc/fedora-release);
|
|
elif [ -e /etc/redhat-release ]; then
|
|
release=$(cat /etc/redhat-release);
|
|
elif [ -e /etc/system-release ]; then
|
|
release=$(cat /etc/system-release);
|
|
elif [ "$CMD_LSB_RELEASE" ]; then
|
|
release="$($CMD_LSB_RELEASE -ds) ($($CMD_LSB_RELEASE -cs))"
|
|
elif [ -e /etc/lsb-release ]; then
|
|
release=$(grep DISTRIB_DESCRIPTION /etc/lsb-release |awk -F'=' '{print $2}' |sed 's#"##g');
|
|
elif [ -e /etc/debian_version ]; then
|
|
release="Debian-based version $(cat /etc/debian_version)";
|
|
if [ -e /etc/apt/sources.list ]; then
|
|
local code=` awk '/^deb/ {print $3}' /etc/apt/sources.list \
|
|
| awk -F/ '{print $1}'| awk 'BEGIN {FS="|"}{print $1}' \
|
|
| sort | uniq -c | sort -rn | head -n1 | awk '{print $2}'`
|
|
release="${release} (${code})"
|
|
fi
|
|
elif ls /etc/*release >/dev/null 2>&1; then
|
|
if grep -q DISTRIB_DESCRIPTION /etc/*release; then
|
|
release=$(grep DISTRIB_DESCRIPTION /etc/*release | head -n1);
|
|
else
|
|
release=$(cat /etc/*release | head -n1);
|
|
fi
|
|
fi
|
|
elif [ "${platform}" = "FreeBSD" ] \
|
|
|| [ "${platform}" = "NetBSD" ] \
|
|
|| [ "${platform}" = "OpenBSD" ]; then
|
|
release="$(uname -r)"
|
|
kernel="$($CMD_SYSCTL -n "kern.osrevision")"
|
|
elif [ "${platform}" = "SunOS" ]; then
|
|
release="$(head -n1 /etc/release)"
|
|
if [ -z "${release}" ]; then
|
|
release="$(uname -r)"
|
|
fi
|
|
kernel="$(uname -v)"
|
|
fi
|
|
echo "kernel $kernel"
|
|
echo "release $release"
|
|
}
|
|
|
|
cpu_and_os_arch () { local PTFUNCNAME=cpu_and_os_arch;
|
|
local platform="$1"
|
|
|
|
local CPU_ARCH='32-bit'
|
|
local OS_ARCH='32-bit'
|
|
if [ "${platform}" = "Linux" ]; then
|
|
if grep -q ' lm ' /proc/cpuinfo; then
|
|
CPU_ARCH='64-bit'
|
|
fi
|
|
elif [ "${platform}" = "FreeBSD" ] || [ "${platform}" = "NetBSD" ]; then
|
|
if $CMD_SYSCTL "hw.machine_arch" | grep -v 'i[36]86' >/dev/null; then
|
|
CPU_ARCH='64-bit'
|
|
fi
|
|
elif [ "${platform}" = "OpenBSD" ]; then
|
|
if $CMD_SYSCTL "hw.machine" | grep -v 'i[36]86' >/dev/null; then
|
|
CPU_ARCH='64-bit'
|
|
fi
|
|
elif [ "${platform}" = "SunOS" ]; then
|
|
if $CMD_ISAINFO -b | grep 64 >/dev/null ; then
|
|
CPU_ARCH="64-bit"
|
|
fi
|
|
fi
|
|
if [ -z "$CMD_FILE" ]; then
|
|
if [ "$CMD_GETCONF" ] && $CMD_GETCONF LONG_BIT 1>/dev/null 2>&1; then
|
|
OS_ARCH="$($CMD_GETCONF LONG_BIT 2>/dev/null)-bit"
|
|
else
|
|
OS_ARCH='N/A'
|
|
fi
|
|
elif $CMD_FILE /bin/sh | grep '64-bit' >/dev/null; then
|
|
OS_ARCH='64-bit'
|
|
fi
|
|
|
|
echo "CPU_ARCH $CPU_ARCH"
|
|
echo "OS_ARCH $OS_ARCH"
|
|
}
|
|
|
|
find_virtualization () { local PTFUNCNAME=find_virtualization;
|
|
local platform="$1"
|
|
local dmesg_file="$2"
|
|
local lspci_file="$3"
|
|
|
|
local tempfile="$PT_TMPDIR/find_virtualziation.tmp"
|
|
|
|
local virt=""
|
|
if [ -s "$dmesg_file" ]; then
|
|
virt="$(find_virtualization_dmesg "$dmesg_file")"
|
|
fi
|
|
if [ -z "${virt}" ] && [ -s "$lspci_file" ]; then
|
|
if grep -qi "virtualbox" "$lspci_file" ; then
|
|
virt="VirtualBox"
|
|
elif grep -qi "vmware" "$lspci_file" ; then
|
|
virt="VMWare"
|
|
fi
|
|
elif [ "${platform}" = "FreeBSD" ]; then
|
|
if ps -o stat | grep J ; then
|
|
virt="FreeBSD Jail"
|
|
fi
|
|
elif [ "${platform}" = "SunOS" ]; then
|
|
if [ "$CMD_PRTDIAG" ] && $CMD_PRTDIAG > "$tempfile" 2>/dev/null; then
|
|
virt="$(find_virtualization_generic "$tempfile" )"
|
|
elif [ "$CMD_SMBIOS" ] && $CMD_SMBIOS > "$tempfile" 2>/dev/null; then
|
|
virt="$(find_virtualization_generic "$tempfile" )"
|
|
fi
|
|
elif [ -e /proc/user_beancounters ]; then
|
|
virt="OpenVZ/Virtuozzo"
|
|
fi
|
|
echo "virt ${virt:-"No virtualization detected"}"
|
|
}
|
|
|
|
find_virtualization_generic() { local PTFUNCNAME=find_virtualization_generic;
|
|
local file="$1"
|
|
if grep -i -e "virtualbox" "$file" >/dev/null; then
|
|
echo "VirtualBox"
|
|
elif grep -i -e "vmware" "$file" >/dev/null; then
|
|
echo "VMWare"
|
|
fi
|
|
}
|
|
|
|
find_virtualization_dmesg () { local PTFUNCNAME=find_virtualization_dmesg;
|
|
local file="$1"
|
|
if grep -qi -e "vmware" -e "vmxnet" -e 'paravirtualized kernel on vmi' "${file}"; then
|
|
echo "VMWare";
|
|
elif grep -qi -e 'paravirtualized kernel on xen' -e 'Xen virtual console' "${file}"; then
|
|
echo "Xen";
|
|
elif grep -qi "qemu" "${file}"; then
|
|
echo "QEmu";
|
|
elif grep -qi 'paravirtualized kernel on KVM' "${file}"; then
|
|
echo "KVM";
|
|
elif grep -q "VBOX" "${file}"; then
|
|
echo "VirtualBox";
|
|
elif grep -qi 'hd.: Virtual .., ATA.*drive' "${file}"; then
|
|
echo "Microsoft VirtualPC";
|
|
fi
|
|
}
|
|
|
|
dmidecode_system_info () { local PTFUNCNAME=dmidecode_system_info;
|
|
if [ "${CMD_DMIDECODE}" ]; then
|
|
local vendor="$($CMD_DMIDECODE -s "system-manufacturer" 2>/dev/null | sed 's/ *$//g')"
|
|
echo "vendor ${vendor}"
|
|
if [ "${vendor}" ]; then
|
|
local product="$($CMD_DMIDECODE -s "system-product-name" 2>/dev/null | sed 's/ *$//g')"
|
|
local version="$($CMD_DMIDECODE -s "system-version" 2>/dev/null | sed 's/ *$//g')"
|
|
local chassis="$($CMD_DMIDECODE -s "chassis-type" 2>/dev/null | sed 's/ *$//g')"
|
|
local servicetag="$($CMD_DMIDECODE -s "system-serial-number" 2>/dev/null | sed 's/ *$//g')"
|
|
local system="${vendor}; ${product}; v${version} (${chassis})"
|
|
|
|
echo "system ${system}"
|
|
echo "servicetag ${servicetag:-"Not found"}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
find_memory_stats () { local PTFUNCNAME=find_memory_stats;
|
|
local platform="$1"
|
|
|
|
if [ "${platform}" = "Linux" ]; then
|
|
free -b
|
|
cat /proc/meminfo
|
|
elif [ "${platform}" = "SunOS" ]; then
|
|
$CMD_PRTCONF | awk -F: '/Memory/{print $2}'
|
|
fi
|
|
}
|
|
|
|
find_numa_stats () { local PTFUNCNAME=find_numa_stats;
|
|
if command -v numactl >/dev/null; then
|
|
numactl --hardware
|
|
numactl --show
|
|
fi
|
|
}
|
|
|
|
mounted_fs_info () { local PTFUNCNAME=mounted_fs_info;
|
|
local platform="$1"
|
|
|
|
if [ "${platform}" != "SunOS" ]; then
|
|
local cmd="df -h"
|
|
if [ "${platform}" = "Linux" ]; then
|
|
cmd="df -h -P"
|
|
fi
|
|
$cmd | sort > "$PT_TMPDIR/mounted_fs_info.tmp"
|
|
mount | sort | join "$PT_TMPDIR/mounted_fs_info.tmp" -
|
|
fi
|
|
}
|
|
|
|
raid_controller () { local PTFUNCNAME=raid_controller;
|
|
local dmesg_file="$1"
|
|
local lspci_file="$2"
|
|
|
|
local tempfile="$PT_TMPDIR/raid_controller.tmp"
|
|
|
|
local controller=""
|
|
if [ -s "$lspci_file" ]; then
|
|
controller="$(find_raid_controller_lspci "$lspci_file")"
|
|
fi
|
|
if [ -z "${controller}" ] && [ -s "$dmesg_file" ]; then
|
|
controller="$(find_raid_controller_dmesg "$dmesg_file")"
|
|
fi
|
|
|
|
echo "raid_controller ${controller:-"No RAID controller detected"}"
|
|
}
|
|
|
|
find_raid_controller_dmesg () { local PTFUNCNAME=find_raid_controller_dmesg;
|
|
local file="$1"
|
|
local pat='scsi[0-9].*: .*'
|
|
if grep -qi "${pat}megaraid" "${file}"; then
|
|
echo 'LSI Logic MegaRAID SAS'
|
|
elif grep -q "Fusion MPT SAS" "${file}"; then
|
|
echo 'Fusion-MPT SAS'
|
|
elif grep -q "${pat}aacraid" "${file}"; then
|
|
echo 'AACRAID'
|
|
elif grep -q "${pat}3ware [0-9]* Storage Controller" "${file}"; then
|
|
echo '3Ware'
|
|
fi
|
|
}
|
|
|
|
find_raid_controller_lspci () { local PTFUNCNAME=find_raid_controller_lspci;
|
|
local file="$1"
|
|
if grep -q "RAID bus controller: LSI Logic / Symbios Logic MegaRAID SAS" "${file}" \
|
|
|| grep -q "RAID bus controller: LSI Logic / Symbios Logic LSI MegaSAS" $file; then
|
|
echo 'LSI Logic MegaRAID SAS'
|
|
elif grep -q "Fusion-MPT SAS" "${file}"; then
|
|
echo 'Fusion-MPT SAS'
|
|
elif grep -q "RAID bus controller: LSI Logic / Symbios Logic Unknown" "${file}"; then
|
|
echo 'LSI Logic Unknown'
|
|
elif grep -q "RAID bus controller: Adaptec AAC-RAID" "${file}"; then
|
|
echo 'AACRAID'
|
|
elif grep -q "3ware [0-9]* Storage Controller" "${file}"; then
|
|
echo '3Ware'
|
|
elif grep -q "Hewlett-Packard Company Smart Array" "${file}"; then
|
|
echo 'HP Smart Array'
|
|
elif grep -q " RAID bus controller: " "${file}"; then
|
|
awk -F: '/RAID bus controller\:/ {print $3" "$5" "$6}' "${file}"
|
|
fi
|
|
}
|
|
|
|
schedulers_and_queue_size () { local PTFUNCNAME=schedulers_and_queue_size;
|
|
local file="$1"
|
|
|
|
local disks="$(ls /sys/block/ | grep -v -e ram -e loop -e 'fd[0-9]' | xargs echo)"
|
|
echo "internal::disks $disks" >> "$file"
|
|
|
|
for disk in $disks; do
|
|
if [ -e "/sys/block/${disk}/queue/scheduler" ]; then
|
|
echo "internal::${disk} $(cat /sys/block/${disk}/queue/scheduler | grep -o '\[.*\]') $(cat /sys/block/${disk}/queue/nr_requests)" >> "$file"
|
|
fdisk -l "/dev/${disk}" 2>/dev/null
|
|
fi
|
|
done
|
|
}
|
|
|
|
top_processes () { local PTFUNCNAME=top_processes;
|
|
if [ "$CMD_PRSTAT" ]; then
|
|
$CMD_PRSTAT | head
|
|
elif [ "$CMD_TOP" ]; then
|
|
local cmd="$CMD_TOP -bn 1"
|
|
if [ "${platform}" = "FreeBSD" ] \
|
|
|| [ "${platform}" = "NetBSD" ] \
|
|
|| [ "${platform}" = "OpenBSD" ]; then
|
|
cmd="$CMD_TOP -b -d 1"
|
|
fi
|
|
$cmd \
|
|
| sed -e 's# *$##g' -e '/./{H;$!d;}' -e 'x;/PID/!d;' \
|
|
| grep . \
|
|
| head
|
|
fi
|
|
}
|
|
|
|
notable_processes_info () { local PTFUNCNAME=notable_processes_info;
|
|
local format="%5s %+2d %s\n"
|
|
local sshd_pid=$(ps -eo pid,args | awk '$2 ~ /\/usr\/sbin\/sshd/ { print $1; exit }')
|
|
|
|
echo " PID OOM COMMAND"
|
|
|
|
if [ "$sshd_pid" ]; then
|
|
printf "$format" "$sshd_pid" "$(get_oom_of_pid $sshd_pid)" "sshd"
|
|
else
|
|
printf "%5s %3s %s\n" "?" "?" "sshd doesn't appear to be running"
|
|
fi
|
|
|
|
local PTDEBUG=""
|
|
ps -eo pid,ucomm | grep '^[0-9]' | while read pid proc; do
|
|
[ "$sshd_pid" ] && [ "$sshd_pid" = "$pid" ] && continue
|
|
local oom="$(get_oom_of_pid $pid)"
|
|
if [ "$oom" ] && [ "$oom" != "?" ] && [ "$oom" = "-17" ]; then
|
|
printf "$format" "$pid" "$oom" "$proc"
|
|
fi
|
|
done
|
|
}
|
|
|
|
processor_info () { local PTFUNCNAME=processor_info;
|
|
local data_dir="$1"
|
|
if [ -f /proc/cpuinfo ]; then
|
|
cat /proc/cpuinfo > "$data_dir/proc_cpuinfo_copy" 2>/dev/null
|
|
elif [ "${platform}" = "SunOS" ]; then
|
|
$CMD_PSRINFO -v > "$data_dir/psrinfo_minus_v"
|
|
fi
|
|
}
|
|
|
|
proprietary_raid_controller () { local PTFUNCNAME=proprietary_raid_controller;
|
|
local file="$1"
|
|
local variable_file="$2"
|
|
local data_dir="$3"
|
|
local controller="$4"
|
|
|
|
notfound=""
|
|
if [ "${controller}" = "AACRAID" ]; then
|
|
if [ -z "$CMD_ARCCONF" ]; then
|
|
notfound="e.g. http://www.adaptec.com/en-US/support/raid/scsi_raid/ASR-2120S/"
|
|
elif $CMD_ARCCONF getconfig 1 > "$file" 2>/dev/null; then
|
|
echo "internal::raid_opt 1" >> "$variable_file"
|
|
fi
|
|
elif [ "${controller}" = "HP Smart Array" ]; then
|
|
if [ -z "$CMD_HPACUCLI" ]; then
|
|
notfound="your package repository or the manufacturer's website"
|
|
elif $CMD_HPACUCLI ctrl all show config > "$file" 2>/dev/null; then
|
|
echo "internal::raid_opt 2" >> "$variable_file"
|
|
fi
|
|
elif [ "${controller}" = "LSI Logic MegaRAID SAS" ]; then
|
|
if [ -z "$CMD_MEGACLI64" ]; then
|
|
notfound="your package repository or the manufacturer's website"
|
|
else
|
|
echo "internal::raid_opt 3" >> "$variable_file"
|
|
$CMD_MEGACLI64 -AdpAllInfo -aALL -NoLog > "$data_dir/lsi_megaraid_adapter_info.tmp" 2>/dev/null
|
|
$CMD_MEGACLI64 -AdpBbuCmd -GetBbuStatus -aALL -NoLog > "$data_dir/lsi_megaraid_bbu_status.tmp" 2>/dev/null
|
|
$CMD_MEGACLI64 -LdPdInfo -aALL -NoLog > "$data_dir/lsi_megaraid_devices.tmp" 2>/dev/null
|
|
fi
|
|
fi
|
|
|
|
if [ "${notfound}" ]; then
|
|
echo "internal::raid_opt 0" >> "$variable_file"
|
|
echo " RAID controller software not found; try getting it from" > "$file"
|
|
echo " ${notfound}" >> "$file"
|
|
fi
|
|
}
|
|
|
|
# ###########################################################################
|
|
# End collect_system_info package
|
|
# ###########################################################################
|
|
|
|
# ###########################################################################
|
|
# report_system_info package
|
|
# This package is a copy without comments from the original. The original
|
|
# with comments and its test file can be found in the GitHub repository at,
|
|
# lib/bash/report_system_info.sh
|
|
# t/lib/bash/report_system_info.sh
|
|
# See https://github.com/percona/percona-toolkit for more information.
|
|
# ###########################################################################
|
|
|
|
|
|
set -u
|
|
|
|
|
|
parse_proc_cpuinfo () { local PTFUNCNAME=parse_proc_cpuinfo;
|
|
local file="$1"
|
|
local virtual="$(grep -c ^processor "${file}")";
|
|
local physical="$(grep 'physical id' "${file}" | sort -u | wc -l)";
|
|
local cores="$(grep 'cpu cores' "${file}" | head -n 1 | cut -d: -f2)";
|
|
|
|
[ "${physical}" = "0" ] && physical="${virtual}"
|
|
[ -z "${cores}" ] && cores=0
|
|
|
|
cores=$((${cores} * ${physical}));
|
|
local htt=""
|
|
if [ ${cores} -gt 0 -a $cores -lt $virtual ]; then htt=yes; else htt=no; fi
|
|
|
|
name_val "Processors" "physical = ${physical}, cores = ${cores}, virtual = ${virtual}, hyperthreading = ${htt}"
|
|
|
|
awk -F: '/cpu MHz/{print $2}' "${file}" \
|
|
| sort | uniq -c > "$PT_TMPDIR/parse_proc_cpuinfo_cpu.unq"
|
|
name_val "Speeds" "$(group_concat "$PT_TMPDIR/parse_proc_cpuinfo_cpu.unq")"
|
|
|
|
awk -F: '/model name/{print $2}' "${file}" \
|
|
| sort | uniq -c > "$PT_TMPDIR/parse_proc_cpuinfo_model.unq"
|
|
name_val "Models" "$(group_concat "$PT_TMPDIR/parse_proc_cpuinfo_model.unq")"
|
|
|
|
awk -F: '/cache size/{print $2}' "${file}" \
|
|
| sort | uniq -c > "$PT_TMPDIR/parse_proc_cpuinfo_cache.unq"
|
|
name_val "Caches" "$(group_concat "$PT_TMPDIR/parse_proc_cpuinfo_cache.unq")"
|
|
}
|
|
|
|
parse_sysctl_cpu_freebsd() { local PTFUNCNAME=parse_sysctl_cpu_freebsd;
|
|
local file="$1"
|
|
[ -e "$file" ] || return;
|
|
local virtual="$(awk '/hw.ncpu/{print $2}' "$file")"
|
|
name_val "Processors" "virtual = ${virtual}"
|
|
name_val "Speeds" "$(awk '/hw.clockrate/{print $2}' "$file")"
|
|
name_val "Models" "$(awk -F: '/hw.model/{print substr($2, 2)}' "$file")"
|
|
}
|
|
|
|
parse_sysctl_cpu_netbsd() { local PTFUNCNAME=parse_sysctl_cpu_netbsd;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
local virtual="$(awk '/hw.ncpu /{print $NF}' "$file")"
|
|
name_val "Processors" "virtual = ${virtual}"
|
|
name_val "Models" "$(awk -F: '/hw.model/{print $3}' "$file")"
|
|
}
|
|
|
|
parse_sysctl_cpu_openbsd() { local PTFUNCNAME=parse_sysctl_cpu_openbsd;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
name_val "Processors" "$(awk -F= '/hw.ncpu=/{print $2}' "$file")"
|
|
name_val "Speeds" "$(awk -F= '/hw.cpuspeed/{print $2}' "$file")"
|
|
name_val "Models" "$(awk -F= '/hw.model/{print substr($2, 1, index($2, " "))}' "$file")"
|
|
}
|
|
|
|
parse_psrinfo_cpus() { local PTFUNCNAME=parse_psrinfo_cpus;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
name_val "Processors" "$(grep -c 'Status of .* processor' "$file")"
|
|
awk '/operates at/ {
|
|
start = index($0, " at ") + 4;
|
|
end = length($0) - start - 4
|
|
print substr($0, start, end);
|
|
}' "$file" | sort | uniq -c > "$PT_TMPDIR/parse_psrinfo_cpus.tmp"
|
|
name_val "Speeds" "$(group_concat "$PT_TMPDIR/parse_psrinfo_cpus.tmp")"
|
|
}
|
|
|
|
parse_free_minus_b () { local PTFUNCNAME=parse_free_minus_b;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
local physical=$(awk '/Mem:/{print $3}' "${file}")
|
|
local swap_alloc=$(awk '/Swap:/{print $2}' "${file}")
|
|
local swap_used=$(awk '/Swap:/{print $3}' "${file}")
|
|
local virtual=$(shorten $(($physical + $swap_used)) 1)
|
|
|
|
name_val "Total" $(shorten $(awk '/Mem:/{print $2}' "${file}") 1)
|
|
name_val "Free" $(shorten $(awk '/Mem:/{print $4}' "${file}") 1)
|
|
name_val "Used" "physical = $(shorten ${physical} 1), swap allocated = $(shorten ${swap_alloc} 1), swap used = $(shorten ${swap_used} 1), virtual = ${virtual}"
|
|
name_val "Shared" $(shorten $(awk '/Mem:/{print $5}' "${file}") 1)
|
|
name_val "Buffers" $(shorten $(awk '/Mem:/{print $6}' "${file}") 1)
|
|
name_val "Caches" $(shorten $(awk '/Mem:/{print $7}' "${file}") 1)
|
|
name_val "Dirty" "$(awk '/Dirty:/ {print $2, $3}' "${file}")"
|
|
}
|
|
|
|
parse_memory_sysctl_freebsd() { local PTFUNCNAME=parse_memory_sysctl_freebsd;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
local physical=$(awk '/hw.realmem:/{print $2}' "${file}")
|
|
local mem_hw=$(awk '/hw.physmem:/{print $2}' "${file}")
|
|
local mem_used=$(awk '
|
|
/hw.physmem/ { mem_hw = $2; }
|
|
/vm.stats.vm.v_inactive_count/ { mem_inactive = $2; }
|
|
/vm.stats.vm.v_cache_count/ { mem_cache = $2; }
|
|
/vm.stats.vm.v_free_count/ { mem_free = $2; }
|
|
/hw.pagesize/ { pagesize = $2; }
|
|
END {
|
|
mem_inactive *= pagesize;
|
|
mem_cache *= pagesize;
|
|
mem_free *= pagesize;
|
|
print mem_hw - mem_inactive - mem_cache - mem_free;
|
|
}
|
|
' "$file");
|
|
name_val "Total" $(shorten ${mem_hw} 1)
|
|
name_val "Virtual" $(shorten ${physical} 1)
|
|
name_val "Used" $(shorten ${mem_used} 1)
|
|
}
|
|
|
|
parse_memory_sysctl_netbsd() { local PTFUNCNAME=parse_memory_sysctl_netbsd;
|
|
local file="$1"
|
|
local swapctl_file="$2"
|
|
|
|
[ -e "$file" -a -e "$swapctl_file" ] || return
|
|
|
|
local swap_mem="$(awk '{print $2*512}' "$swapctl_file")"
|
|
name_val "Total" $(shorten "$(awk '/hw.physmem /{print $NF}' "$file")" 1)
|
|
name_val "User" $(shorten "$(awk '/hw.usermem /{print $NF}' "$file")" 1)
|
|
name_val "Swap" $(shorten ${swap_mem} 1)
|
|
}
|
|
|
|
parse_memory_sysctl_openbsd() { local PTFUNCNAME=parse_memory_sysctl_openbsd;
|
|
local file="$1"
|
|
local swapctl_file="$2"
|
|
|
|
[ -e "$file" -a -e "$swapctl_file" ] || return
|
|
|
|
local swap_mem="$(awk '{print $2*512}' "$swapctl_file")"
|
|
name_val "Total" $(shorten "$(awk -F= '/hw.physmem/{print $2}' "$file")" 1)
|
|
name_val "User" $(shorten "$(awk -F= '/hw.usermem/{print $2}' "$file")" 1)
|
|
name_val "Swap" $(shorten ${swap_mem} 1)
|
|
}
|
|
|
|
parse_dmidecode_mem_devices () { local PTFUNCNAME=parse_dmidecode_mem_devices;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
echo " Locator Size Speed Form Factor Type Type Detail"
|
|
echo " ========= ======== ================= ============= ============= ==========="
|
|
sed -e '/./{H;$!d;}' \
|
|
-e 'x;/Memory Device\n/!d;' \
|
|
-e 's/: /:/g' \
|
|
-e 's/</{/g' \
|
|
-e 's/>/}/g' \
|
|
-e 's/[ \t]*\n/\n/g' \
|
|
"${file}" \
|
|
| awk -F: '/Size|Type|Form.Factor|Type.Detail|^[\t ]+Locator|^[\t ]+Speed/{printf("|%s", $2)}/^$/{print}' \
|
|
| sed '/^$/d' \
|
|
| sed -e 's/No Module Installed/{EMPTY}/' \
|
|
| sort \
|
|
| awk -F'|' '{printf(" %-9s %-8s %-17s %-13s %-13s %-8s\n", $4, $2, $7, $3, $5, $6);}'
|
|
}
|
|
|
|
parse_dmidecode_cache_info () { local PTFUNCNAME=parse_dmidecode_cache_info;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
echo " Designation Configuration Size Associativity"
|
|
echo " ========================= ============================== ======== ======================"
|
|
sed -e '/./{H;$!d;}' \
|
|
-e 'x;/Cache Information\n/!d;' \
|
|
-e 's/: /:/g' \
|
|
-e 's/</{/g' \
|
|
-e 's/>/}/g' \
|
|
-e 's/[ \t]*\n/\n/g' \
|
|
"${file}" \
|
|
| awk -F: '/Socket Designation|Configuration|Installed Size/{printf("|%s", $2)}/^[\t ]+Associativity/{print "|" $2}' \
|
|
| awk -F'|' '{printf(" %-25s %-30s %-8s %-22s\n", $2, $3, $4, $5);}'
|
|
}
|
|
|
|
parse_numactl () { local PTFUNCNAME=parse_numactl;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
echo " Node Size Free CPUs"
|
|
echo " ==== ==== ==== ===="
|
|
|
|
sed -n -e 's/node /node/g' \
|
|
-e '/node[[:digit:]]/p' \
|
|
"${file}" \
|
|
| sort -r \
|
|
| awk '$1 == cnode {
|
|
if (NF > 4) { for(i=3;i<=NF;i++){printf("%s ", $i)} printf "\n" }
|
|
else { printf("%-12s", $3" "$4); }
|
|
}
|
|
$1 != cnode { cnode = $1; printf(" %-8s", $1); printf("%-12s", $3" "$4); }'
|
|
|
|
echo
|
|
}
|
|
|
|
parse_ip_s_link () { local PTFUNCNAME=parse_ip_s_link;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
echo " interface rx_bytes rx_packets rx_errors tx_bytes tx_packets tx_errors"
|
|
echo " ========= ========= ========== ========== ========== ========== =========="
|
|
|
|
awk "/^[1-9][0-9]*:/ {
|
|
save[\"iface\"] = substr(\$2, 1, index(\$2, \":\") - 1);
|
|
new = 1;
|
|
}
|
|
\$0 !~ /[^0-9 ]/ {
|
|
if ( new == 1 ) {
|
|
new = 0;
|
|
fuzzy_var = \$1; ${fuzzy_formula} save[\"bytes\"] = fuzzy_var;
|
|
fuzzy_var = \$2; ${fuzzy_formula} save[\"packs\"] = fuzzy_var;
|
|
fuzzy_var = \$3; ${fuzzy_formula} save[\"errs\"] = fuzzy_var;
|
|
}
|
|
else {
|
|
fuzzy_var = \$1; ${fuzzy_formula} tx_bytes = fuzzy_var;
|
|
fuzzy_var = \$2; ${fuzzy_formula} tx_packets = fuzzy_var;
|
|
fuzzy_var = \$3; ${fuzzy_formula} tx_errors = fuzzy_var;
|
|
printf \" %-8s %10.0f %10.0f %10.0f %10.0f %10.0f %10.0f\\n\", save[\"iface\"], save[\"bytes\"], save[\"packs\"], save[\"errs\"], tx_bytes, tx_packets, tx_errors;
|
|
}
|
|
}" "$file"
|
|
}
|
|
|
|
parse_ethtool () {
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
echo " Device Speed Duplex"
|
|
echo " ========= ========= ========="
|
|
|
|
|
|
awk '
|
|
/^Settings for / {
|
|
device = substr($3, 1, index($3, ":") ? index($3, ":")-1 : length($3));
|
|
device_names[device] = device;
|
|
}
|
|
/Speed:/ { devices[device ",speed"] = $2 }
|
|
/Duplex:/ { devices[device ",duplex"] = $2 }
|
|
END {
|
|
for ( device in device_names ) {
|
|
printf(" %-10s %-10s %-10s\n",
|
|
device,
|
|
devices[device ",speed"],
|
|
devices[device ",duplex"]);
|
|
}
|
|
}
|
|
' "$file"
|
|
|
|
}
|
|
|
|
parse_netstat () { local PTFUNCNAME=parse_netstat;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
echo " Connections from remote IP addresses"
|
|
awk '$1 ~ /^tcp/ && $5 ~ /^[1-9]/ {
|
|
print substr($5, 1, index($5, ":") - 1);
|
|
}' "${file}" | sort | uniq -c \
|
|
| awk "{
|
|
fuzzy_var=\$1;
|
|
${fuzzy_formula}
|
|
printf \" %-15s %5d\\n\", \$2, fuzzy_var;
|
|
}" \
|
|
| sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4
|
|
echo " Connections to local IP addresses"
|
|
awk '$1 ~ /^tcp/ && $5 ~ /^[1-9]/ {
|
|
print substr($4, 1, index($4, ":") - 1);
|
|
}' "${file}" | sort | uniq -c \
|
|
| awk "{
|
|
fuzzy_var=\$1;
|
|
${fuzzy_formula}
|
|
printf \" %-15s %5d\\n\", \$2, fuzzy_var;
|
|
}" \
|
|
| sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4
|
|
echo " Connections to top 10 local ports"
|
|
awk '$1 ~ /^tcp/ && $5 ~ /^[1-9]/ {
|
|
print substr($4, index($4, ":") + 1);
|
|
}' "${file}" | sort | uniq -c | sort -rn | head -n10 \
|
|
| awk "{
|
|
fuzzy_var=\$1;
|
|
${fuzzy_formula}
|
|
printf \" %-15s %5d\\n\", \$2, fuzzy_var;
|
|
}" | sort
|
|
echo " States of connections"
|
|
awk '$1 ~ /^tcp/ {
|
|
print $6;
|
|
}' "${file}" | sort | uniq -c | sort -rn \
|
|
| awk "{
|
|
fuzzy_var=\$1;
|
|
${fuzzy_formula}
|
|
printf \" %-15s %5d\\n\", \$2, fuzzy_var;
|
|
}" | sort
|
|
}
|
|
|
|
parse_filesystems () { local PTFUNCNAME=parse_filesystems;
|
|
local file="$1"
|
|
local platform="$2"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
local spec="$(awk "
|
|
BEGIN {
|
|
device = 10;
|
|
fstype = 4;
|
|
options = 4;
|
|
}
|
|
/./ {
|
|
f_device = \$1;
|
|
f_fstype = \$10;
|
|
f_options = substr(\$11, 2, length(\$11) - 2);
|
|
if ( \"$2\" ~ /(Free|Open|Net)BSD/ ) {
|
|
f_fstype = substr(\$9, 2, length(\$9) - 2);
|
|
f_options = substr(\$0, index(\$0, \",\") + 2);
|
|
f_options = substr(f_options, 1, length(f_options) - 1);
|
|
}
|
|
if ( length(f_device) > device ) {
|
|
device=length(f_device);
|
|
}
|
|
if ( length(f_fstype) > fstype ) {
|
|
fstype=length(f_fstype);
|
|
}
|
|
if ( length(f_options) > options ) {
|
|
options=length(f_options);
|
|
}
|
|
}
|
|
END{
|
|
print \"%-\" device \"s %5s %4s %-\" fstype \"s %-\" options \"s %s\";
|
|
}
|
|
" "${file}")"
|
|
|
|
awk "
|
|
BEGIN {
|
|
spec=\" ${spec}\\n\";
|
|
printf spec, \"Filesystem\", \"Size\", \"Used\", \"Type\", \"Opts\", \"Mountpoint\";
|
|
}
|
|
{
|
|
f_fstype = \$10;
|
|
f_options = substr(\$11, 2, length(\$11) - 2);
|
|
if ( \"$2\" ~ /(Free|Open|Net)BSD/ ) {
|
|
f_fstype = substr(\$9, 2, length(\$9) - 2);
|
|
f_options = substr(\$0, index(\$0, \",\") + 2);
|
|
f_options = substr(f_options, 1, length(f_options) - 1);
|
|
}
|
|
printf spec, \$1, \$2, \$5, f_fstype, f_options, \$6;
|
|
}
|
|
" "${file}"
|
|
}
|
|
|
|
parse_fdisk () { local PTFUNCNAME=parse_fdisk;
|
|
local file="$1"
|
|
|
|
[ -e "$file" -a -s "$file" ] || return
|
|
|
|
awk '
|
|
BEGIN {
|
|
format="%-12s %4s %10s %10s %18s\n";
|
|
printf(format, "Device", "Type", "Start", "End", "Size");
|
|
printf(format, "============", "====", "==========", "==========", "==================");
|
|
}
|
|
/Disk.*bytes/ {
|
|
disk = substr($2, 1, length($2) - 1);
|
|
size = $5;
|
|
printf(format, disk, "Disk", "", "", size);
|
|
}
|
|
/Units/ {
|
|
units = $9;
|
|
}
|
|
/^\/dev/ {
|
|
if ( $2 == "*" ) {
|
|
start = $3;
|
|
end = $4;
|
|
}
|
|
else {
|
|
start = $2;
|
|
end = $3;
|
|
}
|
|
printf(format, $1, "Part", start, end, sprintf("%.0f", (end - start) * units));
|
|
}
|
|
' "${file}"
|
|
}
|
|
|
|
parse_ethernet_controller_lspci () { local PTFUNCNAME=parse_ethernet_controller_lspci;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
grep -i ethernet "${file}" | cut -d: -f3 | while read line; do
|
|
name_val "Controller" "${line}"
|
|
done
|
|
}
|
|
|
|
parse_hpacucli () { local PTFUNCNAME=parse_hpacucli;
|
|
local file="$1"
|
|
[ -e "$file" ] || return
|
|
grep 'logicaldrive\|physicaldrive' "${file}"
|
|
}
|
|
|
|
parse_arcconf () { local PTFUNCNAME=parse_arcconf;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
local model="$(awk -F: '/Controller Model/{print $2}' "${file}")"
|
|
local chan="$(awk -F: '/Channel description/{print $2}' "${file}")"
|
|
local cache="$(awk -F: '/Installed memory/{print $2}' "${file}")"
|
|
local status="$(awk -F: '/Controller Status/{print $2}' "${file}")"
|
|
name_val "Specs" "$(echo "$model" | sed -e 's/ //'),${chan},${cache} cache,${status}"
|
|
|
|
local battery=""
|
|
if grep -q "ZMM" "$file"; then
|
|
battery="$(grep -A2 'Controller ZMM Information' "$file" \
|
|
| awk '/Status/ {s=$4}
|
|
END {printf "ZMM %s", s}')"
|
|
else
|
|
battery="$(grep -A5 'Controller Battery Info' "${file}" \
|
|
| awk '/Capacity remaining/ {c=$4}
|
|
/Status/ {s=$3}
|
|
/Time remaining/ {t=sprintf("%dd%dh%dm", $7, $9, $11)}
|
|
END {printf("%d%%, %s remaining, %s", c, t, s)}')"
|
|
fi
|
|
name_val "Battery" "${battery}"
|
|
|
|
echo
|
|
echo " LogicalDev Size RAID Disks Stripe Status Cache"
|
|
echo " ========== ========= ==== ===== ====== ======= ======="
|
|
for dev in $(awk '/Logical device number/{print $4}' "${file}"); do
|
|
sed -n -e "/^Logical device .* ${dev}$/,/^$\|^Logical device number/p" "${file}" \
|
|
| awk '
|
|
/Logical device name/ {d=$5}
|
|
/Size/ {z=$3 " " $4}
|
|
/RAID level/ {r=$4}
|
|
/Group [0-9]/ {g++}
|
|
/Stripe-unit size/ {p=$4 " " $5}
|
|
/Status of logical/ {s=$6}
|
|
/Write-cache mode.*Ena.*write-back/ {c="On (WB)"}
|
|
/Write-cache mode.*Ena.*write-thro/ {c="On (WT)"}
|
|
/Write-cache mode.*Disabled/ {c="Off"}
|
|
END {
|
|
printf(" %-10s %-9s %4d %5d %-6s %-7s %-7s\n",
|
|
d, z, r, g, p, s, c);
|
|
}'
|
|
done
|
|
|
|
echo
|
|
echo " PhysiclDev State Speed Vendor Model Size Cache"
|
|
echo " ========== ======= ============= ======= ============ =========== ======="
|
|
|
|
local tempresult=""
|
|
sed -n -e '/Physical Device information/,/^$/p' "${file}" \
|
|
| awk -F: '
|
|
/Device #[0-9]/ {
|
|
device=substr($0, index($0, "#"));
|
|
devicenames[device]=device;
|
|
}
|
|
/Device is a/ {
|
|
devices[device ",isa"] = substr($0, index($0, "is a") + 5);
|
|
}
|
|
/State/ {
|
|
devices[device ",state"] = substr($2, 2);
|
|
}
|
|
/Transfer Speed/ {
|
|
devices[device ",speed"] = substr($2, 2);
|
|
}
|
|
/Vendor/ {
|
|
devices[device ",vendor"] = substr($2, 2);
|
|
}
|
|
/Model/ {
|
|
devices[device ",model"] = substr($2, 2);
|
|
}
|
|
/Size/ {
|
|
devices[device ",size"] = substr($2, 2);
|
|
}
|
|
/Write Cache/ {
|
|
if ( $2 ~ /Enabled .write-back./ )
|
|
devices[device ",cache"] = "On (WB)";
|
|
else
|
|
if ( $2 ~ /Enabled .write-th/ )
|
|
devices[device ",cache"] = "On (WT)";
|
|
else
|
|
devices[device ",cache"] = "Off";
|
|
}
|
|
END {
|
|
for ( device in devicenames ) {
|
|
if ( devices[device ",isa"] ~ /Hard drive/ ) {
|
|
printf(" %-10s %-7s %-13s %-7s %-12s %-11s %-7s\n",
|
|
devices[device ",isa"],
|
|
devices[device ",state"],
|
|
devices[device ",speed"],
|
|
devices[device ",vendor"],
|
|
devices[device ",model"],
|
|
devices[device ",size"],
|
|
devices[device ",cache"]);
|
|
}
|
|
}
|
|
}'
|
|
}
|
|
|
|
parse_fusionmpt_lsiutil () { local PTFUNCNAME=parse_fusionmpt_lsiutil;
|
|
local file="$1"
|
|
echo
|
|
awk '/LSI.*Firmware/ { print " ", $0 }' "${file}"
|
|
grep . "${file}" | sed -n -e '/B___T___L/,$ {s/^/ /; p}'
|
|
}
|
|
|
|
parse_lsi_megaraid_adapter_info () { local PTFUNCNAME=parse_lsi_megaraid_adapter_info;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
local name="$(awk -F: '/Product Name/{print substr($2, 2)}' "${file}")";
|
|
local int=$(awk '/Host Interface/{print $4}' "${file}");
|
|
local prt=$(awk '/Number of Backend Port/{print $5}' "${file}");
|
|
local bbu=$(awk '/^BBU :/{print $3}' "${file}");
|
|
local mem=$(awk '/Memory Size/{print $4}' "${file}");
|
|
local vdr=$(awk '/Virtual Drives/{print $4}' "${file}");
|
|
local dvd=$(awk '/Degraded/{print $3}' "${file}");
|
|
local phy=$(awk '/^ Disks/{print $3}' "${file}");
|
|
local crd=$(awk '/Critical Disks/{print $4}' "${file}");
|
|
local fad=$(awk '/Failed Disks/{print $4}' "${file}");
|
|
|
|
name_val "Model" "${name}, ${int} interface, ${prt} ports"
|
|
name_val "Cache" "${mem} Memory, BBU ${bbu}"
|
|
}
|
|
|
|
parse_lsi_megaraid_bbu_status () { local PTFUNCNAME=parse_lsi_megaraid_bbu_status;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
local charge=$(awk '/Relative State/{print $5}' "${file}");
|
|
local temp=$(awk '/^Temperature/{print $2}' "${file}");
|
|
local soh=$(awk '/isSOHGood:/{print $2}' "${file}");
|
|
name_val "BBU" "${charge}% Charged, Temperature ${temp}C, isSOHGood=${soh}"
|
|
}
|
|
|
|
format_lvs () { local PTFUNCNAME=format_lvs;
|
|
local file="$1"
|
|
if [ -e "$file" ]; then
|
|
grep -v "open failed" "$file"
|
|
else
|
|
echo "Unable to collect information";
|
|
fi
|
|
}
|
|
|
|
parse_lsi_megaraid_devices () { local PTFUNCNAME=parse_lsi_megaraid_devices;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
echo
|
|
echo " PhysiclDev Type State Errors Vendor Model Size"
|
|
echo " ========== ==== ======= ====== ======= ============ ==========="
|
|
for dev in $(awk '/Device Id/{print $3}' "${file}"); do
|
|
sed -e '/./{H;$!d;}' -e "x;/Device Id: ${dev}/!d;" "${file}" \
|
|
| awk '
|
|
/Media Type/ {d=substr($0, index($0, ":") + 2)}
|
|
/PD Type/ {t=$3}
|
|
/Firmware state/ {s=$3}
|
|
/Media Error Count/ {me=$4}
|
|
/Other Error Count/ {oe=$4}
|
|
/Predictive Failure Count/ {pe=$4}
|
|
/Inquiry Data/ {v=$3; m=$4;}
|
|
/Raw Size/ {z=$3}
|
|
END {
|
|
printf(" %-10s %-4s %-7s %6s %-7s %-12s %-7s\n",
|
|
substr(d, 1, 10), t, s, me "/" oe "/" pe, v, m, z);
|
|
}'
|
|
done
|
|
}
|
|
|
|
parse_lsi_megaraid_virtual_devices () { local PTFUNCNAME=parse_lsi_megaraid_virtual_devices;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
echo
|
|
echo " VirtualDev Size RAID Level Disks SpnDpth Stripe Status Cache"
|
|
echo " ========== ========= ========== ===== ======= ====== ======= ========="
|
|
awk '
|
|
/^Virtual (Drive|Disk):/ {
|
|
device = $3;
|
|
devicenames[device] = device;
|
|
}
|
|
/Number Of Drives/ {
|
|
devices[device ",numdisks"] = substr($0, index($0, ":") + 1);
|
|
}
|
|
/^Name/ {
|
|
devices[device ",name"] = substr($0, index($0, ":") + 1) > "" ? substr($0, index($0, ":") + 1) : "(no name)";
|
|
}
|
|
/RAID Level/ {
|
|
devices[device ",primary"] = substr($3, index($3, "-") + 1, 1);
|
|
devices[device ",secondary"] = substr($4, index($4, "-") + 1, 1);
|
|
devices[device ",qualifier"] = substr($NF, index($NF, "-") + 1, 1);
|
|
}
|
|
/Span Depth/ {
|
|
devices[device ",spandepth"] = substr($2, index($2, ":") + 1);
|
|
}
|
|
/Number of Spans/ {
|
|
devices[device ",numspans"] = $4;
|
|
}
|
|
/^Size/ {
|
|
devices[device ",size"] = substr($0, index($0, ":") + 1);
|
|
}
|
|
/^State/ {
|
|
devices[device ",state"] = substr($0, index($0, ":") + 2);
|
|
}
|
|
/^Stripe? Size/ {
|
|
devices[device ",stripe"] = substr($0, index($0, ":") + 1);
|
|
}
|
|
/^Current Cache Policy/ {
|
|
devices[device ",wpolicy"] = $4 ~ /WriteBack/ ? "WB" : "WT";
|
|
devices[device ",rpolicy"] = $5 ~ /ReadAheadNone/ ? "no RA" : "RA";
|
|
}
|
|
END {
|
|
for ( device in devicenames ) {
|
|
raid = 0;
|
|
if ( devices[device ",primary"] == 1 ) {
|
|
raid = 1;
|
|
if ( devices[device ",secondary"] == 3 ) {
|
|
raid = 10;
|
|
}
|
|
}
|
|
else {
|
|
if ( devices[device ",primary"] == 5 ) {
|
|
raid = 5;
|
|
}
|
|
}
|
|
printf(" %-10s %-9s %-10s %5d %7s %6s %-7s %s\n",
|
|
device devices[device ",name"],
|
|
devices[device ",size"],
|
|
raid " (" devices[device ",primary"] "-" devices[device ",secondary"] "-" devices[device ",qualifier"] ")",
|
|
devices[device ",numdisks"],
|
|
devices[device ",spandepth"] "-" devices[device ",numspans"],
|
|
devices[device ",stripe"], devices[device ",state"],
|
|
devices[device ",wpolicy"] ", " devices[device ",rpolicy"]);
|
|
}
|
|
}' "${file}"
|
|
}
|
|
|
|
format_vmstat () { local PTFUNCNAME=format_vmstat;
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
awk "
|
|
BEGIN {
|
|
format = \" %2s %2s %4s %4s %5s %5s %6s %6s %3s %3s %3s %3s %3s\n\";
|
|
}
|
|
/procs/ {
|
|
print \" procs ---swap-- -----io---- ---system---- --------cpu--------\";
|
|
}
|
|
/bo/ {
|
|
printf format, \"r\", \"b\", \"si\", \"so\", \"bi\", \"bo\", \"ir\", \"cs\", \"us\", \"sy\", \"il\", \"wa\", \"st\";
|
|
}
|
|
\$0 !~ /r/ {
|
|
fuzzy_var = \$1; ${fuzzy_formula} r = fuzzy_var;
|
|
fuzzy_var = \$2; ${fuzzy_formula} b = fuzzy_var;
|
|
fuzzy_var = \$7; ${fuzzy_formula} si = fuzzy_var;
|
|
fuzzy_var = \$8; ${fuzzy_formula} so = fuzzy_var;
|
|
fuzzy_var = \$9; ${fuzzy_formula} bi = fuzzy_var;
|
|
fuzzy_var = \$10; ${fuzzy_formula} bo = fuzzy_var;
|
|
fuzzy_var = \$11; ${fuzzy_formula} ir = fuzzy_var;
|
|
fuzzy_var = \$12; ${fuzzy_formula} cs = fuzzy_var;
|
|
fuzzy_var = \$13; us = fuzzy_var;
|
|
fuzzy_var = \$14; sy = fuzzy_var;
|
|
fuzzy_var = \$15; il = fuzzy_var;
|
|
fuzzy_var = \$16; wa = fuzzy_var;
|
|
fuzzy_var = \$17; st = fuzzy_var;
|
|
printf format, r, b, si, so, bi, bo, ir, cs, us, sy, il, wa, st;
|
|
}
|
|
" "${file}"
|
|
}
|
|
|
|
processes_section () { local PTFUNCNAME=processes_section;
|
|
local top_process_file="$1"
|
|
local notable_procs_file="$2"
|
|
local vmstat_file="$3"
|
|
local platform="$4"
|
|
|
|
section "Top Processes"
|
|
cat "$top_process_file"
|
|
section "Notable Processes"
|
|
cat "$notable_procs_file"
|
|
if [ -e "$vmstat_file" ]; then
|
|
section "Simplified and fuzzy rounded vmstat (wait please)"
|
|
wait # For the process we forked that was gathering vmstat samples
|
|
if [ "${platform}" = "Linux" ]; then
|
|
format_vmstat "$vmstat_file"
|
|
else
|
|
cat "$vmstat_file"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
section_Processor () {
|
|
local platform="$1"
|
|
local data_dir="$2"
|
|
|
|
section "Processor"
|
|
|
|
if [ -e "$data_dir/proc_cpuinfo_copy" ]; then
|
|
parse_proc_cpuinfo "$data_dir/proc_cpuinfo_copy"
|
|
elif [ "${platform}" = "FreeBSD" ]; then
|
|
parse_sysctl_cpu_freebsd "$data_dir/sysctl"
|
|
elif [ "${platform}" = "NetBSD" ]; then
|
|
parse_sysctl_cpu_netbsd "$data_dir/sysctl"
|
|
elif [ "${platform}" = "OpenBSD" ]; then
|
|
parse_sysctl_cpu_openbsd "$data_dir/sysctl"
|
|
elif [ "${platform}" = "SunOS" ]; then
|
|
parse_psrinfo_cpus "$data_dir/psrinfo_minus_v"
|
|
fi
|
|
|
|
if [ -s "$data_dir/dmidecode" ]; then
|
|
parse_dmidecode_cache_info "$data_dir/dmidecode"
|
|
fi
|
|
}
|
|
|
|
section_Memory () {
|
|
local platform="$1"
|
|
local data_dir="$2"
|
|
|
|
local name_val_len_orig=$NAME_VAL_LEN;
|
|
local NAME_VAL_LEN=14
|
|
|
|
section "Memory"
|
|
if [ "${platform}" = "Linux" ]; then
|
|
parse_free_minus_b "$data_dir/memory"
|
|
elif [ "${platform}" = "FreeBSD" ]; then
|
|
parse_memory_sysctl_freebsd "$data_dir/sysctl"
|
|
elif [ "${platform}" = "NetBSD" ]; then
|
|
parse_memory_sysctl_netbsd "$data_dir/sysctl" "$data_dir/swapctl"
|
|
elif [ "${platform}" = "OpenBSD" ]; then
|
|
parse_memory_sysctl_openbsd "$data_dir/sysctl" "$data_dir/swapctl"
|
|
elif [ "${platform}" = "SunOS" ]; then
|
|
name_val "Memory" "$(cat "$data_dir/memory")"
|
|
fi
|
|
|
|
local rss=$( get_var "rss" "$data_dir/summary" )
|
|
name_val "UsedRSS" "$(shorten ${rss} 1)"
|
|
|
|
if [ "${platform}" = "Linux" ]; then
|
|
name_val "Swappiness" "$(get_var "swappiness" "$data_dir/summary")"
|
|
name_val "DirtyPolicy" "$(get_var "dirtypolicy" "$data_dir/summary")"
|
|
local dirty_status="$(get_var "dirtystatus" "$data_dir/summary")"
|
|
if [ -n "$dirty_status" ]; then
|
|
name_val "DirtyStatus" "$dirty_status"
|
|
fi
|
|
fi
|
|
|
|
if [ -s "$data_dir/numactl" ]; then
|
|
name_val "Numa Nodes" "$(get_var "numa-available" "$data_dir/summary")"
|
|
name_val "Numa Policy" "$(get_var "numa-policy" "$data_dir/summary")"
|
|
name_val "Preferred Node" "$(get_var "numa-preferred-node" "$data_dir/summary")"
|
|
|
|
parse_numactl "$data_dir/numactl"
|
|
fi
|
|
|
|
local NAME_VAL_LEN=$name_val_len_orig;
|
|
|
|
if [ -s "$data_dir/dmidecode" ]; then
|
|
parse_dmidecode_mem_devices "$data_dir/dmidecode"
|
|
fi
|
|
}
|
|
|
|
parse_uptime () {
|
|
local file="$1"
|
|
|
|
awk ' / up / {
|
|
printf substr($0, index($0, " up ")+4 );
|
|
}
|
|
!/ up / {
|
|
printf $0;
|
|
}
|
|
' "$file"
|
|
}
|
|
|
|
report_fio_minus_a () {
|
|
local file="$1"
|
|
|
|
name_val "fio Driver" "$(get_var driver_version "$file")"
|
|
|
|
local adapters="$( get_var "adapters" "$file" )"
|
|
for adapter in $( echo $adapters | awk '{for (i=1; i<=NF; i++) print $i;}' ); do
|
|
local adapter_for_output="$(echo "$adapter" | sed 's/::[0-9]*$//' | tr ':' ' ')"
|
|
name_val "$adapter_for_output" "$(get_var "${adapter}_general" "$file")"
|
|
|
|
local modules="$(get_var "${adapter}_modules" "$file")"
|
|
for module in $( echo $modules | awk '{for (i=1; i<=NF; i++) print $i;}' ); do
|
|
local name_val_len_orig=$NAME_VAL_LEN;
|
|
local NAME_VAL_LEN=16
|
|
name_val "$module" "$(get_var "${adapter}_${module}_attached_as" "$file")"
|
|
name_val "" "$(get_var "${adapter}_${module}_general" "$file")"
|
|
name_val "" "$(get_var "${adapter}_${module}_firmware" "$file")"
|
|
name_val "" "$(get_var "${adapter}_${module}_temperature" "$file")"
|
|
name_val "" "$(get_var "${adapter}_${module}_media_status" "$file")"
|
|
if [ "$(get_var "${adapter}_${module}_rated_pbw" "$file")" ]; then
|
|
name_val "" "$(get_var "${adapter}_${module}_rated_pbw" "$file")"
|
|
fi
|
|
local NAME_VAL_LEN=$name_val_len_orig;
|
|
done
|
|
done
|
|
}
|
|
|
|
report_system_summary () { local PTFUNCNAME=report_system_summary;
|
|
local data_dir="$1"
|
|
|
|
section "Percona Toolkit System Summary Report"
|
|
|
|
|
|
[ -e "$data_dir/summary" ] \
|
|
|| die "The data directory doesn't have a summary file, exiting."
|
|
|
|
local platform="$(get_var "platform" "$data_dir/summary")"
|
|
name_val "Date" "`date -u +'%F %T UTC'` (local TZ: `date +'%Z %z'`)"
|
|
name_val "Hostname" "$(get_var hostname "$data_dir/summary")"
|
|
name_val "Uptime" "$(parse_uptime "$data_dir/uptime")"
|
|
|
|
if [ "$(get_var "vendor" "$data_dir/summary")" ]; then
|
|
name_val "System" "$(get_var "system" "$data_dir/summary")";
|
|
name_val "Service Tag" "$(get_var "servicetag" "$data_dir/summary")";
|
|
fi
|
|
|
|
name_val "Platform" "${platform}"
|
|
local zonename="$(get_var zonename "$data_dir/summary")";
|
|
[ -n "${zonename}" ] && name_val "Zonename" "$zonename"
|
|
|
|
name_val "Release" "$(get_var "release" "$data_dir/summary")"
|
|
name_val "Kernel" "$(get_var "kernel" "$data_dir/summary")"
|
|
|
|
name_val "Architecture" "CPU = $(get_var "CPU_ARCH" "$data_dir/summary"), OS = $(get_var "OS_ARCH" "$data_dir/summary")"
|
|
|
|
local threading="$(get_var threading "$data_dir/summary")"
|
|
local compiler="$(get_var compiler "$data_dir/summary")"
|
|
[ -n "$threading" ] && name_val "Threading" "$threading"
|
|
[ -n "$compiler" ] && name_val "Compiler" "$compiler"
|
|
|
|
local getenforce="$(get_var getenforce "$data_dir/summary")"
|
|
[ -n "$getenforce" ] && name_val "SELinux" "${getenforce}";
|
|
|
|
name_val "Virtualized" "$(get_var "virt" "$data_dir/summary")"
|
|
|
|
section_Processor "$platform" "$data_dir"
|
|
|
|
section_Memory "$platform" "$data_dir"
|
|
|
|
|
|
if [ -s "$data_dir/fusion-io_card" ]; then
|
|
section "Fusion-io Card"
|
|
report_fio_minus_a "$data_dir/fusion-io_card"
|
|
fi
|
|
|
|
if [ -s "$data_dir/mounted_fs" ]; then
|
|
section "Mounted Filesystems"
|
|
parse_filesystems "$data_dir/mounted_fs" "${platform}"
|
|
fi
|
|
|
|
if [ "${platform}" = "Linux" ]; then
|
|
|
|
section "Disk Schedulers And Queue Size"
|
|
local disks="$( get_var "internal::disks" "$data_dir/summary" )"
|
|
for disk in $disks; do
|
|
local scheduler="$( get_var "internal::${disk}" "$data_dir/summary" )"
|
|
name_val "${disk}" "${scheduler:-"UNREADABLE"}"
|
|
done
|
|
|
|
section "Disk Partitioning"
|
|
parse_fdisk "$data_dir/partitioning"
|
|
|
|
section "Kernel Inode State"
|
|
for file in dentry-state file-nr inode-nr; do
|
|
name_val "${file}" "$(get_var "${file}" "$data_dir/summary")"
|
|
done
|
|
|
|
section "LVM Volumes"
|
|
format_lvs "$data_dir/lvs"
|
|
section "LVM Volume Groups"
|
|
format_lvs "$data_dir/vgs"
|
|
fi
|
|
|
|
section "RAID Controller"
|
|
local controller="$(get_var "raid_controller" "$data_dir/summary")"
|
|
name_val "Controller" "$controller"
|
|
local key="$(get_var "internal::raid_opt" "$data_dir/summary")"
|
|
case "$key" in
|
|
0)
|
|
cat "$data_dir/raid-controller"
|
|
;;
|
|
1)
|
|
parse_arcconf "$data_dir/raid-controller"
|
|
;;
|
|
2)
|
|
parse_hpacucli "$data_dir/raid-controller"
|
|
;;
|
|
3)
|
|
[ -e "$data_dir/lsi_megaraid_adapter_info.tmp" ] && \
|
|
parse_lsi_megaraid_adapter_info "$data_dir/lsi_megaraid_adapter_info.tmp"
|
|
[ -e "$data_dir/lsi_megaraid_bbu_status.tmp" ] && \
|
|
parse_lsi_megaraid_bbu_status "$data_dir/lsi_megaraid_bbu_status.tmp"
|
|
if [ -e "$data_dir/lsi_megaraid_devices.tmp" ]; then
|
|
parse_lsi_megaraid_virtual_devices "$data_dir/lsi_megaraid_devices.tmp"
|
|
parse_lsi_megaraid_devices "$data_dir/lsi_megaraid_devices.tmp"
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
if [ "${OPT_SUMMARIZE_NETWORK}" ]; then
|
|
if [ "${platform}" = "Linux" ]; then
|
|
section "Network Config"
|
|
if [ -s "$data_dir/lspci_file" ]; then
|
|
parse_ethernet_controller_lspci "$data_dir/lspci_file"
|
|
fi
|
|
if grep "net.ipv4.tcp_fin_timeout" "$data_dir/sysctl" > /dev/null 2>&1; then
|
|
name_val "FIN Timeout" "$(awk '/net.ipv4.tcp_fin_timeout/{print $NF}' "$data_dir/sysctl")"
|
|
name_val "Port Range" "$(awk '/net.ipv4.ip_local_port_range/{print $NF}' "$data_dir/sysctl")"
|
|
fi
|
|
fi
|
|
|
|
|
|
if [ -s "$data_dir/ip" ]; then
|
|
section "Interface Statistics"
|
|
parse_ip_s_link "$data_dir/ip"
|
|
fi
|
|
|
|
if [ -s "$data_dir/network_devices" ]; then
|
|
section "Network Devices"
|
|
parse_ethtool "$data_dir/network_devices"
|
|
fi
|
|
|
|
if [ "${platform}" = "Linux" -a -e "$data_dir/netstat" ]; then
|
|
section "Network Connections"
|
|
parse_netstat "$data_dir/netstat"
|
|
fi
|
|
fi
|
|
|
|
[ "$OPT_SUMMARIZE_PROCESSES" ] && processes_section \
|
|
"$data_dir/processes" \
|
|
"$data_dir/notable_procs" \
|
|
"$data_dir/vmstat" \
|
|
"$platform"
|
|
|
|
section "Memory management"
|
|
report_transparent_huge_pages "$data_dir/transparent_hugepage"
|
|
|
|
section "The End"
|
|
}
|
|
|
|
report_transparent_huge_pages () {
|
|
local file="$1"
|
|
|
|
[ -e "$file" ] || return
|
|
|
|
if [ $(grep -cv '\[never\]' $file) = 0 ]; then
|
|
echo "Transparent huge pages are currently disabled on the system."
|
|
else
|
|
echo "Transparent huge pages are enabled."
|
|
fi
|
|
}
|
|
|
|
# ###########################################################################
|
|
# End report_system_info package
|
|
# ###########################################################################
|
|
|
|
# ##############################################################################
|
|
# The main() function is called at the end of the script. This makes it
|
|
# testable. Major bits of parsing are separated into functions for testability.
|
|
# ##############################################################################
|
|
main () { local PTFUNCNAME=main;
|
|
trap sigtrap HUP INT TERM
|
|
|
|
local RAN_WITH="--sleep=$OPT_SLEEP --save-samples=$OPT_SAVE_SAMPLES --read-samples=$OPT_READ_SAMPLES"
|
|
|
|
# Begin by setting the $PATH to include some common locations that are not
|
|
# always in the $PATH, including the "sbin" locations, and some common
|
|
# locations for proprietary management software, such as RAID controllers.
|
|
export PATH="${PATH}:/usr/local/bin:/usr/bin:/bin:/usr/libexec"
|
|
export PATH="${PATH}:/usr/local/sbin:/usr/sbin:/sbin"
|
|
export PATH="${PATH}:/usr/StorMan/:/opt/MegaRAID/MegaCli/"
|
|
|
|
setup_commands
|
|
|
|
_d "Starting $0 $RAN_WITH"
|
|
|
|
# Set up temporary files.
|
|
mk_tmpdir
|
|
|
|
local data_dir="$(setup_data_dir "${OPT_SAVE_SAMPLES:-""}")"
|
|
|
|
if [ -n "$OPT_READ_SAMPLES" -a -d "$OPT_READ_SAMPLES" ]; then
|
|
data_dir="$OPT_READ_SAMPLES"
|
|
else
|
|
collect_system_data "$data_dir" 2>"$data_dir/collect.err"
|
|
fi
|
|
|
|
report_system_summary "$data_dir"
|
|
|
|
rm_tmpdir
|
|
}
|
|
|
|
sigtrap() { local PTFUNCNAME=sigtrap;
|
|
warn "Caught signal, forcing exit"
|
|
rm_tmpdir
|
|
exit $EXIT_STATUS
|
|
}
|
|
|
|
# Execute the program if it was not included from another file. This makes it
|
|
# possible to include without executing, and thus test.
|
|
if [ "${0##*/}" = "$TOOL" ] \
|
|
|| [ "${0##*/}" = "bash" -a "${_:-""}" = "$0" ]; then
|
|
|
|
# Set up temporary dir.
|
|
mk_tmpdir
|
|
# Parse command line options.
|
|
parse_options "$0" "${@:-""}"
|
|
usage_or_errors "$0"
|
|
po_status=$?
|
|
rm_tmpdir
|
|
|
|
if [ $po_status -ne 0 ]; then
|
|
exit $po_status
|
|
fi
|
|
|
|
main "${@:-""}"
|
|
fi
|
|
|
|
|
|
# ############################################################################
|
|
# Documentation
|
|
# ############################################################################
|
|
:<<'DOCUMENTATION'
|
|
=pod
|
|
|
|
=head1 NAME
|
|
|
|
pt-summary - Summarize system information nicely.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
Usage: pt-summary
|
|
|
|
pt-summary conveniently summarizes the status and configuration of a server.
|
|
It is not a tuning tool or diagnosis tool. It produces a report that is easy
|
|
to diff and can be pasted into emails without losing the formatting. This
|
|
tool works well on many types of Unix systems.
|
|
|
|
Download and run:
|
|
|
|
wget http://percona.com/get/pt-summary
|
|
bash ./pt-summary
|
|
|
|
=head1 RISKS
|
|
|
|
Percona Toolkit is mature, proven in the real world, and well tested,
|
|
but all database tools can pose a risk to the system and the database
|
|
server. Before using this tool, please:
|
|
|
|
=over
|
|
|
|
=item * Read the tool's documentation
|
|
|
|
=item * Review the tool's known L<"BUGS">
|
|
|
|
=item * Test the tool on a non-production server
|
|
|
|
=item * Backup your production server and verify the backups
|
|
|
|
=back
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
pt-summary runs a large variety of commands to inspect system status and
|
|
configuration, saves the output into files in a temporary directory, and
|
|
then runs Unix commands on these results to format them nicely. It works
|
|
best when executed as a privileged user, but will also work without privileges,
|
|
although some output might not be possible to generate without root.
|
|
|
|
=head1 OUTPUT
|
|
|
|
Many of the outputs from this tool are deliberately rounded to show their
|
|
magnitude but not the exact detail. This is called fuzzy-rounding. The idea is
|
|
that it doesn't matter whether a particular counter is 918 or 921; such a small
|
|
variation is insignificant, and only makes the output hard to compare to other
|
|
servers. Fuzzy-rounding rounds in larger increments as the input grows. It
|
|
begins by rounding to the nearest 5, then the nearest 10, nearest 25, and then
|
|
repeats by a factor of 10 larger (50, 100, 250), and so on, as the input grows.
|
|
|
|
The following is a simple report generated from a CentOS virtual machine,
|
|
broken into sections with commentary following each section. Some long lines
|
|
are reformatted for clarity when reading this documentation as a manual page in
|
|
a terminal.
|
|
|
|
# Percona Toolkit System Summary Report ######################
|
|
Date | 2012-03-30 00:58:07 UTC (local TZ: EDT -0400)
|
|
Hostname | localhost.localdomain
|
|
Uptime | 20:58:06 up 1 day, 20 min, 1 user,
|
|
load average: 0.14, 0.18, 0.18
|
|
System | innotek GmbH; VirtualBox; v1.2 ()
|
|
Service Tag | 0
|
|
Platform | Linux
|
|
Release | CentOS release 5.5 (Final)
|
|
Kernel | 2.6.18-194.el5
|
|
Architecture | CPU = 32-bit, OS = 32-bit
|
|
Threading | NPTL 2.5
|
|
Compiler | GNU CC version 4.1.2 20080704 (Red Hat 4.1.2-48).
|
|
SELinux | Enforcing
|
|
Virtualized | VirtualBox
|
|
|
|
This section shows the current date and time, and a synopsis of the server and
|
|
operating system.
|
|
|
|
# Processor ##################################################
|
|
Processors | physical = 1, cores = 0, virtual = 1, hyperthreading = no
|
|
Speeds | 1x2510.626
|
|
Models | 1xIntel(R) Core(TM) i5-2400S CPU @ 2.50GHz
|
|
Caches | 1x6144 KB
|
|
|
|
This section is derived from F</proc/cpuinfo>.
|
|
|
|
# Memory #####################################################
|
|
Total | 503.2M
|
|
Free | 29.0M
|
|
Used | physical = 474.2M, swap allocated = 1.0M,
|
|
swap used = 16.0k, virtual = 474.3M
|
|
Buffers | 33.9M
|
|
Caches | 262.6M
|
|
Dirty | 396 kB
|
|
UsedRSS | 201.9M
|
|
Swappiness | 60
|
|
DirtyPolicy | 40, 10
|
|
Locator Size Speed Form Factor Type Type Detail
|
|
======= ==== ===== =========== ==== ===========
|
|
|
|
Information about memory is gathered from C<free>. The Used statistic is the
|
|
total of the rss sizes displayed by C<ps>. The Dirty statistic for the cached
|
|
value comes from F</proc/meminfo>. On Linux, the swappiness settings are
|
|
gathered from C<sysctl>. The final portion of this section is a table of the
|
|
DIMMs, which comes from C<dmidecode>. In this example there is no output.
|
|
|
|
# Mounted Filesystems ########################################
|
|
Filesystem Size Used Type Opts Mountpoint
|
|
/dev/mapper/VolGroup00-LogVol00 15G 17% ext3 rw /
|
|
/dev/sda1 99M 13% ext3 rw /boot
|
|
tmpfs 252M 0% tmpfs rw /dev/shm
|
|
|
|
The mounted filesystem section is a combination of information from C<mount> and
|
|
C<df>. This section is skipped if you disable L<"--summarize-mounts">.
|
|
|
|
# Disk Schedulers And Queue Size #############################
|
|
dm-0 | UNREADABLE
|
|
dm-1 | UNREADABLE
|
|
hdc | [cfq] 128
|
|
md0 | UNREADABLE
|
|
sda | [cfq] 128
|
|
|
|
The disk scheduler information is extracted from the F</sys> filesystem in
|
|
Linux.
|
|
|
|
# Disk Partitioning ######################################
|
|
Device Type Start End Size
|
|
============ ==== ========== ========== ==================
|
|
/dev/sda Disk 17179869184
|
|
/dev/sda1 Part 1 13 98703360
|
|
/dev/sda2 Part 14 2088 17059230720
|
|
|
|
Information about disk partitioning comes from C<fdisk -l>.
|
|
|
|
# Kernel Inode State #########################################
|
|
dentry-state | 10697 8559 45 0 0 0
|
|
file-nr | 960 0 50539
|
|
inode-nr | 14059 8139
|
|
|
|
These lines are from the files of the same name in the F</proc/sys/fs>
|
|
directory on Linux. Read the C<proc> man page to learn about the meaning of
|
|
these files on your system.
|
|
|
|
# LVM Volumes ################################################
|
|
LV VG Attr LSize Origin Snap% Move Log Copy% Convert
|
|
LogVol00 VolGroup00 -wi-ao 269.00G
|
|
LogVol01 VolGroup00 -wi-ao 9.75G
|
|
|
|
This section shows the output of C<lvs>.
|
|
|
|
# RAID Controller ############################################
|
|
Controller | No RAID controller detected
|
|
|
|
The tool can detect a variety of RAID controllers by examining C<lspci> and
|
|
C<dmesg> information. If the controller software is installed on the system, in
|
|
many cases it is able to execute status commands and show a summary of the RAID
|
|
controller's status and configuration. If your system is not supported, please
|
|
file a bug report.
|
|
|
|
# Network Config #############################################
|
|
Controller | Intel Corporation 82540EM Gigabit Ethernet Controller
|
|
FIN Timeout | 60
|
|
Port Range | 61000
|
|
|
|
The network controllers attached to the system are detected from C<lspci>. The
|
|
TCP/IP protocol configuration parameters are extracted from C<sysctl>. You can skip this section by disabling the L<"--summarize-network"> option.
|
|
|
|
# Interface Statistics #######################################
|
|
interface rx_bytes rx_packets rx_errors tx_bytes tx_packets tx_errors
|
|
========= ======== ========== ========= ======== ========== =========
|
|
lo 60000000 12500 0 60000000 12500 0
|
|
eth0 15000000 80000 0 1500000 10000 0
|
|
sit0 0 0 0 0 0 0
|
|
|
|
Interface statistics are gathered from C<ip -s link> and are fuzzy-rounded. The
|
|
columns are received and transmitted bytes, packets, and errors. You can skip
|
|
this section by disabling the L<"--summarize-network"> option.
|
|
|
|
# Network Connections ########################################
|
|
Connections from remote IP addresses
|
|
127.0.0.1 2
|
|
Connections to local IP addresses
|
|
127.0.0.1 2
|
|
Connections to top 10 local ports
|
|
38346 1
|
|
60875 1
|
|
States of connections
|
|
ESTABLISHED 5
|
|
LISTEN 8
|
|
|
|
This section shows a summary of network connections, retrieved from C<netstat>
|
|
and "fuzzy-rounded" to make them easier to compare when the numbers grow large.
|
|
There are two sub-sections showing how many connections there are per origin
|
|
and destination IP address, and a sub-section showing the count of ports in
|
|
use. The section ends with the count of the network connections' states. You
|
|
can skip this section by disabling the L<"--summarize-network"> option.
|
|
|
|
# Top Processes ##############################################
|
|
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
|
1 root 15 0 2072 628 540 S 0.0 0.1 0:02.55 init
|
|
2 root RT -5 0 0 0 S 0.0 0.0 0:00.00 migration/0
|
|
3 root 34 19 0 0 0 S 0.0 0.0 0:00.03 ksoftirqd/0
|
|
4 root RT -5 0 0 0 S 0.0 0.0 0:00.00 watchdog/0
|
|
5 root 10 -5 0 0 0 S 0.0 0.0 0:00.97 events/0
|
|
6 root 10 -5 0 0 0 S 0.0 0.0 0:00.00 khelper
|
|
7 root 10 -5 0 0 0 S 0.0 0.0 0:00.00 kthread
|
|
10 root 10 -5 0 0 0 S 0.0 0.0 0:00.13 kblockd/0
|
|
11 root 20 -5 0 0 0 S 0.0 0.0 0:00.00 kacpid
|
|
# Notable Processes ##########################################
|
|
PID OOM COMMAND
|
|
2028 +0 sshd
|
|
|
|
This section shows the first few lines of C<top> so that you can see what
|
|
processes are actively using CPU time. The notable processes include the SSH
|
|
daemon and any process whose out-of-memory-killer priority is set to 17. You
|
|
can skip this section by disabling the L<"--summarize-processes"> option.
|
|
|
|
# Simplified and fuzzy rounded vmstat (wait please) ##########
|
|
procs ---swap-- -----io---- ---system---- --------cpu--------
|
|
r b si so bi bo ir cs us sy il wa st
|
|
2 0 0 0 3 15 30 125 0 0 99 0 0
|
|
0 0 0 0 0 0 1250 800 6 10 84 0 0
|
|
0 0 0 0 0 0 1000 125 0 0 100 0 0
|
|
0 0 0 0 0 0 1000 125 0 0 100 0 0
|
|
0 0 0 0 0 450 1000 125 0 1 88 11 0
|
|
# The End ####################################################
|
|
|
|
This section is a trimmed-down sample of C<vmstat 1 5>, so you can see the
|
|
general status of the system at present. The values in the table are
|
|
fuzzy-rounded, except for the CPU columns. You can skip this section by
|
|
disabling the L<"--summarize-processes"> option.
|
|
|
|
=head1 OPTIONS
|
|
|
|
=over
|
|
|
|
=item --config
|
|
|
|
type: string
|
|
|
|
Read this comma-separated list of config files. If specified, this must be the
|
|
first option on the command line.
|
|
|
|
=item --help
|
|
|
|
Print help and exit.
|
|
|
|
=item --read-samples
|
|
|
|
type: string
|
|
|
|
Create a report from the files in this directory.
|
|
|
|
=item --save-samples
|
|
|
|
type: string
|
|
|
|
Save the collected data in this directory.
|
|
|
|
=item --sleep
|
|
|
|
type: int; default: 5
|
|
|
|
How long to sleep when gathering samples from vmstat.
|
|
|
|
=item --summarize-mounts
|
|
|
|
default: yes; negatable: yes
|
|
|
|
Report on mounted filesystems and disk usage.
|
|
|
|
=item --summarize-network
|
|
|
|
default: yes; negatable: yes
|
|
|
|
Report on network controllers and configuration.
|
|
|
|
=item --summarize-processes
|
|
|
|
default: yes; negatable: yes
|
|
|
|
Report on top processes and C<vmstat> output.
|
|
|
|
=item --version
|
|
|
|
Print tool's version and exit.
|
|
|
|
=back
|
|
|
|
=head1 ENVIRONMENT
|
|
|
|
This tool does not use any environment variables.
|
|
|
|
=head1 SYSTEM REQUIREMENTS
|
|
|
|
This tool requires the Bourne shell (F</bin/sh>).
|
|
|
|
=head1 BUGS
|
|
|
|
For a list of known bugs, see L<https://jira.percona.com/projects/PT/issues>.
|
|
|
|
Please report bugs at L<https://jira.percona.com/projects/PT>.
|
|
Include the following information in your bug report:
|
|
|
|
=over
|
|
|
|
=item * Complete command-line used to run the tool
|
|
|
|
=item * Tool L<"--version">
|
|
|
|
=item * MySQL version of all servers involved
|
|
|
|
=item * Output from the tool including STDERR
|
|
|
|
=item * Input files (log/dump/config files, etc.)
|
|
|
|
=back
|
|
|
|
If possible, include debugging output by running the tool with C<PTDEBUG>;
|
|
see L<"ENVIRONMENT">.
|
|
|
|
=head1 ATTENTION
|
|
|
|
Using <PTDEBUG> might expose passwords. When debug is enabled, all command line
|
|
parameters are shown in the output.
|
|
|
|
=head1 DOWNLOADING
|
|
|
|
Visit L<http://www.percona.com/software/percona-toolkit/> to download the
|
|
latest release of Percona Toolkit. Or, get the latest release from the
|
|
command line:
|
|
|
|
wget percona.com/get/percona-toolkit.tar.gz
|
|
|
|
wget percona.com/get/percona-toolkit.rpm
|
|
|
|
wget percona.com/get/percona-toolkit.deb
|
|
|
|
You can also get individual tools from the latest release:
|
|
|
|
wget percona.com/get/TOOL
|
|
|
|
Replace C<TOOL> with the name of any tool.
|
|
|
|
=head1 AUTHORS
|
|
|
|
Baron Schwartz, Kevin van Zonneveld, and Brian Fraser
|
|
|
|
=head1 ABOUT PERCONA TOOLKIT
|
|
|
|
This tool is part of Percona Toolkit, a collection of advanced command-line
|
|
tools for MySQL developed by Percona. Percona Toolkit was forked from two
|
|
projects in June, 2011: Maatkit and Aspersa. Those projects were created by
|
|
Baron Schwartz and primarily developed by him and Daniel Nichter. Visit
|
|
L<http://www.percona.com/software/> to learn about other free, open-source
|
|
software from Percona.
|
|
|
|
=head1 COPYRIGHT, LICENSE, AND WARRANTY
|
|
|
|
This program is copyright 2011-2024 Percona LLC and/or its affiliates,
|
|
2010-2011 Baron Schwartz.
|
|
|
|
THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
This program is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free Software
|
|
Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
|
|
systems, you can issue `man perlgpl' or `man perlartistic' to read these
|
|
licenses.
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
|
|
=head1 VERSION
|
|
|
|
pt-summary 3.7.0
|
|
|
|
=cut
|
|
|
|
DOCUMENTATION
|