Capturing a stack trace from a recovered panic

17,249 views
Skip to first unread message

Paul Borman

unread,
Aug 10, 2011, 12:10:54 PM8/10/11
to golang-nuts
Is there any reasonable way to capture a stack trace from a recovered panic?  I would like to do something akin to:

    defer func() {
        if p := recover(); p != nil {
            mylogger.DumpStack(?)
            panic(p)
        }
    }()

I could not find anything for the ?.  The system does keep the information as the full stack trace from the recovered panic will still be displayed by the runtime when an un-recovered panic is hit.

I realize I can re-direct stderr, but I would prefer to have all my information in my logfile using the appropriate logfile formatting.

    -Paul

Jan Mercl

unread,
Aug 10, 2011, 12:24:33 PM8/10/11
to golan...@googlegroups.com

Paul Borman

unread,
Aug 10, 2011, 12:36:28 PM8/10/11
to golan...@googlegroups.com
Well, no, that will only display the stack from the point you call debug.Stack(), which will be my recover.  I know where my recover is, I want to know where the panic was.

On Wed, Aug 10, 2011 at 9:18 AM, gary b <gary...@gmail.com> wrote:
http://golang.org/pkg/runtime/debug/#Stack

Dmitry Vyukov

unread,
Aug 10, 2011, 12:38:04 PM8/10/11
to Paul Borman, golan...@googlegroups.com
panic("foo\n" + debug.Stack())?

Jan Mercl

unread,
Aug 10, 2011, 12:47:44 PM8/10/11
to golan...@googlegroups.com
On Wednesday, August 10, 2011 6:36:28 PM UTC+2, Paul Borman wrote:
Well, no, that will only display the stack from the point you call debug.Stack(), which will be my recover.  I know where my recover is, I want to know where the panic was.

It does show that. Did you try to run the code in my previous post? 

chris dollin

unread,
Aug 10, 2011, 1:12:46 PM8/10/11
to golan...@googlegroups.com
On 10 August 2011 17:47, Jan Mercl <jan....@nic.cz> wrote:

> It does show that. Did you try to run the code in my previous post?

I think the code got lost along the way: the link http://goo.gl/Oh57Y
just gets you to a default instance of the Go playground.

Chris

--
Chris "allusive" Dollin

Dmitry Vyukov

unread,
Aug 10, 2011, 1:14:10 PM8/10/11
to chris dollin, golan...@googlegroups.com
On Wed, Aug 10, 2011 at 9:12 PM, chris dollin <ehog....@googlemail.com> wrote:
On 10 August 2011 17:47, Jan Mercl <jan....@nic.cz> wrote:

> It does show that. Did you try to run the code in my previous post?

I think the code got lost along the way: the link http://goo.gl/Oh57Y
just gets you to a default instance of the Go playground.


Works for me. The code is:

package main

import (
"log"
"os"
"runtime/debug"
)

func f2() {
panic(os.NewError("oops")) // line 10
}

func f1() {
f2() // line 14
}

func main() {
defer func() {
if e := recover(); e != nil {
log.Printf("%s: %s", e, debug.Stack()) // line 20
}
}()
f1() // line 24
}

Output is:

2009/11/10 23:00:00 oops: /tmpfs/gosandbox-b09dc5b6_0fad6379_d8e30e8a_ae284a8e_aa48d082/prog.go:20 (0x400da1)
/tmp/sandbox/go/src/pkg/runtime/proc.c:1041 (0x40dded)
/tmpfs/gosandbox-b09dc5b6_0fad6379_d8e30e8a_ae284a8e_aa48d082/prog.go:10 (0x400c50)
/tmpfs/gosandbox-b09dc5b6_0fad6379_d8e30e8a_ae284a8e_aa48d082/prog.go:14 (0x400c6d)
/tmpfs/gosandbox-b09dc5b6_0fad6379_d8e30e8a_ae284a8e_aa48d082/prog.go:24 (0x400cb7)
/tmp/sandbox/go/src/pkg/runtime/amd64/asm.s:77 (0x401b01)
/tmp/sandbox/go/src/pkg/runtime/proc.c:178 (0x40c7c5)

