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 "errors" 29 "fmt" 30 "math" 31 "time" 32) 33 34var ( 35 adaptiveLoggerMaxInterval = time.Minute 36 adaptiveLoggerMaxCriticalMsgCount = uint32(1000) 37) 38 39// asyncAdaptiveLogger represents asynchronous adaptive logger which acts like 40// an async timer logger, but its interval depends on the current message count 41// in the queue. 42// 43// Interval = I, minInterval = m, maxInterval = M, criticalMsgCount = C, msgCount = c: 44// I = m + (C - Min(c, C)) / C * (M - m) 45type asyncAdaptiveLogger struct { 46 asyncLogger 47 minInterval time.Duration 48 criticalMsgCount uint32 49 maxInterval time.Duration 50} 51 52// NewAsyncLoopLogger creates a new asynchronous adaptive logger 53func NewAsyncAdaptiveLogger( 54 config *logConfig, 55 minInterval time.Duration, 56 maxInterval time.Duration, 57 criticalMsgCount uint32) (*asyncAdaptiveLogger, error) { 58 59 if minInterval <= 0 { 60 return nil, errors.New("async adaptive logger min interval should be > 0") 61 } 62 63 if maxInterval > adaptiveLoggerMaxInterval { 64 return nil, fmt.Errorf("async adaptive logger max interval should be <= %s", 65 adaptiveLoggerMaxInterval) 66 } 67 68 if criticalMsgCount <= 0 { 69 return nil, errors.New("async adaptive logger critical msg count should be > 0") 70 } 71 72 if criticalMsgCount > adaptiveLoggerMaxCriticalMsgCount { 73 return nil, fmt.Errorf("async adaptive logger critical msg count should be <= %s", 74 adaptiveLoggerMaxInterval) 75 } 76 77 asnAdaptiveLogger := new(asyncAdaptiveLogger) 78 79 asnAdaptiveLogger.asyncLogger = *newAsyncLogger(config) 80 asnAdaptiveLogger.minInterval = minInterval 81 asnAdaptiveLogger.maxInterval = maxInterval 82 asnAdaptiveLogger.criticalMsgCount = criticalMsgCount 83 84 go asnAdaptiveLogger.processQueue() 85 86 return asnAdaptiveLogger, nil 87} 88 89func (asnAdaptiveLogger *asyncAdaptiveLogger) processItem() (closed bool, itemCount int) { 90 asnAdaptiveLogger.queueHasElements.L.Lock() 91 defer asnAdaptiveLogger.queueHasElements.L.Unlock() 92 93 for asnAdaptiveLogger.msgQueue.Len() == 0 && !asnAdaptiveLogger.Closed() { 94 asnAdaptiveLogger.queueHasElements.Wait() 95 } 96 97 if asnAdaptiveLogger.Closed() { 98 return true, asnAdaptiveLogger.msgQueue.Len() 99 } 100 101 asnAdaptiveLogger.processQueueElement() 102 return false, asnAdaptiveLogger.msgQueue.Len() - 1 103} 104 105// I = m + (C - Min(c, C)) / C * (M - m) => 106// I = m + cDiff * mDiff, 107// cDiff = (C - Min(c, C)) / C) 108// mDiff = (M - m) 109func (asnAdaptiveLogger *asyncAdaptiveLogger) calcAdaptiveInterval(msgCount int) time.Duration { 110 critCountF := float64(asnAdaptiveLogger.criticalMsgCount) 111 cDiff := (critCountF - math.Min(float64(msgCount), critCountF)) / critCountF 112 mDiff := float64(asnAdaptiveLogger.maxInterval - asnAdaptiveLogger.minInterval) 113 114 return asnAdaptiveLogger.minInterval + time.Duration(cDiff*mDiff) 115} 116 117func (asnAdaptiveLogger *asyncAdaptiveLogger) processQueue() { 118 for !asnAdaptiveLogger.Closed() { 119 closed, itemCount := asnAdaptiveLogger.processItem() 120 121 if closed { 122 break 123 } 124 125 interval := asnAdaptiveLogger.calcAdaptiveInterval(itemCount) 126 127 <-time.After(interval) 128 } 129} 130