First pretty stable release
diff --git a/README.md b/README.md
index 7bfe15c..15a378d 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,125 @@
jWalterWeatherman
=================
-a simple feedback and logging library for go
+A simple printing and logging library for go
+
+
+Graphic by [JonnyEtc](http://jonnyetc.deviantart.com/art/And-That-s-Why-You-Always-Leave-a-Note-315311422)
+
+JWW is primarily a convenience wrapper around the
+excellent standard log library.
+
+I really wanted a very straightforward library that could seamlessly do
+the following things.
+
+1. Replace all the println, printf, etc statements thought my code with
+ something more useful
+2. Allow the user to easily control what levels are printed
+3. Allow the user to easily control what levels are logged
+4. Provide good feedback (which can easily be logged) to the user
+5. Due to 2 & 3 provide easy verbose mode for output and logs
+6. Not have any unnecessary initialization cruft. Just use it.
+
+# Usage
+
+## Step 1. Use it
+Put calls throughout your source based on type of feedback.
+
+Available Loggers are:
+
+ * TRACE
+ * DEBUG
+ * INFO
+ * WARN
+ * ERROR
+ * CRITICAL
+ * FATAL
+
+These each are loggers based on the log standard library and follow the
+standard usage. Eg..
+
+```go
+ import (
+ jww "github.com/spf13/jwalterweatherman"
+ )
+
+ ...
+
+ if err != nil {
+ jww.ERROR.Println(err)
+ }
+
+ // this isn’t that important, but they may want to know
+ jww.INFO.Printf("information %q", response)
+
+```
+
+
+## Step 2. Optionally configure it
+
+By default:
+ * Debug, Trace & Info goto /dev/null
+ * Warn and above is logged (when a log file/io.Writer is provided)
+ * Error and above is printed to the terminal (stdout)
+
+
+### Changing the thresholds
+
+The threshold can be changed at any time, but will only affect calls that
+execute after the change was made.
+
+This is very useful if your application has a verbose mode. Of course you
+can decide what verbose means to you or even have multiple levels of
+verbosity.
+
+
+```go
+ import (
+ jww "github.com/spf13/jwalterweatherman"
+ )
+
+ if Verbose {
+ jww.SetLogThreshold(jww.LevelTrace)
+ jww.SetOutputThreshold(jww.LevelInfo)
+ }
+```
+
+### 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.
+
+```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.
+
+
+```go
+ import (
+ jww "github.com/spf13/jwalterweatherman"
+ )
+
+ jww.SetLogFile("/path/to/logfile")
+
+```
+
+
+# More information
+
+This is an early release. I’ve been using it for a while and this is the
+third interface I’ve tried. I like this one pretty well, but no guarantees
+that it won’t change a bit.
+
+I wrote this for use in [hugo](http://hugo.spf13.com). If you are looking
+for a static website engine that’s super fast please checkout Hugo.
diff --git a/jww_test.go b/jww_test.go
index 4b122d5..91c6b9b 100644
--- a/jww_test.go
+++ b/jww_test.go
@@ -12,13 +12,13 @@
)
func TestLevels(t *testing.T) {
- SetOutLevel(LevelError)
- assert.Equal(t, OutLevel(), LevelError)
- SetLogLevel(LevelCritical)
- assert.Equal(t, LogLevel(), LevelCritical)
- assert.NotEqual(t, OutLevel(), LevelCritical)
- SetOutLevel(LevelWarn)
- assert.Equal(t, OutLevel(), LevelWarn)
+ SetOutputThreshold(LevelError)
+ assert.Equal(t, OutputThreshold(), LevelError)
+ SetLogThreshold(LevelCritical)
+ assert.Equal(t, LogThreshold(), LevelCritical)
+ assert.NotEqual(t, OutputThreshold(), LevelCritical)
+ SetOutputThreshold(LevelWarn)
+ assert.Equal(t, OutputThreshold(), LevelWarn)
}
func TestDefaultLogging(t *testing.T) {
@@ -27,23 +27,30 @@
LogHandle = logBuf
OutHandle = outputBuf
- SetOutLevel(LevelInfo)
- SetLogLevel(LevelWarn)
+ SetLogThreshold(LevelWarn)
+ SetOutputThreshold(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(), "information")
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.Contains(t, outputBuf.String(), "information")
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")
}
diff --git a/thatswhyyoualwaysleaveanote.go b/thatswhyyoualwaysleaveanote.go
index 2470578..9a2e2f1 100644
--- a/thatswhyyoualwaysleaveanote.go
+++ b/thatswhyyoualwaysleaveanote.go
@@ -17,109 +17,124 @@
// debug and critical.
type Level int
-//TRACE
-//DEBUG
-//INFO
-//WARN
-//ERROR
-//CRITICAL
-//FATAL
-
-type JWWLevel struct {
+type NotePad struct {
Handle io.Writer
- Level int
- *log.Logger
+ Level Level
+ Prefix string
+ Logger **log.Logger
}
+// 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{}
-// Log levels to control the logging output.
const (
- LevelDebug Level = iota
- LevelWarn
+ LevelTrace Level = iota
+ LevelDebug
LevelInfo
+ LevelWarn
LevelError
LevelCritical
+ LevelFatal
+ DefaultLogThreshold = LevelWarn
+ DefaultOutputThreshold = LevelError
)
var (
- DEBUG *log.Logger
- WARN *log.Logger
- INFO *log.Logger
- LOG *log.Logger
- ERROR *log.Logger
- CRITICAL *log.Logger
- FEEDBACK Feedback
- DebugHandle io.Writer = os.Stdout
- WarnHandle io.Writer = os.Stdout
- InfoHandle io.Writer = os.Stdout
- ErrorHandle io.Writer = os.Stdout
- CriticalHandle io.Writer = os.Stdout
- logLevel Level = LevelWarn // 1
- outLevel Level = LevelInfo // 2
- LogHandle io.Writer = ioutil.Discard
- OutHandle io.Writer = os.Stdout
- BothHandle io.Writer = io.MultiWriter(LogHandle, OutHandle)
+ 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 = DefaultOutputThreshold
)
func init() {
- SetOutLevel(LevelInfo)
+ SetOutputThreshold(DefaultOutputThreshold)
}
+// 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() {
- initWriters()
+ BothHandle = io.MultiWriter(LogHandle, OutHandle)
- DEBUG = log.New(DebugHandle,
- "DEBUG: ",
- log.Ldate|log.Ltime|log.Lshortfile)
+ 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
+ }
+ }
- INFO = log.New(InfoHandle,
- "INFO: ",
- log.Ldate|log.Ltime|log.Lshortfile)
+ for _, n := range NotePads {
+ *n.Logger = log.New(n.Handle, n.Prefix, log.Ldate)
+ }
LOG = log.New(LogHandle,
"LOG: ",
log.Ldate|log.Ltime|log.Lshortfile)
-
- WARN = log.New(WarnHandle,
- "WARN: ",
- log.Ldate|log.Ltime|log.Lshortfile)
-
- ERROR = log.New(ErrorHandle,
- "ERROR: ",
- log.Ldate|log.Ltime|log.Lshortfile)
-
- CRITICAL = log.New(CriticalHandle,
- "CRITICAL: ",
- log.Ldate|log.Ltime|log.Lshortfile)
}
-// Level returns the current log level.
-func LogLevel() Level {
- return logLevel
+// Level returns the current global log threshold.
+func LogThreshold() Level {
+ return logThreshold
}
-func OutLevel() Level {
- return outLevel
+// Level returns the current global output threshold.
+func OutputThreshold() Level {
+ return outputThreshold
}
+// Ensures that the level provided is within the bounds of available levels
func levelCheck(level Level) Level {
switch {
- case level <= LevelDebug:
- return LevelDebug
- case level >= LevelCritical:
- return LevelCritical
+ case level <= LevelTrace:
+ return LevelTrace
+ case level >= LevelFatal:
+ return LevelFatal
default:
return level
}
}
-// SetLevel switches to a new log level.
-func SetLogLevel(level Level) {
- logLevel = levelCheck(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 SetOutputThreshold(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)
fmt.Println("Logging to", file.Name())
@@ -132,6 +147,7 @@
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 {
@@ -144,80 +160,23 @@
Initialize()
}
+// Disables logging for the entire JWW system
func DiscardLogging() {
LogHandle = ioutil.Discard
Initialize()
}
-func SetOutLevel(level Level) {
- outLevel = levelCheck(level) // 1
- Initialize()
-}
-
-// Don't use if you have manually set the Handles of the different levels as it will overwrite them.
-func initWriters() {
- BothHandle = io.MultiWriter(LogHandle, OutHandle)
- //DEBUG
- if LevelDebug < outLevel && LevelDebug < logLevel {
- DebugHandle = ioutil.Discard
- } else if LevelDebug >= outLevel && LevelDebug >= logLevel {
- DebugHandle = BothHandle
- } else if LevelDebug >= outLevel && LevelDebug < logLevel {
- DebugHandle = OutHandle
- } else {
- DebugHandle = LogHandle
- }
-
- //WARN
- if LevelWarn < outLevel && LevelWarn < logLevel {
- WarnHandle = ioutil.Discard
- } else if LevelWarn >= outLevel && LevelWarn >= logLevel {
- WarnHandle = BothHandle
- } else if LevelWarn >= outLevel && LevelWarn < logLevel {
- WarnHandle = OutHandle
- } else {
- WarnHandle = LogHandle
- }
-
- //INFO
- if LevelInfo < outLevel && LevelInfo < logLevel {
- InfoHandle = ioutil.Discard
- } else if LevelInfo >= outLevel && LevelInfo >= logLevel {
- InfoHandle = BothHandle
- } else if LevelInfo >= outLevel && LevelInfo < logLevel {
- InfoHandle = OutHandle
- } else {
- InfoHandle = LogHandle
- }
-
- //ERROR
- if LevelError < outLevel && LevelError < logLevel {
- ErrorHandle = ioutil.Discard
- } else if LevelError >= outLevel && LevelError >= logLevel {
- ErrorHandle = BothHandle
- } else if LevelError >= outLevel && LevelError < logLevel {
- ErrorHandle = OutHandle
- } else {
- ErrorHandle = LogHandle
- }
-
- //CRITICAL
- if LevelCritical < outLevel && LevelCritical < logLevel {
- CriticalHandle = ioutil.Discard
- } else if LevelCritical >= outLevel && LevelCritical >= logLevel {
- CriticalHandle = BothHandle
- } else if LevelCritical >= outLevel && LevelCritical < logLevel {
- CriticalHandle = OutHandle
- } else {
- CriticalHandle = LogHandle
- }
-}
-
+// 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{}) {
fmt.Println(v...)
LOG.Println(v...)
}
+// 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{}) {
fmt.Printf(format, v...)
LOG.Printf(format, v...)