You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

141 lines
3.3 KiB

// Copyright 2017 Unknwon
//
// 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 clog
import "fmt"
// Logger is an interface for a logger adapter with specific mode and level.
type Logger interface {
// Level returns minimum level of given logger.
Level() LEVEL
// Init accepts a config struct specific for given logger and performs any necessary initialization.
Init(interface{}) error
// ExchangeChans accepts error channel, and returns message receive channel.
ExchangeChans(chan<- error) chan *Message
// Start starts message processing.
Start()
// Destroy releases all resources.
Destroy()
}
// Adapter contains common fields for any logger adapter. This struct should be used as embedded struct.
type Adapter struct {
level LEVEL
msgChan chan *Message
quitChan chan struct{}
errorChan chan<- error
}
type Factory func() Logger
// factories keeps factory function of registered loggers.
var factories = map[MODE]Factory{}
func Register(mode MODE, f Factory) {
if f == nil {
panic("clog: register function is nil")
}
if factories[mode] != nil {
panic("clog: register duplicated mode '" + mode + "'")
}
factories[mode] = f
}
type receiver struct {
Logger
mode MODE
msgChan chan *Message
}
var (
// receivers is a list of loggers with their message channel for broadcasting.
receivers []*receiver
errorChan = make(chan error, 5)
quitChan = make(chan struct{})
)
func init() {
// Start background error handling goroutine.
go func() {
for {
select {
case err := <-errorChan:
fmt.Printf("clog: unable to write message: %v\n", err)
case <-quitChan:
return
}
}
}()
}
// New initializes and appends a new logger to the receiver list.
// Calling this function multiple times will overwrite previous logger with same mode.
func New(mode MODE, cfg interface{}) error {
factory, ok := factories[mode]
if !ok {
return fmt.Errorf("unknown mode '%s'", mode)
}
logger := factory()
if err := logger.Init(cfg); err != nil {
return err
}
msgChan := logger.ExchangeChans(errorChan)
// Check and replace previous logger.
hasFound := false
for i := range receivers {
if receivers[i].mode == mode {
hasFound = true
// Release previous logger.
receivers[i].Destroy()
// Update info to new one.
receivers[i].Logger = logger
receivers[i].msgChan = msgChan
break
}
}
if !hasFound {
receivers = append(receivers, &receiver{
Logger: logger,
mode: mode,
msgChan: msgChan,
})
}
go logger.Start()
return nil
}
// Delete removes logger from the receiver list.
func Delete(mode MODE) {
foundIdx := -1
for i := range receivers {
if receivers[i].mode == mode {
foundIdx = i
receivers[i].Destroy()
}
}
if foundIdx >= 0 {
newList := make([]*receiver, len(receivers)-1)
copy(newList, receivers[:foundIdx])
copy(newList[foundIdx:], receivers[foundIdx+1:])
receivers = newList
}
}