96 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package grpc
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/rs/zerolog"
 | |
| 	"go.opentelemetry.io/otel/attribute"
 | |
| 	"go.opentelemetry.io/otel/codes"
 | |
| 	"go.opentelemetry.io/otel/metric"
 | |
| 	"go.opentelemetry.io/otel/trace"
 | |
| 	"google.golang.org/grpc"
 | |
| 
 | |
| 	appotel "gitea.libretechconsulting.com/rmcguire/go-app/pkg/otel"
 | |
| 	"gitea.libretechconsulting.com/rmcguire/go-app/pkg/srv/grpc/opts"
 | |
| )
 | |
| 
 | |
| type appGRPCServer struct {
 | |
| 	ctx          context.Context
 | |
| 	tracer       trace.Tracer
 | |
| 	meter        metric.Meter
 | |
| 	opts         *opts.GRPCOpts
 | |
| 	serverOpts   []grpc.ServerOption
 | |
| 	logger       *zerolog.Logger
 | |
| 	server       *grpc.Server
 | |
| 	shutdownFunc func(context.Context) error
 | |
| 	doneChan     chan error
 | |
| }
 | |
| 
 | |
| // Returns a shutdown func, a channel indicating done / error,
 | |
| // and an up-front error if server fails to start
 | |
| func InitGRPCServer(ctx context.Context, opts *opts.GRPCOpts) (
 | |
| 	func(context.Context) error, <-chan error, error,
 | |
| ) {
 | |
| 	appGRPC := &appGRPCServer{
 | |
| 		ctx:        ctx,
 | |
| 		tracer:     appotel.GetTracer(ctx, "grpc"),
 | |
| 		meter:      appotel.GetMeter(ctx, "grpc"),
 | |
| 		opts:       opts,
 | |
| 		serverOpts: make([]grpc.ServerOption, 0),
 | |
| 		logger:     zerolog.Ctx(ctx),
 | |
| 		doneChan:   make(chan error),
 | |
| 	}
 | |
| 
 | |
| 	ctx, span := appGRPC.tracer.Start(ctx, "appgrpc.init")
 | |
| 	defer span.End()
 | |
| 
 | |
| 	// Prepare grpc.Server for use
 | |
| 	if err := appGRPC.prepGRPCServer(ctx); err != nil {
 | |
| 		span.RecordError(err)
 | |
| 		span.SetStatus(codes.Error, "failed to prepare GRPC Server")
 | |
| 		return nil, nil, err
 | |
| 	}
 | |
| 
 | |
| 	// Load span with server info
 | |
| 	span.SetAttributes(appGRPC.getServerAttributes()...)
 | |
| 
 | |
| 	err := appGRPC.runGRPCServer(ctx)
 | |
| 	if err != nil {
 | |
| 		span.RecordError(err)
 | |
| 		span.SetStatus(codes.Error, "failed to start GRPC Server")
 | |
| 		return nil, nil, err
 | |
| 	}
 | |
| 
 | |
| 	span.SetStatus(codes.Ok, "")
 | |
| 	return appGRPC.shutdownFunc, appGRPC.doneChan, nil
 | |
| }
 | |
| 
 | |
| // Convert grpc.ServiceInfo map to []attribute.KeyValue
 | |
| func (a *appGRPCServer) getServerAttributes() []attribute.KeyValue {
 | |
| 	var attrs []attribute.KeyValue
 | |
| 
 | |
| 	for serviceName, info := range a.server.GetServiceInfo() {
 | |
| 		// Add the service name
 | |
| 		attrs = append(attrs, attribute.String("grpc.service", serviceName))
 | |
| 
 | |
| 		// Convert methods into a comma-separated string
 | |
| 		var methods []string
 | |
| 		for _, method := range info.Methods {
 | |
| 			methods = append(methods, method.Name)
 | |
| 		}
 | |
| 
 | |
| 		// Add methods if present
 | |
| 		if len(methods) > 0 {
 | |
| 			attrs = append(attrs, attribute.String("grpc.service.methods", strings.Join(methods, ",")))
 | |
| 		}
 | |
| 
 | |
| 		// If metadata is a string, store it
 | |
| 		if metadata, ok := info.Metadata.(string); ok && metadata != "" {
 | |
| 			attrs = append(attrs, attribute.String("grpc.service.metadata", metadata))
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return attrs
 | |
| }
 |