@ -47,75 +47,97 @@ const (
)
)
var (
var (
mutex sync . RWMutex // protects logSystems
logMessageC = make ( chan message )
logSystems [ ] LogSystem
addSystemC = make ( chan LogSystem )
flushC = make ( chan chan struct { } )
logMessages = make ( chan message )
resetC = make ( chan chan struct { } )
drainWaitReq = make ( chan chan struct { } )
)
)
func init ( ) {
func init ( ) {
go dispatchLoop ( )
go dispatchLoop ( )
}
}
// each system can buffer this many messages before
// blocking incoming log messages.
const sysBufferSize = 500
func dispatchLoop ( ) {
func dispatchLoop ( ) {
var drainWait [ ] chan struct { }
var (
dispatchDone := make ( chan struct { } )
systems [ ] LogSystem
pending := 0
systemIn [ ] chan message
systemWG sync . WaitGroup
)
bootSystem := func ( sys LogSystem ) {
in := make ( chan message , sysBufferSize )
systemIn = append ( systemIn , in )
systemWG . Add ( 1 )
go sysLoop ( sys , in , & systemWG )
}
for {
for {
select {
select {
case msg := <- logMessages :
case msg := <- logMessageC :
go dispatch ( msg , dispatchDone )
for _ , c := range systemIn {
pending ++
c <- msg
case waiter := <- drainWaitReq :
}
if pending == 0 {
close ( waiter )
case sys := <- addSystemC :
} else {
systems = append ( systems , sys )
drainWait = append ( drainWait , waiter )
bootSystem ( sys )
case waiter := <- resetC :
// reset means terminate all systems
for _ , c := range systemIn {
close ( c )
}
}
case <- dispatchDone :
systems = nil
pending --
systemIn = nil
if pending == 0 {
systemWG . Wait ( )
for _ , c := range drainWait {
close ( waiter )
case waiter := <- flushC :
// flush means reboot all systems
for _ , c := range systemIn {
close ( c )
close ( c )
}
}
drainWait = nil
systemIn = nil
systemWG . Wait ( )
for _ , sys := range systems {
bootSystem ( sys )
}
}
close ( waiter )
}
}
}
}
}
}
func dispatch ( msg message , done chan <- struct { } ) {
func sysLoop ( sys LogSystem , in <- chan message , wg * sync . WaitGroup ) {
mutex . RLock ( )
for msg := range in {
for _ , sys := range logSystems {
if sys . GetLogLevel ( ) >= msg . level {
if sys . GetLogLevel ( ) >= msg . level {
sys . LogPrint ( msg . level , msg . msg )
sys . LogPrint ( msg . level , msg . msg )
}
}
}
}
mutex . RUnlock ( )
wg . Done ( )
done <- struct { } { }
}
}
// Reset removes all active log systems.
// Reset removes all active log systems.
// It blocks until all current messages have been delivered.
func Reset ( ) {
func Reset ( ) {
mutex . Lock ( )
waiter := make ( chan struct { } )
logSystems = nil
resetC <- waiter
mutex . Unlock ( )
<- waiter
}
}
// Flush waits until all current log messages have been dispatched to
// Flush waits until all current log messages have been dispatched to
// the active log systems.
// the active log systems.
func Flush ( ) {
func Flush ( ) {
waiter := make ( chan struct { } )
waiter := make ( chan struct { } )
drainWaitReq <- waiter
flushC <- waiter
<- waiter
<- waiter
}
}
// AddLogSystem starts printing messages to the given LogSystem.
// AddLogSystem starts printing messages to the given LogSystem.
func AddLogSystem ( logSystem LogSystem ) {
func AddLogSystem ( sys LogSystem ) {
mutex . Lock ( )
addSystemC <- sys
logSystems = append ( logSystems , logSystem )
mutex . Unlock ( )
}
}
// A Logger prints messages prefixed by a given tag. It provides named
// A Logger prints messages prefixed by a given tag. It provides named
@ -130,11 +152,11 @@ func NewLogger(tag string) *Logger {
}
}
func ( logger * Logger ) sendln ( level LogLevel , v ... interface { } ) {
func ( logger * Logger ) sendln ( level LogLevel , v ... interface { } ) {
logMessages <- message { level , logger . tag + fmt . Sprintln ( v ... ) }
logMessageC <- message { level , logger . tag + fmt . Sprintln ( v ... ) }
}
}
func ( logger * Logger ) sendf ( level LogLevel , format string , v ... interface { } ) {
func ( logger * Logger ) sendf ( level LogLevel , format string , v ... interface { } ) {
logMessages <- message { level , logger . tag + fmt . Sprintf ( format , v ... ) }
logMessageC <- message { level , logger . tag + fmt . Sprintf ( format , v ... ) }
}
}
// Errorln writes a message with ErrorLevel.
// Errorln writes a message with ErrorLevel.