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