Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upload end of log as breadcrumbs, use exceptions and stacktrace #1775

Merged
merged 7 commits into from
Oct 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions _unit-test/error-handling-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ export -f send_envelope
echo "Testing initial send_event"
export log_file="test_log.txt"
echo "Test Logs" >"$basedir/$log_file"
SEND_EVENT_RESPONSE=$(send_event "12345123451234512345123451234512" "Test exited with status 1")
SEND_EVENT_RESPONSE=$(send_event "12345123451234512345123451234512" "Test exited with status 1" "{\"ignore\": \"me\"}")
rm "$basedir/$log_file"
test "$SEND_EVENT_RESPONSE" == 'Test Sending sentry-envelope-12345123451234512345123451234512'
ENVELOPE_CONTENTS=$(cat /tmp/sentry-envelope-12345123451234512345123451234512)
test "$ENVELOPE_CONTENTS" == "$(cat "$basedir/_unit-test/snapshots/sentry-envelope-12345123451234512345123451234512")"
echo "Pass."

echo "Testing send_event duplicate"
SEND_EVENT_RESPONSE=$(send_event "12345123451234512345123451234512" "Test exited with status 1")
SEND_EVENT_RESPONSE=$(send_event "12345123451234512345123451234512" "Test exited with status 1" "{\"ignore\": \"me\"}")
test "$SEND_EVENT_RESPONSE" == "Looks like you've already sent this error to us, we're on it :)"
echo "Pass."
rm '/tmp/sentry-envelope-12345123451234512345123451234512'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{"event_id":"12345123451234512345123451234512","dsn":"https://[email protected]/3"}
{"type":"event"}
{"message":"Test exited with status 1","level":"error"}
{"level":"error","exception":{"values":[{"type":"Error","value":"Test exited with status 1","stacktrace":{"frames":[{"ignore":"me"}]}}]},"breadcrumbs":{"values":[{"message":"Test Logs","category":"log","level":"info"}]}}
{"type":"attachment","length":10,"content_type":"text/plain","filename":"install_log.txt"}
Test Logs
2 changes: 2 additions & 0 deletions install/build-docker-images.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ echo ""
# as it is used as the base image for sentry-cleanup-self-hosted-local.
$dc build --build-arg "http_proxy=${http_proxy:-}" --build-arg "https_proxy=${https_proxy:-}" --build-arg "no_proxy=${no_proxy:-}" --force-rm web
$dc build --build-arg "http_proxy=${http_proxy:-}" --build-arg "https_proxy=${https_proxy:-}" --build-arg "no_proxy=${no_proxy:-}" --force-rm
# Used in error-handling.sh for error envelope payloads
docker build -t sentry-self-hosted-jq-local $basedir/jq
echo ""
echo "Docker images built."

Expand Down
79 changes: 67 additions & 12 deletions install/error-handling.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,32 @@ export SENTRY_DSN='https://[email protected]
export SENTRY_ORG=self-hosted
export SENTRY_PROJECT=installer

jq="docker run --rm -i sentry-self-hosted-jq-local"
sentry_cli="docker run --rm -v /tmp:/work -e SENTRY_ORG=$SENTRY_ORG -e SENTRY_PROJECT=$SENTRY_PROJECT -e SENTRY_DSN=$SENTRY_DSN getsentry/sentry-cli"

send_envelope() {
# Send envelope
local sentry_cli="docker run --rm -v /tmp:/work -e SENTRY_ORG=$SENTRY_ORG -e SENTRY_PROJECT=$SENTRY_PROJECT -e SENTRY_DSN=$SENTRY_DSN getsentry/sentry-cli"
$sentry_cli send-envelope $envelope_file
$sentry_cli send-envelope "$envelope_file"
}

generate_breadcrumb_json() {
emmatyping marked this conversation as resolved.
Show resolved Hide resolved
# Based on https://stackoverflow.com/a/1521498
while IFS="" read -r line || [ -n "$line" ]; do
emmatyping marked this conversation as resolved.
Show resolved Hide resolved
jq -n -c --arg message "$line" \
--arg category log \
--arg level info \
'$ARGS.named'
done <$log_path
}

