diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b53cfcc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +crashes.json diff --git a/debug.go b/debug.go index 016ca46..e036d67 100644 --- a/debug.go +++ b/debug.go @@ -20,7 +20,7 @@ var ( ) // Debugger function. -type DebugFunction func(string, ...interface{}) +type DebugFunction func(interface{}, ...interface{}) // Terminal colors used at random. var colors []string = []string{ @@ -80,7 +80,7 @@ func Debug(name string) DebugFunction { color := colors[rand.Intn(len(colors))] prev := time.Now() - return func(format string, args ...interface{}) { + return func(strOrFunc interface{}, args ...interface{}) { if !enabled { return } @@ -89,6 +89,16 @@ func Debug(name string) DebugFunction { return } + var format, isString = strOrFunc.(string) + + if !isString { + lazy, isFunc := strOrFunc.(func() string) + if !isFunc { + panic("invalid first argument type for Debug, must either be a string or lazy function") + } + format = lazy() + } + d := deltas(prevGlobal, prev, color) fmt.Fprintf(writer, d+" \033["+color+"m"+name+"\033[0m - "+format+"\n", args...) prevGlobal = time.Now() diff --git a/debug_test.go b/debug_test.go index 7ce2764..07dbf74 100644 --- a/debug_test.go +++ b/debug_test.go @@ -1,9 +1,15 @@ package debug -import "testing" -import "strings" -import "bytes" -import "time" +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" + "time" +) func assertContains(t *testing.T, str, substr string) { if !strings.Contains(str, substr) { @@ -32,6 +38,21 @@ func TestDefault(t *testing.T) { } } +func TestDefaultLazy(t *testing.T) { + var b []byte + buf := bytes.NewBuffer(b) + SetWriter(buf) + + debug := Debug("foo") + debug(func() string { return "something" }) + debug(func() string { return "here" }) + debug(func() string { return "whoop" }) + + if buf.Len() != 0 { + t.Fatalf("buffer should be empty") + } +} + func TestEnable(t *testing.T) { var b []byte buf := bytes.NewBuffer(b) @@ -43,6 +64,7 @@ func TestEnable(t *testing.T) { debug("something") debug("here") debug("whoop") + debug(func() string { return "lazy" }) if buf.Len() == 0 { t.Fatalf("buffer should have output") @@ -52,6 +74,7 @@ func TestEnable(t *testing.T) { assertContains(t, str, "something") assertContains(t, str, "here") assertContains(t, str, "whoop") + assertContains(t, str, "lazy") } func TestMultipleOneEnabled(t *testing.T) { @@ -63,9 +86,11 @@ func TestMultipleOneEnabled(t *testing.T) { foo := Debug("foo") foo("foo") + foo(func() string { return "foo lazy" }) bar := Debug("bar") bar("bar") + bar(func() string { return "bar lazy" }) if buf.Len() == 0 { t.Fatalf("buffer should have output") @@ -73,7 +98,9 @@ func TestMultipleOneEnabled(t *testing.T) { str := string(buf.Bytes()) assertContains(t, str, "foo") + assertContains(t, str, "foo lazy") assertNotContains(t, str, "bar") + assertNotContains(t, str, "bar lazy") } func TestMultipleEnabled(t *testing.T) { @@ -85,9 +112,11 @@ func TestMultipleEnabled(t *testing.T) { foo := Debug("foo") foo("foo") + foo(func() string { return "foo lazy" }) bar := Debug("bar") bar("bar") + bar(func() string { return "bar lazy" }) if buf.Len() == 0 { t.Fatalf("buffer should have output") @@ -95,7 +124,9 @@ func TestMultipleEnabled(t *testing.T) { str := string(buf.Bytes()) assertContains(t, str, "foo") + assertContains(t, str, "foo lazy") assertContains(t, str, "bar") + assertContains(t, str, "bar lazy") } func TestEnableDisable(t *testing.T) { @@ -108,9 +139,11 @@ func TestEnableDisable(t *testing.T) { foo := Debug("foo") foo("foo") + foo(func() string { return "foo" }) bar := Debug("bar") bar("bar") + bar(func() string { return "bar" }) if buf.Len() != 0 { t.Fatalf("buffer should not have output") @@ -143,6 +176,13 @@ func BenchmarkDisabled(b *testing.B) { } } +func BenchmarkDisabledLazy(b *testing.B) { + debug := Debug("something") + for i := 0; i < b.N; i++ { + debug(func() string { return "lazy" }) + } +} + func BenchmarkNonMatch(b *testing.B) { debug := Debug("something") Enable("nonmatch") @@ -150,3 +190,56 @@ func BenchmarkNonMatch(b *testing.B) { debug("stuff") } } + +func BenchmarkLargeNonMatch(b *testing.B) { + debug := Debug("large:not:lazy") + + abs, _ := filepath.Abs("./crashes.json") + file := GetFileBytes(abs) + + Enable("nonmatch") + for i := 0; i < b.N; i++ { + debug(string(file)) + } +} + +func BenchmarkLargeLazyNonMatch(b *testing.B) { + debug := Debug("large:lazy") + + abs, _ := filepath.Abs("./crashes.json") + file := GetFileBytes(abs) + + Enable("nonmatch") + for i := 0; i < b.N; i++ { + debug(func() string { + return string(file) + }) + } +} + +func BenchmarkLargeLazyMatch(b *testing.B) { + debug := Debug("large:lazy") + + abs, _ := filepath.Abs("./crashes.json") + file := GetFileBytes(abs) + + Enable("large:lazy") + for i := 0; i < b.N; i++ { + debug(func() string { + return string(file) + }) + } +} + +func GetFileBytes(filename string) []byte { + file, err := os.Open(filename) + // if we os.Open returns an error then handle it + if err != nil { + fmt.Println(err) + } + // defer the closing of our jsonFile so that we can parse it later on + defer file.Close() + bytes, _ := ioutil.ReadAll(file) + + return bytes +} diff --git a/example/multiple.lazy.go b/example/multiple.lazy.go new file mode 100644 index 0000000..f897529 --- /dev/null +++ b/example/multiple.lazy.go @@ -0,0 +1,28 @@ +package main + +import ( + "time" + + . "github.com/visionmedia/go-debug" +) + +var a = Debug("multiple:a") +var b = Debug("multiple:b") +var c = Debug("multiple:c") + +func work(debug DebugFunction, delay time.Duration) { + for { + debug(func() string { return "doing stuff" }) + time.Sleep(delay) + } +} + +func main() { + q := make(chan bool) + + go work(a, 1000*time.Millisecond) + go work(b, 250*time.Millisecond) + go work(c, 100*time.Millisecond) + + <-q +} diff --git a/scripts/getSomeDataForPefTests.sh b/scripts/getSomeDataForPefTests.sh new file mode 100755 index 0000000..d66d2ed --- /dev/null +++ b/scripts/getSomeDataForPefTests.sh @@ -0,0 +1,2 @@ +#!/bin/sh +curl -o crashes.json 'https://data.ny.gov/api/views/xe9x-a24f/rows.json?accessType=DOWNLOAD'