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 } // TODO: This probably needs to pass back an error chan and a shutdown // func like the http server does func InitGRPCServer(ctx context.Context, opts *opts.GRPCOpts) 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), } 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 err } // Load span with server info span.SetAttributes(appGRPC.getServerAttributes()...) // Run, returning a shutdown func and an error chan // TODO: Implement shutdown func and error chan err := appGRPC.runGRPCServer(ctx) if err != nil { span.RecordError(err) span.SetStatus(codes.Error, "failed to start GRPC Server") return err } span.SetStatus(codes.Ok, "") return 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 }