diff options
Diffstat (limited to 'pkg/log/log.go')
| -rw-r--r-- | pkg/log/log.go | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/pkg/log/log.go b/pkg/log/log.go new file mode 100644 index 000000000..d57e8c1ad --- /dev/null +++ b/pkg/log/log.go @@ -0,0 +1,98 @@ +// Copyright 2016 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +// log package provides functionality similar to standard log package with some extensions: +// - verbosity levels +// - global verbosity setting that can be used by multiple packages +// - ability to disable all output +// - ability to cache recent output in memory +package log + +import ( + "bytes" + "flag" + "fmt" + golog "log" + "sync" + "time" +) + +var ( + flagV = flag.Int("v", 0, "verbosity") + mu sync.Mutex + cacheMem int + cacheMaxMem int + cachePos int + cacheEntries []string + prependTime = true // for testing +) + +// EnableCaching enables in memory caching of log output. +// Caches up to maxLines, but no more than maxMem bytes. +// Cached output can later be queried with CachedOutput. +func EnableLogCaching(maxLines, maxMem int) { + mu.Lock() + defer mu.Unlock() + if cacheEntries != nil { + Fatalf("log caching is already enabled") + } + if maxLines < 1 || maxMem < 1 { + panic("invalid maxLines/maxMem") + } + cacheMaxMem = maxMem + cacheEntries = make([]string, maxLines) +} + +// Retrieves cached log output. +func CachedLogOutput() string { + mu.Lock() + defer mu.Unlock() + buf := new(bytes.Buffer) + for i := range cacheEntries { + pos := (cachePos + i) % len(cacheEntries) + if cacheEntries[pos] == "" { + continue + } + buf.WriteString(cacheEntries[pos]) + buf.Write([]byte{'\n'}) + } + return buf.String() +} + +func Logf(v int, msg string, args ...interface{}) { + mu.Lock() + doLog := v <= *flagV + if cacheEntries != nil && v <= 1 { + cacheMem -= len(cacheEntries[cachePos]) + if cacheMem < 0 { + panic("log cache size underflow") + } + timeStr := "" + if prependTime { + timeStr = time.Now().Format("2006/01/02 15:04:05 ") + } + cacheEntries[cachePos] = fmt.Sprintf(timeStr+msg, args...) + cacheMem += len(cacheEntries[cachePos]) + cachePos++ + if cachePos == len(cacheEntries) { + cachePos = 0 + } + for i := 0; i < len(cacheEntries)-1 && cacheMem > cacheMaxMem; i++ { + pos := (cachePos + i) % len(cacheEntries) + cacheMem -= len(cacheEntries[pos]) + cacheEntries[pos] = "" + } + if cacheMem < 0 { + panic("log cache size underflow") + } + } + mu.Unlock() + + if doLog { + golog.Printf(msg, args...) + } +} + +func Fatalf(msg string, args ...interface{}) { + golog.Fatalf(msg, args...) +} |
