Skip to content

Instantly share code, notes, and snippets.

@kylelemons
Created June 20, 2014 23:03
Show Gist options
  • Save kylelemons/399d6a37df7004e6e577 to your computer and use it in GitHub Desktop.
Save kylelemons/399d6a37df7004e6e577 to your computer and use it in GitHub Desktop.
This is a playground paste that demonstrates extracting the caller and call for error messages
package main
import (
"fmt"
"log"
"path/filepath"
"runtime"
"strings"
"unicode"
)
// exported API
func Software() error {
if err := inner(42); err != nil {
return errorf("bad software: %s", err)
}
return nil
}
// some inner function, which will be skipped
func inner(id int) error {
return fmt.Errorf("unknown ID %d", id)
}
// errorf helper
func errorf(format string, args ...interface{}) error {
text := fmt.Sprintf(format, args...)
return fmt.Errorf("%s %s", text, caller())
}
func caller() string {
var lastExported, caller string
skip := 0
packageName := func(f *runtime.Func) string {
return strings.Split(f.Name(), ".")[0]
}
isExported := func(f *runtime.Func) bool {
name := strings.Split(f.Name(), ".")[1]
return unicode.IsUpper(rune(name[0]))
}
// Skip unexported functions
var where, currentPkg string
for {
skip++
pc, file, line, ok := runtime.Caller(skip)
if !ok {
return "(broken symbol table)"
}
file = filepath.Base(file)
f := runtime.FuncForPC(pc)
if f == nil {
return "(unknown local function)"
}
if currentPkg == "" {
currentPkg = packageName(f)
}
if pkg := packageName(f); currentPkg != pkg {
where = fmt.Sprintf("%s:%d", file, line)
caller = f.Name()
break
}
if isExported(f) {
lastExported = f.Name()
}
}
return fmt.Sprintf("(%s called %s at %s)", caller, lastExported, where)
}
func main() {
if err := Software(); err != nil {
log.Fatal(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment