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