github.com/anjalikarhana/fabric@v2.1.1+incompatible/common/grpcmetrics/interceptor.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package grpcmetrics
     8  
     9  import (
    10  	"context"
    11  	"strings"
    12  	"time"
    13  
    14  	"github.com/hyperledger/fabric/common/metrics"
    15  	"google.golang.org/grpc"
    16  	"google.golang.org/grpc/status"
    17  )
    18  
    19  type UnaryMetrics struct {
    20  	RequestDuration   metrics.Histogram
    21  	RequestsReceived  metrics.Counter
    22  	RequestsCompleted metrics.Counter
    23  }
    24  
    25  func UnaryServerInterceptor(um *UnaryMetrics) grpc.UnaryServerInterceptor {
    26  	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    27  		service, method := serviceMethod(info.FullMethod)
    28  		um.RequestsReceived.With("service", service, "method", method).Add(1)
    29  
    30  		startTime := time.Now()
    31  		resp, err := handler(ctx, req)
    32  		st, _ := status.FromError(err)
    33  		duration := time.Since(startTime)
    34  
    35  		um.RequestDuration.With(
    36  			"service", service, "method", method, "code", st.Code().String(),
    37  		).Observe(duration.Seconds())
    38  		um.RequestsCompleted.With("service", service, "method", method, "code", st.Code().String()).Add(1)
    39  
    40  		return resp, err
    41  	}
    42  }
    43  
    44  type StreamMetrics struct {
    45  	RequestDuration   metrics.Histogram
    46  	RequestsReceived  metrics.Counter
    47  	RequestsCompleted metrics.Counter
    48  	MessagesSent      metrics.Counter
    49  	MessagesReceived  metrics.Counter
    50  }
    51  
    52  func StreamServerInterceptor(sm *StreamMetrics) grpc.StreamServerInterceptor {
    53  	return func(svc interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
    54  		sm := sm
    55  		service, method := serviceMethod(info.FullMethod)
    56  		sm.RequestsReceived.With("service", service, "method", method).Add(1)
    57  
    58  		wrappedStream := &serverStream{
    59  			ServerStream:     stream,
    60  			messagesSent:     sm.MessagesSent.With("service", service, "method", method),
    61  			messagesReceived: sm.MessagesReceived.With("service", service, "method", method),
    62  		}
    63  
    64  		startTime := time.Now()
    65  		err := handler(svc, wrappedStream)
    66  		st, _ := status.FromError(err)
    67  		duration := time.Since(startTime)
    68  
    69  		sm.RequestDuration.With(
    70  			"service", service, "method", method, "code", st.Code().String(),
    71  		).Observe(duration.Seconds())
    72  		sm.RequestsCompleted.With("service", service, "method", method, "code", st.Code().String()).Add(1)
    73  
    74  		return err
    75  	}
    76  }
    77  
    78  func serviceMethod(fullMethod string) (service, method string) {
    79  	normalizedMethod := strings.Replace(fullMethod, ".", "_", -1)
    80  	parts := strings.SplitN(normalizedMethod, "/", -1)
    81  	if len(parts) != 3 {
    82  		return "unknown", "unknown"
    83  	}
    84  	return parts[1], parts[2]
    85  }
    86  
    87  type serverStream struct {
    88  	grpc.ServerStream
    89  	messagesSent     metrics.Counter
    90  	messagesReceived metrics.Counter
    91  }
    92  
    93  func (ss *serverStream) SendMsg(msg interface{}) error {
    94  	ss.messagesSent.Add(1)
    95  	return ss.ServerStream.SendMsg(msg)
    96  }
    97  
    98  func (ss *serverStream) RecvMsg(msg interface{}) error {
    99  	err := ss.ServerStream.RecvMsg(msg)
   100  	if err == nil {
   101  		ss.messagesReceived.Add(1)
   102  	}
   103  	return err
   104  }