]>
Commit | Line | Data |
---|---|---|
107c1cdb ND |
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 | ) | |
29 | ||
30 | // Logger is the global binary logger. It can be used to get binary logger for | |
31 | // each method. | |
32 | type 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. | |
40 | var binLogger Logger | |
41 | ||
42 | // SetLogger sets the binarg logger. | |
43 | // | |
44 | // Only call this at init time. | |
45 | func 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. | |
55 | func GetMethodLogger(methodName string) *MethodLogger { | |
56 | if binLogger == nil { | |
57 | return nil | |
58 | } | |
59 | return binLogger.getMethodLogger(methodName) | |
60 | } | |
61 | ||
62 | func init() { | |
63 | const envStr = "GRPC_BINARY_LOG_FILTER" | |
64 | configStr := os.Getenv(envStr) | |
65 | binLogger = NewLoggerFromConfigString(configStr) | |
66 | } | |
67 | ||
68 | type methodLoggerConfig struct { | |
69 | // Max length of header and message. | |
70 | hdr, msg uint64 | |
71 | } | |
72 | ||
73 | type 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. | |
83 | func newEmptyLogger() *logger { | |
84 | return &logger{} | |
85 | } | |
86 | ||
87 | // Set method logger for "*". | |
88 | func (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. | |
99 | func (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. | |
113 | func (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". | |
128 | func (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. | |
148 | func (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 | } |