add grpc support

This commit is contained in:
Ryan McGuire 2025-03-07 11:44:50 -05:00
parent 5aa5dda111
commit 98fba4eac8
4 changed files with 57 additions and 11 deletions

View File

@ -22,7 +22,7 @@ import (
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource"
traceSDK "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
semconv "go.opentelemetry.io/otel/semconv/v1.27.0"
trace "go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/noop"
)
@ -170,7 +170,7 @@ func newResource(ctx context.Context) *resource.Resource {
attributes := []attribute.KeyValue{
semconv.ServiceName(cfg.Name),
semconv.ServiceVersion(cfg.Version),
semconv.DeploymentEnvironment(cfg.Environment),
semconv.DeploymentEnvironmentName(cfg.Environment),
semconv.K8SPodName(os.Getenv("HOSTNAME")),
}

View File

@ -2,8 +2,10 @@ 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"
@ -38,12 +40,18 @@ func InitGRPCServer(ctx context.Context, opts *opts.GRPCOpts) 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 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)
@ -54,3 +62,31 @@ func InitGRPCServer(ctx context.Context, opts *opts.GRPCOpts) error {
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
}

View File

@ -34,31 +34,31 @@ func (a *appGRPCServer) prepGRPCServer(spanCtx context.Context) error {
// Chain interceptors for unary RPCs
a.serverOpts = append(a.serverOpts,
grpc.ChainUnaryInterceptor(a.opts.UnaryInterceptors...))
span.SetAttributes(attribute.Int("numUnaryInterceptors",
span.SetAttributes(attribute.Int("grpc.server.unaryinterceptors",
len(a.opts.UnaryInterceptors)))
// Chain interceptors for streaming RPCs
a.serverOpts = append(a.serverOpts,
grpc.ChainStreamInterceptor(a.opts.StreamInterceptors...))
span.SetAttributes(attribute.Int("numStreamInterceptors",
span.SetAttributes(attribute.Int("grpc.server.streaminterceptors",
len(a.opts.StreamInterceptors)))
// Prepare GRPC Server
a.server = grpc.NewServer(a.serverOpts...)
span.SetAttributes(attribute.Int("numServerOpts", len(a.serverOpts)))
span.SetAttributes(attribute.Int("grpc.server.serveropts", len(a.serverOpts)))
// Load given services into server registry
for _, service := range a.opts.Services {
span.AddEvent(fmt.Sprintf("registered %s service", service.Name))
a.server.RegisterService(service.Type, service.Service)
}
span.SetAttributes(attribute.Int("numGRPCServices", len(a.opts.Services)))
span.SetAttributes(attribute.Int("grpc.server.grpcservices", len(a.opts.Services)))
// Enable reflection if desired
if a.opts.EnableReflection {
reflection.Register(a.server)
}
span.SetAttributes(attribute.Bool("reflectionEnabled", a.opts.EnableReflection))
span.SetAttributes(attribute.Bool("grpc.server.reflection", a.opts.EnableReflection))
span.SetStatus(codes.Ok, "")
return nil
@ -66,8 +66,7 @@ func (a *appGRPCServer) prepGRPCServer(spanCtx context.Context) error {
func (a *appGRPCServer) prepareOTEL(spanCtx context.Context) {
_, span := a.tracer.Start(spanCtx, "appgrpc.init.prepare.otel", trace.WithAttributes(
attribute.Bool("instrumentationEnabled", a.opts.EnableInstrumentation),
attribute.String("logLevel", a.logger.GetLevel().String())))
attribute.Bool("grpc.server.instrumented", a.opts.EnableInstrumentation)))
defer span.End()
if a.opts.EnableInstrumentation {
@ -83,7 +82,8 @@ func (a *appGRPCServer) prepareOTEL(spanCtx context.Context) {
func (a *appGRPCServer) prepareLogging(spanCtx context.Context) {
_, span := a.tracer.Start(spanCtx, "appgrpc.init.prepare.logging", trace.WithAttributes(
attribute.Bool("instrumentationEnabled", a.opts.LogRequests)))
attribute.Bool("grpc.server.instrumentated", a.opts.LogRequests),
attribute.String("grpc.server.loglevel", a.logger.GetLevel().String())))
defer span.End()
if a.opts.LogRequests {

View File

@ -1,11 +1,21 @@
package grpc
import "context"
import (
"context"
semconv "go.opentelemetry.io/otel/semconv/v1.27.0"
)
// TODO: Implement
func (a *appGRPCServer) runGRPCServer(spanCtx context.Context) error {
_, span := a.tracer.Start(spanCtx, "appgrpc.init.start")
defer span.End()
span.SetAttributes(
semconv.RPCSystemGRPC,
semconv.NetworkProtocolName("grpc"),
semconv.ServerAddress(a.opts.Listen),
)
return nil
}