New returns a new RPC server with a set of middlewares. The given context is used in some of the middlewares, the given server options are passed to gRPC Currently the following middlewares are included: tag extraction, metrics, logging, sending errors to Sentry, validation, errors, panic recovery
(ctx context.Context, opts ...Option)
| 165 | // Currently the following middlewares are included: tag extraction, metrics, |
| 166 | // logging, sending errors to Sentry, validation, errors, panic recovery |
| 167 | func New(ctx context.Context, opts ...Option) *Server { |
| 168 | options := new(options) |
| 169 | options.limiter = &ratelimit.NoopRateLimiter{} |
| 170 | for _, opt := range opts { |
| 171 | opt(options) |
| 172 | } |
| 173 | |
| 174 | server := &Server{ctx: ctx, Hooks: &hooks.Hooks{}} |
| 175 | |
| 176 | statsHandler := rpcmiddleware.StatsHandlers{ |
| 177 | otelgrpc.NewServerHandler( |
| 178 | otelgrpc.WithTracerProvider(tracing.FromContext(ctx)), |
| 179 | // As pkg/metrics is currently Prometheus based, the OpenTelemetry metrics are unused. |
| 180 | // TODO: https://github.com/TheThingsNetwork/lorawan-stack/issues/5692. |
| 181 | otelgrpc.WithMeterProvider(noop.MeterProvider{}), |
| 182 | ), |
| 183 | metrics.StatsHandler, |
| 184 | } |
| 185 | |
| 186 | ctxtagsOpts := []grpc_ctxtags.Option{ |
| 187 | grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor), |
| 188 | } |
| 189 | var proxyHeaders rpcmiddleware.ProxyHeaders |
| 190 | proxyHeaders.ParseAndAddTrusted(options.trustedProxies...) |
| 191 | recoveryOpts := []grpc_recovery.Option{ |
| 192 | grpc_recovery.WithRecoveryHandler(func(p any) (err error) { |
| 193 | fmt.Fprintln(os.Stderr, p) |
| 194 | os.Stderr.Write(debug.Stack()) |
| 195 | if pErr, ok := p.(error); ok { |
| 196 | err = ErrRPCRecovered.WithCause(pErr) |
| 197 | } else { |
| 198 | err = ErrRPCRecovered.WithAttributes("panic", p) |
| 199 | } |
| 200 | return err |
| 201 | }), |
| 202 | } |
| 203 | |
| 204 | streamInterceptors := []grpc.StreamServerInterceptor{ |
| 205 | rpcfillcontext.StreamServerInterceptor(options.contextFillers...), |
| 206 | grpc_ctxtags.StreamServerInterceptor(ctxtagsOpts...), |
| 207 | rpcmiddleware.RequestIDStreamServerInterceptor(), |
| 208 | proxyHeaders.StreamServerInterceptor(), |
| 209 | events.StreamServerInterceptor(options.correlationIDsIgnoreMethods), |
| 210 | rpclog.StreamServerInterceptor(ctx, rpclog.WithIgnoreMethods(options.logIgnoreMethods)), |
| 211 | metrics.StreamServerInterceptor, |
| 212 | errors.StreamServerInterceptor(), |
| 213 | // NOTE: All middleware that works with lorawan-stack/pkg/errors errors must be placed below. |
| 214 | sentrymiddleware.StreamServerInterceptor(), |
| 215 | grpc_recovery.StreamServerInterceptor(recoveryOpts...), |
| 216 | validator.StreamServerInterceptor(), |
| 217 | ratelimit.StreamServerInterceptor(options.limiter), |
| 218 | server.Hooks.StreamServerInterceptor(), |
| 219 | } |
| 220 | |
| 221 | unaryInterceptors := []grpc.UnaryServerInterceptor{ |
| 222 | rpcfillcontext.UnaryServerInterceptor(options.contextFillers...), |
| 223 | grpc_ctxtags.UnaryServerInterceptor(ctxtagsOpts...), |
| 224 | rpcmiddleware.RequestIDUnaryServerInterceptor(), |