Recently I had the requirement to allow multiple containers of the same application to be run on a single development server. This requirement drastically changed how we retrieve logs over SSH from the servers, and because I am not extremely well versed in bash, I wanted to get this script reviewed to see if there is an easier/cleaner way to approach this problem.
The goal of the script is to produce a single log file on the local system for each container on that is running on the remote server. It is currently working as expected for 1 and N containers running on a single server.
The script I wrote does the following:
- Verify that the server being requested can provide the logs
- SSH into the remote server and save the logs for each container to a file on the local system
- Post-Process the logs into individual log files for each container that is present
I am fairly certain there is a much easier way to accomplish this task, hence the post here to see if anyone can point me in the right direction (I have a feeling, as I write this, that I can just scp the docker log files for each container to the local system instead of all of this.... But I also want to practice some bash, so I would still like this reviewed)
Script:
#!/bin/bash
# Add a help parameter to the script
if [ "$1" == "-h" ] || [ "$1" == "-help" ]; then
echo "Usage: $(basename "$0")"
echo " Logs will be placed in /c/temp/logs/<server>.log"
echo " Prompts:"
echo " - Username: AD Username for Logins"
echo " - Server: This is a dev server, valid choices are:"
echo " (<SERVER_NAME>1 <SERVER_NAME>2 <SERVER_NAME>3 <SERVER_NAME>4)"
exit 0
fi
# Create an array of valid servers to check for logs
servers=(<SERVER_NAME>1 <SERVER_NAME>2 <SERVER_NAME>3 <SERVER_NAME>4)
# Ask the user where they want to get the logs from
read -rp "Username: " user
read -rp "Server: " server
# Validate the server can retrieve logs
foundServer=0
for i in "${servers[@]}"; do
if [ "$i" == "$server" ]; then
foundServer=1
break
fi
done
if [ $foundServer == 0 ]; then
echo "Please select a dev server"
echo "Use -h or -help for help with $(basename "$0")"
exit 1
fi
# Set the working directory
(cd /c/temp/logs/temp/ &&
# Get the logs. Servers with multiple containers will have the following structure:
# HeaderA
# A
# A
# A
# HeaderB
# B
# B
# B
now=$(date '+%Y%m%d_%H%M')
ssh -tt "$user"@"$server" "sudo setfacl --modify user:${user}:rw /var/run/docker.sock && docker ps --format '{{.Names}}' | xargs -L 1 -t docker logs" > ./"${server}_${now}.log"
# Process the temp file into individual files for each container ....
# Get the headers for each Log File
grep -n "docker logs" ./"${server}_${now}.log" >> ./docker_logs.txt
total_matches=$(wc -l ./docker_logs.txt | cut -d' ' -f1)
# From Line 1 -> First Match == Log A, From First Match -> Next Match == Log B, etc
start_line=1
# Get the file name for the first file
file_name_match=$(head -n 1 ./docker_logs.txt)
current_name=$(echo "$file_name_match" | cut -f2 -d: | sed "s/^docker logs //")
# Get the end line index for the first file
end_line_text=$(awk "NR==2" ./docker_logs.txt | cut -f1 -d:)
if [[ $end_line_text ]]; then
end_line=$(("$end_line_text"-1))
else
end_line="$"
fi
# Skipping the first file (starting from index 2), loop through any log files that are present
for (( n=2; n<="$total_matches"+1; n++ )) do
# Copy the current file from start -> end to the log file for the current name, if end_line was EOF
# then break from the loop
sed -n "${start_line},${end_line}p" ./"${server}_${now}.log" > ../"${server}_${now}_${current_name}.log"
if [[ $end_line == "$" ]]; then
break
fi
# Get the start line of the next file
start_line=$(("$end_line"+1))
# Get the file name of the next log file
file_name_match=$(awk "NR==$n" ./docker_logs.txt)
current_name=$(echo "$file_name_match" | cut -f2 -d: | sed "s/^docker logs //")
# Get the ending index of the next log file, if there is nothing returned, set end_line to
# be the EOF
end_index=$(("$n"+1))
end_line_text=$(awk "NR==$end_index" ./docker_logs.txt | cut -f1 -d:)
if [[ $end_line_text ]]; then
end_line=$(("$end_line_text"-1))
else
end_line="$"
fi
done
# Remove the temp files
rm -f /c/temp/logs/temp/*
)
# Open the logs directory for the user
start /c/temp/logs/
This produces N number of logfiles on the local system, of the format ${server}_${now}_${container_name}.log
.