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...)