go.uber.org/yarpc@v1.72.1/config.go (about) 1 // Copyright (c) 2022 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package yarpc 22 23 import ( 24 "context" 25 "time" 26 27 opentracing "github.com/opentracing/opentracing-go" 28 "github.com/uber-go/tally" 29 "go.uber.org/net/metrics" 30 "go.uber.org/net/metrics/tallypush" 31 "go.uber.org/yarpc/api/middleware" 32 "go.uber.org/yarpc/internal/observability" 33 "go.uber.org/zap" 34 "go.uber.org/zap/zapcore" 35 ) 36 37 const ( 38 // Sleep between pushes to Tally metrics. At some point, we may want this 39 // to be configurable. 40 _tallyPushInterval = 500 * time.Millisecond 41 _packageName = "yarpc" 42 ) 43 44 // DirectionalLogLevelConfig may override the log levels for any combination of 45 // successes, failures, and application errors. 46 type DirectionalLogLevelConfig struct { 47 // Level at which successful requests are logged. 48 // Defaults to DebugLevel. 49 Success *zapcore.Level 50 // Level at which errors are logged. 51 // Thrift exceptions are application errors, which we log as a separate 52 // class from success and failure. 53 // Deprecated in favor of ServerError and ClientError. 54 Failure *zapcore.Level 55 // Level at which application errors are logged. 56 // All Thrift exceptions are considered application errors. 57 // All errors from Protobuf handlers are application errors. 58 // Defaults to ErrorLevel. 59 // Deprecated in favor of ServerError and ClientError. 60 ApplicationError *zapcore.Level 61 // Level at which client errors are logged. 62 // All Thrift exceptions are considered application errors if 63 // they are not annotated with the option rpc.code. 64 // Defaults to ErrorLevel. 65 ClientError *zapcore.Level 66 // Level at which server errors are logged. 67 // Defaults to ErrorLevel. 68 ServerError *zapcore.Level 69 } 70 71 // LogLevelConfig configures the levels at which YARPC logs various things. 72 type LogLevelConfig struct { 73 // Level at which successful requests are logged. 74 // Defaults to DebugLevel. 75 // Can be overridden by Inbound.Success or Outbound.Success for inbound or 76 // outbound requests. 77 Success *zapcore.Level 78 // Level at which errors are logged. 79 // Thrift exceptions are application errors, which we log as a separate 80 // class from success and failure. 81 // Can be overridden by Inbound.Failure or Outbound.Failure for inbound or 82 // outbound requests. 83 // Deprecated in favor of ServerError and ClientError. 84 Failure *zapcore.Level 85 // Level at which application errors are logged. 86 // All Thrift exceptions are considered application errors. 87 // Defaults to ErrorLevel. 88 // Can be overridden by Inbound.ApplicationError or 89 // Outbound.ApplicationError for inbound or outbound requests. 90 // Deprecated in favor of ServerError and ClientError. 91 ApplicationError *zapcore.Level 92 // Level at which client errors are logged. 93 // All Thrift exceptions are considered application errors if 94 // they are not annotated with the option rpc.code. 95 // Defaults to ErrorLevel. 96 // Can be overridden by Inbound.ApplicationError or 97 // Outbound.ApplicationError for inbound or outbound requests. 98 ClientError *zapcore.Level 99 // Level at which server errors are logged. 100 // Defaults to ErrorLevel. 101 // Can be overridden by Inbound.ApplicationError or 102 // Outbound.ApplicationError for inbound or outbound requests. 103 ServerError *zapcore.Level 104 // Specific overrides for inbound and outbound requests. 105 Inbound, Outbound DirectionalLogLevelConfig 106 } 107 108 // LoggingConfig describes how logging should be configured. 109 type LoggingConfig struct { 110 // Supplies a logger for the dispatcher. By default, no logs are 111 // emitted. 112 Zap *zap.Logger 113 114 // If supplied, ExtractContext is used to log request-scoped 115 // information carried on the context (e.g., trace and span IDs). 116 ContextExtractor func(context.Context) zapcore.Field 117 118 // Levels configures the levels at which YARPC logs various messages. 119 Levels LogLevelConfig 120 } 121 122 func (c LoggingConfig) logger(name string) *zap.Logger { 123 if c.Zap == nil { 124 return zap.NewNop() 125 } 126 return c.Zap.Named(_packageName).With( 127 // Use a namespace to prevent key collisions with other libraries. 128 zap.Namespace(_packageName), 129 zap.String("dispatcher", name), 130 ) 131 } 132 133 func (c LoggingConfig) extractor() observability.ContextExtractor { 134 if c.ContextExtractor == nil { 135 return observability.NewNopContextExtractor() 136 } 137 return observability.ContextExtractor(c.ContextExtractor) 138 } 139 140 // MetricsConfig describes how telemetry should be configured. 141 // Scope and Tally are exclusive; choose one. 142 // If neither is present, metrics are not recorded, all instrumentation becomes 143 // no-ops. 144 // If both are present, we emit a warning and ignore Tally. 145 // If a metrics scope is preseent, we use that scope to record metrics and they 146 // are not pushed to Tally. 147 // If Tally is present, we use its metrics scope and push them periodically. 148 type MetricsConfig struct { 149 // Metrics is a *"go.uber.org/net/metrics".Scope for recording stats. 150 // YARPC does not push these metrics; pushing metrics from the root is an 151 // external concern. 152 Metrics *metrics.Scope 153 // Tally scope used for pushing to M3 or StatsD-based systems. By 154 // default, metrics are collected in memory but not pushed. 155 // TODO deprecate this option for metrics configuration. 156 Tally tally.Scope 157 // TagsBlocklist enlists tags' keys that should be suppressed from all the metrics 158 // emitted from w/in YARPC middleware. 159 TagsBlocklist []string 160 } 161 162 func (c MetricsConfig) scope(name string, logger *zap.Logger) (*metrics.Scope, context.CancelFunc) { 163 // Neither: no-op metrics, not pushed 164 if c.Metrics == nil && c.Tally == nil { 165 return nil, func() {} 166 } 167 168 // Both: ignore Tally and warn. 169 if c.Metrics != nil && c.Tally != nil { 170 logger.Warn("yarpc.NewDispatcher expects only one of Metrics.Tally or Metrics.Scope. " + 171 "To push to Tally, either use a Metrics.Scope and use tallypush, or just pass a Tally Scope") 172 c.Tally = nil 173 } 174 175 // Hereafter: We have one of either c.Metrics or c.Tally exclusively. 176 177 var root *metrics.Root // For pushing, if present 178 var parent *metrics.Scope // For measuring 179 180 if c.Metrics != nil { 181 // root remains nil 182 parent = c.Metrics 183 } else { // c.Tally != nil 184 root = metrics.New() 185 parent = root.Scope() 186 } 187 188 meter := parent.Tagged(metrics.Tags{ 189 "component": _packageName, 190 "dispatcher": name, 191 }) 192 193 // When we have c.Metrics, we do not push 194 if root == nil { 195 return meter, func() {} 196 } 197 198 // When we have c.Tally, we measure *and* push 199 stopMeter, err := root.Push(tallypush.New(c.Tally), _tallyPushInterval) 200 if err != nil { 201 logger.Error("Failed to start pushing metrics to Tally.", zap.Error(err)) 202 return meter, func() {} 203 } 204 return meter, stopMeter 205 } 206 207 // Config specifies the parameters of a new Dispatcher constructed via 208 // NewDispatcher. 209 type Config struct { 210 // Name of the service. This is the name used by other services when 211 // making requests to this service. 212 Name string 213 214 // Inbounds define how this service receives incoming requests from other 215 // services. 216 // 217 // This may be nil if this service does not receive any requests. 218 Inbounds Inbounds 219 220 // Outbounds defines how this service makes requests to other services. 221 // 222 // This may be nil if this service does not send any requests. 223 Outbounds Outbounds 224 225 // Inbound and Outbound Middleware that will be applied to all incoming 226 // and outgoing requests respectively. 227 // 228 // These may be nil if there is no middleware to apply. 229 InboundMiddleware InboundMiddleware 230 OutboundMiddleware OutboundMiddleware 231 232 // Tracer is meant to add/record tracing information to a request. 233 // 234 // Deprecated: The dispatcher does nothing with this property. Set the 235 // tracer directly on the transports used to build inbounds and outbounds. 236 Tracer opentracing.Tracer 237 238 // RouterMiddleware is middleware to control how requests are routed. 239 RouterMiddleware middleware.Router 240 241 // Configures logging. 242 Logging LoggingConfig 243 244 // Configures telemetry. 245 Metrics MetricsConfig 246 247 // DisableAutoObservabilityMiddleware is used to stop the dispatcher from 248 // automatically attaching observability middleware to all inbounds and 249 // outbounds. It is the assumption that if if this option is disabled the 250 // observability middleware is being inserted in the Inbound/Outbound 251 // Middleware. 252 DisableAutoObservabilityMiddleware bool 253 }