func caller() { //FIXME add a test to make sure file, pc from Callers matches // the equivalent from Caller. for i := 0; i < 2; i++ { _, _, _, ok := runtime.Caller(i) if !ok { panic(i) } } _, _, _, ok := runtime.Caller(20) if ok { panic(3) } pcA := make([]uintptr, 6, 6) count := runtime.Callers(0, pcA) pcB := make([]uintptr, 6, 6) countM1 := runtime.Callers(1, pcB) if count-1 != countM1 { panic(5) } for i := 1; i < countM1-1; i++ { if pcA[i+1] != pcB[i] { panic(100 + i) } } }
func NewRecord(level Level, message string) *Record { record := &Record{ Level: level, Message: message, } record.Time = time.Now() var pcs [2]uintptr numStack := runtime.Callers(4, pcs[:]) for i := 0; i < numStack; i += 1 { function := runtime.FuncForPC(pcs[i]) if function == nil { break } filename, line := function.FileLine(pcs[i]) if filename == srcFile { continue } else { record.FileName = filename record.LineNo = line record.FuncName = function.Name() break } } return record }
func formatCallpath(calldepth int) string { v := "" callers := make([]uintptr, 64) n := runtime.Callers(calldepth+2, callers) oldPc := callers[n-1] recursiveCall := false for i := n - 3; i >= 0; i-- { pc := callers[i] if oldPc == pc { recursiveCall = true continue } oldPc = pc if recursiveCall { recursiveCall = false v += ".." } if i < n-3 { v += "." } if f := runtime.FuncForPC(pc); f != nil { v += formatFuncName(fmtVerbShortfunc, f.Name()) } } return v }
// VDepth reports whether verbosity at the call site is at least the requested // level. func VDepth(level level, depth int) bool { // This function tries hard to be cheap unless there's work to do. // The fast path is two atomic loads and compares. // Here is a cheap but safe test to see if V logging is enabled globally. if logging.verbosity.get() >= level { return true } // It's off globally but it vmodule may still be set. // Here is another cheap but safe test to see if vmodule is enabled. if atomic.LoadInt32(&logging.filterLength) > 0 { // Now we need a proper lock to use the logging structure. The pcs field // is shared so we must lock before accessing it. This is fairly expensive, // but if V logging is enabled we're slow anyway. logging.mu.Lock() defer logging.mu.Unlock() if runtime.Callers(2+depth, logging.pcs[:]) == 0 { return false } v, ok := logging.vmap[logging.pcs[0]] if !ok { v = logging.setV(logging.pcs[0]) } return v >= level } return false }
// Generates a stack from runtime.Callers() func stackFrames(skip int, ignoreRuntime bool) []*frameInfo { frames := []*frameInfo{} size := 20 pcs := make([]uintptr, size) // always skip the first frame, since it's runtime.Callers itself pcs = pcs[:runtime.Callers(1+skip, pcs)] for _, pc := range pcs { fn := runtime.FuncForPC(pc) name := fn.Name() file, line := fn.FileLine(pc - 1) if ignoreRuntime && strings.Contains(file, filepath.Join("src", "runtime")) { break } ci := &frameInfo{ filename: file, lineno: line, method: name, pc: pc, } frames = append(frames, ci) } return frames }
func identifyPanic() string { var name, file string var line int var pc [16]uintptr n := runtime.Callers(3, pc[:]) for _, pc := range pc[:n] { fn := runtime.FuncForPC(pc) if fn == nil { continue } file, line = fn.FileLine(pc) name = fn.Name() if !strings.HasPrefix(name, "runtime.") { break } } switch { case name != "": return fmt.Sprintf("%v:%v", name, line) case file != "": return fmt.Sprintf("%v:%v", file, line) } return fmt.Sprintf("pc:%x", pc) }
// getPanic returns the number of frames to skip and the PC // for the uppermost panic in the call stack (there might be // multiple panics when a recover() catches a panic and then // panics again). The second value indicates how many stack frames // should be skipped in the stacktrace (they might not always match). // The last return value indicates a frame could be found. func getPanic() (int, int, uintptr, bool) { skip := 0 callers := make([]uintptr, 10) for { calls := callers[:runtime.Callers(skip, callers)] c := len(calls) if c == 0 { break } for ii := c - 1; ii >= 0; ii-- { f := runtime.FuncForPC(calls[ii]) if f != nil { name := f.Name() if strings.HasPrefix(name, "runtime.") && strings.Contains(name, "panic") { pcSkip := skip + ii - 1 stackSkip := pcSkip switch name { case "runtime.panic": case "runtime.sigpanic": stackSkip -= 2 default: stackSkip-- } return pcSkip, stackSkip, calls[ii], true } } } skip += c } return 0, 0, 0, false }
func getCaller() string { pc := make([]uintptr, 10) // at least 1 entry needed runtime.Callers(3, pc) f := runtime.FuncForPC(pc[0]) return f.Name() }
func Warn(v ...interface{}) { if logobj.level <= WARN { pc := make([]uintptr, 1) runtime.Callers(2, pc) logobj.output("WARN", pc[0], v...) } }
func Info(v ...interface{}) { if logobj.level <= INFO { pc := make([]uintptr, 1) runtime.Callers(2, pc) logobj.output("INFO", pc[0], v...) } }
func Debug(v ...interface{}) { if logobj.level <= DEBUG { pc := make([]uintptr, 1) runtime.Callers(2, pc) // 层次越深 性能越差 logobj.output("DEBUG", pc[0], v...) } }
func (self *ErrorField) format(e *Event) string { if e.Error == nil { return "" } var buffer bytes.Buffer callers := make([]uintptr, 20) n := runtime.Callers(3, callers) // starts in (*Logger).Log or similar callers = callers[:n] buffer.WriteString("\n") errorType := reflect.TypeOf(e.Error) buffer.WriteString(errorType.String() + ": ") buffer.WriteString(e.Error.Error()) for _, pc := range callers { f := runtime.FuncForPC(pc) if !strings.Contains(f.Name(), "/slf4g/") { pathname, lineno := f.FileLine(pc) filename := path.Base(pathname) s := fmt.Sprintf("\n at %s (%s:%d)", f.Name(), filename, lineno) buffer.WriteString(s) } } return buffer.String() }
func Fail(message string) { log.Error("Failed assertion: %v", message) var buffer bytes.Buffer callers := make([]uintptr, 20) skip := 1 n := runtime.Callers(skip, callers) callers = callers[:n] buffer.WriteString("Assertion failed") buffer.WriteString("\n") for _, pc := range callers { f := runtime.FuncForPC(pc) //if !strings.Contains(f.Name(), "/gova/log/") { pathname, lineno := f.FileLine(pc) filename := path.Base(pathname) s := fmt.Sprintf("\n at %s (%s:%d)", f.Name(), filename, lineno) buffer.WriteString(s) } } log.Error(buffer.String()) // TODO: Should we panic? panic("Assertion failed: " + buffer.String()) }
// callerName returns the package path and function name of the calling // function. The skip argument has the same meaning as the skip argument of // runtime.Callers. func callerName(skip int) (pkgPath, funcName string, ok bool) { var pc [1]uintptr n := runtime.Callers(skip+1, pc[:]) if n != 1 { return "", "", false } f := runtime.FuncForPC(pc[0]) fullName := f.Name() lastDotIndex := strings.LastIndex(fullName, ".") if lastDotIndex == -1 { panic("unable to distinguish function name from package") } if fullName[lastDotIndex-1] == ')' { // The caller is a method on some type, so it's name looks like // "pkg/path.(type).method". We need to go back one dot farther to get // to the package name. lastDotIndex = strings.LastIndex(fullName[:lastDotIndex], ".") } pkgPath = fullName[:lastDotIndex] funcName = fullName[lastDotIndex+1:] ok = true return }
func recordDBConn(path string, db *gouchstore.Gouchstore) { callers := make([]uintptr, 32) n := runtime.Callers(2, callers) openConnLock.Lock() openConns[db] = dbOpenState{path, frameSnap(callers[:n-1])} openConnLock.Unlock() }
// NewStorageError - return new Error type. func traceError(e error, errs ...error) error { if e == nil { return nil } err := &Error{} err.e = e err.errs = errs stack := make([]uintptr, 40) length := runtime.Callers(2, stack) if length > len(stack) { length = len(stack) } stack = stack[:length] for _, pc := range stack { pc = pc - 1 fn := runtime.FuncForPC(pc) file, line := fn.FileLine(pc) name := fn.Name() if strings.HasSuffix(name, "ServeHTTP") { break } if strings.HasSuffix(name, "runtime.") { break } file = strings.TrimPrefix(file, rootPath+string(os.PathSeparator)) name = strings.TrimPrefix(name, "github.com/minio/minio/cmd.") err.trace = append(err.trace, traceInfo{file, line, name}) } return err }
func (h ErrorHandler) recovery(w http.ResponseWriter, r *http.Request) { rec := recover() if rec == nil { return } // Obtain source of panic // From: https://gist.github.com/swdunlop/9629168 var name, file string // function name, file name var line int var pc [16]uintptr n := runtime.Callers(3, pc[:]) for _, pc := range pc[:n] { fn := runtime.FuncForPC(pc) if fn == nil { continue } file, line = fn.FileLine(pc) name = fn.Name() if !strings.HasPrefix(name, "runtime.") { break } } // Trim file path delim := "/caddy/" pkgPathPos := strings.Index(file, delim) if pkgPathPos > -1 && len(file) > pkgPathPos+len(delim) { file = file[pkgPathPos+len(delim):] } // Currently we don't use the function name, as file:line is more conventional h.Log.Printf("%s [PANIC %s] %s:%d - %v", time.Now().Format(timeFormat), r.URL.String(), file, line, rec) h.errorPage(w, http.StatusInternalServerError) }
func Fatal(v ...interface{}) { if logobj.level <= FATAL { pc := make([]uintptr, 1) runtime.Callers(2, pc) logobj.output("FATAL", pc[0], v...) } }
// Wrap makes an Error from the given value. If that value is already an // error then it will be used directly, if not, it will be passed to // fmt.Errorf("%v"). The skip parameter indicates how far up the stack // to start the stacktrace. 0 is from the current call, 1 from its caller, etc. func Wrap(e interface{}, skip int) *Error { var err error switch e := e.(type) { case *Error: return e case error: err = e default: err = fmt.Errorf("%v", e) } s := make([]uintptr, MaxStackDepth) length := runtime.Callers(2+skip, s[:]) f := stackFrames(s[:length]) return &Error{ Err: err, stack: s[:length], frames: f, // StackTrace: string(stack(f)), Stack: errorStack(typeName(err), err, stack(f)), Description: err.Error(), Title: err.Error(), } }
func NewRecord(s string, l LogLevel, m string, d map[string]interface{}) *Record { r := &Record{ Timestamp: RecordTimestamp(time.Now().UnixNano()) / 1000000000, Pid: pid, Source: s, Level: l, Message: m, Data: d, } if config.EnableLOC { var function *runtime.Func var file string var line int pc := make([]uintptr, 50) nptrs := runtime.Callers(2, pc) for i := 0; i < nptrs; i++ { function = runtime.FuncForPC(pc[i]) file, line = function.FileLine(pc[i]) if !strings.HasSuffix(file, "logger.go") { break } } r.File = file r.Line = line r.Method = function.Name() } return r }
//gets name of function that called the currently executing function. func myCallerName() string { fpcs := make([]uintptr, 1) runtime.Callers(3, fpcs) fun := runtime.FuncForPC(fpcs[0]) nameSplit := strings.Split(fun.Name(), ".") return nameSplit[len(nameSplit)-1] }
func callers() *stack { const depth = 32 var pcs [depth]uintptr n := runtime.Callers(3, pcs[:]) var st stack = pcs[0:n] return &st }
func (w *Writer) startLine(n Line, nn *int64, err *error) { if *err != nil { return } if _, ok := w.taken[n]; ok { panic("bitgen: duplicate line number") } var pc [64]uint64 if *flagMap != "" { var pcnative [len(pc)]uintptr if i := runtime.Callers(1, pcnative[:]); i >= len(pc) { panic("call stack too deep for profile") } for i, n := range pcnative { pc[i] = uint64(n) } } w.taken[n] = pc if n == Line(*flagCrashOnLine) { panic("DEBUG") } write(w.w, "LINE NUMBER ", nn, err) number(w.w, uint64(n), nn, err) write(w.w, " CODE ", nn, err) }
func getStackTraceMessage(msg string) string { var name, file string var line int var pc [16]uintptr n := runtime.Callers(3, pc[:]) buff := &bytes.Buffer{} buff.WriteString(msg) buff.WriteString("\n") for _, pc := range pc[:n] { fn := runtime.FuncForPC(pc) if fn == nil { continue } file, line = fn.FileLine(pc) name = fn.Name() switch { case name != "": buff.WriteString(fmt.Sprintf("! %v:%v\n", name, line)) case file != "": buff.WriteString(fmt.Sprintf("! %v:%v\n", file, line)) } } return string(buff.Bytes()) }
func DumpEtcdOnFailure(t *testing.T) { if !t.Failed() { return } pc := make([]uintptr, 10) goruntime.Callers(2, pc) f := goruntime.FuncForPC(pc[0]) last := strings.LastIndex(f.Name(), "Test") if last == -1 { last = 0 } name := f.Name()[last:] client := NewEtcdClient() etcdResponse, err := client.RawGet("/", false, true) if err != nil { t.Logf("error dumping etcd: %v", err) return } if err := ioutil.WriteFile(GetBaseDir()+"/etcd-dump-"+name+".json", etcdResponse.Body, os.FileMode(0444)); err != nil { t.Logf("error dumping etcd: %v", err) return } }
func NewTrace(skip int) *Trace { stack := make([]uintptr, MaxStackDepth) length := runtime.Callers(2+skip, stack) return &Trace{ stack: stack[:length], } }
// When a test is skipped or fails, runtime.Goexit() is called which destroys the callstack. // This means the name of the test case is lost, so we need to grab a copy of pc before. func Report(t testing.TB) { // If the goroutine panics, Fatal()s, or Skip()s, the function name is at the 3rd callstack // layer. On success, its at 1st. Since it's hard to check which happened, just try both. pcs := make([]uintptr, 10) total := runtime.Callers(1, pcs) var name string for _, pc := range pcs[:total] { fn := runtime.FuncForPC(pc) fullName := fn.Name() if strings.HasPrefix(path.Ext(fullName), ".Test") { // Skip the leading . name = string([]byte(path.Ext(fullName))[1:]) break } } if name == "" { return } allCaseInfos.lock.Lock() defer allCaseInfos.lock.Unlock() allCaseInfos.Cases = append(allCaseInfos.Cases, &caseInfo{ Name: name, Passed: !t.Failed() && !t.Skipped(), Skipped: t.Skipped(), Fatal: t.Failed() && !strings.HasPrefix(name, "TestSoon"), }) }
func stacktrace() StackTrace { const depth = 8 var pcs [depth]uintptr n := runtime.Callers(1, pcs[:]) var st stack = pcs[0:n] return st.StackTrace() }
func trace() (funcTrace string) { pc := make([]uintptr, 10) // at least 1 entry needed runtime.Callers(2, pc) f := runtime.FuncForPC(pc[0]) file, line := f.FileLine(pc[0]) return fmt.Sprintf("%s:%d %s", file, line, f.Name()) }
func f3(pan bool) []uintptr { if pan { panic("f3") // line 23 } ret := make([]uintptr, 20) return ret[:runtime.Callers(0, ret)] // line 26 }