diff options
Diffstat (limited to 'utils/trace')
-rw-r--r-- | utils/trace/trace.go | 55 | ||||
-rw-r--r-- | utils/trace/trace_test.go | 95 |
2 files changed, 150 insertions, 0 deletions
diff --git a/utils/trace/trace.go b/utils/trace/trace.go new file mode 100644 index 0000000..3e15c5b --- /dev/null +++ b/utils/trace/trace.go @@ -0,0 +1,55 @@ +package trace + +import ( + "fmt" + "log" + "os" + "sync/atomic" +) + +var ( + // logger is the logger to use for tracing. + logger = newLogger() + + // current is the targets that are enabled for tracing. + current atomic.Int32 +) + +func newLogger() *log.Logger { + return log.New(os.Stderr, "", log.Ltime|log.Lmicroseconds|log.Lshortfile) +} + +// Target is a tracing target. +type Target int32 + +const ( + // General traces general operations. + General Target = 1 << iota + + // Packet traces git packets. + Packet +) + +// SetTarget sets the tracing targets. +func SetTarget(target Target) { + current.Store(int32(target)) +} + +// SetLogger sets the logger to use for tracing. +func SetLogger(l *log.Logger) { + logger = l +} + +// Print prints the given message only if the target is enabled. +func (t Target) Print(args ...interface{}) { + if int32(t)¤t.Load() != 0 { + logger.Output(2, fmt.Sprint(args...)) // nolint: errcheck + } +} + +// Printf prints the given message only if the target is enabled. +func (t Target) Printf(format string, args ...interface{}) { + if int32(t)¤t.Load() != 0 { + logger.Output(2, fmt.Sprintf(format, args...)) // nolint: errcheck + } +} diff --git a/utils/trace/trace_test.go b/utils/trace/trace_test.go new file mode 100644 index 0000000..6f8f140 --- /dev/null +++ b/utils/trace/trace_test.go @@ -0,0 +1,95 @@ +package trace + +import ( + "bytes" + "io" + "log" + "testing" +) + +func TestMain(m *testing.M) { + defer SetLogger(newLogger()) + if code := m.Run(); code != 0 { + panic(code) + } +} + +func setUpTest(t testing.TB, buf *bytes.Buffer) { + t.Cleanup(func() { + if buf != nil { + buf.Reset() + } + SetTarget(0) + }) + w := io.Discard + if buf != nil { + w = buf + } + SetLogger(log.New(w, "", 0)) +} + +func TestEmpty(t *testing.T) { + var buf bytes.Buffer + setUpTest(t, &buf) + General.Print("test") + if buf.String() != "" { + t.Error("expected empty string") + } +} + +func TestOneTarget(t *testing.T) { + var buf bytes.Buffer + setUpTest(t, &buf) + SetTarget(General) + General.Print("test") + if buf.String() != "test\n" { + t.Error("expected 'test'") + } +} + +func TestMultipleTargets(t *testing.T) { + var buf bytes.Buffer + setUpTest(t, &buf) + SetTarget(General | Packet) + General.Print("a") + Packet.Print("b") + if buf.String() != "a\nb\n" { + t.Error("expected 'a\nb\n'") + } +} + +func TestPrintf(t *testing.T) { + var buf bytes.Buffer + setUpTest(t, &buf) + SetTarget(General) + General.Printf("a %d", 1) + if buf.String() != "a 1\n" { + t.Error("expected 'a 1\n'") + } +} + +func TestDisabledMultipleTargets(t *testing.T) { + var buf bytes.Buffer + setUpTest(t, &buf) + SetTarget(General) + General.Print("a") + Packet.Print("b") + if buf.String() != "a\n" { + t.Error("expected 'a\n'") + } +} + +func BenchmarkDisabledTarget(b *testing.B) { + setUpTest(b, nil) + for i := 0; i < b.N; i++ { + General.Print("test") + } +} + +func BenchmarkEnabledTarget(b *testing.B) { + setUpTest(b, nil) + SetTarget(General) + for i := 0; i < b.N; i++ { + General.Print("test") + } +} |