-
-
Notifications
You must be signed in to change notification settings - Fork 197
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merged internal logger from v0.6.0. (#161)
- Loading branch information
1 parent
3df3417
commit 81fc214
Showing
4 changed files
with
374 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
Logger Proxy API | ||
================ | ||
|
||
## Consts (in decreasing order of severity): | ||
* FATAL | ||
* ERROR | ||
* WARN | ||
* INFO | ||
* DEBUG | ||
* TRACE | ||
|
||
## Functions: | ||
* log.SetLogLevel(<const from above>): | ||
Log messages below this level of severity will be ignored. | ||
Default Log Level is INFO. | ||
|
||
* log.Fatal(string, vals... interface{}): | ||
prevents the program from continuing | ||
i.e. can't allocate additional memory | ||
|
||
* log.Error(string, vals... interface{}): | ||
non-fatal, but prevents valid execution | ||
i.e. can't connect to a database, complete a function call, open file, invalid format | ||
|
||
* log.Warn(string, vals... interface{}): | ||
looks unusual, but does not clearly prevent execution | ||
|
||
* log.Info(string, vals... interface{}): | ||
Least severe message that a sysadmin would be interested in | ||
i.e. server request logs | ||
|
||
* log.Debug(string, vals... interface{}): | ||
high level info for a developer. more than what a sysadmin would typically want | ||
|
||
* log.Trace(string, vals... interface{}): | ||
excruciating detail. | ||
|
||
* log.SetOutput(io.Writer): | ||
Indicates the location for log messages to be written. | ||
Default is stdout. | ||
|
||
## Flags: | ||
|
||
These package-level flags are provided to disable expensive code when the code is only needed at | ||
a lower severity than the logger is set at: | ||
IsError | ||
IsWarn | ||
IsInfo | ||
IsDebug | ||
IsTrace | ||
|
||
example usage: | ||
if log.IsDebug { | ||
... | ||
} | ||
|
||
## Output will look like: | ||
"timestamp•LOG_LEVEL•filename.go•linenumber•output" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package log | ||
|
||
import ( | ||
"io" | ||
"sync" | ||
) | ||
|
||
type Interface interface { | ||
// These all take args the same as calls to fmt.Printf() | ||
Fatal(string, ...interface{}) | ||
Error(string, ...interface{}) | ||
Warn(string, ...interface{}) | ||
Info(string, ...interface{}) | ||
Debug(string, ...interface{}) | ||
Trace(string, ...interface{}) | ||
SetOutput(io.Writer) | ||
} | ||
|
||
func init() { | ||
logger = standard | ||
SetLogLevel(INFO) | ||
} | ||
|
||
type Level int | ||
|
||
// Allows the ordering of severity to be checked | ||
const ( | ||
TRACE = Level(iota - 2) | ||
DEBUG | ||
INFO | ||
WARN | ||
ERROR | ||
FATAL | ||
) | ||
|
||
var ( | ||
logger Interface | ||
level Level | ||
lock sync.Mutex | ||
// FATAL level is never disabled | ||
IsError bool | ||
IsWarn bool | ||
IsInfo bool | ||
IsDebug bool | ||
IsTrace bool | ||
) | ||
|
||
func SetOutput(w io.Writer) { | ||
logger.SetOutput(w) | ||
} | ||
|
||
func SetLogLevel(lvl Level) { | ||
lock.Lock() | ||
IsTrace = false | ||
IsDebug = false | ||
IsInfo = false | ||
IsWarn = false | ||
IsError = false | ||
IsTrace = false | ||
if lvl != TRACE && lvl != DEBUG && lvl != INFO && lvl != WARN && lvl != ERROR && lvl != FATAL { | ||
lvl = INFO | ||
} | ||
level = lvl | ||
switch level { | ||
case TRACE: | ||
IsTrace = true | ||
fallthrough | ||
case DEBUG: | ||
IsDebug = true | ||
fallthrough | ||
case INFO: | ||
IsInfo = true | ||
fallthrough | ||
case WARN: | ||
IsWarn = true | ||
fallthrough | ||
case ERROR: | ||
IsError = true | ||
} | ||
lock.Unlock() | ||
} | ||
|
||
// Output format should be: "timestamp•LOG_LEVEL•filename.go•linenumber•output" | ||
func Fatal(format string, args ...interface{}) { | ||
logger.Fatal(format, args...) | ||
} | ||
|
||
func Error(format string, args ...interface{}) { | ||
if !IsError { | ||
return | ||
} | ||
logger.Error(format, args...) | ||
} | ||
|
||
func Warn(format string, args ...interface{}) { | ||
if !IsWarn { | ||
return | ||
} | ||
logger.Warn(format, args...) | ||
} | ||
|
||
func Info(format string, args ...interface{}) { | ||
if !IsInfo { | ||
return | ||
} | ||
logger.Info(format, args...) | ||
} | ||
|
||
func Debug(format string, args ...interface{}) { | ||
if !IsDebug { | ||
return | ||
} | ||
logger.Debug(format, args...) | ||
} | ||
|
||
func Trace(format string, args ...interface{}) { | ||
if !IsTrace { | ||
return | ||
} | ||
logger.Trace(format, args...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
package log | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"regexp" | ||
"testing" | ||
) | ||
|
||
func TestSetLevel(t *testing.T) { | ||
// Check default level is INFO & Is* flags are set appropriately | ||
if level != INFO || !IsError || !IsWarn || !IsInfo || IsDebug || IsTrace { | ||
fmt.Println("Default level is not set as expected") | ||
t.Fail() | ||
} | ||
|
||
// Check TRACE | ||
SetLogLevel(TRACE) | ||
if level != TRACE || !IsError || !IsWarn || !IsInfo || !IsDebug || !IsTrace { | ||
fmt.Println("TRACE level is not set as expected") | ||
t.Fail() | ||
} | ||
|
||
// Check DEBUG | ||
SetLogLevel(DEBUG) | ||
if level != DEBUG || !IsError || !IsWarn || !IsInfo || !IsDebug || IsTrace { | ||
fmt.Println("DEBUG level is not set as expected") | ||
t.Fail() | ||
} | ||
|
||
// Check INFO | ||
SetLogLevel(INFO) | ||
if level != INFO || !IsError || !IsWarn || !IsInfo || IsDebug || IsTrace { | ||
fmt.Println("INFO level is not set as expected") | ||
t.Fail() | ||
} | ||
|
||
// Check WARN | ||
SetLogLevel(WARN) | ||
if level != WARN || !IsError || !IsWarn || IsInfo || IsDebug || IsTrace { | ||
fmt.Println("WARN level is not set as expected") | ||
t.Fail() | ||
} | ||
|
||
// Check ERROR | ||
SetLogLevel(ERROR) | ||
if level != ERROR || !IsError || IsWarn || IsInfo || IsDebug || IsTrace { | ||
fmt.Println("ERROR level is not set as expected") | ||
t.Fail() | ||
} | ||
|
||
// Check FATAL | ||
SetLogLevel(FATAL) | ||
if level != FATAL || IsError || IsWarn || IsInfo || IsDebug || IsTrace { | ||
fmt.Println("FATAL level is not set as expected") | ||
t.Fail() | ||
} | ||
} | ||
|
||
func TestLogging(t *testing.T) { | ||
type TestCase struct { | ||
loggerLevel Level | ||
msgLevel Level | ||
msg string | ||
msgArgs []interface{} | ||
expected string // regex pattern | ||
} | ||
|
||
var testCases []TestCase = []TestCase{ | ||
// These test cases use ".*" to avoid specifics of timestamp, file location, and line number. | ||
{ | ||
loggerLevel: INFO, | ||
msgLevel: INFO, | ||
msg: "Hello", | ||
expected: ".*•INFO•.*log_test.go•.*•Hello", | ||
}, | ||
// Logging with logger's level set higher than message should result in no output. | ||
{ | ||
loggerLevel: WARN, | ||
msgLevel: INFO, | ||
msg: "Hello", | ||
expected: "", | ||
}, | ||
{ | ||
loggerLevel: TRACE, | ||
msgLevel: TRACE, | ||
msg: "Hello", | ||
expected: ".*•TRACE•.*log_test.go•.*•Hello", | ||
}, | ||
{ | ||
loggerLevel: TRACE, | ||
msgLevel: DEBUG, | ||
msg: "Hello", | ||
expected: ".*•DEBUG•.*log_test.go•.*•Hello", | ||
}, | ||
{ | ||
loggerLevel: TRACE, | ||
msgLevel: INFO, | ||
msg: "Hello", | ||
expected: ".*•INFO•.*log_test.go•.*•Hello", | ||
}, | ||
{ | ||
loggerLevel: TRACE, | ||
msgLevel: WARN, | ||
msg: "Hello", | ||
expected: ".*•WARN•.*log_test.go•.*•Hello", | ||
}, | ||
{ | ||
loggerLevel: TRACE, | ||
msgLevel: ERROR, | ||
msg: "Hello", | ||
expected: ".*•ERROR•.*log_test.go•.*•Hello", | ||
}, | ||
// Check use of formatting args. | ||
{ | ||
loggerLevel: TRACE, | ||
msgLevel: ERROR, | ||
msg: "Hello #%v %v", | ||
msgArgs: []interface{}{1, "Joe"}, | ||
expected: ".*•ERROR•.*log_test.go•.*•Hello", | ||
}, | ||
} | ||
|
||
loggerCalls := map[Level]func(string, ...interface{}){ | ||
FATAL: Fatal, | ||
ERROR: Error, | ||
WARN: Warn, | ||
INFO: Info, | ||
DEBUG: Debug, | ||
TRACE: Trace, | ||
} | ||
|
||
for i, tc := range testCases { | ||
testOut := bytes.NewBufferString("") | ||
SetOutput(testOut) | ||
SetLogLevel(tc.loggerLevel) | ||
loggerCalls[tc.msgLevel](tc.msg, tc.msgArgs...) | ||
|
||
resultMsg := testOut.String() | ||
matched, err := regexp.MatchString(tc.expected, resultMsg) | ||
if err != nil || !matched { | ||
fmt.Printf("TestCase[%v] failed, \n'%v'\ndoesn't match\n'%v'\n", i, tc.expected, resultMsg) | ||
t.Fail() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package log | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
goLog "log" | ||
"os" | ||
"runtime" | ||
) | ||
|
||
var standard Standard | ||
|
||
type Standard struct{} | ||
|
||
func (_ Standard) SetOutput(w io.Writer) { | ||
goLog.SetOutput(w) | ||
} | ||
|
||
func Output(level string, format string, args ...interface{}) { | ||
logMsg := fmt.Sprintf(format, args...) | ||
_, file, line, _ := runtime.Caller(4) | ||
// timestamp will be provided by goLog | ||
goLog.Printf("•%v•%v•%v•%v", level, file, line, logMsg) | ||
} | ||
|
||
func (_ Standard) Fatal(format string, args ...interface{}) { | ||
Output("FATAL", format, args...) | ||
os.Exit(1) | ||
} | ||
|
||
func (_ Standard) Error(format string, args ...interface{}) { | ||
Output("ERROR", format, args...) | ||
} | ||
|
||
func (_ Standard) Warn(format string, args ...interface{}) { | ||
Output("WARN", format, args...) | ||
} | ||
|
||
func (_ Standard) Info(format string, args ...interface{}) { | ||
Output("INFO", format, args...) | ||
} | ||
|
||
func (_ Standard) Debug(format string, args ...interface{}) { | ||
Output("DEBUG", format, args...) | ||
} | ||
|
||
func (_ Standard) Trace(format string, args ...interface{}) { | ||
Output("TRACE", format, args...) | ||
} |