From 17a762ffb003108fd38adc1e8e57418e335c0a13 Mon Sep 17 00:00:00 2001 From: Bel LaPointe Date: Tue, 17 Dec 2019 15:20:40 -0700 Subject: [PATCH] initial commit --- level.go | 63 +++++++++++++++++++++++++++++++++++++++ level_test.go | 71 ++++++++++++++++++++++++++++++++++++++++++++ logb.go | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ logb_test.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 294 insertions(+) create mode 100644 level.go create mode 100644 level_test.go create mode 100644 logb.go create mode 100644 logb_test.go diff --git a/level.go b/level.go new file mode 100644 index 0000000..d1f2666 --- /dev/null +++ b/level.go @@ -0,0 +1,63 @@ +package logb + +import ( + "sync" +) + +const ( + cError = iota + cWarn + cInfo + cDebug + cVerbose +) + +var ( + ERROR = Level{Level: cError} + WARN = Level{Level: cWarn} + INFO = Level{Level: cInfo} + DEBUG = Level{Level: cDebug} + VERBOSE = Level{Level: cVerbose} +) + +type Level struct { + Level int + Lock sync.Mutex +} + +func NewLevel() *Level { + return &Level{ + Level: cInfo, + } +} + +func (l *Level) Set(v Level) { + l.Lock.Lock() + defer l.Lock.Unlock() + l.Level = v.Level +} + +func (l *Level) Get(v Level) int { + return l.Level +} + +func (l Level) Should(v Level) bool { + return l.Level >= v.Level +} + +func (l Level) String() string { + s := "undefined" + switch l.Level { + case ERROR.Level: + s = "ERROR" + case WARN.Level: + s = "WARN" + case INFO.Level: + s = "INFO" + case DEBUG.Level: + s = "DEBUG" + case VERBOSE.Level: + s = "VERBOSE" + } + return s +} diff --git a/level_test.go b/level_test.go new file mode 100644 index 0000000..a9a5072 --- /dev/null +++ b/level_test.go @@ -0,0 +1,71 @@ +package logb + +import ( + "sync" + "testing" + "time" +) + +func TestNewLevel(t *testing.T) { + NewLevel() +} + +func TestConsts(t *testing.T) { + for _, c := range []int{ + cInfo, + cWarn, + cError, + cDebug, + cVerbose, + } { + l := Level{Level: c} + if l.String() == "undefined" { + t.Error(l) + } + } +} + +func TestLevelLock(t *testing.T) { + l := NewLevel() + doLock := &sync.WaitGroup{} + doLock.Add(1) + didLock := make(chan struct{}) + + go func() { + doLock.Wait() + l.Lock.Lock() + didLock <- struct{}{} + }() + + l.Lock.Lock() + doLock.Done() + select { + case <-didLock: + t.Error("did a lock while locked") + case <-time.After(time.Millisecond * 50): + l.Lock.Unlock() + <-didLock + } +} + +func TestLevelShould(t *testing.T) { + levels := []Level{ + ERROR, + WARN, + INFO, + DEBUG, + VERBOSE, + } + for i := range levels { + okayed := 0 + for j := range levels { + should := levels[i].Should(levels[j]) + if should { + okayed += 1 + } + } + if okayed != i+1 { + t.Error(levels[i]) + } + } +} diff --git a/logb.go b/logb.go new file mode 100644 index 0000000..d7c8b25 --- /dev/null +++ b/logb.go @@ -0,0 +1,79 @@ +package logb + +import ( + "fmt" + "io" + "os" +) + +var level Level = INFO +var writer io.Writer = os.Stderr + +func Set(l ...Level) { + if len(l) < 1 { + l = []Level{INFO} + } + level.Set(l[0]) +} + +func SetWriter(w io.Writer) { + writer = w +} + +func Info(args ...interface{}) { + log(INFO, args...) +} + +func Warn(args ...interface{}) { + log(WARN, args...) +} + +func Error(args ...interface{}) { + log(ERROR, args...) +} + +func Debug(args ...interface{}) { + log(DEBUG, args...) +} + +func Verbose(args ...interface{}) { + log(VERBOSE, args...) +} + +func Infof(form string, args ...interface{}) { + logf(INFO, form, args...) +} + +func Warnf(form string, args ...interface{}) { + logf(WARN, form, args...) +} + +func Errorf(form string, args ...interface{}) { + logf(ERROR, form, args...) +} + +func Debugf(form string, args ...interface{}) { + logf(DEBUG, form, args...) +} + +func Verbosef(form string, args ...interface{}) { + logf(VERBOSE, form, args...) +} + +func log(lvl Level, args ...interface{}) { + v := "" + if len(args) > 0 { + args = append([]interface{}{}, args...) + v = fmt.Sprint(args) + v = v[1 : len(v)-1] + } + logf(lvl, "%s", v) +} + +func logf(lvl Level, form string, args ...interface{}) { + if !level.Should(lvl) { + return + } + form = fmt.Sprintf("[%v] %s\n", lvl.String()[:3], form) + fmt.Fprintf(writer, form, args...) +} diff --git a/logb_test.go b/logb_test.go new file mode 100644 index 0000000..58dca8b --- /dev/null +++ b/logb_test.go @@ -0,0 +1,81 @@ +package logb + +import ( + "bytes" + "fmt" + "testing" +) + +func TestSet(t *testing.T) { + Set() + if level != INFO { + t.Error(level, INFO) + } + Set(VERBOSE) + if level != VERBOSE { + t.Error(level, VERBOSE) + } +} + +func TestLogf(t *testing.T) { + cases := map[string]struct { + foo func(...interface{}) + in []interface{} + out string + }{ + "info empty": { + foo: Info, + in: []interface{}{}, + out: "[INF] ", + }, + "info args": { + foo: Info, + in: []interface{}{"hello", "info"}, + out: "[INF] hello info", + }, + "debug empty": { + foo: Debug, + in: []interface{}{}, + out: "[DEB] ", + }, + "debug args": { + foo: Debug, + in: []interface{}{"hello", "debug"}, + out: "[DEB] hello debug", + }, + "error empty": { + foo: Error, + in: []interface{}{}, + out: "[ERR] ", + }, + "error args": { + foo: Error, + in: []interface{}{"hello", "error"}, + out: "[ERR] hello error", + }, + "verbose empty": { + foo: Verbose, + in: []interface{}{}, + out: "[VER] ", + }, + "verbose args": { + foo: Verbose, + in: []interface{}{"hello", "verbose"}, + out: "[VER] hello verbose", + }, + } + + for i, c := range cases { + w := bytes.NewBuffer(nil) + SetWriter(w) + Set(VERBOSE) + c.foo(c.in...) + out := fmt.Sprintf("%s", w.Bytes()) + if out != c.out+"\n" { + t.Errorf("[%s]: %v => %q, want %q", i, c.in, out, c.out) + } + } +} + +func TestLog(t *testing.T) { +}