Skip to content

Commit

Permalink
Remove init register pattern (#11)
Browse files Browse the repository at this point in the history
* Remove init register pattern

* codecov: rename config file
  • Loading branch information
unknwon authored Nov 10, 2019
1 parent f7f4c3a commit e927c36
Show file tree
Hide file tree
Showing 15 changed files with 347 additions and 344 deletions.
49 changes: 25 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
)

func init() {
err := log.New(log.ModeConsole)
err := log.NewConsole()
if err != nil {
panic("unable to create new logger: " + err.Error())
}
Expand All @@ -48,7 +48,7 @@ The code inside `init` function is equivalent to the following:

```go
func init() {
err := log.New(log.ModeConsole, 0, log.ConsoleConfig{
err := log.NewConsole(0, log.ConsoleConfig{
Level: log.LevelTrace,
})
if err != nil {
Expand All @@ -67,7 +67,7 @@ In production, you may want to make log less verbose and be asynchronous:
func init() {
// The buffer size mainly depends on number of logs could be produced at the same time,
// 100 is a good default.
err := log.New(log.ModeConsole, 100, log.ConsoleConfig{
err := log.NewConsole(100, log.ConsoleConfig{
Level: log.LevelInfo,
})
if err != nil {
Expand All @@ -79,19 +79,19 @@ func init() {
- When you set level to be `LevelInfo`, calls to the `log.Trace` will be simply noop.
- The console logger comes with color output, but for non-colorable destination, the color output will be disabled automatically.

Other builtin loggers are file (`log.ModeFile`), Slack (`log.ModeSlack`) and Discord (`log.ModeDiscord`), see later sections in the documentation for usage details.
Other builtin loggers are file (`log.NewFile`), Slack (`log.NewSlack`) and Discord (`log.NewDiscord`), see later sections in the documentation for usage details.

### Multiple Loggers

You can have multiple loggers in different modes across levels.

```go
func init() {
err := log.New(log.ModeConsole)
err := log.NewConsole()
if err != nil {
panic("unable to create new logger: " + err.Error())
}
err := log.New(log.ModeFile, log.FileConfig{
err := log.NewFile(log.FileConfig{
Level: log.LevelInfo,
Filename: "clog.log",
})
Expand Down Expand Up @@ -131,7 +131,7 @@ File logger is the single most powerful builtin logger, it has the ability to ro

```go
func init() {
err := log.New(log.ModeFile, 100, log.FileConfig{
err := log.NewFile(100, log.FileConfig{
Level: log.LevelInfo,
Filename: "clog.log",
FileRotationConfig: log.FileRotationConfig {
Expand Down Expand Up @@ -165,7 +165,7 @@ Slack logger is also supported in a simple way:

```go
func init() {
err := log.New(log.ModeSlack, 100, log.SlackConfig{
err := log.NewSlack(100, log.SlackConfig{
Level: log.LevelInfo,
URL: "https://url-to-slack-webhook",
})
Expand All @@ -183,7 +183,7 @@ Discord logger is supported in rich format via [Embed Object](https://discordapp

```go
func init() {
err := log.New(log.ModeDiscord, 100, log.DiscordConfig{
err := log.NewDiscord(100, log.DiscordConfig{
Level: log.LevelInfo,
URL: "https://url-to-discord-webhook",
})
Expand All @@ -204,44 +204,45 @@ Here is an example which sends all logs to a channel, we call it `chanLogger` he
```go
import log "unknwon.dev/clog/v2"

const modeChannel log.Mode = "channel"

type chanConfig struct {
c chan string
}

var _ log.Logger = (*chanLogger)(nil)

type chanLogger struct {
name string
level log.Level
c chan string
}

func (*chanLogger) Mode() log.Mode { return modeChannel }
func (l *chanLogger) Name() string { return l.name }
func (l *chanLogger) Level() log.Level { return l.level }

func (l *chanLogger) Write(m Messager) error {
func (l *chanLogger) Write(m log.Messager) error {
l.c <- m.String()
return nil
}

func init() {
log.NewRegister(modeChannel, func(v interface{}) (log.Logger, error) {
if v == nil {
v = chanConfig{}
}

cfg, ok := v.(chanConfig)
if !ok {
return nil, fmt.Errorf("invalid config object: want %T got %T", chanConfig{}, v)
func main() {
log.New("channel", func(name string, vs ...interface{}) (log.Logger, error) {
var cfg *chanLogger
for i := range vs {
switch v := vs[i].(type) {
case chanLogger:
cfg = &v
}
}

if cfg.c == nil {
if cfg == nil {
return nil, fmt.Errorf("config object with the type '%T' not found", chanLogger{})
} else if cfg.c == nil {
return nil, errors.New("channel is nil")
}

return &chanLogger{
c: cfg.c,
name: name,
c: cfg.c,
}, nil
})
}
Expand Down
3 changes: 0 additions & 3 deletions clog.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import (
"os"
)

// Mode is the output source.
type Mode string

// Level is the logging level.
type Level int

Expand Down
83 changes: 40 additions & 43 deletions clog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,37 +37,47 @@ func (l *chanLogger) Write(m Messager) error {
}

func Test_chanLogger(t *testing.T) {
mode1 := Mode("mode1")
level1 := LevelTrace
NewRegister(mode1, func(v interface{}) (Logger, error) {
cfg, ok := v.(chanConfig)
if !ok {
return nil, fmt.Errorf("invalid config object: want %T got %T", chanConfig{}, v)
}
return &chanLogger{
c: cfg.c,
noopLogger: &noopLogger{
mode: mode1,
level: level1,
},
}, nil
})

mode2 := Mode("mode2")
level2 := LevelError
NewRegister(mode2, func(v interface{}) (Logger, error) {
cfg, ok := v.(chanConfig)
if !ok {
return nil, fmt.Errorf("invalid config object: want %T got %T", &chanConfig{}, v)
initer := func(name string, level Level) Initer {
return func(_ string, vs ...interface{}) (Logger, error) {
var cfg *chanConfig
for i := range vs {
switch v := vs[i].(type) {
case chanConfig:
cfg = &v
}
}

if cfg == nil {
return nil, fmt.Errorf("config object with the type '%T' not found", chanConfig{})
}

return &chanLogger{
c: cfg.c,
noopLogger: &noopLogger{
name: name,
level: level,
},
}, nil
}
return &chanLogger{
c: cfg.c,
noopLogger: &noopLogger{
mode: mode2,
level: level2,
},
}, nil
})
}

test1 := "mode1"
test1Initer := initer(test1, LevelTrace)

test2 := "mode2"
test2Initer := initer(test2, LevelError)

c1 := make(chan string)
c2 := make(chan string)

defer Remove(test1)
defer Remove(test2)
assert.Nil(t, New(test1, test1Initer, 1, chanConfig{
c: c1,
}))
assert.Nil(t, New(test2, test2Initer, 1, chanConfig{
c: c2,
}))

tests := []struct {
name string
Expand Down Expand Up @@ -106,19 +116,6 @@ func Test_chanLogger(t *testing.T) {
containsStr2: "()] log message",
},
}

c1 := make(chan string)
c2 := make(chan string)

defer Remove(mode1)
defer Remove(mode2)
assert.Nil(t, New(mode1, 1, chanConfig{
c: c1,
}))
assert.Nil(t, New(mode2, 1, chanConfig{
c: c2,
}))

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, 2, mgr.len())
Expand Down
File renamed without changes.
54 changes: 32 additions & 22 deletions console.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
package clog

import (
"fmt"
"log"

"github.com/fatih/color"
)

// ModeConsole is used to indicate console logger.
const ModeConsole Mode = "console"

// Console color set for different levels.
// consoleColors is the color set for different levels.
var consoleColors = []func(a ...interface{}) string{
color.New(color.FgBlue).SprintFunc(), // Trace
color.New(color.FgGreen).SprintFunc(), // Info
Expand All @@ -28,37 +24,51 @@ type ConsoleConfig struct {
var _ Logger = (*consoleLogger)(nil)

type consoleLogger struct {
level Level
*noopLogger
*log.Logger
}

func (*consoleLogger) Mode() Mode {
return ModeConsole
func (l *consoleLogger) Write(m Messager) error {
l.Print(consoleColors[m.Level()](m.String()))
return nil
}

func (l *consoleLogger) Level() Level {
return l.level
// DefaultConsoleName is the default name for the console logger.
const DefaultConsoleName = "console"

// NewConsole initializes and appends a new console logger with default name
// to the managed list.
func NewConsole(vs ...interface{}) error {
return NewConsoleWithName(DefaultConsoleName, vs...)
}

func (l *consoleLogger) Write(m Messager) error {
l.Print(consoleColors[m.Level()](m.String()))
return nil
// NewConsoleWithName initializes and appends a new console logger with given
// name to the managed list.
func NewConsoleWithName(name string, vs ...interface{}) error {
return New(name, ConsoleIniter(), vs...)
}

func init() {
NewRegister(ModeConsole, func(v interface{}) (Logger, error) {
if v == nil {
v = ConsoleConfig{}
// ConsoleIniter returns the initer for the console logger.
func ConsoleIniter() Initer {
return func(name string, vs ...interface{}) (Logger, error) {
var cfg *ConsoleConfig
for i := range vs {
switch v := vs[i].(type) {
case ConsoleConfig:
cfg = &v
}
}

cfg, ok := v.(ConsoleConfig)
if !ok {
return nil, fmt.Errorf("invalid config object: want %T got %T", ConsoleConfig{}, v)
if cfg == nil {
cfg = &ConsoleConfig{}
}

return &consoleLogger{
level: cfg.Level,
noopLogger: &noopLogger{
name: name,
level: cfg.Level,
},
Logger: log.New(color.Output, "", log.Ldate|log.Ltime),
}, nil
})
}
}
24 changes: 15 additions & 9 deletions console_test.go
Original file line number Diff line number Diff line change
@@ -1,45 +1,51 @@
package clog

import (
"errors"
"testing"

"github.com/stretchr/testify/assert"
)

func Test_ModeConsole(t *testing.T) {
defer Remove(ModeConsole)
func Test_consoleLogger(t *testing.T) {
testName := "Test_consoleLogger"
defer Remove(DefaultConsoleName)
defer Remove(testName)

tests := []struct {
name string
mode string
config interface{}
wantLevel Level
wantErr error
}{
{
name: "nil config",
mode: DefaultConsoleName,
wantErr: nil,
},
{
name: "valid config",
mode: DefaultConsoleName,
config: ConsoleConfig{
Level: LevelInfo,
},
wantErr: nil,
},
{
name: "invalid config",
config: "random things",
wantErr: errors.New("initialize logger: invalid config object: want clog.ConsoleConfig got string"),
name: "custom name",
mode: testName,
wantErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.wantErr, New(ModeConsole, 10, tt.config))
assert.Equal(t, tt.wantErr, NewConsoleWithName(tt.mode, 10, tt.config))
})
}

assert.Equal(t, 1, mgr.len())
assert.Equal(t, ModeConsole, mgr.loggers[0].Mode())
assert.Equal(t, 2, mgr.len())
assert.Equal(t, DefaultConsoleName, mgr.loggers[0].Name())
assert.Equal(t, LevelInfo, mgr.loggers[0].Level())
assert.Equal(t, testName, mgr.loggers[1].Name())
assert.Equal(t, LevelTrace, mgr.loggers[1].Level())
}
Loading

0 comments on commit e927c36

Please sign in to comment.