Skip to content

Instantly share code, notes, and snippets.

@andkirby
Last active June 30, 2016 12:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andkirby/0526613849d76e46081d190cb1f0a9e1 to your computer and use it in GitHub Desktop.
Save andkirby/0526613849d76e46081d190cb1f0a9e1 to your computer and use it in GitHub Desktop.
Magento Exceptions Log Monitor for Slack.
#!/usr/bin/env bash
# This script can send Magento 1.x exception messages to Slack
#
# This file can be added to the root of a project
# Please be sure that you have a file var/log/exception.log in your project
#
# Run this file in background via command with "&" in the end
# $ slack-log-monitor.sh [OPTIONS] &
# See more options by command: $ slack-log-monitor.sh --help
# Slack settings
slack_webhook_url=''
# The channel option can be empty if it's defined in webhook
slack_channel=''
# It uses directory name if it's empty
project_name=''
# Replace project path in path to file of the thrown exception
replace_base_path=1
# Relative path to log file for watching
log_file_relative='var/log/exception.log'
# Project directory, it will use this file directory if it's empty
prj_dir=''
# Regular expression for matching line log file stream
regular_log_line="^exception '"
# Enable parsing message. It will find class name, message, and path to file.
parse_message='1'
# Log CURL errors
log_curl_error='0'
# Filter messages by string
grep_string=''
# Invert grep result
grep_invert='0'
# Do not post grep string with message
no_grep_message='1'
# Ignored messages list (regular, use "|" (pipe) as a separator)
ignore_messages=''
CURRENT_DIR=$(pwd)
readonly CURRENT_DIR
# Show help
function show_me_help {
echo "This script can send Magento 1.x exception messages to Slack.
Run this file in background via command with '&' in the end:
$ bash slack-log-monitor.sh [OPTIONS] &
-p, --project-dir DIRECTORY
Path to Magento root directory.
If it's empty it will use path to this file by default.
-m, --project-name NAME
Project name, used in the output message.
If it's empty it will use project directory name by default.
-l, --webhook-url URL
Slack service URL.
-c, --channel CHANNEL
Slack channel name, @username or #group
-g, --grep REGEXP
Filter messages by regexp.
--grep-invert
Invert grep match.
--no-grep-in-message
Do not add filter in Slack message.
--ignore-messages-file
File which contains message examples (by lines) which should be ignored.
E.g. 'Invalid token' - in file
Similar message 'Invalid token #234' will be ignored.
-f, --log-file FILE
Relative path to the 'exception.log' file.
Default: var/log/exception.log
--use-absolute-path
Keep absolute path to files in the output message.
-r, --regular-line REGULAR_EXPR
Regular expression for matching log line.
Not matched lines will be omitted.
Default: ^exception '
--not-parse-message
Not parse log line but send it as is.
-d, --log-curl-errors
Log CURL errors into slack_curl.log in a project dir.
"
}
# Parse input params
while [[ $# > 0 ]]; do
key="$1"
case ${key} in
-m|--project-name)
project_name="$2"
shift # past argument
;;
-p|--project-dir)
# Argument PROJECT_DIR
# Set path to this file location
prj_dir="$2"
shift # past argument
;;
-l|--webhook-url)
slack_webhook_url="$2"
shift # past argument
;;
-c|--channel)
slack_channel="$2"
shift # past argument
;;
-g|--grep)
grep_string="$2"
shift # past argument
;;
--grep-in-message)
no_grep_message='0'
;;
--grep-invert)
grep_invert='1'
;;
-f|--log-file)
log_file_relative="$2"
shift # past argument
;;
-i|--ignore-messages-file)
ignore_messages_file="$2"
if [ ! -f "${ignore_messages_file}" ]; then
show_me_help
echo "error: File '${ignore_messages_file}' not found."
exit 2
fi
shift # past argument
;;
-r|--regular-line)
regular_log_line="$2"
shift # past argument
;;
--absolute-path)
replace_base_path='0'
# no value
;;
--not-parse-message)
parse_message='0'
;;
-d|--log-curl-errors)
log_curl_error='1'
;;
-h|--help)
show_me_help
exit
;;
*)
show_me_help
echo "error: Unknown option '${key}'"
exit 2
;;
esac
shift # past argument or value
done
# Code
if [ -z "${prj_dir}" ];then
PRJ_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd -P)"
elif [ ! -d "${prj_dir}" ]; then
echo "error: Project directory '${prj_dir}' not found."
exit 1
else
PRJ_DIR="$( cd "${prj_dir}" && pwd -P)"
fi
readonly PRJ_DIR
# Full path to log file
if [[ ${log_file_relative:0:1} == '/' ]]; then
# use absolute path
log_file=${log_file_relative}
else
# use path within a project directory
log_file=${PRJ_DIR}/${log_file_relative#/}
fi
# CURL errors log file
curl_log_file="$( cd "$( dirname "${log_file}" )" && pwd -P)"'/slack_curl.log'
# Check Slack webhook URL
if [ -z "${slack_webhook_url}" ]; then
show_me_help
echo "error: Slack webhook URL cannot be empty."
exit 1
fi
# Set project name if it's an empty
if [ '' == "${project_name}" ]; then
# Project name will be taken from a project directory name
# it will use real path instead symlink
project_name="$( cd ${PRJ_DIR} && basename $(pwd -P))"
fi
if [ ! -f ${log_file} ]; then
echo "error: File '${log_file}' not found."
exit 1
fi
slack_head_message='File: '${log_file_relative}
catch_full_message='0'
catch_trace='0'
tail -fn0 ${log_file} | \
while read line ; do
if [ "${catch_trace}" == '1' ]; then
trace=${trace}"\n"${line}
if [ ${line} == *'{main}'* ]; then
# End line, send a message
catch_trace='0'
fi
else
# check ignored messages
if [ -n "${ignore_messages_file}" ]; then
ignore_messages=$(cat ${ignore_messages_file} | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/|/g')
printf "2 ${ignore_messages}"
if [ -n "${ignore_messages}" ]; then
line=$(echo "${line}" | grep -Ev "(${ignore_messages})" 2>&1)
if [ -z "${line}" ]; then
continue
fi
fi
fi
echo "${line}" | grep -E "${regular_log_line}" 2>&1
if [ $? != 0 ]; then
# line doesn't matched
continue
fi
# Apply custom filter
if [ -n "${grep_string}" ]; then
if [ '1' == "${grep_invert}" ]; then
# invert match
line=$(echo "${line}" | grep -Ev "${grep_string}" 2>&1)
else
line=$(echo "${line}" | grep -E "${grep_string}" 2>&1)
fi
if [ -z "${line}" ]; then
# line doesn't matched with filter
continue
fi
fi
head_line=${line}
# Catch trace strings...
if [ "${catch_full_message}" == '1' ]; then
catch_trace='1'
trace_lines=''
fi
echo 'Sending...'
fi
if [ '1' == ${parse_message} ]; then
# Parse message
exception_class=$(echo ${head_line} | grep -Eo "exception '[^']*'" | sed "s|exception '||" | tr -d "'")
exception_message=$(echo ${head_line} | grep -Eo "' with message '.*' in /" | sed "s|' with message '||" | sed "s|' in /||")
exception_path='/'$(echo ${head_line} | grep -Eo "' in /.+" | sed "s|' in /||")
# Cut project path
if [ "${replace_base_path}" == '1' ]; then
exception_path=$(echo ${exception_path} | sed "s|${PRJ_DIR}/||")
fi
message="${exception_message}\n${exception_class}\n${exception_path}\n"
else
# Show message line as is
message=${head_line}
# Cut project path
if [ "${replace_base_path}" == '1' ]; then
message=$(echo ${message} | sed "s|${PRJ_DIR}/||")
fi
if [ -n "${trace}" ]; then
trace=$(echo ${trace} | sed "s|${PRJ_DIR}/||")
message="${message}\n${trace}"
fi
fi
# escape quotes
message=$(echo ${message} | sed 's|"|\\"|g')
message=$(echo ${message} | sed "s|'|\\'|g")
# ---- Send message to Slack ----
curl_body='payload={'
# Prepare message attachments
attachments='{"color": "danger", "text": "'${message}'"}'
# Add showing filter string
if [ -n "${grep_string}" ] && [ '1' != ${no_grep_message} ]; then
grep_string=$(echo ${grep_string} | sed 's|"|\\"|g')
grep_string=$(echo ${grep_string} | sed "s|'|\\'|g")
attachments+=',{"color": "#439fe0", "text": "Filter: '${grep_string}'"}'
fi
# Add attachments into cURL body
curl_body=${curl_body}'"attachments":['${attachments}'],'
curl_body=${curl_body}'"username": "'${project_name}' log",'
if [ -n "${slack_channel}" ]; then
curl_body=${curl_body}'"channel":"'${slack_channel}'",'
fi
curl_body=${curl_body}'"text": "'${slack_head_message}'"'
curl_body=${curl_body}'}'
# Send message to Slack
result=$(curl -s --data "${curl_body}" ${slack_webhook_url} 2>&1)
if [ "${result}" != 'ok' ]; then
echo 'error: Could not make request to slack. Please check your options.'
# Log Slack errors
if [ "${log_curl_error}" == '1' ]; then
err=$(date)" : CURL error"
err="${err}\nCURL Response: ${result}"
err="${err}\nCURL body: ${curl_body}"
err="${err}\nService URL: ${slack_webhook_url}"
if [ -n "${slack_channel}" ]; then
err="${err}\nChannel: ${slack_channel}"
fi
exist_log=''
if [ -f ${curl_log_file} ]; then
exist_log=$(cat ${curl_log_file})
fi
printf "${err}\n${exist_log}" > ${curl_log_file}
echo 'See log file: '${curl_log_file}
fi
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment