Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / google.golang.org / grpc / internal / binarylog / env_config.go
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
20
21 import (
22         "errors"
23         "fmt"
24         "regexp"
25         "strconv"
26         "strings"
27
28         "google.golang.org/grpc/grpclog"
29 )
30
31 // NewLoggerFromConfigString reads the string and build a logger. It can be used
32 // to build a new logger and assign it to binarylog.Logger.
33 //
34 // Example filter config strings:
35 //  - "" Nothing will be logged
36 //  - "*" All headers and messages will be fully logged.
37 //  - "*{h}" Only headers will be logged.
38 //  - "*{m:256}" Only the first 256 bytes of each message will be logged.
39 //  - "Foo/*" Logs every method in service Foo
40 //  - "Foo/*,-Foo/Bar" Logs every method in service Foo except method /Foo/Bar
41 //  - "Foo/*,Foo/Bar{m:256}" Logs the first 256 bytes of each message in method
42 //    /Foo/Bar, logs all headers and messages in every other method in service
43 //    Foo.
44 //
45 // If two configs exist for one certain method or service, the one specified
46 // later overrides the privous config.
47 func NewLoggerFromConfigString(s string) Logger {
48         if s == "" {
49                 return nil
50         }
51         l := newEmptyLogger()
52         methods := strings.Split(s, ",")
53         for _, method := range methods {
54                 if err := l.fillMethodLoggerWithConfigString(method); err != nil {
55                         grpclog.Warningf("failed to parse binary log config: %v", err)
56                         return nil
57                 }
58         }
59         return l
60 }
61
62 // fillMethodLoggerWithConfigString parses config, creates methodLogger and adds
63 // it to the right map in the logger.
64 func (l *logger) fillMethodLoggerWithConfigString(config string) error {
65         // "" is invalid.
66         if config == "" {
67                 return errors.New("empty string is not a valid method binary logging config")
68         }
69
70         // "-service/method", blacklist, no * or {} allowed.
71         if config[0] == '-' {
72                 s, m, suffix, err := parseMethodConfigAndSuffix(config[1:])
73                 if err != nil {
74                         return fmt.Errorf("invalid config: %q, %v", config, err)
75                 }
76                 if m == "*" {
77                         return fmt.Errorf("invalid config: %q, %v", config, "* not allowd in blacklist config")
78                 }
79                 if suffix != "" {
80                         return fmt.Errorf("invalid config: %q, %v", config, "header/message limit not allowed in blacklist config")
81                 }
82                 if err := l.setBlacklist(s + "/" + m); err != nil {
83                         return fmt.Errorf("invalid config: %v", err)
84                 }
85                 return nil
86         }
87
88         // "*{h:256;m:256}"
89         if config[0] == '*' {
90                 hdr, msg, err := parseHeaderMessageLengthConfig(config[1:])
91                 if err != nil {
92                         return fmt.Errorf("invalid config: %q, %v", config, err)
93                 }
94                 if err := l.setDefaultMethodLogger(&methodLoggerConfig{hdr: hdr, msg: msg}); err != nil {
95                         return fmt.Errorf("invalid config: %v", err)
96                 }
97                 return nil
98         }
99
100         s, m, suffix, err := parseMethodConfigAndSuffix(config)
101         if err != nil {
102                 return fmt.Errorf("invalid config: %q, %v", config, err)
103         }
104         hdr, msg, err := parseHeaderMessageLengthConfig(suffix)
105         if err != nil {
106                 return fmt.Errorf("invalid header/message length config: %q, %v", suffix, err)
107         }
108         if m == "*" {
109                 if err := l.setServiceMethodLogger(s, &methodLoggerConfig{hdr: hdr, msg: msg}); err != nil {
110                         return fmt.Errorf("invalid config: %v", err)
111                 }
112         } else {
113                 if err := l.setMethodMethodLogger(s+"/"+m, &methodLoggerConfig{hdr: hdr, msg: msg}); err != nil {
114                         return fmt.Errorf("invalid config: %v", err)
115                 }
116         }
117         return nil
118 }
119
120 const (
121         // TODO: this const is only used by env_config now. But could be useful for
122         // other config. Move to binarylog.go if necessary.
123         maxUInt = ^uint64(0)
124
125         // For "p.s/m" plus any suffix. Suffix will be parsed again. See test for
126         // expected output.
127         longMethodConfigRegexpStr = `^([\w./]+)/((?:\w+)|[*])(.+)?$`
128
129         // For suffix from above, "{h:123,m:123}". See test for expected output.
130         optionalLengthRegexpStr      = `(?::(\d+))?` // Optional ":123".
131         headerConfigRegexpStr        = `^{h` + optionalLengthRegexpStr + `}$`
132         messageConfigRegexpStr       = `^{m` + optionalLengthRegexpStr + `}$`
133         headerMessageConfigRegexpStr = `^{h` + optionalLengthRegexpStr + `;m` + optionalLengthRegexpStr + `}$`
134 )
135
136 var (
137         longMethodConfigRegexp    = regexp.MustCompile(longMethodConfigRegexpStr)
138         headerConfigRegexp        = regexp.MustCompile(headerConfigRegexpStr)
139         messageConfigRegexp       = regexp.MustCompile(messageConfigRegexpStr)
140         headerMessageConfigRegexp = regexp.MustCompile(headerMessageConfigRegexpStr)
141 )
142
143 // Turn "service/method{h;m}" into "service", "method", "{h;m}".
144 func parseMethodConfigAndSuffix(c string) (service, method, suffix string, _ error) {
145         // Regexp result:
146         //
147         // in:  "p.s/m{h:123,m:123}",
148         // out: []string{"p.s/m{h:123,m:123}", "p.s", "m", "{h:123,m:123}"},
149         match := longMethodConfigRegexp.FindStringSubmatch(c)
150         if match == nil {
151                 return "", "", "", fmt.Errorf("%q contains invalid substring", c)
152         }
153         service = match[1]
154         method = match[2]
155         suffix = match[3]
156         return
157 }
158
159 // Turn "{h:123;m:345}" into 123, 345.
160 //
161 // Return maxUInt if length is unspecified.
162 func parseHeaderMessageLengthConfig(c string) (hdrLenStr, msgLenStr uint64, err error) {
163         if c == "" {
164                 return maxUInt, maxUInt, nil
165         }
166         // Header config only.
167         if match := headerConfigRegexp.FindStringSubmatch(c); match != nil {
168                 if s := match[1]; s != "" {
169                         hdrLenStr, err = strconv.ParseUint(s, 10, 64)
170                         if err != nil {
171                                 return 0, 0, fmt.Errorf("failed to convert %q to uint", s)
172                         }
173                         return hdrLenStr, 0, nil
174                 }
175                 return maxUInt, 0, nil
176         }
177
178         // Message config only.
179         if match := messageConfigRegexp.FindStringSubmatch(c); match != nil {
180                 if s := match[1]; s != "" {
181                         msgLenStr, err = strconv.ParseUint(s, 10, 64)
182                         if err != nil {
183                                 return 0, 0, fmt.Errorf("failed to convert %q to uint", s)
184                         }
185                         return 0, msgLenStr, nil
186                 }
187                 return 0, maxUInt, nil
188         }
189
190         // Header and message config both.
191         if match := headerMessageConfigRegexp.FindStringSubmatch(c); match != nil {
192                 // Both hdr and msg are specified, but one or two of them might be empty.
193                 hdrLenStr = maxUInt
194                 msgLenStr = maxUInt
195                 if s := match[1]; s != "" {
196                         hdrLenStr, err = strconv.ParseUint(s, 10, 64)
197                         if err != nil {
198                                 return 0, 0, fmt.Errorf("failed to convert %q to uint", s)
199                         }
200                 }
201                 if s := match[2]; s != "" {
202                         msgLenStr, err = strconv.ParseUint(s, 10, 64)
203                         if err != nil {
204                                 return 0, 0, fmt.Errorf("failed to convert %q to uint", s)
205                         }
206                 }
207                 return hdrLenStr, msgLenStr, nil
208         }
209         return 0, 0, fmt.Errorf("%q contains invalid substring", c)
210 }