Skip to content

proposal: runtime/debug: add SetCrashHeader function #64590

Closed
@EtiennePerot

Description

@EtiennePerot

Proposal Details

Add a function like SetCrashHeader(header []byte) to runtime/debug. When called, this copies the first K bytes of header into a region of memory owned by the Go runtime. If the program later panics, the contents of this buffer are printed out before any of the usual panic information.

This buffer would have a tight maximum byte size smaller or equal to the size of a page of memory. This ensures the crashing procedure remains fast and that this feature doesn't introduce more unpredictability when a process is already crashing. This header is global, not per-goroutine. The SetCrashHeader function may be called with nil as argument in order to clear out the runtime-owned buffer.

The idea is to capture useful information about a program that's crashing if crashing does happen, and to print it in a convenient place where an out-of-program system can easily consume it. This information could include basic program information (start time, version number, build options, architecture, etc.) or structured debugging information that isn't always easily obtainable from means outside of the Go program itself.

To disambiguate between this header and the rest of the panic message, the panic output also prints an extra \n--------------- backtrace ---------------\n after the header. This is not printed when the header isn't set (or has been reset by calling SetCrashHeader(nil)).

This pairs well with proposal #42888 (runtime/debug: add SetCrashOutput(file *os.File)). With these two proposals, this allows an out-of-program crash logging system consuming the output of panic logs (which are separate from other logs when using SetCrashOutput(file *os.File)) to obtain the information in the header from the same file handle as the one it already has to receive panic data.

Example

package main
import "runtime/debug"

func init() {
	debug.SetCrashHeader([]byte("MyCrashyProgram version 0.1\nfoo bar"))
}

func main() {
	panic("oops I crashed")
}

... would output to stderr:

MyCrashyProgram version 0.1
foo bar
--------------- backtrace ---------------
panic: oops I crashed

goroutine 1 [running]:
main.main()
	/path/to/prog.go:8 +0x...

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions