Skip to content

Commit 8d2249e

Browse files
zombiezenigorpeshansky
authored andcommitted
Fix multiple issues with Go panic captures (#18)
- Capture would stop at "created by function" lines - Capture was expecting two blank lines between goroutines, whereas goroutines only have one blank line between them. - Capture would stop when given a panic started by a signal (like a nil panic) - Frame matching was only checking for an identifier character followed by an opening paren. Updated to be more precise. - The substring "panic:" could start a Go capture even in the middle of a word.
1 parent cf34e7d commit 8d2249e

File tree

2 files changed

+87
-12
lines changed

2 files changed

+87
-12
lines changed

lib/fluent/plugin/exception_detector.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,13 @@ def self.supported
7575
].freeze
7676

7777
GO_RULES = [
78-
rule(:start_state, /panic: /, :go_before_goroutine),
79-
rule(:go_before_goroutine, /^$/, :go_goroutine),
78+
rule(:start_state, /\bpanic: /, :go_after_panic),
79+
rule(:go_after_panic, /^$/, :go_goroutine),
80+
rule(:go_after_panic, /^\[signal /, :go_after_signal),
81+
rule(:go_after_signal, /^$/, :go_goroutine),
8082
rule(:go_goroutine, /^goroutine \d+ \[[^\]]+\]:$/, :go_frame_1),
81-
rule(:go_frame_1, /(?:[^\s.():]+\.)*[^\s.():]\(/, :go_frame_2),
82-
rule(:go_frame_1, /^$/, :go_before_goroutine),
83+
rule(:go_frame_1, /^(?:[^\s.:]+\.)*[^\s.():]+\(|^created by /, :go_frame_2),
84+
rule(:go_frame_1, /^$/, :go_goroutine),
8385
rule(:go_frame_2, /^\s/, :go_frame_1)
8486
].freeze
8587

test/plugin/test_exception_detector.rb

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,25 +126,92 @@ class ExceptionDetectorTest < Test::Unit::TestCase
126126
END
127127

128128
GO_EXC = <<END.freeze
129+
panic: my panic
130+
131+
goroutine 4 [running]:
132+
panic(0x45cb40, 0x47ad70)
133+
/usr/local/go/src/runtime/panic.go:542 +0x46c fp=0xc42003f7b8 sp=0xc42003f710 pc=0x422f7c
134+
main.main.func1(0xc420024120)
135+
foo.go:6 +0x39 fp=0xc42003f7d8 sp=0xc42003f7b8 pc=0x451339
136+
runtime.goexit()
137+
/usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003f7e0 sp=0xc42003f7d8 pc=0x44b4d1
138+
created by main.main
139+
foo.go:5 +0x58
140+
141+
goroutine 1 [chan receive]:
142+
runtime.gopark(0x4739b8, 0xc420024178, 0x46fcd7, 0xc, 0xc420028e17, 0x3)
143+
/usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc420053e30 sp=0xc420053e00 pc=0x42503c
144+
runtime.goparkunlock(0xc420024178, 0x46fcd7, 0xc, 0x1000f010040c217, 0x3)
145+
/usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc420053e70 sp=0xc420053e30 pc=0x42512e
146+
runtime.chanrecv(0xc420024120, 0x0, 0xc420053f01, 0x4512d8)
147+
/usr/local/go/src/runtime/chan.go:506 +0x304 fp=0xc420053f20 sp=0xc420053e70 pc=0x4046b4
148+
runtime.chanrecv1(0xc420024120, 0x0)
149+
/usr/local/go/src/runtime/chan.go:388 +0x2b fp=0xc420053f50 sp=0xc420053f20 pc=0x40439b
150+
main.main()
151+
foo.go:9 +0x6f fp=0xc420053f80 sp=0xc420053f50 pc=0x4512ef
152+
runtime.main()
153+
/usr/local/go/src/runtime/proc.go:185 +0x20d fp=0xc420053fe0 sp=0xc420053f80 pc=0x424bad
154+
runtime.goexit()
155+
/usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc420053fe8 sp=0xc420053fe0 pc=0x44b4d1
156+
157+
goroutine 2 [force gc (idle)]:
158+
runtime.gopark(0x4739b8, 0x4ad720, 0x47001e, 0xf, 0x14, 0x1)
159+
/usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003e768 sp=0xc42003e738 pc=0x42503c
160+
runtime.goparkunlock(0x4ad720, 0x47001e, 0xf, 0xc420000114, 0x1)
161+
/usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003e7a8 sp=0xc42003e768 pc=0x42512e
162+
runtime.forcegchelper()
163+
/usr/local/go/src/runtime/proc.go:238 +0xcc fp=0xc42003e7e0 sp=0xc42003e7a8 pc=0x424e5c
164+
runtime.goexit()
165+
/usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003e7e8 sp=0xc42003e7e0 pc=0x44b4d1
166+
created by runtime.init.4
167+
/usr/local/go/src/runtime/proc.go:227 +0x35
168+
169+
goroutine 3 [GC sweep wait]:
170+
runtime.gopark(0x4739b8, 0x4ad7e0, 0x46fdd2, 0xd, 0x419914, 0x1)
171+
/usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003ef60 sp=0xc42003ef30 pc=0x42503c
172+
runtime.goparkunlock(0x4ad7e0, 0x46fdd2, 0xd, 0x14, 0x1)
173+
/usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003efa0 sp=0xc42003ef60 pc=0x42512e
174+
runtime.bgsweep(0xc42001e150)
175+
/usr/local/go/src/runtime/mgcsweep.go:52 +0xa3 fp=0xc42003efd8 sp=0xc42003efa0 pc=0x419973
176+
runtime.goexit()
177+
/usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003efe0 sp=0xc42003efd8 pc=0x44b4d1
178+
created by runtime.gcenable
179+
/usr/local/go/src/runtime/mgc.go:216 +0x58
180+
END
181+
182+
GO_ON_GAE_EXC = <<END.freeze
129183
panic: runtime error: index out of range
130184
131185
goroutine 12 [running]:
132186
main88989.memoryAccessException()
133-
crash_example_go.go:58 +0x12a
187+
crash_example_go.go:58 +0x12a
134188
main88989.handler(0x2afb7042a408, 0xc01042f880, 0xc0104d3450)
135-
crash_example_go.go:36 +0x7ec
189+
crash_example_go.go:36 +0x7ec
136190
net/http.HandlerFunc.ServeHTTP(0x13e5128, 0x2afb7042a408, 0xc01042f880, 0xc0104d3450)
137-
go/src/net/http/server.go:1265 +0x56
191+
go/src/net/http/server.go:1265 +0x56
138192
net/http.(*ServeMux).ServeHTTP(0xc01045cab0, 0x2afb7042a408, 0xc01042f880, 0xc0104d3450)
139-
go/src/net/http/server.go:1541 +0x1b4
193+
go/src/net/http/server.go:1541 +0x1b4
140194
appengine_internal.executeRequestSafely(0xc01042f880, 0xc0104d3450)
141-
go/src/appengine_internal/api_prod.go:288 +0xb7
195+
go/src/appengine_internal/api_prod.go:288 +0xb7
142196
appengine_internal.(*server).HandleRequest(0x15819b0, 0xc010401560, 0xc0104c8180, 0xc010431380, 0x0, 0x0)
143-
go/src/appengine_internal/api_prod.go:222 +0x102b
197+
go/src/appengine_internal/api_prod.go:222 +0x102b
144198
reflect.Value.call(0x1243fe0, 0x15819b0, 0x113, 0x12c8a20, 0x4, 0xc010485f78, 0x3, 0x3, 0x0, 0x0, ...)
145-
/tmp/appengine/go/src/reflect/value.go:419 +0x10fd
199+
/tmp/appengine/go/src/reflect/value.go:419 +0x10fd
146200
reflect.Value.Call(0x1243fe0, 0x15819b0, 0x113, 0xc010485f78, 0x3, 0x3, 0x0, 0x0, 0x0)
147-
/tmp/ap"
201+
/tmp/ap
202+
END
203+
204+
GO_SIGNAL_EXC = <<END.freeze
205+
panic: runtime error: invalid memory address or nil pointer dereference
206+
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x7fd34f]
207+
208+
goroutine 5 [running]:
209+
panics.nilPtrDereference()
210+
panics/panics.go:33 +0x1f
211+
panics.Wait()
212+
panics/panics.go:16 +0x3b
213+
created by main.main
214+
server.go:20 +0x91
148215
END
149216

150217
CSHARP_EXC = <<END.freeze
@@ -205,6 +272,8 @@ class ExceptionDetectorTest < Test::Unit::TestCase
205272

206273
ARBITRARY_TEXT = <<END.freeze
207274
This arbitrary text.
275+
It sounds tympanic: a word which means like a drum.
276+
208277
I am glad it contains no exception.
209278
END
210279

@@ -269,6 +338,8 @@ def test_php
269338

270339
def test_go
271340
check_exception(GO_EXC, false)
341+
check_exception(GO_ON_GAE_EXC, false)
342+
check_exception(GO_SIGNAL_EXC, false)
272343
end
273344

274345
def test_ruby
@@ -285,6 +356,8 @@ def test_mixed_languages
285356
check_exception(PHP_ON_GAE_EXC, true)
286357
check_exception(CLIENT_JS_EXC, false)
287358
check_exception(GO_EXC, false)
359+
check_exception(GO_ON_GAE_EXC, false)
360+
check_exception(GO_SIGNAL_EXC, false)
288361
check_exception(CSHARP_EXC, false)
289362
check_exception(V8_JS_EXC, false)
290363
check_exception(RUBY_EXC, false)

0 commit comments

Comments
 (0)