Skip to content

Instantly share code, notes, and snippets.

@gildas
Last active July 17, 2020 09:44
Show Gist options
  • Save gildas/012891cba31d38245acd7d608b88d35a to your computer and use it in GitHub Desktop.
Save gildas/012891cba31d38245acd7d608b88d35a to your computer and use it in GitHub Desktop.
view pm2 log files through the bunyan log viewer
#!/usr/bin/env bash
shopt -s extglob
set -o errtrace
#set -o errexit
set +o noclobber
# Defaults {{{
NOOP=
VERBOSE=${VERBOSE:0}
LOGVIEW_OPTS=%{LOGVIEW_OPTS:=}
FOLLOW=--nostream
TAIL=15
LOGPAGER=0
LOGCOLOR=--color
LOGTIME=-L
LOGFORMAT="--output short"
LOGLEVEL=${LOGLEVEL:=}
LOGFILTER=
# Defaults }}}
# DO NOT MODIFY ANYTHING AFTER THIS LINE ###############################################################
# General variables
SUBSYSTEM=
VERSION=1.0.0
# tracing and messages {{{
function trace() { [[ $VERBOSE == 2 ]] && echo -e "Trace: $@" >&2; }
function verbose() { [[ $VERBOSE == 1 ]] && echo -e "$@"; }
function warn() { echo -e "\033[33mWarning: $@\033[0m"; }
function error() { echo -e "\033[1;31mError: $@\033[0m" >&2; }
function die() { error "$1" ; exit ${2:-1} ; }
function die_on_error() { local status=$?; [[ $status != 0 ]] && die "$@, Error: $status" $status || return 0; }
# }}}
# Arguments {{{
function usage() { # {{{2
echo "$(basename $0) [options] [subsystem|pm2 id]"
echo " View and Interpret logs for the given subsystem"
echo " Subsystems can be: config, line or line_connector, pnp or pnp_provider,"
echo " pureconnect or pureconnect_connector."
echo " Subsystems can also be mentioned by their pm2 id."
echo " "
echo " Options below can also be set in the environment variable LOGVIEW_OPTS. Example:"
echo " export LOGVIEW_OPTS=\"--follow --more --local --short\""
echo " "
echo " Options are:"
echo " --condition CONDITION, --filter CONDITION, -c CONDITION"
echo " Runs each log message through the condition and"
echo " only show those that return truish. E.g.:"
echo " -c 'this.pid == 123'"
echo " -c 'this.level == DEBUG'"
echo " -c 'this.msg.indexOf("boom") != -1'"
echo " \"CONDITION\" must be legal JS code. \`this\` holds the log record."
echo " The TRACE, DEBUG, ... FATAL values are defined to help with "
echo " comparing \`this.level\`."
echo " --level LEVEL"
echo " Shows only messages at or above the specified level."
echo " \"LEVEL\" can be a level name or a numeric value."
echo " --color"
echo " Colorizes the output (Default)."
echo " --no-color"
echo " Does not colorize the output."
echo " --follow, --tail, -f "
echo " Follows the log file like \`tail -f\`."
echo " --no-follow, --no-stream, --nostream"
echo " Does not follow the log file."
echo " --lines LINES"
echo " Shows the last \"LINES\" lines of the log."
echo " --pager, --more "
echo " Pauses at the end of every page."
echo " Pipes output into \$PAGER, less, or more"
echo " --no-pager, --no-more "
echo " Does not Pause at the end of every page."
echo " --local, --localtime, -L"
echo " Shows timestamps to the local time of this machine (Default)."
echo " --utc"
echo " Shows timestamps in UTC"
echo " --long"
echo " shows more information for each log entry."
echo " --short"
echo " shows less information for each log entry (Default)."
echo " --help "
echo " Prints some help on the output."
echo " --quiet "
echo " Runs the script as silently as possible."
echo " --noop, --dry-run, --dryrun "
echo " Does not run any command that would change the state of the OS."
echo " Used with \`-v -v\` (yes, -v twice), it will show the actual "
echo " command it would execute."
echo " --verbose "
echo " Runs the script verbosely."
echo " --version, -V "
echo " Shows the version of this application."
echo " --yes, --assumeyes, -y "
echo " Answers yes to any questions automatically."
} # 2}}}
function parse_args() { # {{{2
local status=0
while (( "$#" )); do
trace "Parsing option: $1"
# Replace --parm=arg with --parm arg
[[ $1 == --*=* ]] && set -- "${1%%=*}" "${1#*=}" "${@:2}"
case $1 in
# GENERAL Stuff
-c|--condition|--filter)
[[ -z $2 || ${2:0:1} == '-' ]] && die "Argument for option $1 is missing"
LOGFILTER="-c '$2'"
shift
;;
--color)
LOGCOLOR="--color"
;;
--no-color|--no_color)
LOGCOLOR="--no-color"
;;
-f|--follow|--tail)
FOLLOW=
;;
--lines)
[[ -z $2 || ${2:0:1} == '-' ]] && die "Argument for option $1 is missing"
TAIL=$2
shift
;;
--no-follow|--no-stream|--nostream)
FOLLOW="--nostream"
;;
--pager|--more)
LOGPAGER=1
;;
--no-pager|--no-more)
LOGPAGER=0
;;
-L|--local|--localtime|--local_time|--local-time)
LOGTIME=-L
;;
--utc|--UTC)
LOGTIME=
;;
-l|--level)
[[ -z $2 || ${2:0:1} == '-' ]] && die "Argument for option $1 is missing"
LOGLEVEL="--level $2"
shift
;;
--long)
LOGFORMAT="--output long"
;;
--short)
LOGFORMAT="--output short"
;;
# Standard options
-h|-\?|--help)
usage
exit 0
;;
--noop|--dry_run|--dry-run)
warn "This program will execute in dry mode, your system will not be modified"
NOOP=:
;;
--quiet)
VERBOSE=0
;;
-v|--verbose)
VERBOSE=$((VERBOSE + 1))
;;
--version|-V)
echo "$(basename $0) version $VERSION"
exit 0
;;
-?*) # Invalid options
warn "Unknown option $1 will be ignored"
;;
--) # Force end of options
shift
break
;;
*) # End of options
ARGS+=( "$1" )
break
;;
esac
shift
done
# Set all positional arguments back in the proper order
eval set -- "${ARGS[@]}"
# Validations
trace "$# Positional arguments: $@"
[[ $# < 1 ]] && die "Missing subsystem name or id"
SUBSYSTEM=$1
return 0
} # 2}}}
# }}}
function main() { # {{{
parse_args "$@" ; status=$? && [[ $status != 0 ]] && die "Failed to parse command line, error: $status" $status
# Seems like --pager does not work with bunyan, so let's DIY!!!
if [[ $LOGPAGER == 1 ]]; then
if command -v less; then
LOGPAGER=${PAGER:-less}
else
LOGPAGER=${PAGER:-more}
fi
trace "pm2 logs --raw --lines=$TAIL $FOLLOW $SUBSYSTEM | bunyan $LOGCOLOR $LOGTIME $LOGLEVEL $LOGFILER $LOGFORMAT | $LOGPAGER"
$NOOP pm2 logs --raw --lines=$TAIL $FOLLOW $SUBSYSTEM | bunyan $LOGCOLOR $LOGTIME $LOGLEVEL $LOGFILER $LOGFORMAT | $LOGPAGER
else
trace "pm2 logs --raw --lines=$TAIL $FOLLOW $SUBSYSTEM | bunyan $LOGCOLOR $LOGTIME $LOGLEVEL $LOGFILER $LOGFORMAT"
$NOOP pm2 logs --raw --lines=$TAIL $FOLLOW $SUBSYSTEM | bunyan $LOGCOLOR $LOGTIME $LOGLEVEL $LOGFILER $LOGFORMAT
fi
die_on_error "Failed to view log $SUBSYSTEM"
exit 0
} # }}}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment