env_config.go 6.6 KB

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