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. 21package binarylog 22 23import ( 24 "fmt" 25 "os" 26 27 "google.golang.org/grpc/grpclog" 28 "google.golang.org/grpc/internal/grpcutil" 29) 30 31// Logger is the global binary logger. It can be used to get binary logger for 32// each method. 33type Logger interface { 34 getMethodLogger(methodName string) *MethodLogger 35} 36 37// binLogger is the global binary logger for the binary. One of this should be 38// built at init time from the configuration (environment variable or flags). 39// 40// It is used to get a methodLogger for each individual method. 41var binLogger Logger 42 43// SetLogger sets the binarg logger. 44// 45// Only call this at init time. 46func SetLogger(l Logger) { 47 binLogger = l 48} 49 50// GetMethodLogger returns the methodLogger for the given methodName. 51// 52// methodName should be in the format of "/service/method". 53// 54// Each methodLogger returned by this method is a new instance. This is to 55// generate sequence id within the call. 56func GetMethodLogger(methodName string) *MethodLogger { 57 if binLogger == nil { 58 return nil 59 } 60 return binLogger.getMethodLogger(methodName) 61} 62 63func init() { 64 const envStr = "GRPC_BINARY_LOG_FILTER" 65 configStr := os.Getenv(envStr) 66 binLogger = NewLoggerFromConfigString(configStr) 67} 68 69type methodLoggerConfig struct { 70 // Max length of header and message. 71 hdr, msg uint64 72} 73 74type logger struct { 75 all *methodLoggerConfig 76 services map[string]*methodLoggerConfig 77 methods map[string]*methodLoggerConfig 78 79 blacklist map[string]struct{} 80} 81 82// newEmptyLogger creates an empty logger. The map fields need to be filled in 83// using the set* functions. 84func newEmptyLogger() *logger { 85 return &logger{} 86} 87 88// Set method logger for "*". 89func (l *logger) setDefaultMethodLogger(ml *methodLoggerConfig) error { 90 if l.all != nil { 91 return fmt.Errorf("conflicting global rules found") 92 } 93 l.all = ml 94 return nil 95} 96 97// Set method logger for "service/*". 98// 99// New methodLogger with same service overrides the old one. 100func (l *logger) setServiceMethodLogger(service string, ml *methodLoggerConfig) error { 101 if _, ok := l.services[service]; ok { 102 return fmt.Errorf("conflicting service rules for service %v found", service) 103 } 104 if l.services == nil { 105 l.services = make(map[string]*methodLoggerConfig) 106 } 107 l.services[service] = ml 108 return nil 109} 110 111// Set method logger for "service/method". 112// 113// New methodLogger with same method overrides the old one. 114func (l *logger) setMethodMethodLogger(method string, ml *methodLoggerConfig) error { 115 if _, ok := l.blacklist[method]; ok { 116 return fmt.Errorf("conflicting blacklist rules for method %v found", method) 117 } 118 if _, ok := l.methods[method]; ok { 119 return fmt.Errorf("conflicting method rules for method %v found", method) 120 } 121 if l.methods == nil { 122 l.methods = make(map[string]*methodLoggerConfig) 123 } 124 l.methods[method] = ml 125 return nil 126} 127 128// Set blacklist method for "-service/method". 129func (l *logger) setBlacklist(method string) error { 130 if _, ok := l.blacklist[method]; ok { 131 return fmt.Errorf("conflicting blacklist rules for method %v found", method) 132 } 133 if _, ok := l.methods[method]; ok { 134 return fmt.Errorf("conflicting method rules for method %v found", method) 135 } 136 if l.blacklist == nil { 137 l.blacklist = make(map[string]struct{}) 138 } 139 l.blacklist[method] = struct{}{} 140 return nil 141} 142 143// getMethodLogger returns the methodLogger for the given methodName. 144// 145// methodName should be in the format of "/service/method". 146// 147// Each methodLogger returned by this method is a new instance. This is to 148// generate sequence id within the call. 149func (l *logger) getMethodLogger(methodName string) *MethodLogger { 150 s, m, err := grpcutil.ParseMethod(methodName) 151 if err != nil { 152 grpclog.Infof("binarylogging: failed to parse %q: %v", methodName, err) 153 return nil 154 } 155 if ml, ok := l.methods[s+"/"+m]; ok { 156 return newMethodLogger(ml.hdr, ml.msg) 157 } 158 if _, ok := l.blacklist[s+"/"+m]; ok { 159 return nil 160 } 161 if ml, ok := l.services[s]; ok { 162 return newMethodLogger(ml.hdr, ml.msg) 163 } 164 if l.all == nil { 165 return nil 166 } 167 return newMethodLogger(l.all.hdr, l.all.msg) 168} 169