1// Copyright (c) 2012 - Cloud Instruments Co., Ltd. 2// 3// All rights reserved. 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are met: 7// 8// 1. Redistributions of source code must retain the above copyright notice, this 9// list of conditions and the following disclaimer. 10// 2. Redistributions in binary form must reproduce the above copyright notice, 11// this list of conditions and the following disclaimer in the documentation 12// and/or other materials provided with the distribution. 13// 14// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 25package seelog 26 27import ( 28 "container/list" 29 "fmt" 30 "sync" 31) 32 33// MaxQueueSize is the critical number of messages in the queue that result in an immediate flush. 34const ( 35 MaxQueueSize = 10000 36) 37 38type msgQueueItem struct { 39 level LogLevel 40 context LogContextInterface 41 message fmt.Stringer 42} 43 44// asyncLogger represents common data for all asynchronous loggers 45type asyncLogger struct { 46 commonLogger 47 msgQueue *list.List 48 queueHasElements *sync.Cond 49} 50 51// newAsyncLogger creates a new asynchronous logger 52func newAsyncLogger(config *logConfig) *asyncLogger { 53 asnLogger := new(asyncLogger) 54 55 asnLogger.msgQueue = list.New() 56 asnLogger.queueHasElements = sync.NewCond(new(sync.Mutex)) 57 58 asnLogger.commonLogger = *newCommonLogger(config, asnLogger) 59 60 return asnLogger 61} 62 63func (asnLogger *asyncLogger) innerLog( 64 level LogLevel, 65 context LogContextInterface, 66 message fmt.Stringer) { 67 68 asnLogger.addMsgToQueue(level, context, message) 69} 70 71func (asnLogger *asyncLogger) Close() { 72 asnLogger.m.Lock() 73 defer asnLogger.m.Unlock() 74 75 if !asnLogger.Closed() { 76 asnLogger.flushQueue(true) 77 asnLogger.config.RootDispatcher.Flush() 78 79 if err := asnLogger.config.RootDispatcher.Close(); err != nil { 80 reportInternalError(err) 81 } 82 83 asnLogger.closedM.Lock() 84 asnLogger.closed = true 85 asnLogger.closedM.Unlock() 86 asnLogger.queueHasElements.Broadcast() 87 } 88} 89 90func (asnLogger *asyncLogger) Flush() { 91 asnLogger.m.Lock() 92 defer asnLogger.m.Unlock() 93 94 if !asnLogger.Closed() { 95 asnLogger.flushQueue(true) 96 asnLogger.config.RootDispatcher.Flush() 97 } 98} 99 100func (asnLogger *asyncLogger) flushQueue(lockNeeded bool) { 101 if lockNeeded { 102 asnLogger.queueHasElements.L.Lock() 103 defer asnLogger.queueHasElements.L.Unlock() 104 } 105 106 for asnLogger.msgQueue.Len() > 0 { 107 asnLogger.processQueueElement() 108 } 109} 110 111func (asnLogger *asyncLogger) processQueueElement() { 112 if asnLogger.msgQueue.Len() > 0 { 113 backElement := asnLogger.msgQueue.Front() 114 msg, _ := backElement.Value.(msgQueueItem) 115 asnLogger.processLogMsg(msg.level, msg.message, msg.context) 116 asnLogger.msgQueue.Remove(backElement) 117 } 118} 119 120func (asnLogger *asyncLogger) addMsgToQueue( 121 level LogLevel, 122 context LogContextInterface, 123 message fmt.Stringer) { 124 125 if !asnLogger.Closed() { 126 asnLogger.queueHasElements.L.Lock() 127 defer asnLogger.queueHasElements.L.Unlock() 128 129 if asnLogger.msgQueue.Len() >= MaxQueueSize { 130 fmt.Printf("Seelog queue overflow: more than %v messages in the queue. Flushing.\n", MaxQueueSize) 131 asnLogger.flushQueue(false) 132 } 133 134 queueItem := msgQueueItem{level, context, message} 135 136 asnLogger.msgQueue.PushBack(queueItem) 137 asnLogger.queueHasElements.Broadcast() 138 } else { 139 err := fmt.Errorf("queue closed! Cannot process element: %d %#v", level, message) 140 reportInternalError(err) 141 } 142} 143