code: func UnaryServerInterceptor(entry *logrus.Entry, opts ...Option) grpc.UnaryServerInterceptor {
  	o := evaluateServerOpt(opts)
  	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
  		startTime := time.Now()
  		newCtx := newLoggerForCall(ctx, entry, info.FullMethod, startTime)
  
  		resp, err := handler(newCtx, req)
  
  		if !o.shouldLog(info.FullMethod, err) {
  			return resp, err
  		}
  		code := o.codeFunc(err)
  		level := o.levelFunc(code)
  		durField, durVal := o.durationFunc(time.Since(startTime))
  		fields := logrus.Fields{
  			"grpc.code": code.String(),
  			durField:    durVal,
  		}
  		if err != nil {
  			fields[logrus.ErrorKey] = err
  		}
  
  		levelLogf(
  			ctx_logrus.Extract(newCtx).WithFields(fields), // re-extract logger from newCtx, as it may have extra fields that changed in the holder.
  			level,
  			"finished unary call with code "+code.String())
  
  		return resp, err
  	}
  }
docs: // UnaryServerInterceptor returns a new unary server interceptors that adds logrus.Entry to the context.