package ripsawlogger import ( "sync" "time" ) const ( bufferSize = 128 flushTimeoutMilliseconds = 2500 ) type asyncLogger struct { channel chan LogEntry logger Logger m sync.Mutex } // Creates a logger that performs writes asynchronously and non-blocking-ly func NewAsyncLogger(next Logger) Logger { entries := make(chan LogEntry, bufferSize) go func(logger Logger, entries chan LogEntry) { for { // wait for some data and forward it to the right place logger.Log(<-entries) } }(next, entries) return &asyncLogger{channel: entries, logger: next} } func (rl *asyncLogger) Flush() { // prevent additional writes rl.m.Lock() defer rl.m.Unlock() timeoutStart := time.Now() // flush downstream logs when we finish defer rl.logger.Flush() // wait for the channel to clear out for { length := len(rl.channel) // if the channel is empty, then we're done if length == 0 { return } // if we've exhausted our timeout, just finish if time.Now().Sub(timeoutStart) >= flushTimeoutMilliseconds*time.Millisecond { return } // wait a slight amount time.Sleep(30 * time.Millisecond) } } func (rl *asyncLogger) Log(data LogEntry) { rl.m.Lock() defer rl.m.Unlock() rl.channel <- data }