send_event() {
# Use traceback hash as the UUID since it is 32 characters long
local event_hash=$1
local traceback=$2
# escape traceback for quotes so that we are sending valid json
local traceback_escaped="${traceback//\"/\\\"}"
local error_message=$2
local traceback_json=$3
local envelope_file="sentry-envelope-${event_hash}"
local envelope_file_path="/tmp/$envelope_file"
local log_path="$basedir/$log_file"
# If the envelope file exists, we've already sent it
if [[ -f $envelope_file_path ]]; then
echo "Looks like you've already sent this error to us, we're on it :)"
Expand All @@ -26,16 +38,51 @@ send_event() {
# If we haven't sent the envelope file, make it and send to Sentry
# The format is documented at https://develop.sentry.dev/sdk/envelopes/
# Grab length of log file, needed for the envelope header to send an attachment
local file_length=$(wc -c <"$basedir/$log_file" | awk '{print $1}')
local file_length=$(wc -c <$log_path | awk '{print $1}')

# Add header for initial envelope information
echo '{"event_id":"'$event_hash'","dsn":"'$SENTRY_DSN'"}' >$envelope_file_path
jq -n -c --arg event_id "$event_hash" \
--arg dsn "$SENTRY_DSN" \
'$ARGS.named' >$envelope_file_path
# Add header to specify the event type of envelope to be sent
echo '{"type":"event"}' >>$envelope_file_path
# Add traceback message to event
echo '{"message":"'$traceback_escaped'","level":"error"}' >>$envelope_file_path

# Next we construct the meat of the event payload, which we build up
# inside out using jq
emmatyping marked this conversation as resolved.
Show resolved Hide resolved
# See https://develop.sentry.dev/sdk/event-payloads/
# for details about the event payload

# First, create the breadcrumb payload
# https://develop.sentry.dev/sdk/event-payloads/breadcrumbs/
breadcrumbs=$(generate_breadcrumb_json | jq -s -c)
# Next we need the exception payload
# https://develop.sentry.dev/sdk/event-payloads/exception/
# but first we need to make the stacktrace which goes in the exception payload
frames=$(echo "$traceback_json" | jq -s -c)
stacktrace=$(jq -n -c --argjson frames $frames '$ARGS.named')
exception=$(
jq -n -c --arg "type" Error \
emmatyping marked this conversation as resolved.
Show resolved Hide resolved
--arg value "$error_message" \
--argjson stacktrace $stacktrace \
'$ARGS.named'
)
event_body=$(
jq -n -c --arg level error \
--argjson exception "{\"values\":[$exception]}" \
--argjson breadcrumbs "{\"values\": $breadcrumbs}" \
'$ARGS.named'
)
echo "$event_body" >>$envelope_file_path
# Add attachment to the event
echo '{"type":"attachment","length":'$file_length',"content_type":"text/plain","filename":"install_log.txt"}' >>$envelope_file_path
cat "$basedir/$log_file" >>$envelope_file_path
attachment=$(
jq -n -c --arg "type" attachment \
--arg length $file_length \
--arg content_type "text/plain" \
--arg filename install_log.txt \
'{"type": $type,"length": $length|tonumber,"content_type": $content_type,"filename": $filename}'
)
echo "$attachment" >>$envelope_file_path
cat $log_path >>$envelope_file_path
# Send envelope
send_envelope $envelope_file
}
Expand Down Expand Up @@ -173,12 +220,20 @@ cleanup() {
printf '%s\n%s\n' "$err" "$cmd_exit"
local stack_depth=${#FUNCNAME[@]}
local traceback=""
local traceback_json=""
if [ $stack_depth -gt 2 ]; then
for ((i = $(($stack_depth - 1)), j = 1; i > 0; i--, j++)); do
local indent="$(yes a | head -$j | tr -d '\n')"
local src=${BASH_SOURCE[$i]}
local lineno=${BASH_LINENO[$i - 1]}
local funcname=${FUNCNAME[$i]}
JSON=$(
jq -n -c --arg filename $src \
--arg "function" $funcname \
--arg lineno "$lineno" \
'{"filename": $filename, "function": $function, "lineno": $lineno|tonumber}'
)
printf -v traceback_json '%s\n' "$traceback_json$JSON"
printf -v traceback '%s\n' "$traceback${indent//a/-}> $src:$funcname:$lineno"
done
fi
Expand All @@ -187,7 +242,7 @@ cleanup() {
# Only send event when report issues flag is set and if trap signal is not INT (ctrl+c)
if [[ "$REPORT_SELF_HOSTED_ISSUES" == 1 && "$1" != "INT" ]]; then
local event_hash=$(echo -n "$cmd_exit $traceback" | docker run -i --rm busybox md5sum | cut -d' ' -f1)
send_event "$event_hash" "$cmd_exit"
send_event "$event_hash" "$cmd_exit" "$traceback_json"
fi

if [[ -n "$MINIMIZE_DOWNTIME" ]]; then
Expand Down
11 changes: 11 additions & 0 deletions jq/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM debian:bullseye-slim

LABEL MAINTAINER="[email protected]"

RUN set -x \
emmatyping marked this conversation as resolved.
Show resolved Hide resolved
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends jq \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

CMD ["jq"]