Created
June 20, 2014 23:03
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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