blob: d38dd2e1d4430d9ffe6725b366ae03936cdf82fa [file] [log] [blame]
#!/usr/bin/env bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
JDKPATH=$JAVA_HOME
BINPATH="/usr/bin/"
USER=`whoami`
#SETTINGS=/Library/Java/JavaVirtualMachines/jdk1.8.0_51.jdk/Contents/Home/jre/lib/jfr/profile.jfc
SETTINGS=profile
platform='unknown'
unamestr=`uname`
if [[ "$unamestr" == 'Linux' ]]; then
platform='linux'
elif [[ "$unamestr" == 'Darwin' ]]; then
platform='darwin'
elif [[ "$unamestr" == 'FreeBSD' ]]; then
platform='freebsd'
fi
if [[ $platform == 'linux' ]]; then
if [ -z "$JDKPATH" ]; then
BINPATH="/usr/bin/"
else
BINPATH="$JDKPATH/bin/"
fi
elif [[ $platform == 'darwin' ]]; then
BINPATH="/usr/bin/"
fi
#check if java is available at $BINPATH; if not, fall back to use java commands directly.
JAVAPATH="${BINPATH}java"
if [ -f "$JAVAPATH" ]; then
echo "$JAVAPATH found. Will use java utils from $BINPATH"
else
echo "$JAVAPATH or JAVA_HOME not found. Will use java utils directly";
BINPATH=""
fi
export RECORDING_NAME_PREFIX="storm-recording-"
function start_record {
# start_record pid
timestamps=`get_recording_timestamps $1`
if [ -z "${timestamps}" ]; then
# append timestamp to ${RECORDING_NAME_PREFIX} to form a recording name
${BINPATH}jcmd $1 JFR.start name=${RECORDING_NAME_PREFIX}${NOW} settings=${SETTINGS}
else
echo "Another recoding session is already in progress; skipping"
fi
}
function dump_record {
timestamps=`get_recording_timestamps $1`
if [ -z "${timestamps}" ]; then
echo "No exsiting recording session to stop"
else
for start_timestamp in ${timestamps}; do
FILENAME=recording-$1-${start_timestamp}-${NOW}.jfr
${BINPATH}jcmd $1 JFR.dump name=${RECORDING_NAME_PREFIX}${start_timestamp} filename="$2/${FILENAME}"
done
fi
}
function stop_record {
timestamps=`get_recording_timestamps $1`
if [ -z "${timestamps}" ]; then
echo "No exsiting recording session to stop"
else
for start_timestamp in ${timestamps}; do
FILENAME=recording-$1-${start_timestamp}-${NOW}.jfr
${BINPATH}jcmd $1 JFR.dump name=${RECORDING_NAME_PREFIX}${start_timestamp} filename="$2/${FILENAME}"
${BINPATH}jcmd $1 JFR.stop name=${RECORDING_NAME_PREFIX}${start_timestamp}
done
fi
}
# recoding name is coded as ${RECORDING_NAME_PREFIX}${start_timestamp}, see start_record.
# On different JFR version (e.g. 5.4 vs 5.5), the output format is different: 5.4 has double quotes for the recording name, 5.5 doesn't have double quotes.
function get_recording_timestamps {
${BINPATH}jcmd $1 JFR.check | perl -n -e '/name=(")?$ENV{RECORDING_NAME_PREFIX}([0-9]+)(?(1)\1|)/ && print "$2 "'
}
function jstack_record {
FILENAME=jstack-$1-${NOW}.txt
${BINPATH}jstack $1 > "$2/${FILENAME}" 2>&1
}
function jmap_record {
FILENAME=recording-$1-${NOW}.bin
${BINPATH}jmap -dump:format=b,file="$2/${FILENAME}" $1
/bin/chmod g+r "$2/${FILENAME}"
}
function usage_and_quit {
echo "Usage: $0 pid start [profile_settings]"
echo " $0 pid dump target_dir"
echo " $0 pid stop target_dir"
echo " $0 pid jstack target_dir"
echo " $0 pid jmap target_dir"
echo " $0 pid kill"
exit -1
}
# Before using this script: make sure FlightRecorder is enabled
if [ "$#" -le 1 ]; then
echo "Wrong number of arguments.."
usage_and_quit
fi
# call this script with the process pid, example: "./flight PID start" or "./flight PID stop"
PID="$1"
CMD="$2"
if /bin/ps -p $PID > /dev/null
then
if [[ $platform == 'linux' ]]; then
USER=`/bin/ps -ouser --noheader $PID`
elif [[ $platform == 'darwin' ]]; then
USER=`/bin/ps -ouser $PID`
fi
else
echo "No such pid running: $PID"
usage_and_quit
fi
if [ "$CMD" != "start" ] && [ "$CMD" != "kill" ]; then
if [[ $3 ]] && [[ -d $3 ]]
then
TARGETDIR="$3"
mkdir -p ${TARGETDIR}
else
echo "Missing target directory"
usage_and_quit
fi
fi
NOW=`date +'%Y%m%d%H%M%S'`
if [ "$CMD" = "" ]; then
usage_and_quit
elif [ "$CMD" = "kill" ]; then
echo "Killing process with pid: $PID"
kill -9 ${PID}
elif [ "$CMD" = "start" ]; then
if [[ $3 ]]
then
SETTINGS=$3
fi
start_record ${PID}
elif [ "$CMD" = "stop" ]; then
echo "Capturing dump before stopping in dir $TARGETDIR"
stop_record ${PID} ${TARGETDIR}
elif [ "$CMD" = "jstack" ]; then
echo "Capturing dump in dir $TARGETDIR"
jstack_record ${PID} ${TARGETDIR}
elif [ "$CMD" = "jmap" ]; then
echo "Capturing dump in dir $TARGETDIR"
jmap_record ${PID} ${TARGETDIR}
elif [ "$CMD" = "dump" ]; then
echo "Capturing dump in dir $TARGETDIR"
dump_record ${PID} ${TARGETDIR}
else
usage_and_quit
fi