Refactor so it can be used in non-global settings
diff --git a/README.md b/README.md
index c6f327c..350a968 100644
--- a/README.md
+++ b/README.md
@@ -44,7 +44,7 @@
* FATAL
These each are loggers based on the log standard library and follow the
-standard usage. Eg..
+standard usage. Eg.
```go
import (
@@ -79,6 +79,13 @@
```
+NOTE: You can also use the library in a non-global setting by creating an instance of a Notebook:
+
+```go
+notepad = jww.NewNotepad(jww.LevelInfo, jww.LevelTrace, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
+notepad.WARN.Println("Some warning"")
+```
+
_Why 7 levels?_
Maybe you think that 7 levels are too much for any application... and you
@@ -118,35 +125,15 @@
Note that JWW's own internal output uses log levels as well, so set the log
level before making any other calls if you want to see what it's up to.
-### Using a temp log file
-
-JWW conveniently creates a temporary file and sets the log Handle to
-a io.Writer created for it. You should call this early in your application
-initialization routine as it will only log calls made after it is executed.
-When this option is used, the library will fmt.Println where to find the
-log file.
-
-```go
- import (
- jww "github.com/spf13/jwalterweatherman"
- )
-
- jww.UseTempLogFile("YourAppName")
-
-```
### Setting a log file
-JWW can log to any file you provide a path to (provided it’s writable).
-Will only append to this file.
+JWW can log to any `io.Writer`:
```go
- import (
- jww "github.com/spf13/jwalterweatherman"
- )
- jww.SetLogFile("/path/to/logfile")
+ jww.SetLogOutput(customWriter)
```
diff --git a/default_notepad.go b/default_notepad.go
new file mode 100644
index 0000000..ea8003d
--- /dev/null
+++ b/default_notepad.go
@@ -0,0 +1,103 @@
+// Copyright © 2016 Steve Francia <spf@spf13.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+package jwalterweatherman
+
+import (
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+)
+
+var (
+ TRACE *log.Logger
+ DEBUG *log.Logger
+ INFO *log.Logger
+ WARN *log.Logger
+ ERROR *log.Logger
+ CRITICAL *log.Logger
+ FATAL *log.Logger
+
+ LOG *log.Logger
+ FEEDBACK *Feedback
+
+ defaultNotepad *Notepad
+)
+
+func reloadDefaultNotepad() {
+ TRACE = defaultNotepad.TRACE
+ DEBUG = defaultNotepad.DEBUG
+ INFO = defaultNotepad.INFO
+ WARN = defaultNotepad.WARN
+ ERROR = defaultNotepad.ERROR
+ CRITICAL = defaultNotepad.CRITICAL
+ FATAL = defaultNotepad.FATAL
+
+ LOG = defaultNotepad.LOG
+ FEEDBACK = defaultNotepad.FEEDBACK
+}
+
+func init() {
+ defaultNotepad = NewNotepad(LevelInfo, LevelTrace, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
+ reloadDefaultNotepad()
+}
+
+// SetLogThreshold set the log threshold for the default notepad. Trace by default.
+func SetLogThreshold(threshold Threshold) {
+ defaultNotepad.SetLogThreshold(threshold)
+ reloadDefaultNotepad()
+}
+
+// SetLogOutput set the log output for the default notepad. Discarded by default.
+func SetLogOutput(handle io.Writer) {
+ defaultNotepad.SetLogOutput(handle)
+ reloadDefaultNotepad()
+}
+
+// SetStdoutThreshold set the standard output threshold for the default notepad.
+// Info by default.
+func SetStdoutThreshold(threshold Threshold) {
+ defaultNotepad.SetStdoutThreshold(threshold)
+ reloadDefaultNotepad()
+}
+
+// SetPrefix set the prefix for the default logger. Empty by default.
+func SetPrefix(prefix string) {
+ defaultNotepad.SetPrefix(prefix)
+ reloadDefaultNotepad()
+}
+
+// SetFlags set the flags for the default logger. "log.Ldate | log.Ltime" by default.
+func SetFlags(flags int) {
+ defaultNotepad.SetFlags(flags)
+ reloadDefaultNotepad()
+}
+
+// Level returns the current global log threshold.
+func LogThreshold() Threshold {
+ return defaultNotepad.logThreshold
+}
+
+// Level returns the current global output threshold.
+func StdoutThreshold() Threshold {
+ return defaultNotepad.stdoutThreshold
+}
+
+// LogCountForLevel returns the number of log invocations for a given threshold.
+func LogCountForLevel(l Threshold) uint64 {
+ return defaultNotepad.LogCountForLevel(l)
+}
+
+// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations
+// greater than or equal to a given threshold.
+func LogCountForLevelsGreaterThanorEqualTo(threshold Threshold) uint64 {
+ return defaultNotepad.LogCountForLevelsGreaterThanorEqualTo(threshold)
+}
+
+// ResetLogCounters resets the invocation counters for all levels.
+func ResetLogCounters() {
+ defaultNotepad.ResetLogCounters()
+}
diff --git a/default_notepad_test.go b/default_notepad_test.go
new file mode 100644
index 0000000..2670c8d
--- /dev/null
+++ b/default_notepad_test.go
@@ -0,0 +1,102 @@
+// Copyright © 2016 Steve Francia <spf@spf13.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+package jwalterweatherman
+
+import (
+ "bytes"
+ "io/ioutil"
+ "sync"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestThresholds(t *testing.T) {
+ SetStdoutThreshold(LevelError)
+ require.Equal(t, StdoutThreshold(), LevelError)
+ SetLogThreshold(LevelCritical)
+ require.Equal(t, LogThreshold(), LevelCritical)
+ require.NotEqual(t, StdoutThreshold(), LevelCritical)
+ SetStdoutThreshold(LevelWarn)
+ require.Equal(t, StdoutThreshold(), LevelWarn)
+}
+
+func TestDefaultLogging(t *testing.T) {
+ var outputBuf, logBuf bytes.Buffer
+
+ defaultNotepad.logHandle = &logBuf
+ defaultNotepad.outHandle = &outputBuf
+
+ SetLogThreshold(LevelWarn)
+ SetStdoutThreshold(LevelError)
+
+ FATAL.Println("fatal err")
+ CRITICAL.Println("critical err")
+ ERROR.Println("an error")
+ WARN.Println("a warning")
+ INFO.Println("information")
+ DEBUG.Println("debugging info")
+ TRACE.Println("trace")
+
+ require.Contains(t, logBuf.String(), "fatal err")
+ require.Contains(t, logBuf.String(), "critical err")
+ require.Contains(t, logBuf.String(), "an error")
+ require.Contains(t, logBuf.String(), "a warning")
+ require.NotContains(t, logBuf.String(), "information")
+ require.NotContains(t, logBuf.String(), "debugging info")
+ require.NotContains(t, logBuf.String(), "trace")
+
+ require.Contains(t, outputBuf.String(), "fatal err")
+ require.Contains(t, outputBuf.String(), "critical err")
+ require.Contains(t, outputBuf.String(), "an error")
+ require.NotContains(t, outputBuf.String(), "a warning")
+ require.NotContains(t, outputBuf.String(), "information")
+ require.NotContains(t, outputBuf.String(), "debugging info")
+ require.NotContains(t, outputBuf.String(), "trace")
+}
+
+func TestLogCounter(t *testing.T) {
+ defaultNotepad.logHandle = ioutil.Discard
+ defaultNotepad.outHandle = ioutil.Discard
+
+ SetLogThreshold(LevelTrace)
+ SetStdoutThreshold(LevelTrace)
+
+ FATAL.Println("fatal err")
+ CRITICAL.Println("critical err")
+ WARN.Println("a warning")
+ WARN.Println("another warning")
+ INFO.Println("information")
+ DEBUG.Println("debugging info")
+ TRACE.Println("trace")
+
+ wg := &sync.WaitGroup{}
+
+ for i := 0; i < 10; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for j := 0; j < 10; j++ {
+ ERROR.Println("error", j)
+ // check for data races
+ require.True(t, LogCountForLevel(LevelError) > uint64(j))
+ require.True(t, LogCountForLevelsGreaterThanorEqualTo(LevelError) > uint64(j))
+ }
+ }()
+
+ }
+
+ wg.Wait()
+
+ require.Equal(t, uint64(1), LogCountForLevel(LevelFatal))
+ require.Equal(t, uint64(1), LogCountForLevel(LevelCritical))
+ require.Equal(t, uint64(2), LogCountForLevel(LevelWarn))
+ require.Equal(t, uint64(1), LogCountForLevel(LevelInfo))
+ require.Equal(t, uint64(1), LogCountForLevel(LevelDebug))
+ require.Equal(t, uint64(1), LogCountForLevel(LevelTrace))
+ require.Equal(t, uint64(100), LogCountForLevel(LevelError))
+ require.Equal(t, uint64(102), LogCountForLevelsGreaterThanorEqualTo(LevelError))
+}
diff --git a/jww_test.go b/jww_test.go
deleted file mode 100644
index c405185..0000000
--- a/jww_test.go
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright © 2016 Steve Francia <spf@spf13.com>.
-//
-// Use of this source code is governed by an MIT-style
-// license that can be found in the LICENSE file.
-
-package jwalterweatherman
-
-import (
- "bytes"
- "github.com/stretchr/testify/assert"
- "sync"
- "testing"
-)
-
-func TestLevels(t *testing.T) {
- SetStdoutThreshold(LevelError)
- assert.Equal(t, StdoutThreshold(), LevelError)
- SetLogThreshold(LevelCritical)
- assert.Equal(t, LogThreshold(), LevelCritical)
- assert.NotEqual(t, StdoutThreshold(), LevelCritical)
- SetStdoutThreshold(LevelWarn)
- assert.Equal(t, StdoutThreshold(), LevelWarn)
-}
-
-func TestDefaultLogging(t *testing.T) {
- outputBuf := new(bytes.Buffer)
- logBuf := new(bytes.Buffer)
- LogHandle = logBuf
- OutHandle = outputBuf
-
- SetLogThreshold(LevelWarn)
- SetStdoutThreshold(LevelError)
-
- FATAL.Println("fatal err")
- CRITICAL.Println("critical err")
- ERROR.Println("an error")
- WARN.Println("a warning")
- INFO.Println("information")
- DEBUG.Println("debugging info")
- TRACE.Println("trace")
-
- assert.Contains(t, logBuf.String(), "fatal err")
- assert.Contains(t, logBuf.String(), "critical err")
- assert.Contains(t, logBuf.String(), "an error")
- assert.Contains(t, logBuf.String(), "a warning")
- assert.NotContains(t, logBuf.String(), "information")
- assert.NotContains(t, logBuf.String(), "debugging info")
- assert.NotContains(t, logBuf.String(), "trace")
-
- assert.Contains(t, outputBuf.String(), "fatal err")
- assert.Contains(t, outputBuf.String(), "critical err")
- assert.Contains(t, outputBuf.String(), "an error")
- assert.NotContains(t, outputBuf.String(), "a warning")
- assert.NotContains(t, outputBuf.String(), "information")
- assert.NotContains(t, outputBuf.String(), "debugging info")
- assert.NotContains(t, outputBuf.String(), "trace")
-}
-
-func TestLogCounter(t *testing.T) {
- ResetLogCounters()
-
- FATAL.Println("fatal err")
- CRITICAL.Println("critical err")
- WARN.Println("a warning")
- WARN.Println("another warning")
- INFO.Println("information")
- DEBUG.Println("debugging info")
- TRACE.Println("trace")
-
- wg := &sync.WaitGroup{}
-
- for i := 0; i < 10; i++ {
- wg.Add(1)
- go func() {
- defer wg.Done()
- for j := 0; j < 10; j++ {
- ERROR.Println("error", j)
- // check for data races
- assert.True(t, LogCountForLevel(LevelError) > uint64(j))
- assert.True(t, LogCountForLevelsGreaterThanorEqualTo(LevelError) > uint64(j))
- }
- }()
-
- }
-
- wg.Wait()
-
- assert.Equal(t, uint64(1), LogCountForLevel(LevelFatal))
- assert.Equal(t, uint64(1), LogCountForLevel(LevelCritical))
- assert.Equal(t, uint64(2), LogCountForLevel(LevelWarn))
- assert.Equal(t, uint64(1), LogCountForLevel(LevelInfo))
- assert.Equal(t, uint64(1), LogCountForLevel(LevelDebug))
- assert.Equal(t, uint64(1), LogCountForLevel(LevelTrace))
- assert.Equal(t, uint64(100), LogCountForLevel(LevelError))
- assert.Equal(t, uint64(102), LogCountForLevelsGreaterThanorEqualTo(LevelError))
-}
diff --git a/log_counter.go b/log_counter.go
new file mode 100644
index 0000000..cada5cc
--- /dev/null
+++ b/log_counter.go
@@ -0,0 +1,57 @@
+// Copyright © 2016 Steve Francia <spf@spf13.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+package jwalterweatherman
+
+import (
+ "sync/atomic"
+)
+
+type logCounter struct {
+ id int
+ counter uint64
+}
+
+func (c *logCounter) incr() {
+ atomic.AddUint64(&c.counter, 1)
+}
+
+func (c *logCounter) resetCounter() {
+ atomic.StoreUint64(&c.counter, 0)
+}
+
+func (c *logCounter) getCount() uint64 {
+ return atomic.LoadUint64(&c.counter)
+}
+
+func (c *logCounter) Write(p []byte) (n int, err error) {
+ c.incr()
+
+ return len(p), nil
+}
+
+// LogCountForLevel returns the number of log invocations for a given threshold.
+func (n *Notepad) LogCountForLevel(l Threshold) uint64 {
+ return n.logCounters[l].getCount()
+}
+
+// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations
+// greater than or equal to a given threshold.
+func (n *Notepad) LogCountForLevelsGreaterThanorEqualTo(threshold Threshold) uint64 {
+ var cnt uint64
+
+ for i := int(threshold); i < len(n.logCounters); i++ {
+ cnt += n.LogCountForLevel(Threshold(i))
+ }
+
+ return cnt
+}
+
+// ResetLogCounters resets the invocation counters for all levels.
+func (n *Notepad) ResetLogCounters() {
+ for _, np := range n.logCounters {
+ np.resetCounter()
+ }
+}
diff --git a/notepad.go b/notepad.go
new file mode 100644
index 0000000..40b9620
--- /dev/null
+++ b/notepad.go
@@ -0,0 +1,177 @@
+// Copyright © 2016 Steve Francia <spf@spf13.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+package jwalterweatherman
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "os"
+)
+
+type Threshold int
+
+const (
+ LevelTrace Threshold = iota
+ LevelDebug
+ LevelInfo
+ LevelWarn
+ LevelError
+ LevelCritical
+ LevelFatal
+)
+
+var prefixes map[Threshold]string = map[Threshold]string{
+ LevelTrace: "TRACE ",
+ LevelDebug: "DEBUG ",
+ LevelInfo: "INFO ",
+ LevelWarn: "WARN ",
+ LevelError: "ERROR ",
+ LevelCritical: "CRITICAL ",
+ LevelFatal: "FATAL ",
+}
+
+// Notepad is where you leave a note !
+type Notepad struct {
+ TRACE *log.Logger
+ DEBUG *log.Logger
+ INFO *log.Logger
+ WARN *log.Logger
+ ERROR *log.Logger
+ CRITICAL *log.Logger
+ FATAL *log.Logger
+
+ LOG *log.Logger
+ FEEDBACK *Feedback
+
+ loggers []**log.Logger
+ logHandle io.Writer
+ outHandle io.Writer
+ logThreshold Threshold
+ stdoutThreshold Threshold
+ prefix string
+ flags int
+
+ // One per Threshold
+ logCounters [7]*logCounter
+}
+
+// NewNotepad create a new notepad.
+func NewNotepad(outThreshold Threshold, logThreshold Threshold, outHandle, logHandle io.Writer, prefix string, flags int) *Notepad {
+ n := &Notepad{}
+
+ n.loggers = append(n.loggers, &n.TRACE, &n.DEBUG, &n.INFO, &n.WARN, &n.ERROR, &n.CRITICAL, &n.FATAL)
+ n.logHandle = logHandle
+ n.outHandle = outHandle
+ n.logThreshold = logThreshold
+ n.stdoutThreshold = outThreshold
+
+ if len(prefix) != 0 {
+ n.prefix = "[" + prefix + "] "
+ } else {
+ n.prefix = ""
+ }
+
+ n.flags = flags
+
+ n.LOG = log.New(n.logHandle,
+ "LOG: ",
+ n.flags)
+
+ n.FEEDBACK = &Feedback{n}
+
+ n.init()
+
+ return n
+}
+
+// Feedback is special. It writes plainly to the output while
+// logging with the standard extra information (date, file, etc)
+// Only Println and Printf are currently provided for this
+type Feedback struct {
+ *Notepad
+}
+
+// init create the loggers for each level depending on the notepad thresholds
+func (n *Notepad) init() {
+ bothHandle := io.MultiWriter(n.outHandle, n.logHandle)
+
+ for t, logger := range n.loggers {
+ threshold := Threshold(t)
+ counter := &logCounter{id: t}
+ n.logCounters[t] = counter
+
+ switch {
+ case threshold >= n.logThreshold && threshold >= n.stdoutThreshold:
+ *logger = log.New(io.MultiWriter(counter, bothHandle), n.prefix+prefixes[threshold], n.flags)
+
+ case threshold >= n.logThreshold:
+ *logger = log.New(io.MultiWriter(counter, n.logHandle), n.prefix+prefixes[threshold], n.flags)
+
+ case threshold >= n.stdoutThreshold:
+ *logger = log.New(io.MultiWriter(counter, os.Stdout), n.prefix+prefixes[threshold], n.flags)
+
+ default:
+ *logger = log.New(counter, n.prefix+prefixes[threshold], n.flags)
+ }
+ }
+}
+
+// SetLogThreshold change the threshold above which messages are written to the
+// log file
+func (n *Notepad) SetLogThreshold(threshold Threshold) {
+ n.logThreshold = threshold
+ n.init()
+}
+
+// SetLogOutput change the file where log messages are written
+func (n *Notepad) SetLogOutput(handle io.Writer) {
+ n.logHandle = handle
+ n.init()
+}
+
+// SetStdoutThreshold change the threshold above which messages are written to the
+// standard output
+func (n *Notepad) SetStdoutThreshold(threshold Threshold) {
+ n.stdoutThreshold = threshold
+ n.init()
+}
+
+// SetPrefix change the prefix used by the notepad. Prefixes are displayed between
+// brackets at the begining of the line. An empty prefix won't be displayed at all.
+func (n *Notepad) SetPrefix(prefix string) {
+ if len(prefix) != 0 {
+ n.prefix = "[" + prefix + "] "
+ } else {
+ n.prefix = ""
+ }
+ n.init()
+}
+
+// SetFlags choose which flags the logger will display (after prefix and message
+// level). See the package log for more informations on this.
+func (n *Notepad) SetFlags(flags int) {
+ n.flags = flags
+ n.init()
+}
+
+// Feedback is special. It writes plainly to the output while
+// logging with the standard extra information (date, file, etc)
+// Only Println and Printf are currently provided for this
+func (fb *Feedback) Println(v ...interface{}) {
+ s := fmt.Sprintln(v...)
+ fmt.Print(s)
+ fb.LOG.Output(2, s)
+}
+
+// Feedback is special. It writes plainly to the output while
+// logging with the standard extra information (date, file, etc)
+// Only Println and Printf are currently provided for this
+func (fb *Feedback) Printf(format string, v ...interface{}) {
+ s := fmt.Sprintf(format, v...)
+ fmt.Print(s)
+ fb.LOG.Output(2, s)
+}
diff --git a/notepad_test.go b/notepad_test.go
new file mode 100644
index 0000000..7f6739b
--- /dev/null
+++ b/notepad_test.go
@@ -0,0 +1,33 @@
+// Copyright © 2016 Steve Francia <spf@spf13.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+package jwalterweatherman
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestNotepad(t *testing.T) {
+
+ var logHandle, outHandle bytes.Buffer
+
+ n := NewNotepad(LevelCritical, LevelError, &outHandle, &logHandle, "TestNotePad", 0)
+
+ n.DEBUG.Println("Some debug")
+ n.ERROR.Println("Some error")
+ n.CRITICAL.Println("Some critical error")
+
+ require.Contains(t, logHandle.String(), "[TestNotePad] ERROR Some error")
+ require.NotContains(t, logHandle.String(), "Some debug")
+ require.NotContains(t, outHandle.String(), "Some error")
+ require.Contains(t, outHandle.String(), "Some critical error")
+
+ require.Equal(t, n.LogCountForLevel(LevelError), uint64(1))
+ require.Equal(t, n.LogCountForLevel(LevelDebug), uint64(1))
+ require.Equal(t, n.LogCountForLevel(LevelTrace), uint64(0))
+}
diff --git a/thatswhyyoualwaysleaveanote.go b/thatswhyyoualwaysleaveanote.go
deleted file mode 100644
index b64ed46..0000000
--- a/thatswhyyoualwaysleaveanote.go
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright © 2016 Steve Francia <spf@spf13.com>.
-//
-// Use of this source code is governed by an MIT-style
-// license that can be found in the LICENSE file.
-
-package jwalterweatherman
-
-import (
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "os"
- "sync/atomic"
-)
-
-// Level describes the chosen log level between
-// debug and critical.
-type Level int
-
-type NotePad struct {
- Handle io.Writer
- Level Level
- Prefix string
- Logger **log.Logger
- counter uint64
-}
-
-func (n *NotePad) incr() {
- atomic.AddUint64(&n.counter, 1)
-}
-
-func (n *NotePad) resetCounter() {
- atomic.StoreUint64(&n.counter, 0)
-}
-
-func (n *NotePad) getCount() uint64 {
- return atomic.LoadUint64(&n.counter)
-}
-
-type countingWriter struct {
- incrFunc func()
-}
-
-func (cw *countingWriter) Write(p []byte) (n int, err error) {
- cw.incrFunc()
-
- return 0, nil
-}
-
-// Feedback is special. It writes plainly to the output while
-// logging with the standard extra information (date, file, etc)
-// Only Println and Printf are currently provided for this
-type Feedback struct{}
-
-const (
- LevelTrace Level = iota
- LevelDebug
- LevelInfo
- LevelWarn
- LevelError
- LevelCritical
- LevelFatal
- DefaultLogThreshold = LevelWarn
- DefaultStdoutThreshold = LevelError
-)
-
-var (
- TRACE *log.Logger
- DEBUG *log.Logger
- INFO *log.Logger
- WARN *log.Logger
- ERROR *log.Logger
- CRITICAL *log.Logger
- FATAL *log.Logger
- LOG *log.Logger
- FEEDBACK Feedback
- LogHandle io.Writer = ioutil.Discard
- OutHandle io.Writer = os.Stdout
- BothHandle io.Writer = io.MultiWriter(LogHandle, OutHandle)
- NotePads []*NotePad = []*NotePad{trace, debug, info, warn, err, critical, fatal}
-
- trace *NotePad = &NotePad{Level: LevelTrace, Handle: os.Stdout, Logger: &TRACE, Prefix: "TRACE: "}
- debug *NotePad = &NotePad{Level: LevelDebug, Handle: os.Stdout, Logger: &DEBUG, Prefix: "DEBUG: "}
- info *NotePad = &NotePad{Level: LevelInfo, Handle: os.Stdout, Logger: &INFO, Prefix: "INFO: "}
- warn *NotePad = &NotePad{Level: LevelWarn, Handle: os.Stdout, Logger: &WARN, Prefix: "WARN: "}
- err *NotePad = &NotePad{Level: LevelError, Handle: os.Stdout, Logger: &ERROR, Prefix: "ERROR: "}
- critical *NotePad = &NotePad{Level: LevelCritical, Handle: os.Stdout, Logger: &CRITICAL, Prefix: "CRITICAL: "}
- fatal *NotePad = &NotePad{Level: LevelFatal, Handle: os.Stdout, Logger: &FATAL, Prefix: "FATAL: "}
- logThreshold Level = DefaultLogThreshold
- outputThreshold Level = DefaultStdoutThreshold
-)
-
-const (
- DATE = log.Ldate
- TIME = log.Ltime
- SFILE = log.Lshortfile
- LFILE = log.Llongfile
- MSEC = log.Lmicroseconds
-)
-
-var logFlags = DATE | TIME | SFILE
-
-func init() {
- SetStdoutThreshold(DefaultStdoutThreshold)
-}
-
-// initialize will setup the jWalterWeatherman standard approach of providing the user
-// some feedback and logging a potentially different amount based on independent log and output thresholds.
-// By default the output has a lower threshold than logged
-// Don't use if you have manually set the Handles of the different levels as it will overwrite them.
-func initialize() {
- BothHandle = io.MultiWriter(LogHandle, OutHandle)
-
- for _, n := range NotePads {
- if n.Level < outputThreshold && n.Level < logThreshold {
- n.Handle = ioutil.Discard
- } else if n.Level >= outputThreshold && n.Level >= logThreshold {
- n.Handle = BothHandle
- } else if n.Level >= outputThreshold && n.Level < logThreshold {
- n.Handle = OutHandle
- } else {
- n.Handle = LogHandle
- }
- }
-
- for _, n := range NotePads {
- n.Handle = io.MultiWriter(n.Handle, &countingWriter{n.incr})
- *n.Logger = log.New(n.Handle, n.Prefix, logFlags)
- }
-
- LOG = log.New(LogHandle,
- "LOG: ",
- logFlags)
-}
-
-// Set the log Flags (Available flag: DATE, TIME, SFILE, LFILE and MSEC)
-func SetLogFlag(flags int) {
- logFlags = flags
- initialize()
-}
-
-// Level returns the current global log threshold.
-func LogThreshold() Level {
- return logThreshold
-}
-
-// Level returns the current global output threshold.
-func StdoutThreshold() Level {
- return outputThreshold
-}
-
-// Ensures that the level provided is within the bounds of available levels
-func levelCheck(level Level) Level {
- switch {
- case level <= LevelTrace:
- return LevelTrace
- case level >= LevelFatal:
- return LevelFatal
- default:
- return level
- }
-}
-
-// Establishes a threshold where anything matching or above will be logged
-func SetLogThreshold(level Level) {
- logThreshold = levelCheck(level)
- initialize()
-}
-
-// Establishes a threshold where anything matching or above will be output
-func SetStdoutThreshold(level Level) {
- outputThreshold = levelCheck(level)
- initialize()
-}
-
-// Conveniently Sets the Log Handle to a io.writer created for the file behind the given filepath
-// Will only append to this file
-func SetLogFile(path string) {
- file, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
- if err != nil {
- CRITICAL.Println("Failed to open log file:", path, err)
- os.Exit(-1)
- }
-
- INFO.Println("Logging to", file.Name())
-
- LogHandle = file
- initialize()
-}
-
-// Conveniently Creates a temporary file and sets the Log Handle to a io.writer created for it
-func UseTempLogFile(prefix string) {
- file, err := ioutil.TempFile(os.TempDir(), prefix)
- if err != nil {
- CRITICAL.Println(err)
- }
-
- INFO.Println("Logging to", file.Name())
-
- LogHandle = file
- initialize()
-}
-
-// LogCountForLevel returns the number of log invocations for a given level.
-func LogCountForLevel(l Level) uint64 {
- for _, np := range NotePads {
- if np.Level == l {
- return np.getCount()
- }
- }
- return 0
-}
-
-// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations
-// greater than or equal to a given level threshold.
-func LogCountForLevelsGreaterThanorEqualTo(threshold Level) uint64 {
- var cnt uint64
- for _, np := range NotePads {
- if np.Level >= threshold {
- cnt += np.getCount()
- }
- }
- return cnt
-}
-
-// ResetLogCounters resets the invocation counters for all levels.
-func ResetLogCounters() {
- for _, np := range NotePads {
- np.resetCounter()
- }
-}
-
-// Disables logging for the entire JWW system
-func DiscardLogging() {
- LogHandle = ioutil.Discard
- initialize()
-}
-
-// Feedback is special. It writes plainly to the output while
-// logging with the standard extra information (date, file, etc)
-// Only Println and Printf are currently provided for this
-func (fb *Feedback) Println(v ...interface{}) {
- s := fmt.Sprintln(v...)
- fmt.Print(s)
- LOG.Output(2, s)
-}
-
-// Feedback is special. It writes plainly to the output while
-// logging with the standard extra information (date, file, etc)
-// Only Println and Printf are currently provided for this
-func (fb *Feedback) Printf(format string, v ...interface{}) {
- s := fmt.Sprintf(format, v...)
- fmt.Print(s)
- LOG.Output(2, s)
-}