git » gofer » next » tree

[next] / trace / trace.go

// Package trace extends golang.org/x/net/trace.
package trace

import (
	"context"
	"fmt"
	"strings"

	"blitiri.com.ar/go/log"

	"blitiri.com.ar/go/gofer/nettrace"
)

type key string

const contextKey key = "blitiri.com.ar/go/gofer/trace.Trace"

// A Trace represents an active request.
type Trace struct {
	family string
	title  string
	t      nettrace.Trace
}

// New trace.
func New(family, title string) *Trace {
	return &Trace{family, title, nettrace.New(family, title)}
}

func NewContext(ctx context.Context, tr *Trace) context.Context {
	return context.WithValue(ctx, contextKey, tr)
}

func FromContext(ctx context.Context) (tr *Trace, ok bool) {
	tr, ok = ctx.Value(contextKey).(*Trace)
	return
}

func (t *Trace) SetMaxEvents(n int) {
	t.t.SetMaxEvents(n)
}

// Printf adds this message to the trace's log.
func (t *Trace) Printf(format string, a ...interface{}) {
	t.t.Printf(format, a...)

	if log.Default.Level <= log.Debug {
		log.Log(log.Debug, 1, "%#p %s %s: %s", t, t.family, t.title,
			fmt.Sprintf(format, a...))
	}
}

// Errorf adds this message to the trace's log, with an error level.
func (t *Trace) Errorf(format string, a ...interface{}) error {
	// Note we can't just call t.Error here, as it breaks caller logging.
	err := fmt.Errorf(format, a...)
	t.t.SetError()
	t.t.Printf("error: %v", err)

	log.Log(log.Info, 1, "%#p %s %s error: %s", t, t.family, t.title,
		err.Error())
	return err
}

// SetError marks the trace as having received an error, without emitting any
// particular output.
func (t *Trace) SetError() {
	t.t.SetError()
}

// Finish the trace. It should not be changed after this is called.
func (t *Trace) Finish() {
	t.t.Finish()
}

// Write so Trace implements io.Writer, which means it can be used as output
// for log.Logger.
func (t *Trace) Write(p []byte) (n int, err error) {
	lines := strings.Split(string(p), "\n")
	for _, line := range lines {
		if strings.TrimSpace(line) == "" {
			continue
		}
		t.Printf("%s", line)
	}
	return len(p), nil
}