Adding release candidate for 0.2.0

Signed-off-by: Kris Nóva <kris@nivenly.com>
rc-0.2.0
Kris Nóva 2021-02-14 00:17:49 -08:00
parent 8e2d9fdba2
commit 67063110e4
14 changed files with 699 additions and 416 deletions

2
.gitignore vendored 100644
View File

@ -0,0 +1,2 @@
.idea*
.idea/*

124
README.md
View File

@ -1,10 +1,53 @@
# logger
# Kris Nóva Logger
Ported from it's [original location](https://github.com/kubicorn/kubicorn/tree/master/pkg/logger) in the Kubicorn code base.
## History
- [2017] Originally ported from it's [original location](https://github.com/kubicorn/kubicorn/tree/master/pkg/logger) in the Kubicorn code base.
- [2021] Refactored to support custom `io.Writer`'s
<center><img src="/screenshot.png"></center>
# Rainbow logs
## Install
```bash
go get github.com/kris-nova/logger
```
## Basic Usage
```go
package main
import (
"github.com/kris-nova/logger"
"os"
)
func main() {
// Options
logger.Writer = os.Stdout // This is not needed
logger.BitwiseLevel = logger.LogCritical | logger.LogWarning // Customize your levels
logger.BitwiseLevel = logger.LogEverything // Turn everything on
logger.BitwiseLevel = logger.LogAlways // Only log Always()
logger.BitwiseLevel = logger.LogEverything // Turn everything back on
//
// Log lines
logger.Debug("Check this out %d", 123)
logger.Info("Cool!")
logger.Success("Hooray!")
logger.Always("Hello!")
logger.Critical("Oh No!")
logger.Warning("Beware...")
logger.Deprecated("Don't do this!")
//
}
```
## Rainbow logs
```go
@ -12,74 +55,21 @@ package main
import (
"github.com/kris-nova/logger"
"fmt"
"os"
lol "github.com/kris-nova/lolgopher"
)
func main(){
//
logger.Writer = lol.NewLolWriter() // Sometimes this will work better
logger.Writer = lol.NewTruecolorLolWriter() // Comment one of these out
//
logger.Fabulous = true
logger.Color = false
logger.Level = 4
err := fmt.Errorf("New error")
logger.Always("This is always printed")
logger.Success("Hooray a good thing happened!")
logger.Info("we found an error: %v", err)
logger.Debug("this is a useful message for software enigneers")
logger.Warning("something bad happened but the software can still run")
// Notice this does *NOT* exit!
logger.Critical("the software should stop running, this is bad")
// Now we have to exit
os.Exit(123)
logger.BitwiseLevel = logger.LogEverything
logger.Always("Rainbow logging")
logger.Always("Rainbow logging")
logger.Always("Rainbow logging")
logger.Always("Rainbow logging")
}
```
# Simple golang logger
```go
package main
import (
"github.com/kris-nova/logger"
"fmt"
"os"
)
func main(){
// Most Verbose
//logger.Level = 4
// Normal
// No info or debug messages, only warnings and criticals
logger.Level = 2
// Off
//logger.Level = 0
err := fmt.Errorf("New error")
logger.Info("we found an error: %v", err)
logger.Debug("this is a useful message for software enigneers")
logger.Warning("something bad happened but the software can still run")
// Notice this does *NOT* exit!
logger.Critical("the software should stop running, this is bad")
// Now we have to exit
os.Exit(123)
}
```
```

View File

@ -1,38 +0,0 @@
package main
import (
"github.com/kris-nova/logger"
"fmt"
"os"
)
func main(){
// Most Verbose
//logger.Level = 4
// Normal
// No info or debug messages, only warnings and criticals
logger.Level = 2
// Off
//logger.Level = 0
logger.Always("This is always printed")
logger.Success("Hooray a good thing happened!")
err := fmt.Errorf("New error")
logger.Info("we found an error: %v", err)
logger.Debug("this is a useful message for software enigneers")
logger.Warning("something bad happened but the software can still run")
// Notice this does *NOT* exit!
logger.Critical("the software should stop running, this is bad")
// Now we have to exit
os.Exit(123)
}

View File

@ -1,33 +0,0 @@
package main
import (
"github.com/kris-nova/logger"
"fmt"
"os"
)
func main(){
logger.Fabulous = true
logger.Color = false
logger.Level = 4
err := fmt.Errorf("New error")
logger.Always("This is always printed")
logger.Success("Hooray a good thing happened!")
logger.Info("we found an error: %v", err)
logger.Debug("this is a useful message for software enigneers")
logger.Warning("something bad happened but the software can still run")
// Notice this does *NOT* exit!
logger.Critical("the software should stop running, this is bad")
// Now we have to exit
os.Exit(123)
}

12
examples/legacy.go 100644
View File

@ -0,0 +1,12 @@
package main
import "github.com/kris-nova/novaarchive/logger"
func main() {
logger.Level = 4
logger.Always("Always logging")
logger.Info("Info logging")
logger.Debug("Debug logging")
}

View File

@ -0,0 +1,43 @@
package main
import (
"github.com/kris-nova/logger"
lol "github.com/kris-nova/lolgopher"
)
func main() {
//
logger.Writer = lol.NewLolWriter() // Sometimes this will work better
logger.Writer = lol.NewTruecolorLolWriter() // Comment one of these out
//
logger.BitwiseLevel = logger.LogEverything
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Always(".....................")
logger.Debug("Debug logging")
logger.Critical("Stderr logging")
}

18
examples/simple.go 100644
View File

@ -0,0 +1,18 @@
package main
import (
"os"
"github.com/kris-nova/novaarchive/logger"
)
func main() {
logger.BitwiseLevel = logger.LogEverything
logger.Always("Always logging")
logger.Always("Always logging")
logger.Debug("Debug logging")
logger.Writer = os.Stderr
logger.Critical("Stderr logging")
}

8
go.mod
View File

@ -1,8 +0,0 @@
module github.com/kris-nova/logger
go 1.14
require (
github.com/fatih/color v1.9.0
github.com/kris-nova/lolgopher v0.0.0-20180921204813-313b3abb0d9b
)

12
go.sum
View File

@ -1,12 +0,0 @@
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/kris-nova/lolgopher v0.0.0-20180921204813-313b3abb0d9b h1:xYEM2oBUhBEhQjrV+KJ9lEWDWYZoNVZUaBF++Wyljq4=
github.com/kris-nova/lolgopher v0.0.0-20180921204813-313b3abb0d9b/go.mod h1:V0HF/ZBlN86HqewcDC/cVxMmYDiRukWjSrgKLUAn9Js=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

291
logger.go
View File

@ -1,4 +1,4 @@
// Copyright © 2017
// Copyright © 2021 Kris Nóva <kris@nivenly.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -20,172 +20,167 @@ import (
"os"
"strings"
"time"
"github.com/fatih/color"
lol "github.com/kris-nova/lolgopher"
)
type Logger func(format string, a ...interface{})
type LoggerFunc func(format string, a ...interface{})
//type Logger interface {
// LineBytes(prefix, format string, a ...interface{}) []byte
// Line(prefix, format string, a ...interface{}) string
// Always(format string, a ...interface{})
// Success(format string, a ...interface{})
// Debug(format string, a ...interface{})
// Info(format string, a ...interface{})
// Warning(format string, a ...interface{})
// Critical(format string, a ...interface{})
//}
const (
AlwaysLabel = "✿"
CriticalLabel = "✖"
DebugLabel = "▶"
InfoLabel = ""
SuccessLabel = "✔"
WarningLabel = "!"
// [Log Constants]
//
// These are the bitwise values for the
// various log options.
//
// Also these are the string prefixes
// for the log lines.
LogAlways = 1
PreAlways = "Always "
LogSuccess = 2
PreSuccess = "Success "
LogCritical = 4
PreCritical = "Critical "
LogWarning = 8
PreWarning = "Warning "
LogInfo = 16
PreInfo = "Info "
LogDebug = 32
PreDebug = "Debug "
LogDeprecated = 64
PreDeprecated = "Deprecated"
LogLegacyLevel2 = LogAlways | LogSuccess | LogCritical | LogWarning | LogInfo
LogLegacyLevel2Deprecated = LogLegacyLevel2 | LogDeprecated
// Enable all Logging levels
// [127]
LogEverything = LogAlways | LogSuccess | LogDebug | LogInfo | LogWarning | LogCritical | LogDeprecated
)
type WriterMode int
var (
Level = 2
Color = true
Fabulous = false
FabulousWriter = lol.NewLolWriter()
FabulousTrueWriter = lol.NewTruecolorLolWriter()
TestMode = false
Timestamps = true
// BitwiseLevel is the preferred
// way of managing log levels.
//
// ----- [ Bitwise Chart ] ------
//
// LogEverything (All Levels)
// LogAlways
// LogSuccess
// LogCritical
// LogWarning
// LogInfo
// LogDebug
// LogDeprecated
//
// TODO @kris-nova In the next release flip to LogEverything
// BitwiseLevel = LogEverything
BitwiseLevel = LogLegacyLevel2Deprecated
// A custom io.Writer to use regardless of Mode
Writer io.Writer = os.Stdout
// Layout is the time layout string to use
Layout string = time.RFC3339
)
func Always(format string, a ...interface{}) {
a, w := extractLoggerArgs(format, a...)
s := fmt.Sprintf(label(format, AlwaysLabel), a...)
if !TestMode {
if Color {
w = color.Output
s = color.GreenString(s)
} else if Fabulous {
w = FabulousWriter
}
}
fmt.Fprint(w, s)
// LineBytes will format a log line, and return
// a slice of bytes []byte
func LineBytes(prefix, format string, a ...interface{}) []byte {
return []byte(Line(prefix, format, a...))
}
func Critical(format string, a ...interface{}) {
if Level >= 1 {
a, w := extractLoggerArgs(format, a...)
s := fmt.Sprintf(label(format, CriticalLabel), a...)
if !TestMode {
if Color {
w = color.Output
s = color.RedString(s)
} else if Fabulous {
w = FabulousWriter
}
}
fmt.Fprint(w, s)
// Line will format a log line, and return a string
func Line(prefix, format string, a ...interface{}) string {
if !strings.Contains(format, "\n") {
format = fmt.Sprintf("%s%s", format, "\n")
}
}
func Info(format string, a ...interface{}) {
if Level >= 3 {
a, w := extractLoggerArgs(format, a...)
s := fmt.Sprintf(label(format, InfoLabel), a...)
if !TestMode {
if Color {
w = color.Output
s = color.CyanString(s)
} else if Fabulous {
w = FabulousWriter
}
}
fmt.Fprint(w, s)
}
}
func Success(format string, a ...interface{}) {
if Level >= 3 {
a, w := extractLoggerArgs(format, a...)
s := fmt.Sprintf(label(format, SuccessLabel), a...)
if !TestMode {
if Color {
w = color.Output
s = color.CyanString(s)
} else if Fabulous {
w = FabulousWriter
}
}
fmt.Fprint(w, s)
}
}
func Debug(format string, a ...interface{}) {
if Level >= 4 {
a, w := extractLoggerArgs(format, a...)
s := fmt.Sprintf(label(format, DebugLabel), a...)
if !TestMode {
if Color {
w = color.Output
s = color.GreenString(s)
} else if Fabulous {
w = FabulousWriter
}
}
fmt.Fprint(w, s)
}
}
func Warning(format string, a ...interface{}) {
if Level >= 2 {
a, w := extractLoggerArgs(format, a...)
s := fmt.Sprintf(label(format, WarningLabel), a...)
if !TestMode {
if Color {
w = color.Output
s = color.GreenString(s)
} else if Fabulous {
w = FabulousWriter
}
}
fmt.Fprint(w, s)
}
}
func extractLoggerArgs(format string, a ...interface{}) ([]interface{}, io.Writer) {
var w io.Writer = os.Stdout
if n := len(a); n > 0 {
// extract an io.Writer at the end of a
if value, ok := a[n-1].(io.Writer); ok {
w = value
a = a[0 : n-1]
}
}
return a, w
}
func label(format, label string) string {
if Timestamps {
return labelWithTime(format, label)
now := time.Now()
fNow := now.Format(Layout)
prefix = fmt.Sprintf("%s [%s]", fNow, prefix)
} else {
return labelWithoutTime(format, label)
prefix = fmt.Sprintf("[%s]", prefix)
}
return fmt.Sprintf("%s %s", prefix, fmt.Sprintf(format, a...))
}
// Always
func Always(format string, a ...interface{}) {
d()
a = legacyFindWriter(a...)
if BitwiseLevel&LogAlways != 0 {
fmt.Fprint(Writer, Line(PreAlways, format, a...))
}
}
func labelWithTime(format, label string) string {
t := time.Now()
rfct := t.Format(time.RFC3339)
if !strings.Contains(format, "\n") {
format = fmt.Sprintf("%s%s", format, "\n")
// Success
func Success(format string, a ...interface{}) {
d()
a = legacyFindWriter(a...)
if BitwiseLevel&LogSuccess != 0 {
fmt.Fprint(Writer, Line(PreSuccess, format, a...))
}
return fmt.Sprintf("%s [%s] %s", rfct, label, format)
}
func labelWithoutTime(format, label string) string {
if !strings.Contains(format, "\n") {
format = fmt.Sprintf("%s%s", format, "\n")
// Debug
func Debug(format string, a ...interface{}) {
d()
a = legacyFindWriter(a...)
if BitwiseLevel&LogDebug != 0 {
fmt.Fprint(Writer, Line(PreDebug, format, a...))
}
return fmt.Sprintf("[%s] %s", label, format)
}
// Info
func Info(format string, a ...interface{}) {
d()
a = legacyFindWriter(a...)
if BitwiseLevel&LogInfo != 0 {
fmt.Fprint(Writer, Line(PreInfo, format, a...))
}
}
// Warning
func Warning(format string, a ...interface{}) {
d()
a = legacyFindWriter(a...)
if BitwiseLevel&LogWarning != 0 {
fmt.Fprint(Writer, Line(PreWarning, format, a...))
}
}
// Critical
func Critical(format string, a ...interface{}) {
d()
a = legacyFindWriter(a...)
if BitwiseLevel&LogCritical != 0 {
fmt.Fprint(Writer, Line(PreCritical, format, a...))
}
}
// Used to show deprecated log lines
func Deprecated(format string, a ...interface{}) {
a = legacyFindWriter(a...)
if BitwiseLevel&LogDeprecated != 0 {
fmt.Fprint(Writer, Line(PreDeprecated, format, a...))
}
}
// d is used by every function
// and is an easy way to add
// global logic/state to the logger
func d() {
checkDeprecatedValues()
}

108
logger_legacy.go 100644
View File

@ -0,0 +1,108 @@
// Copyright © 2021 Kris Nóva <kris@nivenly.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package logger
import (
"io"
"sync"
)
// Legacy Logic for 0.1.0
//
// Here we store the legacy (0.1.0) compatible configuration options
// that will eventually be deprecated.
//
var (
// Timestamps are used to toggle timestamps
// deprecated
Timestamps = true
// TestMode is used for running
// the regression tests.
// deprecated
TestMode = false
// Color is no longer used
// deprecated
Color = true
// Level is the legacy log level
//
// 0 (Least verbose)
// 1
// 2
// 3
// 4 (Most verbose)
//
// deprecated
Level = -1
)
var (
testRaceMutex = sync.Mutex{}
annoyed = false
)
// checkDeprecatedValues is a singleton
// that will only execute once.
// This will convert the legacy logger.Level
// to the new logger.BitwiseLevel
//
// LogEverything =
func checkDeprecatedValues() {
testRaceMutex.Lock()
defer testRaceMutex.Unlock()
if Level != -1 {
if !annoyed {
Deprecated("********")
Deprecated("***")
Deprecated("*")
Deprecated("logger.Level is deprecated. Use logger.BitwiseLevel")
Deprecated("*")
Deprecated("***")
Deprecated("********")
annoyed = true
}
if Level == 4 {
BitwiseLevel = LogDeprecated | LogAlways | LogSuccess | LogCritical | LogWarning | LogInfo | LogDebug
} else if Level == 3 {
BitwiseLevel = LogDeprecated | LogAlways | LogSuccess | LogCritical | LogWarning | LogInfo
} else if Level == 2 {
BitwiseLevel = LogDeprecated | LogAlways | LogSuccess | LogCritical | LogWarning
} else if Level == 1 {
BitwiseLevel = LogDeprecated | LogAlways | LogSuccess | LogCritical
} else if Level == 0 {
BitwiseLevel = LogDeprecated | LogAlways | LogSuccess
} else {
BitwiseLevel = LogDeprecated | LogEverything
}
}
}
// legacyFindWriter will check if there is an io.Writer
// appended to the end of the arguments passed to the logger.
//
// deprecated
func legacyFindWriter(a ...interface{}) []interface{} {
if n := len(a); n > 0 {
// extract an io.Writer at the end of a
if newWriter, ok := a[n-1].(io.Writer); ok {
Writer = newWriter
a = a[0 : n-1]
}
}
return a
}

View File

@ -0,0 +1,158 @@
// Copyright © 2021 Kris Nóva <kris@nivenly.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ----------------------------------------------------------------------------
//
// Legacy Regression tests for 0.1.0
//
// Note: @christopherhein added these tests and I am unsure if Amazon
// is still using the old io.Writer append() convention.
// Either way, I am keeping legacy (deprecated) support for it.
//
// All of these regression tests should still pass.
//
// ----------------------------------------------------------------------------
package logger
import (
"bytes"
"fmt"
"regexp"
"testing"
)
const (
format = "%v, %v, %v, all eyes on me!"
formatExp = `^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.* \[%s\] \d, \d, \d, all eyes on me!`
formatWOTimeExp = `\[%s\] \d, \d, \d, all eyes on me!`
)
var (
a = []interface{}{1, 2, 3}
)
func TestMain(m *testing.M) {
TestMode = true
m.Run()
}
func TestAlwaysLegacy(t *testing.T) {
e, err := regexp.Compile(fmt.Sprintf(formatExp, PreAlways))
g := captureLoggerOutput(Always, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Always should produce a pattern '%v' but produces: %v", e.String(), g)
}
}
func TestCriticalLegacy(t *testing.T) {
Level = 1
e, err := regexp.Compile(fmt.Sprintf(formatExp, PreCritical))
g := captureLoggerOutput(Critical, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Critical should produce a pattern '%v' but produces: %v", e.String(), g)
}
}
func TestInfoLegacy(t *testing.T) {
Level = 3
e, err := regexp.Compile(fmt.Sprintf(formatExp, PreInfo))
g := captureLoggerOutput(Info, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Info should produce a pattern '%v' but produces: %v", e.String(), g)
}
}
func TestSuccessLegacy(t *testing.T) {
Level = 3
e, err := regexp.Compile(fmt.Sprintf(formatExp, PreSuccess))
g := captureLoggerOutput(Success, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Success should produce a pattern '%v' but produces: %v", e.String(), g)
}
}
func TestDebugLegacy(t *testing.T) {
Level = 4
e, err := regexp.Compile(fmt.Sprintf(formatExp, PreDebug))
g := captureLoggerOutput(Debug, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Info should produce a pattern '%v' but produces: %v", e.String(), g)
}
}
func TestWarningLegacy(t *testing.T) {
Level = 2
e, err := regexp.Compile(fmt.Sprintf(formatExp, PreWarning))
g := captureLoggerOutput(Warning, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Info should produce a pattern '%v' but produces: %v", e.String(), g)
}
}
func TestWithoutTimestampsLegacy(t *testing.T) {
Timestamps = false
e, err := regexp.Compile(fmt.Sprintf(formatWOTimeExp, PreAlways))
g := captureLoggerOutput(Always, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Always should produce a pattern '%v' but produces: %v", e.String(), g)
}
}
// captureLoggerOutput is used to test the log functions
func captureLoggerOutput(l LoggerFunc, format string, a []interface{}) string {
b := new(bytes.Buffer)
l(format, append(a, b)...)
return b.String()
}

View File

@ -1,146 +1,194 @@
// Copyright © 2017 The Kubicorn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package logger
import (
"bytes"
"fmt"
"regexp"
"testing"
)
const (
format = "%v, %v, %v, all eyes on me!"
formatExp = `^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.* \[%s\] \d, \d, \d, all eyes on me!`
formatWOTimeExp = `\[%s\] \d, \d, \d, all eyes on me!`
TestFormat = "%s %s %s money, success, fame glamour"
)
var (
a = []interface{}{1, 2, 3}
testA = []interface{}{"1", "2", "3"}
)
func TestMain(m *testing.M) {
TestMode = true
m.Run()
}
func TestAlways(t *testing.T) {
e, err := regexp.Compile(fmt.Sprintf(formatExp, AlwaysLabel))
g := captureLoggerOutput(Always, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Always should produce a pattern '%v' but produces: %v", e.String(), g)
func TestAlwaysOnly(t *testing.T) {
Level = -1
BitwiseLevel = LogAlways
buffer := new(bytes.Buffer)
Writer = buffer
expected := Line(PreAlways, TestFormat, testA...)
Deprecated(TestFormat, testA...)
Debug(TestFormat, testA...)
Info(TestFormat, testA...)
Warning(TestFormat, testA...)
Critical(TestFormat, testA...)
Success(TestFormat, testA...)
Always(TestFormat, testA...)
actual := buffer.String()
if expected != actual {
t.Errorf("Expected (%s) Actual (%s)", expected, actual)
}
}
func TestCritical(t *testing.T) {
Level = 1
e, err := regexp.Compile(fmt.Sprintf(formatExp, CriticalLabel))
g := captureLoggerOutput(Critical, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Critical should produce a pattern '%v' but produces: %v", e.String(), g)
func TestSuccessOnly(t *testing.T) {
Level = -1
BitwiseLevel = LogSuccess
buffer := new(bytes.Buffer)
Writer = buffer
expected := Line(PreSuccess, TestFormat, testA...)
Deprecated(TestFormat, testA...)
Debug(TestFormat, testA...)
Info(TestFormat, testA...)
Warning(TestFormat, testA...)
Critical(TestFormat, testA...)
Success(TestFormat, testA...)
Always(TestFormat, testA...)
actual := buffer.String()
if expected != actual {
t.Errorf("Expected (%s) Actual (%s)", expected, actual)
}
}
func TestInfo(t *testing.T) {
Level = 3
e, err := regexp.Compile(fmt.Sprintf(formatExp, InfoLabel))
g := captureLoggerOutput(Info, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Info should produce a pattern '%v' but produces: %v", e.String(), g)
func TestDebugOnly(t *testing.T) {
Level = -1
BitwiseLevel = LogDebug
buffer := new(bytes.Buffer)
Writer = buffer
expected := Line(PreDebug, TestFormat, testA...)
Deprecated(TestFormat, testA...)
Debug(TestFormat, testA...)
Info(TestFormat, testA...)
Warning(TestFormat, testA...)
Critical(TestFormat, testA...)
Success(TestFormat, testA...)
Always(TestFormat, testA...)
actual := buffer.String()
if expected != actual {
t.Errorf("Expected (%s) Actual (%s)", expected, actual)
}
}
func TestSuccess(t *testing.T) {
Level = 3
e, err := regexp.Compile(fmt.Sprintf(formatExp, SuccessLabel))
g := captureLoggerOutput(Success, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Success should produce a pattern '%v' but produces: %v", e.String(), g)
func TestInfoOnly(t *testing.T) {
Level = -1
BitwiseLevel = LogInfo
buffer := new(bytes.Buffer)
Writer = buffer
expected := Line(PreInfo, TestFormat, testA...)
Deprecated(TestFormat, testA...)
Debug(TestFormat, testA...)
Info(TestFormat, testA...)
Warning(TestFormat, testA...)
Critical(TestFormat, testA...)
Success(TestFormat, testA...)
Always(TestFormat, testA...)
actual := buffer.String()
if expected != actual {
t.Errorf("Expected (%s) Actual (%s)", expected, actual)
}
}
func TestDebug(t *testing.T) {
Level = 4
e, err := regexp.Compile(fmt.Sprintf(formatExp, DebugLabel))
g := captureLoggerOutput(Debug, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Info should produce a pattern '%v' but produces: %v", e.String(), g)
func TestWarningOnly(t *testing.T) {
Level = -1
BitwiseLevel = LogWarning
buffer := new(bytes.Buffer)
Writer = buffer
expected := Line(PreWarning, TestFormat, testA...)
Deprecated(TestFormat, testA...)
Debug(TestFormat, testA...)
Info(TestFormat, testA...)
Warning(TestFormat, testA...)
Critical(TestFormat, testA...)
Success(TestFormat, testA...)
Always(TestFormat, testA...)
actual := buffer.String()
if expected != actual {
t.Errorf("Expected (%s) Actual (%s)", expected, actual)
}
}
func TestWarning(t *testing.T) {
Level = 2
e, err := regexp.Compile(fmt.Sprintf(formatExp, WarningLabel))
g := captureLoggerOutput(Warning, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Info should produce a pattern '%v' but produces: %v", e.String(), g)
func TestCriticalOnly(t *testing.T) {
Level = -1
BitwiseLevel = LogCritical
buffer := new(bytes.Buffer)
Writer = buffer
expected := Line(PreCritical, TestFormat, testA...)
Deprecated(TestFormat, testA...)
Debug(TestFormat, testA...)
Info(TestFormat, testA...)
Warning(TestFormat, testA...)
Critical(TestFormat, testA...)
Success(TestFormat, testA...)
Always(TestFormat, testA...)
actual := buffer.String()
if expected != actual {
t.Errorf("Expected (%s) Actual (%s)", expected, actual)
}
}
func TestWithoutTimestamps(t *testing.T) {
Timestamps = false
e, err := regexp.Compile(fmt.Sprintf(formatWOTimeExp, AlwaysLabel))
g := captureLoggerOutput(Always, format, a)
if err != nil {
t.Fatalf("Failed to compile regexp '%v': %v", e.String(), err)
}
if !e.MatchString(g) {
t.Fatalf("Always should produce a pattern '%v' but produces: %v", e.String(), g)
func TestDeprecatedOnly(t *testing.T) {
Level = -1
BitwiseLevel = LogDeprecated
buffer := new(bytes.Buffer)
Writer = buffer
expected := Line(PreDeprecated, TestFormat, testA...)
Deprecated(TestFormat, testA...)
Debug(TestFormat, testA...)
Info(TestFormat, testA...)
Warning(TestFormat, testA...)
Critical(TestFormat, testA...)
Success(TestFormat, testA...)
Always(TestFormat, testA...)
actual := buffer.String()
if expected != actual {
t.Errorf("Expected (%s) Actual (%s)", expected, actual)
}
}
func captureLoggerOutput(l Logger, format string, a []interface{}) string {
b := new(bytes.Buffer)
l(format, append(a, b)...)
return b.String()
func TestEverything(t *testing.T) {
Level = -1
BitwiseLevel = LogEverything
buffer := new(bytes.Buffer)
Writer = buffer
cases := []string{PreDeprecated, PreDebug, PreInfo, PreWarning, PreCritical, PreSuccess, PreAlways}
expected := ""
for _, c := range cases {
expected = fmt.Sprintf("%s%s", expected, Line(c, TestFormat, testA...))
}
Deprecated(TestFormat, testA...)
Debug(TestFormat, testA...)
Info(TestFormat, testA...)
Warning(TestFormat, testA...)
Critical(TestFormat, testA...)
Success(TestFormat, testA...)
Always(TestFormat, testA...)
actual := buffer.String()
if expected != actual {
t.Errorf("Expected (%s) Actual (%s)", expected, actual)
}
}
func TestAlwaysCriticalDebugOnly(t *testing.T) {
Level = -1
BitwiseLevel = LogAlways | LogCritical | LogDebug
buffer := new(bytes.Buffer)
Writer = buffer
cases := []string{PreDebug, PreCritical, PreAlways}
expected := ""
for _, c := range cases {
expected = fmt.Sprintf("%s%s", expected, Line(c, TestFormat, testA...))
}
Deprecated(TestFormat, testA...)
Debug(TestFormat, testA...)
Info(TestFormat, testA...)
Warning(TestFormat, testA...)
Critical(TestFormat, testA...)
Success(TestFormat, testA...)
Always(TestFormat, testA...)
actual := buffer.String()
if expected != actual {
t.Errorf("Expected (%s) Actual (%s)", expected, actual)
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 865 KiB