Sentry is a great error aggregation service. We use it for every service we deploy at work. It lets us monitor and troubleshoot incidents of errors. It also integrates nicely with Slack, a messaging tool we use for everything.
It integrates nicely with Javascript, Ruby, and Python stacks among others — but as a RESTful service you can also access it directly from the command line.
Sometimes, you start writing a Bash shell script that grows so much that you need to start logging errors in a central error aggregation service. Frankly, that’s a sign that you should have picked a different language for the initial implementation, whether Python or Ruby or something else more robust. However, once you have such a Bash script, porting it arguably becomes as problematic as instrumenting it.
Bash client for Sentry
A quick Google search turns up more feature-complete attempts at a command line client. You may want to follow the link and use that instead.
Still, for posterity, here’s something I used to instrument such a Bash script last year:
# Install dependencies on Alpine Linux
apk --no-cache add --virtual build-dependencies gcc python-dev musl-dev
pip2 install httpie
# Transform a Sentry DSN into useful components
trim() {
local var="$*"
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"
echo -n "$var"
}
SENTRY_DSN=$(trim "${SENTRY_DSN:-}")
SENTRY_KEY="$(echo $SENTRY_DSN | sed -E "s@^.*//(.*):.*@1@g")"
SENTRY_SECRET="$(echo $SENTRY_DSN | sed -E "s@^.*:(.*)@.*@1@g")"
SENTRY_PROJECT_ID="$(echo $SENTRY_DSN | sed -E "s@^.*/([0-9]*)@1@g")"
SENTRY_URL_WITH_PROJECT="${SENTRY_DSN/${SENTRY_KEY}:${SENTRY_SECRET}@/}"
SENTRY_URL="${SENTRY_URL_WITH_PROJECT//[0-9]*/}"
# Bash function to report errors to Sentry
# Usage:
# report_error "${FUNCNAME[0]}:$LINENO" "Uh oh, spaghettios!"
report_error() {
[[ -z "${SENTRY_DSN:-}" ]] && return
declare culprit
declare timestamp
declare message
declare x_sentry_auth
declare referer
declare body
declare url
declare content_type
culprit=${1:?}
timestamp=$(date +%Y-%m-%dT%H:%M:%S)
message=${2:?}
x_sentry_auth="X-Sentry-Auth:Sentry sentry_version=5"
x_sentry_auth="${x_sentry_auth:?},sentry_client=0.1.0"
x_sentry_auth="${x_sentry_auth:?},sentry_timestamp=${timestamp:?}"
x_sentry_auth="${x_sentry_auth:?},sentry_key=${SENTRY_KEY:?}"
x_sentry_auth="${x_sentry_auth:?},sentry_secret=${SENTRY_SECRET:?}"
referer="Referer:http://example.com/"
content_type="Content-Type: application/json"
url="${SENTRY_URL:?}/api/${SENTRY_PROJECT_ID:?}/store/"
body=$(cat <<BODY
{
"culprit": "${culprit:?}",
"timestamp": "${timestamp:?}",
"message": "${message:?}",
"tags": {
"BACKUP_INTERVAL": "${BACKUP_INTERVAL:?}"
},
"exception": [{
"type": "BackupError",
"value": "${message:?}",
"module": "${BASH_SOURCE[0]}"
}]
}
BODY
)
echo "$body" | http POST "${url:?}" "${x_sentry_auth:?}" "${referer:?}" "${content_type:?}"
}
Leave a Reply