From 97a4e5cce4fd74685ff0694ab2f67dd75cf5723f Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Fri, 4 Nov 2022 11:38:44 -0400 Subject: [PATCH] Add context line, error msg to envelope (#1784) * add context line, error msg to envelope --- _unit-test/error-handling-test.sh | 20 ++++++++---- ...-envelope-12345123451234512345123451234512 | 3 +- install/error-handling.sh | 32 +++++++++++++------ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/_unit-test/error-handling-test.sh b/_unit-test/error-handling-test.sh index 46a5a2f..e6e4990 100755 --- a/_unit-test/error-handling-test.sh +++ b/_unit-test/error-handling-test.sh @@ -12,17 +12,19 @@ send_envelope() { 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" "{\"ignore\": \"me\"}") -rm "$basedir/$log_file" +export log_path="$basedir/test_log.txt" +echo "Test Logs" >"$log_path" +echo "Error Msg" >>"$log_path" +breadcrumbs=$(generate_breadcrumb_json | sed '$d' | jq -s -c) +SEND_EVENT_RESPONSE=$(send_event "12345123451234512345123451234512" "Test exited with status 1" "{\"ignore\": \"me\"}" "$breadcrumbs") +rm "$log_path" 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" "{\"ignore\": \"me\"}") +SEND_EVENT_RESPONSE=$(send_event "12345123451234512345123451234512" "Test exited with status 1" "{\"ignore\": \"me\"}" "$breadcrumbs") 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' @@ -31,8 +33,10 @@ echo "Testing cleanup without minimizing downtime" export REPORT_SELF_HOSTED_ISSUES=0 export MINIMIZE_DOWNTIME='' export dc=':' +echo "Test Logs" >"$log_path" CLEANUP_RESPONSE=$(cleanup ERROR) -test "$CLEANUP_RESPONSE" == 'Error in ./_unit-test/error-handling-test.sh:34. +rm "$log_path" +test "$CLEANUP_RESPONSE" == 'Error in ./_unit-test/error-handling-test.sh:37. '\''local cmd="${BASH_COMMAND}"'\'' exited with status 0 Cleaning up...' @@ -41,8 +45,10 @@ echo "Pass." echo "Testing cleanup while minimizing downtime" export REPORT_SELF_HOSTED_ISSUES=0 export MINIMIZE_DOWNTIME=1 +echo "Test Logs" >"$log_path" CLEANUP_RESPONSE=$(cleanup ERROR) -test "$CLEANUP_RESPONSE" == 'Error in ./_unit-test/error-handling-test.sh:44. +rm "$log_path" +test "$CLEANUP_RESPONSE" == 'Error in ./_unit-test/error-handling-test.sh:49. '\''local cmd="${BASH_COMMAND}"'\'' exited with status 0 *NOT* cleaning up, to clean your environment run "docker compose stop".' diff --git a/_unit-test/snapshots/sentry-envelope-12345123451234512345123451234512 b/_unit-test/snapshots/sentry-envelope-12345123451234512345123451234512 index 8c66626..1e08ae7 100644 --- a/_unit-test/snapshots/sentry-envelope-12345123451234512345123451234512 +++ b/_unit-test/snapshots/sentry-envelope-12345123451234512345123451234512 @@ -1,5 +1,6 @@ {"event_id":"12345123451234512345123451234512","dsn":"https://19555c489ded4769978daae92f2346ca@self-hosted.getsentry.net/3"} {"type":"event"} {"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"} +{"type":"attachment","length":20,"content_type":"text/plain","filename":"install_log.txt"} Test Logs +Error Msg diff --git a/install/error-handling.sh b/install/error-handling.sh index 318ff5c..a3f3495 100644 --- a/install/error-handling.sh +++ b/install/error-handling.sh @@ -6,6 +6,7 @@ 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" +log_path="$basedir/$log_file" send_envelope() { # Send envelope @@ -25,11 +26,11 @@ generate_breadcrumb_json() { send_event() { # Use traceback hash as the UUID since it is 32 characters long local event_hash=$1 - local error_message=$2 + local error_msg=$2 local traceback_json=$3 + local breadcrumbs=$4 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 :)" @@ -52,18 +53,15 @@ send_event() { # 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 + # Then 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') + stacktrace=$(jq -n -c --argjson frames "$frames" '$ARGS.named') exception=$( jq -n -c --arg "type" Error \ - --arg value "$error_message" \ - --argjson stacktrace $stacktrace \ + --arg value "$error_msg" \ + --argjson stacktrace "$stacktrace" \ '$ARGS.named' ) event_body=$( @@ -170,6 +168,12 @@ cleanup() { DID_CLEAN_UP=1 if [[ "$1" != "EXIT" ]]; then set +o xtrace + # Save the error message that comes from the last line of the log file + error_msg=$(tail -n 1 "$log_path") + # Create the breadcrumb payload now before stacktrace is printed + # https://develop.sentry.dev/sdk/event-payloads/breadcrumbs/ + # Use sed to remove the last line, that is reported through the error message + breadcrumbs=$(generate_breadcrumb_json | sed '$d' | jq -s -c) printf -v err '%s' "Error in ${BASH_SOURCE[1]}:${BASH_LINENO[0]}." printf -v cmd_exit '%s' "'$cmd' exited with status $retcode" printf '%s\n%s\n' "$err" "$cmd_exit" @@ -188,6 +192,14 @@ cleanup() { --arg lineno "$lineno" \ '{"filename": $filename, "function": $function, "lineno": $lineno|tonumber}' ) + # If we're in the stacktrace of the file we failed on, we can add a context line with the command run that failed + if [[ $i -eq 1 ]]; then + JSON=$( + jq -n -c --arg cmd "$cmd" \ + --argjson json "$JSON" \ + '$json + {"context_line": $cmd}' + ) + fi printf -v traceback_json '%s\n' "$traceback_json$JSON" printf -v traceback '%s\n' "$traceback${indent//a/-}> $src:$funcname:$lineno" done @@ -197,7 +209,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" "$traceback_json" + send_event "$event_hash" "$error_msg" "$traceback_json" "$breadcrumbs" fi if [[ -n "$MINIMIZE_DOWNTIME" ]]; then