ast_loggrabber 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #!/usr/bin/env bash
  2. # Turn on extended globbing
  3. shopt -s extglob
  4. # Bail on any error
  5. set -e
  6. prog=$(basename $0)
  7. print_help() {
  8. cat <<EOF
  9. NAME
  10. $prog - Gather asterisk log files
  11. SYNOPSIS
  12. $prog [ --help ] [ --dateformat="<dateformat>" ]
  13. [ --timezone="<timezone>" ] [ --append-logfiles ]
  14. [ --tarball-uniqueid="<uniqueid>" ]
  15. [ <logfiles> | <pattern> ... ]
  16. DESCRIPTION
  17. Gathers log files, optionally converts POSIX timestamps
  18. to readable format. and creates a tarball.
  19. Options:
  20. --help
  21. Print this help.
  22. --dateformat="<dateformat>"
  23. A Python strftime format string to be used when converting
  24. POSIX timestamps in log files to readable format. If not
  25. specified as an argument or in the config file, no conversion
  26. is done.
  27. --timezone="<timezone>"
  28. The timezone to use when converting POSIX timestamps to
  29. readable format. It can be specified in "<continent>/<city>"
  30. format or in abbreviation format such as "CST6CDT". If not
  31. specified as an argument or in the config file, the "local"
  32. timezone is used.
  33. --append-logfiles
  34. Append any log files specified on the command line to the
  35. config file specified ones instead of overriding them.
  36. --tarball-uniqueid="<uniqueid>"
  37. Normally DATEFORMAT is used to make the tarballs unique
  38. but you can use your own unique id in the tarball names
  39. such as a Jira issue id.
  40. <logfiles> | <pattern>
  41. A list of log files or log file search patterns. Unless
  42. --append-logfiles was specified, these entries will override
  43. those specified in the config files.
  44. If no files are specified on the command line the, value of
  45. LOGFILES from ast_debug_tools.conf will be used. Failing
  46. that, the following patterns will be used:
  47. /var/log/asterisk/messages*
  48. /var/log/asterisk/queue*
  49. /var/log/asterisk/debug*
  50. /var/log/asterisk/security*
  51. NOTES
  52. Any files output will have ':' characters changed to '-'. This is
  53. to facilitate uploading those files to Jira which doesn't like the
  54. colons.
  55. FILES
  56. /etc/asterisk/ast_debug_tools.conf
  57. ~/ast_debug_tools.conf
  58. ./ast_debug_tools.conf
  59. # Readable Local time for the tarball names
  60. DATEFORMAT='date +%FT%H-%M-%S%z'
  61. # A list of log files and/or log file search patterns using the
  62. # same syntax as COREDUMPS.
  63. #
  64. LOGFILES=(/var/log/asterisk/messages* /var/log/asterisk/queue* \\
  65. /var/log/asterisk/debug* /var/log/asterisk/security*)
  66. # $prog converts POSIX timestamps to readable format
  67. # using this Python strftime format string. If not specified
  68. # or an empty string, no format covnersion is done.
  69. LOG_DATEFORMAT="%m/%d %H:%M:%S.%f"
  70. # The timezone to use when converting POSIX timestamps to
  71. # readable format. It can be specified in "<continent>/<city>"
  72. # format or in abbreviation format such as "CST6CDT". If not
  73. # specified, the "local" timezone is used.
  74. # LOG_TIMEZONE=
  75. EOF
  76. exit 1
  77. }
  78. append_logfiles=false
  79. declare -a LOGFILES
  80. declare -a ARGS_LOGFILES
  81. # Read config files from least important to most important
  82. [ -f /etc/asterisk/ast_debug_tools.conf ] && source /etc/asterisk/ast_debug_tools.conf
  83. [ -f ~/ast_debug_tools.conf ] && source ~/ast_debug_tools.conf
  84. [ -f ./ast_debug_tools.conf ] && source ./ast_debug_tools.conf
  85. if [ ${#LOGFILES[@]} -eq 0 ] ; then
  86. LOGFILES+=(/var/log/asterisk/messages* /var/log/asterisk/queue* \
  87. /var/log/asterisk/debug* /var/log/asterisk/security*)
  88. fi
  89. DATEFORMAT=${DATEFORMAT:-'date +%FT%H-%M-%S%z'}
  90. # Use "$@" (with the quotes) so spaces in patterns or
  91. # file names are preserved.
  92. # Later on when we have to iterate over LOGFILES, we always
  93. # use the indexes rather than trying to expand the values of LOGFILES
  94. # just in case.
  95. for a in "$@" ; do
  96. case "$a" in
  97. --dateformat=*)
  98. LOG_DATEFORMAT=${a#*=}
  99. ;;
  100. --timezone=*)
  101. LOG_TIMEZONE=${a#*=}
  102. ;;
  103. --append-logfiles)
  104. append_logfiles=true
  105. ;;
  106. --tarball-uniqueid=*)
  107. tarball_uniqueid=${a#*=}
  108. ;;
  109. --help|-*)
  110. print_help
  111. ;;
  112. *)
  113. ARGS_LOGFILES+=("$a")
  114. # If any files are specified on the command line, ignore those
  115. # specified in the config files unless append-logfiles was specified.
  116. if ! $append_logfiles ; then
  117. LOGFILES=()
  118. fi
  119. esac
  120. done
  121. # append logfiles/patterns specified as command line arguments to LOGFILES.
  122. for i in ${!ARGS_LOGFILES[@]} ; do
  123. LOGFILES+=("${ARGS_LOGFILES[$i]}")
  124. done
  125. # At this point, all glob entries that match files should be expanded.
  126. # Any entries that don't exist are probably globs that didn't match anything
  127. # and need to be pruned.
  128. for i in ${!LOGFILES[@]} ; do
  129. if [ ! -f "${LOGFILES[$i]}" ] ; then
  130. unset LOGFILES[$i]
  131. continue
  132. fi
  133. done
  134. # Sort and weed out any dups
  135. IFS=$'\x0a'
  136. readarray -t LOGFILES < <(echo -n "${LOGFILES[*]}" | sort -u )
  137. unset IFS
  138. if [ "${#LOGFILES[@]}" -eq 0 ] ; then
  139. echo "No log files found"
  140. print_help
  141. fi
  142. # Timestamp to use for output files
  143. df=${tarball_uniqueid:-$(${DATEFORMAT})}
  144. # Extract the Python timestamp conver script from the end of this
  145. # script and save it to /tmp/.ast_tsconvert.py
  146. ss=`egrep -n "^#@@@SCRIPTSTART@@@" $0 |cut -f1 -d:`
  147. tail -n +${ss} $0 >/tmp/.ast_tsconvert.py
  148. tmpdir=$(mktemp -d)
  149. if [ -z "$tmpdir" ] ; then
  150. echo "${prog}: Unable to create temporary directory."
  151. exit 1
  152. fi
  153. trap "rm -rf $tmpdir" EXIT
  154. tardir=asterisk-${df}.logfiles
  155. # Now iterate over the logfiles
  156. for i in ${!LOGFILES[@]} ; do
  157. lf=${LOGFILES[$i]}
  158. destdir="$tmpdir/$tardir/$(dirname $lf)"
  159. destfile="$tmpdir/$tardir/$lf"
  160. mkdir -p "$destdir" 2>/dev/null || :
  161. if [ -n "$LOG_DATEFORMAT" ] ; then
  162. echo "Converting $lf"
  163. cat "$lf" | python /tmp/.ast_tsconvert.py --format="$LOG_DATEFORMAT" --timezone="$LOG_TIMEZONE" > "${destfile}"
  164. else
  165. echo "Copying $lf"
  166. cp "$lf" "${destfile}"
  167. fi
  168. done
  169. echo "Creating /tmp/$tardir.tar.gz"
  170. tar -czvf /tmp/$tardir.tar.gz -C $tmpdir $tardir 2>/dev/null
  171. exit
  172. # Be careful editng the inline scripts.
  173. # They're space-indented.
  174. # We need the python bit because lock_infos isn't
  175. # a valid symbol in asterisk unless DEBUG_THREADS was
  176. # used during the compile. Also, interrupt and continue
  177. # are only valid for a running program.
  178. #@@@SCRIPTSTART@@@
  179. import argparse
  180. import datetime as dt
  181. import dateutil.tz as tz
  182. import re
  183. import sys
  184. import time
  185. parser = argparse.ArgumentParser(description="Make POSIX timestamps readable")
  186. parser.add_argument('--format', action='store', required=True)
  187. parser.add_argument('--timezone', action='store', required=False)
  188. args=parser.parse_args()
  189. # We only convert timestamps that are at the beginning of a line
  190. # or are preceeded by a whilespace character or a '['
  191. rets = re.compile(r'(^|(?<=\s|\[))\d+(\.\d+)?', flags=re.M)
  192. if args.timezone and len(args.timezone) > 0:
  193. tzf = tz.tzfile('/usr/share/zoneinfo/' + args.timezone)
  194. else:
  195. tzf = tz.tzfile('/etc/localtime')
  196. now = time.time()
  197. a_year_ago = now - (86400.0 * 365)
  198. def convert(match):
  199. ts = float(match.group(0))
  200. if ts <= now and ts > a_year_ago and len(args.format) > 0:
  201. return dt.datetime.fromtimestamp(ts, tzf).strftime(args.format)
  202. else:
  203. return match.group(0)
  204. while 1:
  205. line = sys.stdin.readline()
  206. if not line:
  207. break
  208. print(rets.sub(convert, line))