Write to file (rather then stderr) on crash

2,783 views
Skip to first unread message

Daniel Theophanes

unread,
Dec 23, 2014, 2:01:19 PM12/23/14
to golan...@googlegroups.com
I've got a windows service (written in go) That's been crashing and my logging code haven't been triggered by the crash so far.

Windows services don't have a stdout or stderr to write to so if anything get's printed, I don't know about it.

Other then doing a work around of running the current service as a child of a simple logging service, is there a flag or env I can set to print crashes to a file? I remember the race detector has such a flag I think.

Thanks,
-Daniel


Ugorji Nwoke

unread,
Dec 23, 2014, 2:24:41 PM12/23/14
to golan...@googlegroups.com
os.Stdout and os.Stderr are variables, so you should be able to set them to whatever *os.File you want.

i.e. 

func main() {
os.Stderr, _ = os.Create("stderr.txt") // handle error appropriately
// ... 

Ugorji Nwoke

unread,
Dec 23, 2014, 2:32:28 PM12/23/14
to golan...@googlegroups.com
There might be some more subtleties to this - see https://github.com/golang/go/issues/325 for pointers.

In summary, use syscall.Dup2 to link the opened file to the standard stream. This seems necessary if panic/crash/etc use the file descriptor directly, not the high-level os.Stderr variable.

func main() {
   logFile, _ := os.Create("stderr.txt") // handle your error appropriately
   syscall.Dup2(int(logFile.Fd()), 2)

Daniel Theophanes

unread,
Dec 23, 2014, 2:35:47 PM12/23/14
to Ugorji Nwoke, golang-nuts
That would work great on Linux! I don't think that's an option for Windows.

Thanks though.
-Daniel


--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/jrsX1f3tXD8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Shawn Milochik

unread,
Dec 23, 2014, 3:18:08 PM12/23/14
to golan...@googlegroups.com
This doesn't answer your question directly, but you can change the location of logging using log.SetOutput(). So put in logging and after a crash you should be able to see what was happening right before. Based on the output, add/edit your log statements to narrow it down. You should be able to pinpoint it that way in about as few iterations as a binary search. Sorry it's not a magic bullet, but it would work.

John Souvestre

unread,
Dec 23, 2014, 3:55:01 PM12/23/14
to Daniel Theophanes, Ugorji Nwoke, golang-nuts

I ran into this limitation also.  Here are 2 ways which will work for Windows.

 

Run the program with CLI StdErr redirection:  xxx.go 2>> error.log

 

Use this very nice routine:  mitchellh/panicwrap

   https://github.com/mitchellh/panicwrap

 

John

    John Souvestre - New Orleans LA

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Daniel Theophanes

unread,
Dec 23, 2014, 3:59:23 PM12/23/14
to John Souvestre, Ugorji Nwoke, golang-nuts
Yeah, right I'm running the service in a terminal session in a CLI, logging output. But then I have to be logged in and everything that entails on windows. Panicwrap looks nice, but won't run as a windows service. Thanks though.

I might just modify the executable to launch itself when running as a service, then catch it's own errors. Good idea.

-Daniel

milo.chr...@gmail.com

unread,
Dec 23, 2014, 7:55:34 PM12/23/14
to golan...@googlegroups.com
What I did for one of my apps is make a simple global panic handler right at the start of main:

defer func(){
err := recover()
if err != nil {
log.Println("Unrecovered Error:")
log.Println("  The following error was not properly recovered, please report this ASAP!")
log.Printf("  %#v\n", err)
log.Println("Stack Trace:")
buf := make([]byte, 4096)
buf = buf[:runtime.Stack(buf, true)]
log.Printf("%s\n", buf)
os.Exit(1)
}
}()

This works like a charm, you may need to play with it a little to get the exact effect you want though. (and you will want to replace my logger with something else)

On Tuesday, December 23, 2014 2:01:19 PM UTC-5, Daniel Theophanes wrote:

Daniel Theophanes

unread,
Dec 23, 2014, 8:27:15 PM12/23/14
to milo.chr...@gmail.com, golang-nuts
I'm actually already doing the equivalent of that in my my main. But haven't gotten anything reported from it. Thus I was looking for capturing the raw output of any runtime level messages. But that is a excellent idea, and usually good to have. Though in go1.4.0 I think the runtime.Stack(x, true) call might not be a good idea. Thanks,

-Daniel


aphill...@gmail.com

unread,
Feb 8, 2019, 2:05:35 AM2/8/19
to golang-nuts
That's fine if you only have one go-routine but if you have lots then you have to recover the panic (ie catch the exception in normal parlance) in every go-routine.
Reply all
Reply to author
Forward
0 new messages