google.golang.org/grpc@v1.62.1/internal/binarylog/binarylog.go (about) 1 /* 2 * 3 * Copyright 2018 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 // Package binarylog implementation binary logging as defined in 20 // https://github.com/grpc/proposal/blob/master/A16-binary-logging.md. 21 package binarylog 22 23 import ( 24 "fmt" 25 "os" 26 27 "google.golang.org/grpc/grpclog" 28 "google.golang.org/grpc/internal/grpcutil" 29 ) 30 31 var grpclogLogger = grpclog.Component("binarylog") 32 33 // Logger specifies MethodLoggers for method names with a Log call that 34 // takes a context. 35 // 36 // This is used in the 1.0 release of gcp/observability, and thus must not be 37 // deleted or changed. 38 type Logger interface { 39 GetMethodLogger(methodName string) MethodLogger 40 } 41 42 // binLogger is the global binary logger for the binary. One of this should be 43 // built at init time from the configuration (environment variable or flags). 44 // 45 // It is used to get a MethodLogger for each individual method. 46 var binLogger Logger 47 48 // SetLogger sets the binary logger. 49 // 50 // Only call this at init time. 51 func SetLogger(l Logger) { 52 binLogger = l 53 } 54 55 // GetLogger gets the binary logger. 56 // 57 // Only call this at init time. 58 func GetLogger() Logger { 59 return binLogger 60 } 61 62 // GetMethodLogger returns the MethodLogger for the given methodName. 63 // 64 // methodName should be in the format of "/service/method". 65 // 66 // Each MethodLogger returned by this method is a new instance. This is to 67 // generate sequence id within the call. 68 func GetMethodLogger(methodName string) MethodLogger { 69 if binLogger == nil { 70 return nil 71 } 72 return binLogger.GetMethodLogger(methodName) 73 } 74 75 func init() { 76 const envStr = "GRPC_BINARY_LOG_FILTER" 77 configStr := os.Getenv(envStr) 78 binLogger = NewLoggerFromConfigString(configStr) 79 } 80 81 // MethodLoggerConfig contains the setting for logging behavior of a method 82 // logger. Currently, it contains the max length of header and message. 83 type MethodLoggerConfig struct { 84 // Max length of header and message. 85 Header, Message uint64 86 } 87 88 // LoggerConfig contains the config for loggers to create method loggers. 89 type LoggerConfig struct { 90 All *MethodLoggerConfig 91 Services map[string]*MethodLoggerConfig 92 Methods map[string]*MethodLoggerConfig 93 94 Blacklist map[string]struct{} 95 } 96 97 type logger struct { 98 config LoggerConfig 99 } 100 101 // NewLoggerFromConfig builds a logger with the given LoggerConfig. 102 func NewLoggerFromConfig(config LoggerConfig) Logger { 103 return &logger{config: config} 104 } 105 106 // newEmptyLogger creates an empty logger. The map fields need to be filled in 107 // using the set* functions. 108 func newEmptyLogger() *logger { 109 return &logger{} 110 } 111 112 // Set method logger for "*". 113 func (l *logger) setDefaultMethodLogger(ml *MethodLoggerConfig) error { 114 if l.config.All != nil { 115 return fmt.Errorf("conflicting global rules found") 116 } 117 l.config.All = ml 118 return nil 119 } 120 121 // Set method logger for "service/*". 122 // 123 // New MethodLogger with same service overrides the old one. 124 func (l *logger) setServiceMethodLogger(service string, ml *MethodLoggerConfig) error { 125 if _, ok := l.config.Services[service]; ok { 126 return fmt.Errorf("conflicting service rules for service %v found", service) 127 } 128 if l.config.Services == nil { 129 l.config.Services = make(map[string]*MethodLoggerConfig) 130 } 131 l.config.Services[service] = ml 132 return nil 133 } 134 135 // Set method logger for "service/method". 136 // 137 // New MethodLogger with same method overrides the old one. 138 func (l *logger) setMethodMethodLogger(method string, ml *MethodLoggerConfig) error { 139 if _, ok := l.config.Blacklist[method]; ok { 140 return fmt.Errorf("conflicting blacklist rules for method %v found", method) 141 } 142 if _, ok := l.config.Methods[method]; ok { 143 return fmt.Errorf("conflicting method rules for method %v found", method) 144 } 145 if l.config.Methods == nil { 146 l.config.Methods = make(map[string]*MethodLoggerConfig) 147 } 148 l.config.Methods[method] = ml 149 return nil 150 } 151 152 // Set blacklist method for "-service/method". 153 func (l *logger) setBlacklist(method string) error { 154 if _, ok := l.config.Blacklist[method]; ok { 155 return fmt.Errorf("conflicting blacklist rules for method %v found", method) 156 } 157 if _, ok := l.config.Methods[method]; ok { 158 return fmt.Errorf("conflicting method rules for method %v found", method) 159 } 160 if l.config.Blacklist == nil { 161 l.config.Blacklist = make(map[string]struct{}) 162 } 163 l.config.Blacklist[method] = struct{}{} 164 return nil 165 } 166 167 // getMethodLogger returns the MethodLogger for the given methodName. 168 // 169 // methodName should be in the format of "/service/method". 170 // 171 // Each MethodLogger returned by this method is a new instance. This is to 172 // generate sequence id within the call. 173 func (l *logger) GetMethodLogger(methodName string) MethodLogger { 174 s, m, err := grpcutil.ParseMethod(methodName) 175 if err != nil { 176 grpclogLogger.Infof("binarylogging: failed to parse %q: %v", methodName, err) 177 return nil 178 } 179 if ml, ok := l.config.Methods[s+"/"+m]; ok { 180 return NewTruncatingMethodLogger(ml.Header, ml.Message) 181 } 182 if _, ok := l.config.Blacklist[s+"/"+m]; ok { 183 return nil 184 } 185 if ml, ok := l.config.Services[s]; ok { 186 return NewTruncatingMethodLogger(ml.Header, ml.Message) 187 } 188 if l.config.All == nil { 189 return nil 190 } 191 return NewTruncatingMethodLogger(l.config.All.Header, l.config.All.Message) 192 }