2017-09-23 18:20:22 +02:00
|
|
|
package logger
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2017-09-24 19:39:44 +02:00
|
|
|
"encoding/json"
|
2017-09-23 18:20:22 +02:00
|
|
|
"fmt"
|
|
|
|
"github.com/pkg/errors"
|
2017-12-23 00:55:02 +01:00
|
|
|
"sync"
|
2017-09-23 18:20:22 +02:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Level int
|
|
|
|
|
2017-09-24 19:39:44 +02:00
|
|
|
func (l Level) MarshalJSON() ([]byte, error) {
|
|
|
|
return json.Marshal(l.String())
|
|
|
|
}
|
|
|
|
|
2017-12-23 00:55:36 +01:00
|
|
|
func (l *Level) UnmarshalJSON(input []byte) (err error) {
|
|
|
|
var s string
|
|
|
|
if err = json.Unmarshal(input, &s); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
*l, err = ParseLevel(s)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-09-23 18:20:22 +02:00
|
|
|
const (
|
|
|
|
Debug Level = iota
|
|
|
|
Info
|
|
|
|
Warn
|
|
|
|
Error
|
|
|
|
)
|
|
|
|
|
|
|
|
func (l Level) Short() string {
|
|
|
|
switch l {
|
|
|
|
case Debug:
|
|
|
|
return "DEBG"
|
|
|
|
case Info:
|
|
|
|
return "INFO"
|
|
|
|
case Warn:
|
|
|
|
return "WARN"
|
|
|
|
case Error:
|
|
|
|
return "ERRO"
|
|
|
|
default:
|
|
|
|
return fmt.Sprintf("%s", l)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l Level) String() string {
|
|
|
|
switch l {
|
|
|
|
case Debug:
|
|
|
|
return "debug"
|
|
|
|
case Info:
|
|
|
|
return "info"
|
|
|
|
case Warn:
|
|
|
|
return "warn"
|
|
|
|
case Error:
|
|
|
|
return "error"
|
|
|
|
default:
|
2017-09-30 16:31:55 +02:00
|
|
|
return fmt.Sprintf("%s", string(l))
|
2017-09-23 18:20:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func ParseLevel(s string) (l Level, err error) {
|
|
|
|
for _, l := range AllLevels {
|
|
|
|
if s == l.String() {
|
|
|
|
return l, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1, errors.Errorf("unknown level '%s'", s)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Levels ordered least severe to most severe
|
|
|
|
var AllLevels []Level = []Level{Debug, Info, Warn, Error}
|
|
|
|
|
|
|
|
type Fields map[string]interface{}
|
|
|
|
|
|
|
|
type Entry struct {
|
|
|
|
Level Level
|
|
|
|
Message string
|
|
|
|
Time time.Time
|
|
|
|
Fields Fields
|
|
|
|
}
|
|
|
|
|
|
|
|
type Outlet interface {
|
|
|
|
// Note: os.Stderr is also used by logger.Logger for reporting errors returned by outlets
|
|
|
|
// => you probably don't want to log there
|
|
|
|
WriteEntry(ctx context.Context, entry Entry) error
|
|
|
|
}
|
|
|
|
|
2017-12-23 00:55:02 +01:00
|
|
|
type Outlets struct {
|
|
|
|
mtx sync.RWMutex
|
|
|
|
outs map[Level][]Outlet
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewOutlets() *Outlets {
|
|
|
|
return &Outlets{
|
|
|
|
mtx: sync.RWMutex{},
|
|
|
|
outs: make(map[Level][]Outlet, len(AllLevels)),
|
|
|
|
}
|
|
|
|
}
|
2017-09-23 18:20:22 +02:00
|
|
|
|
2017-12-23 00:55:02 +01:00
|
|
|
func (os *Outlets) DeepCopy() (copy *Outlets) {
|
|
|
|
copy = NewOutlets()
|
|
|
|
for level := range os.outs {
|
|
|
|
for i := range os.outs[level] {
|
|
|
|
copy.outs[level] = append(copy.outs[level], os.outs[level][i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return copy
|
2017-09-23 18:20:22 +02:00
|
|
|
}
|
|
|
|
|
2017-12-23 00:55:02 +01:00
|
|
|
func (os *Outlets) Add(outlet Outlet, minLevel Level) {
|
|
|
|
os.mtx.Lock()
|
|
|
|
defer os.mtx.Unlock()
|
2017-09-23 18:20:22 +02:00
|
|
|
for _, l := range AllLevels[minLevel:] {
|
2017-12-23 00:55:02 +01:00
|
|
|
os.outs[l] = append(os.outs[l], outlet)
|
2017-09-23 18:20:22 +02:00
|
|
|
}
|
|
|
|
}
|
2017-11-16 23:49:47 +01:00
|
|
|
|
2017-12-23 00:55:02 +01:00
|
|
|
func (os *Outlets) Get(level Level) []Outlet {
|
|
|
|
os.mtx.RLock()
|
|
|
|
defer os.mtx.RUnlock()
|
|
|
|
return os.outs[level]
|
2017-11-16 23:49:47 +01:00
|
|
|
}
|
|
|
|
|
2017-11-17 00:24:22 +01:00
|
|
|
// Return the first outlet added to this Outlets list using Add()
|
|
|
|
// with minLevel <= Error.
|
|
|
|
// If no such outlet is in this Outlets list, a discarding outlet is returned.
|
2017-12-23 00:55:02 +01:00
|
|
|
func (os *Outlets) GetLoggerErrorOutlet() Outlet {
|
|
|
|
os.mtx.RLock()
|
|
|
|
defer os.mtx.RUnlock()
|
|
|
|
if len(os.outs[Error]) < 1 {
|
2017-11-17 00:24:22 +01:00
|
|
|
return nullOutlet{}
|
|
|
|
}
|
2017-12-23 00:55:02 +01:00
|
|
|
return os.outs[Error][0]
|
2017-11-16 23:49:47 +01:00
|
|
|
}
|
2017-11-17 00:24:22 +01:00
|
|
|
|
|
|
|
type nullOutlet struct{}
|
|
|
|
|
|
|
|
func (nullOutlet) WriteEntry(ctx context.Context, entry Entry) error { return nil }
|