Command line client for Sentry (Bash)

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

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.