Tuesday, October 27, 2020

Smashing Walls of Text

On a few projects I work on, we make use of Ansible to automate system-configuration tasks. For better or worse, the automation relies on some upstream content that is outside the control of the customer. Translation: every few months, automation that has worked for months will suddenly no longer work.

By itself, this is more an inconvenience than a real problem. However, because the automation is handed off to other, more-junior people to execute, when errors are encountered, those others are frequently at a loss as to what to do.

Frequently, they don't bother to include logs of any sort ...or if they do, they include log snippets (or, worse: screen-caps of text-based log snippets!), the snippets frequently don't contain the information critical to solve the problem. So, first response in the support request is a "send me all the logs" type of reply.

Now, depending on the size of the Ansible job, the associate log-file might be HUGE. Generally, I'm only interested in where Ansible has failed. Parsing through an entire Ansible log-file can be like trying to find a specific brick in the Great Wall of China. So, to help preserve my sanity, I cooked up a quick BASH script to both help "cut to the chase" and provide more-easily readable log-output. That script looks like:

#!/bin/bash
#
# Script to filter the output of Ansible log files to something more-readable
#
###########################################################################
OUTFILE="${1:-/tmp/Ansible.log}"

mapfile -t ERROUT < <(
   grep ^failed: "${OUTFILE}"
)

# Make sure we got a mount-string
if [[ ${#ERROUT[@]} -lt 1 ]]
then
   echo "No failure-messages found in ${OUTFILE}"
fi

# Iterate over error-string
ITER=0
while [[ ${ITER} -lt ${#ERROUT[@]} ]]
do
   printf '##########\n## %s\n##########\n' "$(
      echo "${ERROUT[${ITER}]}" | sed 's/^failed:.* => //' | 
      python3 -c "import sys, json; print(json.load(sys.stdin)['item'])"
   )"
   
   echo "${ERROUT[${ITER}]}" | sed 's/^failed:.* => //' | \
     python3 -c "import sys, json; print(json.load(sys.stdin)['stderr'])" | sed 's/^/    /'
     
   printf '####################\n\n\n'
   ITER=$(( ITER + 1 ))
done