Paul Borman

unread,
Aug 10, 2011, 1:43:06 PM8/10/11
to golan...@googlegroups.com
Sorry Jan, I was responding to gary and had not seen your post yet.  The documentation for debug.Stack() is a bit misleading in this case: 

Stack returns a formatted stack trace of the goroutine that calls it. For each routine, it includes the source line information and PC value, then attempts to discover, for Go functions, the calling function or method and the text of the line containing the invocation.

It is interesting that defer processing is different in a panic situation.   Stack() exposes implementation details (but it is in runtime).

        func foo() { bar() }
        func bar() { possible-panic() {
        func main() {
                defer func() {
                        fmt.Printf("%s\n", debug.Stack())
                        _ = recover()
                }()
                foo()
        }
 
If possible-panic() is not a panic the trace is:
 
        _func_001: fmt.Printf("%s\n", debug.Stack())
        main: foo()
        mainstart: CALL main·main(SB)
        goexit: runtime·goexit(void)
        
But if it is panic the trace is:
 
        _func_001: fmt.Printf("%s\n", debug.Stack())
        panic: reflect·call(d->fn, d->args, d->siz);
        bar: panic("foobar")
        foo: bar()
        main: foo()
        mainstart: CALL main·main(SB)
        goexit: runtime·goexit(void)
 
I actually had not expected to see foo() in either case.

Anyhow, thank you for pointing out that debug.Stack() actually does include the panic trace.  I have used Stack() elsewhere and from the documentation did not expect it to work this way.

    -Paul

chris dollin

unread,
Aug 10, 2011, 1:50:17 PM8/10/11
to Dmitry Vyukov, golan...@googlegroups.com
On 10 August 2011 18:14, Dmitry Vyukov <dvy...@google.com> wrote:
> On Wed, Aug 10, 2011 at 9:12 PM, chris dollin <ehog....@googlemail.com>
> wrote:
>>
>> On 10 August 2011 17:47, Jan Mercl <jan....@nic.cz> wrote:
>>
>> > It does show that. Did you try to run the code in my previous post?
>>
>> I think the code got lost along the way: the link http://goo.gl/Oh57Y
>> just gets you to a default instance of the Go playground.
>>
>
> Works for me.

That's very odd. When I click the link, I get a page with the right URL,
with the #package main and everything, but it /displays/ the initial
hello-world code, and won't do otherwise.

There's probably some arcane browser config thing going on.

John Asmuth

unread,
Aug 10, 2011, 2:18:29 PM8/10/11
to golan...@googlegroups.com
import "gonicetrace.googlecode.com/hg/nicetrace"

func Foo() {
  defer nicetrace.Print()
  //other stuff that panics
}

Jan Mercl

unread,
Aug 10, 2011, 2:50:06 PM8/10/11
to golan...@googlegroups.com
Chris, I'm "on the road" (read in a pub), so I can only check with an old Android 2.1 stock browser, but the link works for me even in the phone (good!). There is a known bug with the playground in Firefox, perhaps that's what you've encountered.

chris dollin

unread,
Aug 10, 2011, 3:17:12 PM8/10/11
to golan...@googlegroups.com

Well, well. Works on my phone, not on my desktop FireFox. Thanks for the tip, Jan.

Russ Cox

unread,
Aug 10, 2011, 5:57:21 PM8/10/11
to Paul Borman, golan...@googlegroups.com
On Wed, Aug 10, 2011 at 12:36, Paul Borman <bor...@google.com> wrote:
> no, that will only display the stack from the point you call debug.Stack(),
> which will be my recover.  I know where my recover is, I want to know where
> the panic was.

The semantics of panic are that the deferred handlers appear
to have been called from the site of the panic, exactly so that
the stack trace is preserved. This is an intentional feature.

Russ

Reply all
Reply to author
Forward
Message has been deleted
0 new messages