go.temporal.io/server@v1.23.0/common/log/throttle_logger.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package log 26 27 import ( 28 "go.temporal.io/server/common/log/tag" 29 "go.temporal.io/server/common/quotas" 30 ) 31 32 const extraSkipForThrottleLogger = 3 33 34 type throttledLogger struct { 35 limiter quotas.RateLimiter 36 logger Logger 37 } 38 39 var _ Logger = (*throttledLogger)(nil) 40 41 // NewThrottledLogger returns an implementation of logger that throttles the 42 // log messages being emitted. The underlying implementation uses a token bucket 43 // rate limiter and stops emitting logs once the bucket runs out of tokens 44 // 45 // Fatal/Panic logs are always emitted without any throttling 46 func NewThrottledLogger(logger Logger, rps quotas.RateFn) *throttledLogger { 47 if sl, ok := logger.(SkipLogger); ok { 48 logger = sl.Skip(extraSkipForThrottleLogger) 49 } 50 51 limiter := quotas.NewDefaultOutgoingRateLimiter(rps) 52 tl := &throttledLogger{ 53 limiter: limiter, 54 logger: logger, 55 } 56 return tl 57 } 58 59 func (tl *throttledLogger) Debug(msg string, tags ...tag.Tag) { 60 tl.rateLimit(func() { 61 tl.logger.Debug(msg, tags...) 62 }) 63 } 64 65 func (tl *throttledLogger) Info(msg string, tags ...tag.Tag) { 66 tl.rateLimit(func() { 67 tl.logger.Info(msg, tags...) 68 }) 69 } 70 71 func (tl *throttledLogger) Warn(msg string, tags ...tag.Tag) { 72 tl.rateLimit(func() { 73 tl.logger.Warn(msg, tags...) 74 }) 75 } 76 77 func (tl *throttledLogger) Error(msg string, tags ...tag.Tag) { 78 tl.rateLimit(func() { 79 tl.logger.Error(msg, tags...) 80 }) 81 } 82 83 func (tl *throttledLogger) DPanic(msg string, tags ...tag.Tag) { 84 tl.rateLimit(func() { 85 tl.logger.DPanic(msg, tags...) 86 }) 87 } 88 89 func (tl *throttledLogger) Panic(msg string, tags ...tag.Tag) { 90 tl.rateLimit(func() { 91 tl.logger.Panic(msg, tags...) 92 }) 93 } 94 95 func (tl *throttledLogger) Fatal(msg string, tags ...tag.Tag) { 96 tl.rateLimit(func() { 97 tl.logger.Fatal(msg, tags...) 98 }) 99 } 100 101 // Return a logger with the specified key-value pairs set, to be included in a subsequent normal logging call 102 func (tl *throttledLogger) With(tags ...tag.Tag) Logger { 103 result := &throttledLogger{ 104 limiter: tl.limiter, 105 logger: With(tl.logger, tags...), 106 } 107 return result 108 } 109 110 func (tl *throttledLogger) rateLimit(f func()) { 111 if ok := tl.limiter.Allow(); ok { 112 f() 113 } 114 }