binarylog.go (5579B)
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 type Logger interface { 36 GetMethodLogger(methodName string) MethodLogger 37 } 38 39 // binLogger is the global binary logger for the binary. One of this should be 40 // built at init time from the configuration (environment variable or flags). 41 // 42 // It is used to get a MethodLogger for each individual method. 43 var binLogger Logger 44 45 // SetLogger sets the binary logger. 46 // 47 // Only call this at init time. 48 func SetLogger(l Logger) { 49 binLogger = l 50 } 51 52 // GetLogger gets the binary logger. 53 // 54 // Only call this at init time. 55 func GetLogger() Logger { 56 return binLogger 57 } 58 59 // GetMethodLogger returns the MethodLogger for the given methodName. 60 // 61 // methodName should be in the format of "/service/method". 62 // 63 // Each MethodLogger returned by this method is a new instance. This is to 64 // generate sequence id within the call. 65 func GetMethodLogger(methodName string) MethodLogger { 66 if binLogger == nil { 67 return nil 68 } 69 return binLogger.GetMethodLogger(methodName) 70 } 71 72 func init() { 73 const envStr = "GRPC_BINARY_LOG_FILTER" 74 configStr := os.Getenv(envStr) 75 binLogger = NewLoggerFromConfigString(configStr) 76 } 77 78 // MethodLoggerConfig contains the setting for logging behavior of a method 79 // logger. Currently, it contains the max length of header and message. 80 type MethodLoggerConfig struct { 81 // Max length of header and message. 82 Header, Message uint64 83 } 84 85 // LoggerConfig contains the config for loggers to create method loggers. 86 type LoggerConfig struct { 87 All *MethodLoggerConfig 88 Services map[string]*MethodLoggerConfig 89 Methods map[string]*MethodLoggerConfig 90 91 Blacklist map[string]struct{} 92 } 93 94 type logger struct { 95 config LoggerConfig 96 } 97 98 // NewLoggerFromConfig builds a logger with the given LoggerConfig. 99 func NewLoggerFromConfig(config LoggerConfig) Logger { 100 return &logger{config: config} 101 } 102 103 // newEmptyLogger creates an empty logger. The map fields need to be filled in 104 // using the set* functions. 105 func newEmptyLogger() *logger { 106 return &logger{} 107 } 108 109 // Set method logger for "*". 110 func (l *logger) setDefaultMethodLogger(ml *MethodLoggerConfig) error { 111 if l.config.All != nil { 112 return fmt.Errorf("conflicting global rules found") 113 } 114 l.config.All = ml 115 return nil 116 } 117 118 // Set method logger for "service/*". 119 // 120 // New MethodLogger with same service overrides the old one. 121 func (l *logger) setServiceMethodLogger(service string, ml *MethodLoggerConfig) error { 122 if _, ok := l.config.Services[service]; ok { 123 return fmt.Errorf("conflicting service rules for service %v found", service) 124 } 125 if l.config.Services == nil { 126 l.config.Services = make(map[string]*MethodLoggerConfig) 127 } 128 l.config.Services[service] = ml 129 return nil 130 } 131 132 // Set method logger for "service/method". 133 // 134 // New MethodLogger with same method overrides the old one. 135 func (l *logger) setMethodMethodLogger(method string, ml *MethodLoggerConfig) error { 136 if _, ok := l.config.Blacklist[method]; ok { 137 return fmt.Errorf("conflicting blacklist rules for method %v found", method) 138 } 139 if _, ok := l.config.Methods[method]; ok { 140 return fmt.Errorf("conflicting method rules for method %v found", method) 141 } 142 if l.config.Methods == nil { 143 l.config.Methods = make(map[string]*MethodLoggerConfig) 144 } 145 l.config.Methods[method] = ml 146 return nil 147 } 148 149 // Set blacklist method for "-service/method". 150 func (l *logger) setBlacklist(method string) error { 151 if _, ok := l.config.Blacklist[method]; ok { 152 return fmt.Errorf("conflicting blacklist rules for method %v found", method) 153 } 154 if _, ok := l.config.Methods[method]; ok { 155 return fmt.Errorf("conflicting method rules for method %v found", method) 156 } 157 if l.config.Blacklist == nil { 158 l.config.Blacklist = make(map[string]struct{}) 159 } 160 l.config.Blacklist[method] = struct{}{} 161 return nil 162 } 163 164 // getMethodLogger returns the MethodLogger for the given methodName. 165 // 166 // methodName should be in the format of "/service/method". 167 // 168 // Each MethodLogger returned by this method is a new instance. This is to 169 // generate sequence id within the call. 170 func (l *logger) GetMethodLogger(methodName string) MethodLogger { 171 s, m, err := grpcutil.ParseMethod(methodName) 172 if err != nil { 173 grpclogLogger.Infof("binarylogging: failed to parse %q: %v", methodName, err) 174 return nil 175 } 176 if ml, ok := l.config.Methods[s+"/"+m]; ok { 177 return NewTruncatingMethodLogger(ml.Header, ml.Message) 178 } 179 if _, ok := l.config.Blacklist[s+"/"+m]; ok { 180 return nil 181 } 182 if ml, ok := l.config.Services[s]; ok { 183 return NewTruncatingMethodLogger(ml.Header, ml.Message) 184 } 185 if l.config.All == nil { 186 return nil 187 } 188 return NewTruncatingMethodLogger(l.config.All.Header, l.config.All.Message) 189 }