You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@thrift.apache.org by GitBox <gi...@apache.org> on 2020/10/08 10:29:58 UTC

[GitHub] [thrift] voodoo-dn edited a comment on pull request #1992: THRIFT-5073: Optional handler interceptor for processor

voodoo-dn edited a comment on pull request #1992:
URL: https://github.com/apache/thrift/pull/1992#issuecomment-705480455


   @fishy Hi. Every our Golang project in our company uses Thrift Fork with interceptor. They allow us following features:
   
   - Catch panic and return TApplicationException instead of EOF
   - Log incoming/outgoing request/response
   - Tracing
   - Catch and log error
   - Collect metrics for Prometheus
   - Whatever what you want :)
   
   ```
   func NewLoggerInterceptor(logger *logging.Logger, serviceName string) thrift.HandlerInterceptor {
   	return func(ctx context.Context, methodName string, arg interface{}, handlerFunc thrift.HandlerFunc) (result interface{}, err error) {
   		defer func() {
   			if err := recover(); err != nil {
   				log(
   					ctx,
   					logger,
   					serviceName,
   					methodName,
   					"panicked thrift request",
   					map[string]interface{}{
   						"args": maskArg(ctx, logger, arg),
   					},
   				)
   
   				panic(err)
   			}
   		}()
   
   		handlerResult, handlerError := handlerFunc(ctx, arg)
   
   		handlerResultData, handlerResultMarshalErr := json.Marshal(handlerResult)
   		if handlerResultMarshalErr != nil {
   			logger.Error(ctx, handlerResultMarshalErr)
   		}
   
   		log(
   			ctx,
   			logger,
   			serviceName,
   			methodName,
   			"thrift request",
   			map[string]interface{}{
   				"args":   maskArg(ctx, logger, arg),
   				"result": string(handlerResultData),
   			},
   		)
   
   		return handlerResult, handlerError
   	}
   }
   
   func NewPanicInterceptor(logger *logging.Logger) thrift.HandlerInterceptor {
   	return func(ctx context.Context, methodName string, arg interface{}, handlerFunc thrift.HandlerFunc) (result interface{}, err error) {
   		defer func() {
   			if rec := recover(); rec != nil {
   				logger.Error(ctx, errors.New(fmt.Sprint(rec)))
   
   				err = thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal server error")
   			}
   		}()
   
   		return handlerFunc(ctx, arg)
   	}
   }
   
   func NewTracingInterceptor(
   	tracer opentracing.Tracer,
   	parentSpan opentracing.Span,
   	serviceName string,
   ) thrift.HandlerInterceptor {
   	return func(ctx context.Context, methodName string, arg interface{}, handlerFunc thrift.HandlerFunc) (interface{}, error) {
   		span := tracer.StartSpan(
   			fmt.Sprintf("%s:%s", serviceName, methodName),
   			opentracing.ChildOf(parentSpan.Context()),
   		)
   		defer span.Finish()
   		ctx = opentracing.ContextWithSpan(ctx, span)
   		var correlationID string
   		if span, ok := span.(*jaeger.Span); ok {
   			correlationID = span.SpanContext().TraceID().String()
   			ctx = processor.WithCorrelationID(ctx, correlationID)
   		}
   
   		result, err := handlerFunc(ctx, arg)
   		if err != nil {
   			span.SetTag("error", true)
   		}
   
   		return result, err
   	}
   }
   
   // Wrap all errors with UnexpectedError except api errors that implement thrift.TStruct
   func NewErrorInterceptor(serviceName string, logger *logging.Logger) thrift.HandlerInterceptor {
   	return func(ctx context.Context, methodName string, arg interface{}, handlerFunc thrift.HandlerFunc) (interface{}, error) {
   		result, err := handlerFunc(ctx, arg)
   		if err == nil {
   			return result, nil
   		}
   
   		logger = logger.WithFields(logging.Fields{
   			"service": serviceName,
   			"method":  methodName,
   			"request": maskArg(ctx, logger, arg),
   		})
   
   		if _, ok := err.(thrift.TStruct); ok {
   			logger.Info(ctx, err)
   		} else {
   			logger.Error(ctx, err)
   			err = NewUnexpectedError(err)
   		}
   
   		return result, err
   	}
   }
   
   func NewServerInterceptor(
   	metricsCollector MetricsCollector,
   	serviceName string,
   	options ...InterceptorOption,
   ) thrift.HandlerInterceptor {
   	interceptorOptions := evaluateInterceptorOptions(options)
   
   	return func(
   		ctx context.Context,
   		methodName string,
   		arg interface{},
   		handlerFunc thrift.HandlerFunc,
   	) (result interface{}, err error) {
   		if interceptorOptions.filterFunc != nil && !interceptorOptions.filterFunc(serviceName, methodName) {
   			return handlerFunc(ctx, arg)
   		}
   
   		metricsCollector.IncCall(serviceName, methodName)
   
   		startTime := time.Now()
   		success, err := handlerFunc(ctx, arg)
   		if err != nil {
   			if interceptorOptions.errorTrackFunc == nil || interceptorOptions.errorTrackFunc(serviceName, methodName, err) {
   				metricsCollector.IncError(serviceName, methodName)
   			}
   		}
   
   		metricsCollector.ObserveProcessingTime(serviceName, methodName, time.Since(startTime))
   
   		return success, err
   	}
   }
   ```


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org