func TestCallString(t *testing.T) { t.Parallel() c := stack.Caller(0) _, file, line, ok := runtime.Caller(0) line-- if !ok { t.Fatal("runtime.Caller(0) failed") } c2, _, file2, line2, ok2 := testType{}.testMethod() if !ok2 { t.Fatal("runtime.Caller(0) failed") } data := []struct { c stack.Call desc string out string }{ {stack.Call{}, "error", "%!v(NOFUNC)"}, {c, "func", fmt.Sprint(path.Base(file), ":", line)}, {c2, "meth", fmt.Sprint(path.Base(file2), ":", line2)}, } for _, d := range data { got := d.c.String() if got != d.out { t.Errorf("got %s, want %s", got, d.out) } } }
func BenchmarkCallPlusNFmt(b *testing.B) { c := stack.Caller(0) b.ResetTimer() for i := 0; i < b.N; i++ { fmt.Fprintf(ioutil.Discard, "%+n", c) } }
func TestCallFormat(t *testing.T) { t.Parallel() c := stack.Caller(0) pc, file, line, ok := runtime.Caller(0) line-- if !ok { t.Fatal("runtime.Caller(0) failed") } relFile := path.Join(importPath, filepath.Base(file)) c2, pc2, file2, line2, ok2 := testType{}.testMethod() if !ok2 { t.Fatal("runtime.Caller(0) failed") } relFile2 := path.Join(importPath, filepath.Base(file2)) data := []struct { c stack.Call desc string fmt string out string }{ {stack.Call{}, "error", "%s", "%!s(NOFUNC)"}, {c, "func", "%s", path.Base(file)}, {c, "func", "%+s", relFile}, {c, "func", "%#s", file}, {c, "func", "%d", fmt.Sprint(line)}, {c, "func", "%n", "TestCallFormat"}, {c, "func", "%+n", runtime.FuncForPC(pc - 1).Name()}, {c, "func", "%v", fmt.Sprint(path.Base(file), ":", line)}, {c, "func", "%+v", fmt.Sprint(relFile, ":", line)}, {c, "func", "%#v", fmt.Sprint(file, ":", line)}, {c2, "meth", "%s", path.Base(file2)}, {c2, "meth", "%+s", relFile2}, {c2, "meth", "%#s", file2}, {c2, "meth", "%d", fmt.Sprint(line2)}, {c2, "meth", "%n", "testType.testMethod"}, {c2, "meth", "%+n", runtime.FuncForPC(pc2).Name()}, {c2, "meth", "%v", fmt.Sprint(path.Base(file2), ":", line2)}, {c2, "meth", "%+v", fmt.Sprint(relFile2, ":", line2)}, {c2, "meth", "%#v", fmt.Sprint(file2, ":", line2)}, } for _, d := range data { got := fmt.Sprintf(d.fmt, d.c) if got != d.out { t.Errorf("fmt.Sprintf(%q, Call(%s)) = %s, want %s", d.fmt, d.desc, got, d.out) } } }
func (l *logger) write(msg string, lvl Lvl, ctx []interface{}) { l.h.Log(&Record{ Time: time.Now(), Lvl: lvl, Msg: msg, Ctx: newContext(l.ctx, ctx), Call: stack.Caller(2), KeyNames: RecordKeyNames{ Time: timeKey, Msg: msgKey, Lvl: lvlKey, }, }) }
// Test that Context.Log has a consistent function stack depth when binding // log.Valuers, regardless of how many times Context.With has been called or // whether Context.Log is called via an interface typed variable or a concrete // typed variable. func TestContextStackDepth(t *testing.T) { t.Parallel() fn := fmt.Sprintf("%n", stack.Caller(0)) var output []interface{} logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error { output = keyvals return nil })) stackValuer := log.Valuer(func() interface{} { for i, c := range stack.Trace() { if fmt.Sprintf("%n", c) == fn { return i } } t.Fatal("Test function not found in stack trace.") return nil }) concrete := log.NewContext(logger).With("stack", stackValuer) var iface log.Logger = concrete // Call through interface to get baseline. iface.Log("k", "v") want := output[1].(int) for len(output) < 10 { concrete.Log("k", "v") if have := output[1]; have != want { t.Errorf("%d Withs: have %v, want %v", len(output)/2-1, have, want) } iface.Log("k", "v") if have := output[1]; have != want { t.Errorf("%d Withs: have %v, want %v", len(output)/2-1, have, want) } wrapped := log.NewContext(concrete) wrapped.Log("k", "v") if have := output[1]; have != want { t.Errorf("%d Withs: have %v, want %v", len(output)/2-1, have, want) } concrete = concrete.With("k", "v") iface = concrete } }
func TestCallMarshalText(t *testing.T) { t.Parallel() c := stack.Caller(0) _, file, line, ok := runtime.Caller(0) line-- if !ok { t.Fatal("runtime.Caller(0) failed") } c2, _, file2, line2, ok2 := testType{}.testMethod() if !ok2 { t.Fatal("runtime.Caller(0) failed") } data := []struct { c stack.Call desc string out []byte err error }{ {stack.Call{}, "error", nil, stack.ErrNoFunc}, {c, "func", []byte(fmt.Sprint(path.Base(file), ":", line)), nil}, {c2, "meth", []byte(fmt.Sprint(path.Base(file2), ":", line2)), nil}, } for _, d := range data { text, err := d.c.MarshalText() if got, want := err, d.err; got != want { t.Errorf("%s: got err %v, want err %v", d.desc, got, want) } if got, want := text, d.out; !reflect.DeepEqual(got, want) { t.Errorf("%s: got %s, want %s", d.desc, got, want) } } }
func Stack(skip int) string { call := stack.Caller(skip) s := stack.Trace().TrimBelow(call).TrimRuntime() return s.String() }
// Caller returns a Valuer that returns a file and line from a specified depth // in the callstack. Users will probably want to use DefaultCaller. func Caller(depth int) Valuer { return func() interface{} { return stack.Caller(depth) } }
func BenchmarkCallerAndVFmt(b *testing.B) { for i := 0; i < b.N; i++ { fmt.Fprint(ioutil.Discard, stack.Caller(0)) } }
func BenchmarkCaller(b *testing.B) { for i := 0; i < b.N; i++ { stack.Caller(0) } }
func trimBelow() stack.CallStack { call := stack.Caller(1) trace := stack.Trace() return trace.TrimBelow(call) }
func trimAbove() stack.CallStack { call := stack.Caller(1) trace := stack.Trace() return trace.TrimAbove(call) }
func (tt testType) testMethod() (c stack.Call, pc uintptr, file string, line int, ok bool) { c = stack.Caller(0) pc, file, line, ok = runtime.Caller(0) line-- return }
func logCaller(format string) { fmt.Printf(format+"\n", stack.Caller(1)) }