Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions internal/ingest/conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,67 @@ func TestTraceSemanticConventionPriority(t *testing.T) {
}
}

func TestTraceRPCSemanticConventions(t *testing.T) {
for _, tc := range []struct {
name string
attrs map[string]string
service, method string
}{
{"old convention", map[string]string{"rpc.service": "oteldemo.CurrencyService", "rpc.method": "Convert"}, "oteldemo.CurrencyService", "Convert"},
{"grpc", map[string]string{"rpc.system.name": "grpc", "rpc.method": "oteldemo.CurrencyService/Convert"}, "oteldemo.CurrencyService", "Convert"},
{"deprecated grpc", map[string]string{"rpc.system": "grpc", "rpc.method": "oteldemo.CurrencyService/Convert"}, "oteldemo.CurrencyService", "Convert"},
{"connect rpc", map[string]string{"rpc.system.name": "connectrpc", "rpc.method": "oteldemo.CurrencyService/Convert"}, "oteldemo.CurrencyService", "Convert"},
{"connect rpc with deprecated system", map[string]string{"rpc.system.name": "connectrpc", "rpc.system": "connect_rpc", "rpc.method": "oteldemo.CurrencyService/Convert"}, "oteldemo.CurrencyService", "Convert"},
{"deprecated connect rpc", map[string]string{"rpc.system": "connect_rpc", "rpc.method": "oteldemo.CurrencyService/Convert"}, "oteldemo.CurrencyService", "Convert"},
{"jsonrpc", map[string]string{"rpc.system.name": "jsonrpc", "rpc.method": "textDocument/hover"}, "", "textDocument/hover"},
{"deprecated jsonrpc", map[string]string{"rpc.system": "jsonrpc", "rpc.method": "textDocument/hover"}, "", "textDocument/hover"},
{"unknown system", map[string]string{"rpc.system.name": "unknown", "rpc.method": "service/method"}, "", "service/method"},
{"deprecated unknown system", map[string]string{"rpc.system": "unknown", "rpc.method": "service/method"}, "", "service/method"},
{"no system", map[string]string{"rpc.method": "service/method"}, "", "service/method"},
{"current grpc wins", map[string]string{"rpc.system.name": "grpc", "rpc.system": "jsonrpc", "rpc.method": "service/method"}, "service", "method"},
{"current jsonrpc wins", map[string]string{"rpc.system.name": "jsonrpc", "rpc.system": "grpc", "rpc.method": "textDocument/hover"}, "", "textDocument/hover"},
{"explicit service with qualified method", map[string]string{"rpc.system.name": "grpc", "rpc.service": "CurrencyService", "rpc.method": "oteldemo.CurrencyService/Convert"}, "CurrencyService", "oteldemo.CurrencyService/Convert"},
{"method without slash", map[string]string{"rpc.method": "Convert"}, "", "Convert"},
{"last slash", map[string]string{"rpc.system.name": "grpc", "rpc.method": "package/CurrencyService/Convert"}, "package/CurrencyService", "Convert"},
{"trailing slash", map[string]string{"rpc.system.name": "grpc", "rpc.method": "oteldemo.CurrencyService/"}, "oteldemo.CurrencyService", ""},
{"leading slash", map[string]string{"rpc.system.name": "grpc", "rpc.method": "/Convert"}, "", "Convert"},
{"slash only", map[string]string{"rpc.system.name": "grpc", "rpc.method": "/"}, "", ""},
{"empty method", map[string]string{"rpc.method": ""}, "", ""},
{"empty service with qualified method", map[string]string{"rpc.system.name": "grpc", "rpc.service": "", "rpc.method": "oteldemo.CurrencyService/Convert"}, "", "oteldemo.CurrencyService/Convert"},
{"empty values", map[string]string{"rpc.service": "", "rpc.method": ""}, "", ""},
{"service only", map[string]string{"rpc.service": "CurrencyService"}, "CurrencyService", ""},
{"absent", nil, "", ""},
} {
t.Run(tc.name, func(t *testing.T) {
var attrs []*common.KeyValue
for k, v := range tc.attrs {
attrs = append(attrs, &common.KeyValue{Key: k, Value: &common.AnyValue{Value: &common.AnyValue_StringValue{StringValue: v}}})
}
var got telemetrystore.Batch
srv := NewServer(config.Config{}, conversionSubmitter(func(_ context.Context, b telemetrystore.Batch) error { got = b; return nil }))
req := &collectortrace.ExportTraceServiceRequest{ResourceSpans: []*tracepb.ResourceSpans{{ScopeSpans: []*tracepb.ScopeSpans{{Spans: []*tracepb.Span{{Attributes: attrs}}}}}}}
if _, err := srv.exportTraces(t.Context(), req); err != nil {
t.Fatal(err)
}
if len(got.Spans) != 1 {
t.Fatalf("got %d spans, want 1", len(got.Spans))
}
span := got.Spans[0]
if span.RPCService != tc.service || span.RPCMethod != tc.method {
t.Fatalf("extracted service=%q method=%q, want service=%q method=%q", span.RPCService, span.RPCMethod, tc.service, tc.method)
}
if len(span.Attributes) != len(tc.attrs) {
t.Fatalf("raw attributes changed: got %v, want %v", span.Attributes, tc.attrs)
}
for k, v := range tc.attrs {
if span.Attributes[k] != v {
t.Errorf("raw attribute %q = %v, want %q", k, span.Attributes[k], v)
}
}
})
}
}

func BenchmarkExportConversion(b *testing.B) {
traces, logs, metrics := conversionExports(250)
srv := NewServer(config.Config{DefaultNamespace: "fallback"}, conversionSubmitter(func(context.Context, telemetrystore.Batch) error { return nil }))
Expand Down
8 changes: 8 additions & 0 deletions internal/ingest/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,14 @@ func (s *Server) exportTraces(ctx context.Context, req *collectortrace.ExportTra
ServiceVersion: serviceVersion,
DeploymentEnv: deploymentEnv,
}
// gRPC and Connect RPC (current and deprecated spellings) fold rpc.service into a qualified rpc.method.
if _, ok := attrs["rpc.service"]; !ok {
rpcSystem := spanAttr(sp.Attributes, "rpc.system.name", "rpc.system")
if i := strings.LastIndex(row.RPCMethod, "/"); i >= 0 && (rpcSystem == "grpc" || rpcSystem == "connectrpc" || rpcSystem == "connect_rpc") {
row.RPCService = row.RPCMethod[:i]
row.RPCMethod = row.RPCMethod[i+1:]
}
}
// Pre-extracted exception info from span events.
excType, excMsg := extractException(sp.Events)
row.ExceptionType = excType
Expand Down
Loading