github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/grpcutil/log.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package grpcutil 12 13 import ( 14 "context" 15 "math" 16 "regexp" 17 "strings" 18 "time" 19 20 "github.com/cockroachdb/cockroach/pkg/util/log" 21 "github.com/cockroachdb/cockroach/pkg/util/syncutil" 22 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 23 "github.com/petermattis/goid" 24 "google.golang.org/grpc/grpclog" 25 ) 26 27 func init() { 28 SetSeverity(log.Severity_ERROR) 29 } 30 31 // SetSeverity sets the severity level below which GRPC log messages are 32 // suppressed. 33 // 34 // Must be called before GRPC is used. 35 func SetSeverity(s log.Severity) { 36 grpclog.SetLoggerV2((*logger)(&s)) 37 } 38 39 // NB: This interface is implemented by a pointer because using a value causes 40 // a synthetic stack frame to be inserted on calls to the interface methods. 41 // Specifically, we get a stack frame that appears as "<autogenerated>", which 42 // is not useful in logs. 43 // 44 // Also NB: we pass a depth of 2 here because all logging calls originate from 45 // the logging adapter file in grpc, which is an additional stack frame away 46 // from the actual logging site. 47 var _ grpclog.LoggerV2 = (*logger)(nil) 48 49 type logger log.Severity 50 51 func (severity *logger) Info(args ...interface{}) { 52 if log.Severity(*severity) > log.Severity_INFO { 53 return 54 } 55 log.InfofDepth(context.TODO(), 2, "", args...) 56 } 57 58 func (severity *logger) Infoln(args ...interface{}) { 59 if log.Severity(*severity) > log.Severity_INFO { 60 return 61 } 62 log.InfofDepth(context.TODO(), 2, "", args...) 63 } 64 65 func (severity *logger) Infof(format string, args ...interface{}) { 66 if log.Severity(*severity) > log.Severity_INFO { 67 return 68 } 69 log.InfofDepth(context.TODO(), 2, format, args...) 70 } 71 72 func (severity *logger) Warning(args ...interface{}) { 73 if log.Severity(*severity) > log.Severity_WARNING { 74 return 75 } 76 log.WarningfDepth(context.TODO(), 2, "", args...) 77 } 78 79 func (severity *logger) Warningln(args ...interface{}) { 80 if log.Severity(*severity) > log.Severity_WARNING { 81 return 82 } 83 log.WarningfDepth(context.TODO(), 2, "", args...) 84 } 85 86 func (severity *logger) Warningf(format string, args ...interface{}) { 87 if log.Severity(*severity) > log.Severity_WARNING { 88 return 89 } 90 if shouldPrint(transportFailedRe, connectionRefusedRe, time.Minute, format, args...) { 91 log.WarningfDepth(context.TODO(), 2, format, args...) 92 } 93 } 94 95 func (severity *logger) Error(args ...interface{}) { 96 if log.Severity(*severity) > log.Severity_ERROR { 97 return 98 } 99 log.ErrorfDepth(context.TODO(), 2, "", args...) 100 } 101 102 func (severity *logger) Errorln(args ...interface{}) { 103 if log.Severity(*severity) > log.Severity_ERROR { 104 return 105 } 106 log.ErrorfDepth(context.TODO(), 2, "", args...) 107 } 108 109 func (severity *logger) Errorf(format string, args ...interface{}) { 110 if log.Severity(*severity) > log.Severity_ERROR { 111 return 112 } 113 log.ErrorfDepth(context.TODO(), 2, format, args...) 114 } 115 116 func (severity *logger) Fatal(args ...interface{}) { 117 if log.Severity(*severity) > log.Severity_NONE { 118 return 119 } 120 log.FatalfDepth(context.TODO(), 2, "", args...) 121 } 122 123 func (severity *logger) Fatalln(args ...interface{}) { 124 if log.Severity(*severity) > log.Severity_NONE { 125 return 126 } 127 log.FatalfDepth(context.TODO(), 2, "", args...) 128 } 129 130 func (severity *logger) Fatalf(format string, args ...interface{}) { 131 if log.Severity(*severity) > log.Severity_NONE { 132 return 133 } 134 log.FatalfDepth(context.TODO(), 2, format, args...) 135 } 136 137 func (severity *logger) V(i int) bool { 138 if i < 0 { 139 i = 0 140 } 141 if i > math.MaxInt32 { 142 i = math.MaxInt32 143 } 144 return log.VDepth(log.Level(i) /* level */, 1 /* depth */) 145 } 146 147 // https://github.com/grpc/grpc-go/blob/v1.7.0/clientconn.go#L937 148 var ( 149 transportFailedRe = regexp.MustCompile("^" + regexp.QuoteMeta("grpc: addrConn.resetTransport failed to create client transport:")) 150 connectionRefusedRe = regexp.MustCompile( 151 strings.Join([]string{ 152 // *nix 153 regexp.QuoteMeta("connection refused"), 154 // Windows 155 regexp.QuoteMeta("No connection could be made because the target machine actively refused it"), 156 // Host removed from the network and no longer resolvable: 157 // https://github.com/golang/go/blob/go1.8.3/src/net/net.go#L566 158 regexp.QuoteMeta("no such host"), 159 }, "|"), 160 ) 161 ) 162 163 var spamMu = struct { 164 syncutil.Mutex 165 gids map[int64]time.Time 166 }{ 167 gids: make(map[int64]time.Time), 168 } 169 170 func shouldPrint( 171 formatRe, argsRe *regexp.Regexp, freq time.Duration, format string, args ...interface{}, 172 ) bool { 173 if formatRe.MatchString(format) { 174 for _, arg := range args { 175 if err, ok := arg.(error); ok { 176 if argsRe.MatchString(err.Error()) { 177 gid := goid.Get() 178 now := timeutil.Now() 179 spamMu.Lock() 180 t, ok := spamMu.gids[gid] 181 doPrint := !(ok && now.Sub(t) < freq) 182 if doPrint { 183 spamMu.gids[gid] = now 184 } 185 spamMu.Unlock() 186 return doPrint 187 } 188 } 189 } 190 } 191 return true 192 }