Commit fa51f841 authored by Stan Hu's avatar Stan Hu

Fix nil actor errors in Sentry API handler

The Golang SDK often sends up multiple exceptions, with the second one
containing more context with the appropriate stack trace. Previously the
API handler assumed that the stacktrace existed for the first exception.
However, this assumption can be wrong, leading to 500 errors when
clients attempt to report an error to GitLab.

Since the GitLab API can only track one Sentry exception, we now choose
the first exception that has a stacktrace. We also also gracefully
handle an empty stacktrace by reporting no actor.

Relates to https://gitlab.com/gitlab-org/gitlab/-/issues/348672

Changelog: fixed
parent 77e6ac79
......@@ -2,6 +2,8 @@
module ErrorTracking
class CollectErrorService < ::BaseService
include Gitlab::Utils::StrongMemoize
def execute
# Error is a way to group events based on common data like name or cause
# of exception. We need to keep a sane balance here between taking too little
......@@ -43,16 +45,29 @@ module ErrorTracking
end
def exception
event['exception']['values'].first
strong_memoize(:exception) do
# Find the first exception that has a stacktrace since the first
# exception may not provide adequate context (e.g. in the Go SDK).
entries = event['exception']['values']
entries.find { |x| x.key?('stacktrace') } || entries.first
end
end
def stacktrace_frames
strong_memoize(:stacktrace_frames) do
exception.dig('stacktrace', 'frames')
end
end
def actor
return event['transaction'] if event['transaction']
# Some SDK do not have transaction attribute.
# Some SDKs do not have a transaction attribute.
# So we build it by combining function name and module name from
# the last item in stacktrace.
last_line = exception.dig('stacktrace', 'frames').last
return unless stacktrace_frames.present?
last_line = stacktrace_frames.last
"#{last_line['function']}(#{last_line['module']})"
end
......
{"contexts":{"device":{"arch":"amd64","num_cpu":16},"os":{"name":"darwin"},"runtime":{"go_maxprocs":16,"go_numcgocalls":1,"go_numroutines":2,"name":"go","version":"go1.16.10"}},"event_id":"f92492349cda4ceaba1aab9dac55a412","level":"error","platform":"go","release":"v0.12.0-1-g6b72962","sdk":{"name":"sentry.go","version":"0.12.0","integrations":["ContextifyFrames","Environment","IgnoreErrors","Modules"],"packages":[{"name":"sentry-go","version":"0.12.0"}]},"server_name":"jet.fios-router.home","user":{},"modules":{"github.com/getsentry/sentry-go":"(devel)","golang.org/x/sys":"v0.0.0-20211007075335-d3039528d8ac"},"exception":[{"type":"*errors.errorString","value":"unsupported protocol scheme \"\""},{"type":"*url.Error","value":"Get \"foobar\": unsupported protocol scheme \"\"","stacktrace":{"frames":[{"function":"main","module":"main","abs_path":"/Users/stanhu/github/sentry-go/example/basic/main.go","lineno":54,"pre_context":["\t// Set the timeout to the maximum duration the program can afford to wait.","\tdefer sentry.Flush(2 * time.Second)","","\tresp, err := http.Get(os.Args[1])","\tif err != nil {"],"context_line":"\t\tsentry.CaptureException(err)","post_context":["\t\tlog.Printf(\"reported to Sentry: %s\", err)","\t\treturn","\t}","\tdefer resp.Body.Close()",""],"in_app":true}]}}],"timestamp":"2021-12-25T22:32:06.191665-08:00"}
......@@ -92,6 +92,25 @@ RSpec.describe ErrorTracking::CollectErrorService do
expect(event.environment).to eq 'Accumulate'
expect(event.payload).to eq parsed_event
end
context 'with two exceptions' do
let(:parsed_event) { Gitlab::Json.parse(fixture_file('error_tracking/go_two_exception_event.json')) }
it 'reports using second exception', :aggregate_failures do
subject.execute
event = ErrorTracking::ErrorEvent.last
error = event.error
expect(error.name).to eq '*url.Error'
expect(error.description).to eq(%(Get \"foobar\": unsupported protocol scheme \"\"))
expect(error.platform).to eq 'go'
expect(error.actor).to eq('main(main)')
expect(event.description).to eq(%(Get \"foobar\": unsupported protocol scheme \"\"))
expect(event.payload).to eq parsed_event
end
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment