#!/bin/bash
# pt-stat
# author yong.ma
# version 3.2
log() {
  echo "`date '+%Y-%m-%d %H:%M:%S'` $1"
}

usage_and_exit(){
  echo "usage:  `basename $0` [-d] [-c category_column] [-e elapsed_column] [-l latency_column]"
  echo "                [-s status_column] [-o ok_codes] [-x strip_milliseconds]" 
  echo "                [-T toleration_threshold] [-F frustration_threshold]"
  echo "                [-P parallel_number] [-L 1000*lines_per_smaller_jtl_file]"
  echo "                jtl_file"
  echo "  e.g.  `basename $0` test.jtl"
  echo "        `basename $0` -x1000 test.jtl"
  echo "        `basename $0` -x1000 -e14 -T10 -F20 test.jtl"
  echo "        `basename $0` -x1000 -o200,201 test.jtl"
  echo "        `basename $0` -x1000 -otrue -s8 test.jtl"
  echo "        `basename $0` -x1000 -P2 -L1 test.jtl"
  echo ""
  echo "  -c    the index of category column, default 3"
  echo "  -e    the index of elapsed column, default 2"
  echo "  -l    the index of latency column, default 14" 
  echo "  -s    the index of status column, default 4" 
  echo "  -o    the list of OK status code, comma-separated, default 200" 
  echo "  -x    ingore the head and tail records of jtl_file by strip_milliseconds, default 60000" 
  echo "  -T    the toleration threshold in milliseconds, default 500"
  echo "  -F    the frustration threshold in milliseconds, default 1500" 
  echo "  -P    the parallel number of analysing, default is the cpu cores"
  echo "  -L    1000*L lines in per smaller jtl files, default 5000" 
  echo "  -d    debug mode"
  exit $1
}

epoch_to_readable_date(){
  case "`uname`" in
    Darwin)
      echo "`date -r $1 +"%Y-%m-%d %H:%M:%S"`"
      ;;
    *)
      echo "`date -d @$1 +"%Y-%m-%d %H:%M:%S"`"
      ;;    
  esac 
}

cpu_cores(){
  case "`uname`" in
    Darwin)
      echo "`sysctl -n hw.ncpu`"
      ;;
    *)
      echo "`cat /proc/cpuinfo|grep processor|wc -l|tr -d ' '`"
      ;;    
  esac 
}

if [[ $# -eq 0 ]]; then
  usage_and_exit 0
fi	

prgdir=`dirname $0`
category_column=3
elapsed_column=2
latency_column=14
status_column=4
ok_codes=200
strip_milliseconds=60000
Tthreshold=500
Fthreshold=1500
parallel="`cpu_cores`"
lines=5000000
debug=0

while getopts ":c:e:l:s:o:x:T:F:P:L:d" OPT; do
case $OPT in
  c)
    category_column="$OPTARG"
    ;;
  e)
    elapsed_column="$OPTARG"
    ;;  
  l)
    latency_column="$OPTARG"
    ;;  
  s)
    status_column="$OPTARG"
    ;; 
  o)
    ok_codes="$OPTARG"
    ;;     
  x)
    strip_milliseconds="$OPTARG"
    ;;
  T)
    Tthreshold="$OPTARG"
    ;;
  F)
    Fthreshold="$OPTARG"
    ;;    
  P)
    parallel="$OPTARG"
    ;;
  L)
    lines=$((1000*OPTARG))
    ;;       
  d)
    debug=1
    ;;    
  ?) 
    usage_and_exit 1
    ;;
esac
done

log "BEGIN"
shift $((OPTIND-1))
jtl_file="$1"
if [[ -z "$jtl_file" ]]; then
  echo "jtl_file cannot be empty"	
  echo ""
  usage_and_exit 1
fi

log "calculating time range ..."
time_a=`head -2 $jtl_file | tail -1 | awk -F ',' '{print $1}'`
time_b=`tail -1 $jtl_file | awk -F ',' '{print $1}'`

time_a=$((time_a + strip_milliseconds))
time_b=$((time_b - strip_milliseconds))
duration=$((time_b-time_a))

echo "              jtl_file : $jtl_file"
echo "             time_from : $time_a  `epoch_to_readable_date $(($time_a/1000))`"
echo "               time_to : $time_b  `epoch_to_readable_date $(($time_b/1000))`"
echo "              duration : $duration milliseconds"
echo "  toleration threshold : $Tthreshold milliseconds"
echo " frustration threshold : $Fthreshold milliseconds"
echo "       parallel number : $parallel"
echo " lines per smaller jtl : $lines"

if [[ $duration -le 0 ]]; then
  echo "No records selected."
  exit 1
fi  

log "spliting jtl to smaller files"
split_prefix="$jtl_file-split-"
stat_prefix="${split_prefix//-split-/-stat-}"
rm -f "$split_prefix"* "$stat_prefix"*
split -l$lines "$jtl_file" "$split_prefix" 

log "analysing, please wait ..."
count=0
smaller_jtl_count="`ls "$split_prefix"* |wc -l|tr -d " "`"
ls "$split_prefix"* | while read smaller_jtl; do
  count=$((count+1)) 
  echo -ne "\r $count/$smaller_jtl_count analysing $smaller_jtl"

  (awk -F, \
   -v debug=$debug \
   -v time_a=$time_a \
   -v time_b=$time_b \
   -v category_column=$category_column \
   -v elapsed_column=$elapsed_column \
   -v latency_column=$latency_column \
   -v status_column=$status_column \
   -v ok_codes=$ok_codes \
   -v Tthreshold=$Tthreshold \
   -v Fthreshold=$Fthreshold \
   -f "$prgdir"/pt-stat-parallel.awk \
   "$smaller_jtl" > "${smaller_jtl//-split-/-stat-}") &
  
  if [ $((count%parallel)) -eq 0 -o $count -eq $smaller_jtl_count ]; then
    wait
  fi
done

echo ""
log " summary ..."
cat "$stat_prefix"* | awk \
 -v debug=$debug \
 -v time_a=$time_a \
 -v time_b=$time_b \
 -f "$prgdir"/pt-stat.awk

# clean
rm -f "$split_prefix"* "$stat_prefix"*
log "END"
