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
|
|
}
|