#!/bin/bash

export TZ=UTC
export LC_ALL=C

app="${0##*/}"

verbose="0"
host="localhost"
port="6379"
interval="60"
sample_len="5"
duration="3600"

usage() {
  printf 'Usage: %s [-h host] [-p port] [-i interval] [-s sample_len] [-d duration] [-v]\n' "${app}" >&2
}

while getopts ":vh:p:i:s:d:" _o
do
  case ${_o} in
    v)
      verbose=1
    ;;
    h)
      host="${OPTARG}"
    ;;
    p)
      port="${OPTARG}"
    ;;
    i)
      interval="${OPTARG}"
    ;;
    s)
      sample_len="${OPTARG}"
    ;;
    d)
      duration="${OPTARG}"
    ;;
    :)
      printf 'Option "-%s" requires an argument.\n' "${OPTARG}" >&2
      usage
      exit 1
    ;;
    '?')
      printf 'Invalid option: -%s\n' "${OPTARG}" >&2
      usage
      exit 1
    ;;
  esac
done

if ! type redis-cli touch timeout sleep > /dev/null
then
  printf '%s: I need the utils mentioned above installed to work.\n' "${app}"
  exit 1
fi

printf >&2 '%s: host=%s:%d interval=%ds sample_len=%ds duration=%ds verbose=%d\n\n' \
  "${app}" "${host}" "${port}" "${interval}" "${sample_len}" "${duration}" "${verbose}"

if ! redis-cli -h "${host}" -p "${port}" PING >/dev/null
then
  printf '%s: Unexpected PING response from Redis server at %s:%d\n' "${app}" "${host}" "${port}" >&2
  exit 1
fi

export _quit_now_file="/tmp/.redistrace_${UID}_$$_exit_requested"
rm -f "${_quit_now_file}"

set -u

check_end_reached() {
  now=$(date +%s)
  if [[ $(( $start + $duration - $now )) -le 0 ]]
  then
    touch "${_quit_now_file}"
  fi
}

start=$(date +%s)

trap 'echo >&2 ": ${app}: scheduling exit..."; : > "${_quit_now_file}"' SIGINT SIGTERM SIGHUP

while IFS=' ' read -r ts db cl op first_arg _
do
  case "${ts}" in
  [0-9]*)
    db="${db#[}"
    cl="${cl%]}"
    cl_addr="${cl%:*}"
    cl_port="${cl#*:}"
    [[ $op ]] && op="${op:1:-1}"
    printf '%s %s %d %d %s\n'  "${ts}" "${cl_addr}" "${cl_port}" "${db}" "${op}"
  ;;
  OK)
    # noop; connect successful
  ;;
  *)
    printf 'WTF? Unexpected Redis "MONITOR" response...\n' >&2
  ;;
  esac
done < <(
  while ! test -e "${_quit_now_file}"
  do
    [[ ${verbose} -eq 1 ]] && printf 'Tracing (%ds)...\n' "${sample_len}" >&2
    timeout --preserve-status --signal=SIGTERM "${sample_len}" redis-cli -h "${host}" -p "${port}" MONITOR
    check_end_reached
    test -e "${_quit_now_file}" && continue
    [[ ${verbose} -eq 1 ]] && printf 'Waiting (%ds); ~ %ds to go...\n' $(( ${interval} - ${sample_len} )) $(( $start + $duration - $now )) >&2
    sleep $(( ${interval} - ${sample_len} ))
  done
)


rm -f "${_quit_now_file}"
[[ ${verbose} -eq 1 ]] && printf 'Done.\n' >&2
