示例#1
0
// LazyHandler writes all values to the wrapped handler after evaluating
// any lazy functions in the record's context. It is already wrapped
// around StreamHandler and SyslogHandler in this library, you'll only need
// it if you write your own Handler.
func LazyHandler(h Handler) Handler {
	return FuncHandler(func(r *Record) error {
		// go through the values (odd indices) and reassign
		// the values of any lazy fn to the result of its execution
		hadErr := false
		for i := 1; i < len(r.Ctx); i += 2 {
			lz, ok := r.Ctx[i].(Lazy)
			if ok {
				v, err := evaluateLazy(lz)
				if err != nil {
					hadErr = true
					r.Ctx[i] = err
				} else {
					if cs, ok := v.(stack.Trace); ok {
						v = cs.TrimBelow(stack.Call(r.CallPC[0])).
							TrimRuntime()
					}
					r.Ctx[i] = v
				}
			}
		}

		if hadErr {
			r.Ctx = append(r.Ctx, errorKey, "bad lazy")
		}

		return h.Log(r)
	})
}
示例#2
0
// CallerFuncHandler returns a Handler that adds the calling function name to
// the context with key "fn".
func CallerFuncHandler(h Handler) Handler {
	return FuncHandler(func(r *Record) error {
		call := stack.Call(r.CallPC[0])
		r.Ctx = append(r.Ctx, "fn", fmt.Sprintf("%+n", call))
		return h.Log(r)
	})
}
示例#3
0
func BenchmarkCallPlusVFmt(b *testing.B) {
	pc, _, _, ok := runtime.Caller(0)
	if !ok {
		b.Fatal("runtime.Caller(0) failed")
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%+v", stack.Call(pc))
	}
}
示例#4
0
// CallerStackHandler returns a Handler that adds a stack trace to the context
// with key "stack". The stack trace is formated as a space separated list of
// call sites inside matching []'s. The most recent call site is listed first.
// Each call site is formatted according to format. See the documentation of
// log15/stack.Call.Format for the list of supported formats.
func CallerStackHandler(format string, h Handler) Handler {
	return FuncHandler(func(r *Record) error {
		s := stack.Callers().
			TrimBelow(stack.Call(r.CallPC[0])).
			TrimRuntime()
		if len(s) > 0 {
			buf := &bytes.Buffer{}
			buf.WriteByte('[')
			for i, pc := range s {
				if i > 0 {
					buf.WriteByte(' ')
				}
				fmt.Fprintf(buf, format, pc)
			}
			buf.WriteByte(']')
			r.Ctx = append(r.Ctx, "stack", buf.String())
		}
		return h.Log(r)
	})
}
示例#5
0
func TestCallFormat(t *testing.T) {
	t.Parallel()

	pc, file, line, ok := runtime.Caller(0)
	if !ok {
		t.Fatal("runtime.Caller(0) failed")
	}

	gopathSrc := filepath.Join(os.Getenv("GOPATH"), "src")
	relFile, err := filepath.Rel(gopathSrc, file)
	if err != nil {
		t.Fatalf("failed to determine path relative to GOPATH: %v", err)
	}
	relFile = filepath.ToSlash(relFile)

	pc2, file2, line2, ok2 := testType{}.testMethod()
	if !ok2 {
		t.Fatal("runtime.Caller(0) failed")
	}
	relFile2, err := filepath.Rel(gopathSrc, file)
	if err != nil {
		t.Fatalf("failed to determine path relative to GOPATH: %v", err)
	}
	relFile2 = filepath.ToSlash(relFile2)

	data := []struct {
		pc   uintptr
		desc string
		fmt  string
		out  string
	}{
		{0, "error", "%s", "%!s(NOFUNC)"},

		{pc, "func", "%s", path.Base(file)},
		{pc, "func", "%+s", relFile},
		{pc, "func", "%#s", file},
		{pc, "func", "%d", fmt.Sprint(line)},
		{pc, "func", "%n", "TestCallFormat"},
		{pc, "func", "%+n", runtime.FuncForPC(pc).Name()},
		{pc, "func", "%v", fmt.Sprint(path.Base(file), ":", line)},
		{pc, "func", "%+v", fmt.Sprint(relFile, ":", line)},
		{pc, "func", "%#v", fmt.Sprint(file, ":", line)},
		{pc, "func", "%v|%[1]n()", fmt.Sprint(path.Base(file), ":", line, "|", "TestCallFormat()")},

		{pc2, "meth", "%s", path.Base(file2)},
		{pc2, "meth", "%+s", relFile2},
		{pc2, "meth", "%#s", file2},
		{pc2, "meth", "%d", fmt.Sprint(line2)},
		{pc2, "meth", "%n", "testType.testMethod"},
		{pc2, "meth", "%+n", runtime.FuncForPC(pc2).Name()},
		{pc2, "meth", "%v", fmt.Sprint(path.Base(file2), ":", line2)},
		{pc2, "meth", "%+v", fmt.Sprint(relFile2, ":", line2)},
		{pc2, "meth", "%#v", fmt.Sprint(file2, ":", line2)},
		{pc2, "meth", "%v|%[1]n()", fmt.Sprint(path.Base(file2), ":", line2, "|", "testType.testMethod()")},
	}

	for _, d := range data {
		got := fmt.Sprintf(d.fmt, stack.Call(d.pc))
		if got != d.out {
			t.Errorf("fmt.Sprintf(%q, Call(%s)) = %s, want %s", d.fmt, d.desc, got, d.out)
		}
	}
}