diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d820ccf..a3bb4759 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Renamed `go.opentelemetry.io/otel/api/standard` package to `go.opentelemetry.io/otel/semconv` to avoid the ambiguous and generic name `standard` and better describe the package as containing OpenTelemetry semantic conventions. (#1016) +### Removed + +- The `grpctrace` instrumentation was moved to the `go.opentelemetry.io/contrib` repository and out of this repository. + This move includes moving the `grpc` example to the `go.opentelemetry.io/contrib` as well. (#1027) + ### Fixed - The `semconv.HTTPServerMetricAttributesFromHTTPRequest()` function no longer generates the high-cardinality `http.request.content.length` label. (#1031) diff --git a/example/grpc/README.md b/example/grpc/README.md deleted file mode 100644 index ff53b6cc..00000000 --- a/example/grpc/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# gRPC Tracing Example - -Traces client and server calls via interceptors. - -### Compile .proto - -Only required if the service definition (.proto) changes. - -```sh -cd ./example/grpc - -# protobuf v1.3.2 -protoc -I api --go_out=plugins=grpc,paths=source_relative:./api api/hello-service.proto -``` - -### Run server - -```sh -cd ./example/grpc - -go run ./server -``` - -### Run client - -```sh -go run ./client -``` \ No newline at end of file diff --git a/example/grpc/api/hello-service.pb.go b/example/grpc/api/hello-service.pb.go deleted file mode 100644 index e6ec648f..00000000 --- a/example/grpc/api/hello-service.pb.go +++ /dev/null @@ -1,354 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: hello-service.proto - -/* -Package api is a generated protocol buffer package. - -It is generated from these files: - hello-service.proto - -It has these top-level messages: - HelloRequest - HelloResponse -*/ -package api - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" - -import ( - context "golang.org/x/net/context" - grpc "google.golang.org/grpc" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type HelloRequest struct { - Greeting string `protobuf:"bytes,1,opt,name=greeting" json:"greeting,omitempty"` -} - -func (m *HelloRequest) Reset() { *m = HelloRequest{} } -func (m *HelloRequest) String() string { return proto.CompactTextString(m) } -func (*HelloRequest) ProtoMessage() {} -func (*HelloRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -func (m *HelloRequest) GetGreeting() string { - if m != nil { - return m.Greeting - } - return "" -} - -type HelloResponse struct { - Reply string `protobuf:"bytes,1,opt,name=reply" json:"reply,omitempty"` -} - -func (m *HelloResponse) Reset() { *m = HelloResponse{} } -func (m *HelloResponse) String() string { return proto.CompactTextString(m) } -func (*HelloResponse) ProtoMessage() {} -func (*HelloResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -func (m *HelloResponse) GetReply() string { - if m != nil { - return m.Reply - } - return "" -} - -func init() { - proto.RegisterType((*HelloRequest)(nil), "api.HelloRequest") - proto.RegisterType((*HelloResponse)(nil), "api.HelloResponse") -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// Client API for HelloService service - -type HelloServiceClient interface { - SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) - SayHelloServerStream(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (HelloService_SayHelloServerStreamClient, error) - SayHelloClientStream(ctx context.Context, opts ...grpc.CallOption) (HelloService_SayHelloClientStreamClient, error) - SayHelloBidiStream(ctx context.Context, opts ...grpc.CallOption) (HelloService_SayHelloBidiStreamClient, error) -} - -type helloServiceClient struct { - cc *grpc.ClientConn -} - -func NewHelloServiceClient(cc *grpc.ClientConn) HelloServiceClient { - return &helloServiceClient{cc} -} - -func (c *helloServiceClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) { - out := new(HelloResponse) - err := grpc.Invoke(ctx, "/api.HelloService/SayHello", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *helloServiceClient) SayHelloServerStream(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (HelloService_SayHelloServerStreamClient, error) { - stream, err := grpc.NewClientStream(ctx, &_HelloService_serviceDesc.Streams[0], c.cc, "/api.HelloService/SayHelloServerStream", opts...) - if err != nil { - return nil, err - } - x := &helloServiceSayHelloServerStreamClient{stream} - if err := x.ClientStream.SendMsg(in); err != nil { - return nil, err - } - if err := x.ClientStream.CloseSend(); err != nil { - return nil, err - } - return x, nil -} - -type HelloService_SayHelloServerStreamClient interface { - Recv() (*HelloResponse, error) - grpc.ClientStream -} - -type helloServiceSayHelloServerStreamClient struct { - grpc.ClientStream -} - -func (x *helloServiceSayHelloServerStreamClient) Recv() (*HelloResponse, error) { - m := new(HelloResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *helloServiceClient) SayHelloClientStream(ctx context.Context, opts ...grpc.CallOption) (HelloService_SayHelloClientStreamClient, error) { - stream, err := grpc.NewClientStream(ctx, &_HelloService_serviceDesc.Streams[1], c.cc, "/api.HelloService/SayHelloClientStream", opts...) - if err != nil { - return nil, err - } - x := &helloServiceSayHelloClientStreamClient{stream} - return x, nil -} - -type HelloService_SayHelloClientStreamClient interface { - Send(*HelloRequest) error - CloseAndRecv() (*HelloResponse, error) - grpc.ClientStream -} - -type helloServiceSayHelloClientStreamClient struct { - grpc.ClientStream -} - -func (x *helloServiceSayHelloClientStreamClient) Send(m *HelloRequest) error { - return x.ClientStream.SendMsg(m) -} - -func (x *helloServiceSayHelloClientStreamClient) CloseAndRecv() (*HelloResponse, error) { - if err := x.ClientStream.CloseSend(); err != nil { - return nil, err - } - m := new(HelloResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *helloServiceClient) SayHelloBidiStream(ctx context.Context, opts ...grpc.CallOption) (HelloService_SayHelloBidiStreamClient, error) { - stream, err := grpc.NewClientStream(ctx, &_HelloService_serviceDesc.Streams[2], c.cc, "/api.HelloService/SayHelloBidiStream", opts...) - if err != nil { - return nil, err - } - x := &helloServiceSayHelloBidiStreamClient{stream} - return x, nil -} - -type HelloService_SayHelloBidiStreamClient interface { - Send(*HelloRequest) error - Recv() (*HelloResponse, error) - grpc.ClientStream -} - -type helloServiceSayHelloBidiStreamClient struct { - grpc.ClientStream -} - -func (x *helloServiceSayHelloBidiStreamClient) Send(m *HelloRequest) error { - return x.ClientStream.SendMsg(m) -} - -func (x *helloServiceSayHelloBidiStreamClient) Recv() (*HelloResponse, error) { - m := new(HelloResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// Server API for HelloService service - -type HelloServiceServer interface { - SayHello(context.Context, *HelloRequest) (*HelloResponse, error) - SayHelloServerStream(*HelloRequest, HelloService_SayHelloServerStreamServer) error - SayHelloClientStream(HelloService_SayHelloClientStreamServer) error - SayHelloBidiStream(HelloService_SayHelloBidiStreamServer) error -} - -func RegisterHelloServiceServer(s *grpc.Server, srv HelloServiceServer) { - s.RegisterService(&_HelloService_serviceDesc, srv) -} - -func _HelloService_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(HelloRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(HelloServiceServer).SayHello(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/api.HelloService/SayHello", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(HelloServiceServer).SayHello(ctx, req.(*HelloRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _HelloService_SayHelloServerStream_Handler(srv interface{}, stream grpc.ServerStream) error { - m := new(HelloRequest) - if err := stream.RecvMsg(m); err != nil { - return err - } - return srv.(HelloServiceServer).SayHelloServerStream(m, &helloServiceSayHelloServerStreamServer{stream}) -} - -type HelloService_SayHelloServerStreamServer interface { - Send(*HelloResponse) error - grpc.ServerStream -} - -type helloServiceSayHelloServerStreamServer struct { - grpc.ServerStream -} - -func (x *helloServiceSayHelloServerStreamServer) Send(m *HelloResponse) error { - return x.ServerStream.SendMsg(m) -} - -func _HelloService_SayHelloClientStream_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(HelloServiceServer).SayHelloClientStream(&helloServiceSayHelloClientStreamServer{stream}) -} - -type HelloService_SayHelloClientStreamServer interface { - SendAndClose(*HelloResponse) error - Recv() (*HelloRequest, error) - grpc.ServerStream -} - -type helloServiceSayHelloClientStreamServer struct { - grpc.ServerStream -} - -func (x *helloServiceSayHelloClientStreamServer) SendAndClose(m *HelloResponse) error { - return x.ServerStream.SendMsg(m) -} - -func (x *helloServiceSayHelloClientStreamServer) Recv() (*HelloRequest, error) { - m := new(HelloRequest) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func _HelloService_SayHelloBidiStream_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(HelloServiceServer).SayHelloBidiStream(&helloServiceSayHelloBidiStreamServer{stream}) -} - -type HelloService_SayHelloBidiStreamServer interface { - Send(*HelloResponse) error - Recv() (*HelloRequest, error) - grpc.ServerStream -} - -type helloServiceSayHelloBidiStreamServer struct { - grpc.ServerStream -} - -func (x *helloServiceSayHelloBidiStreamServer) Send(m *HelloResponse) error { - return x.ServerStream.SendMsg(m) -} - -func (x *helloServiceSayHelloBidiStreamServer) Recv() (*HelloRequest, error) { - m := new(HelloRequest) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -var _HelloService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "api.HelloService", - HandlerType: (*HelloServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "SayHello", - Handler: _HelloService_SayHello_Handler, - }, - }, - Streams: []grpc.StreamDesc{ - { - StreamName: "SayHelloServerStream", - Handler: _HelloService_SayHelloServerStream_Handler, - ServerStreams: true, - }, - { - StreamName: "SayHelloClientStream", - Handler: _HelloService_SayHelloClientStream_Handler, - ClientStreams: true, - }, - { - StreamName: "SayHelloBidiStream", - Handler: _HelloService_SayHelloBidiStream_Handler, - ServerStreams: true, - ClientStreams: true, - }, - }, - Metadata: "hello-service.proto", -} - -func init() { proto.RegisterFile("hello-service.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 192 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xce, 0x48, 0xcd, 0xc9, - 0xc9, 0xd7, 0x2d, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, - 0x62, 0x4e, 0x2c, 0xc8, 0x54, 0xd2, 0xe2, 0xe2, 0xf1, 0x00, 0xc9, 0x05, 0xa5, 0x16, 0x96, 0xa6, - 0x16, 0x97, 0x08, 0x49, 0x71, 0x71, 0xa4, 0x17, 0xa5, 0xa6, 0x96, 0x64, 0xe6, 0xa5, 0x4b, 0x30, - 0x2a, 0x30, 0x6a, 0x70, 0x06, 0xc1, 0xf9, 0x4a, 0xaa, 0x5c, 0xbc, 0x50, 0xb5, 0xc5, 0x05, 0xf9, - 0x79, 0xc5, 0xa9, 0x42, 0x22, 0x5c, 0xac, 0x45, 0xa9, 0x05, 0x39, 0x95, 0x50, 0x95, 0x10, 0x8e, - 0x51, 0x0b, 0x13, 0xd4, 0xcc, 0x60, 0x88, 0x75, 0x42, 0x86, 0x5c, 0x1c, 0xc1, 0x89, 0x95, 0x60, - 0x21, 0x21, 0x41, 0xbd, 0xc4, 0x82, 0x4c, 0x3d, 0x64, 0x2b, 0xa5, 0x84, 0x90, 0x85, 0xa0, 0x26, - 0xdb, 0x73, 0x89, 0xc0, 0xb4, 0x80, 0x4c, 0x49, 0x2d, 0x0a, 0x2e, 0x29, 0x4a, 0x4d, 0xcc, 0x25, - 0x52, 0xbb, 0x01, 0x23, 0xb2, 0x01, 0xce, 0x39, 0x99, 0xa9, 0x79, 0x25, 0x24, 0x19, 0xa0, 0x01, - 0x32, 0x40, 0x08, 0x66, 0x80, 0x53, 0x66, 0x4a, 0x26, 0x89, 0xda, 0x0d, 0x18, 0x93, 0xd8, 0xc0, - 0xa1, 0x6c, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x0e, 0xd5, 0x1c, 0xd2, 0x7c, 0x01, 0x00, 0x00, -} diff --git a/example/grpc/api/hello-service.proto b/example/grpc/api/hello-service.proto deleted file mode 100644 index 69964512..00000000 --- a/example/grpc/api/hello-service.proto +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; -package api; - -service HelloService { - rpc SayHello (HelloRequest) returns (HelloResponse); - - rpc SayHelloServerStream (HelloRequest) returns (stream HelloResponse); - - rpc SayHelloClientStream (stream HelloRequest) returns (HelloResponse); - - rpc SayHelloBidiStream (stream HelloRequest) returns (stream HelloResponse); -} - -message HelloRequest { - string greeting = 1; -} - -message HelloResponse { - string reply = 1; -} diff --git a/example/grpc/client/main.go b/example/grpc/client/main.go deleted file mode 100644 index 12d07e60..00000000 --- a/example/grpc/client/main.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "io" - "log" - "time" - - "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/example/grpc/api" - "go.opentelemetry.io/otel/example/grpc/config" - "go.opentelemetry.io/otel/instrumentation/grpctrace" - - "google.golang.org/grpc" - "google.golang.org/grpc/metadata" -) - -func main() { - config.Init() - - var conn *grpc.ClientConn - conn, err := grpc.Dial(":7777", grpc.WithInsecure(), - grpc.WithUnaryInterceptor(grpctrace.UnaryClientInterceptor(global.Tracer(""))), - grpc.WithStreamInterceptor(grpctrace.StreamClientInterceptor(global.Tracer(""))), - ) - - if err != nil { - log.Fatalf("did not connect: %s", err) - } - defer func() { _ = conn.Close() }() - - c := api.NewHelloServiceClient(conn) - - callSayHello(c) - callSayHelloClientStream(c) - callSayHelloServerStream(c) - callSayHelloBidiStream(c) - - time.Sleep(10 * time.Millisecond) -} - -func callSayHello(c api.HelloServiceClient) { - md := metadata.Pairs( - "timestamp", time.Now().Format(time.StampNano), - "client-id", "web-api-client-us-east-1", - "user-id", "some-test-user-id", - ) - - ctx := metadata.NewOutgoingContext(context.Background(), md) - response, err := c.SayHello(ctx, &api.HelloRequest{Greeting: "World"}) - if err != nil { - log.Fatalf("Error when calling SayHello: %s", err) - } - log.Printf("Response from server: %s", response.Reply) -} - -func callSayHelloClientStream(c api.HelloServiceClient) { - md := metadata.Pairs( - "timestamp", time.Now().Format(time.StampNano), - "client-id", "web-api-client-us-east-1", - "user-id", "some-test-user-id", - ) - - ctx := metadata.NewOutgoingContext(context.Background(), md) - stream, err := c.SayHelloClientStream(ctx) - if err != nil { - log.Fatalf("Error when opening SayHelloClientStream: %s", err) - } - - for i := 0; i < 5; i++ { - err := stream.Send(&api.HelloRequest{Greeting: "World"}) - - time.Sleep(time.Duration(i*50) * time.Millisecond) - - if err != nil { - log.Fatalf("Error when sending to SayHelloClientStream: %s", err) - } - } - - response, err := stream.CloseAndRecv() - if err != nil { - log.Fatalf("Error when closing SayHelloClientStream: %s", err) - } - - log.Printf("Response from server: %s", response.Reply) -} - -func callSayHelloServerStream(c api.HelloServiceClient) { - md := metadata.Pairs( - "timestamp", time.Now().Format(time.StampNano), - "client-id", "web-api-client-us-east-1", - "user-id", "some-test-user-id", - ) - - ctx := metadata.NewOutgoingContext(context.Background(), md) - stream, err := c.SayHelloServerStream(ctx, &api.HelloRequest{Greeting: "World"}) - if err != nil { - log.Fatalf("Error when opening SayHelloServerStream: %s", err) - } - - for { - response, err := stream.Recv() - if err == io.EOF { - break - } else if err != nil { - log.Fatalf("Error when receiving from SayHelloServerStream: %s", err) - } - - log.Printf("Response from server: %s", response.Reply) - time.Sleep(50 * time.Millisecond) - } -} - -func callSayHelloBidiStream(c api.HelloServiceClient) { - md := metadata.Pairs( - "timestamp", time.Now().Format(time.StampNano), - "client-id", "web-api-client-us-east-1", - "user-id", "some-test-user-id", - ) - - ctx := metadata.NewOutgoingContext(context.Background(), md) - stream, err := c.SayHelloBidiStream(ctx) - if err != nil { - log.Fatalf("Error when opening SayHelloBidiStream: %s", err) - } - - serverClosed := make(chan struct{}) - clientClosed := make(chan struct{}) - - go func() { - for i := 0; i < 5; i++ { - err := stream.Send(&api.HelloRequest{Greeting: "World"}) - - if err != nil { - log.Fatalf("Error when sending to SayHelloBidiStream: %s", err) - } - - time.Sleep(50 * time.Millisecond) - } - - err := stream.CloseSend() - if err != nil { - log.Fatalf("Error when closing SayHelloBidiStream: %s", err) - } - - clientClosed <- struct{}{} - }() - - go func() { - for { - response, err := stream.Recv() - if err == io.EOF { - break - } else if err != nil { - log.Fatalf("Error when receiving from SayHelloBidiStream: %s", err) - } - - log.Printf("Response from server: %s", response.Reply) - time.Sleep(50 * time.Millisecond) - } - - serverClosed <- struct{}{} - }() - - // Wait until client and server both closed the connection. - <-clientClosed - <-serverClosed -} diff --git a/example/grpc/config/config.go b/example/grpc/config/config.go deleted file mode 100644 index 9c1034e7..00000000 --- a/example/grpc/config/config.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package config - -import ( - "log" - - "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/exporters/stdout" - sdktrace "go.opentelemetry.io/otel/sdk/trace" -) - -// Init configures an OpenTelemetry exporter and trace provider -func Init() { - exporter, err := stdout.NewExporter(stdout.WithPrettyPrint()) - if err != nil { - log.Fatal(err) - } - tp, err := sdktrace.NewProvider( - sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}), - sdktrace.WithSyncer(exporter), - ) - if err != nil { - log.Fatal(err) - } - global.SetTraceProvider(tp) -} diff --git a/example/grpc/go.mod b/example/grpc/go.mod deleted file mode 100644 index b57d90ea..00000000 --- a/example/grpc/go.mod +++ /dev/null @@ -1,18 +0,0 @@ -module go.opentelemetry.io/otel/example/grpc - -go 1.14 - -replace ( - go.opentelemetry.io/otel => ../.. - go.opentelemetry.io/otel/exporters/stdout => ../../exporters/stdout - go.opentelemetry.io/otel/sdk => ../../sdk -) - -require ( - github.com/golang/protobuf v1.4.2 - go.opentelemetry.io/otel v0.10.0 - go.opentelemetry.io/otel/exporters/stdout v0.10.0 - go.opentelemetry.io/otel/sdk v0.10.0 - golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 - google.golang.org/grpc v1.31.0 -) diff --git a/example/grpc/go.sum b/example/grpc/go.sum deleted file mode 100644 index 66c206c1..00000000 --- a/example/grpc/go.sum +++ /dev/null @@ -1,104 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/DataDog/sketches-go v0.0.1 h1:RtG+76WKgZuz6FIaGsjoPePmadDBkuD/KC6+ZWu78b8= -github.com/DataDog/sketches-go v0.0.1/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60= -github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg= -github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03 h1:4HYDjxeNXAOTv3o1N2tjo8UUSlhQgAD52FVkwxnWgM8= -google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/example/grpc/server/main.go b/example/grpc/server/main.go deleted file mode 100644 index 04e8a00e..00000000 --- a/example/grpc/server/main.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "fmt" - "io" - "log" - "net" - "time" - - "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/example/grpc/api" - "go.opentelemetry.io/otel/example/grpc/config" - "go.opentelemetry.io/otel/instrumentation/grpctrace" - - "google.golang.org/grpc" -) - -const ( - port = ":7777" -) - -// server is used to implement api.HelloServiceServer -type server struct { - api.HelloServiceServer -} - -// SayHello implements api.HelloServiceServer -func (s *server) SayHello(ctx context.Context, in *api.HelloRequest) (*api.HelloResponse, error) { - log.Printf("Received: %v\n", in.GetGreeting()) - time.Sleep(50 * time.Millisecond) - - return &api.HelloResponse{Reply: "Hello " + in.Greeting}, nil -} - -func (s *server) SayHelloServerStream(in *api.HelloRequest, out api.HelloService_SayHelloServerStreamServer) error { - log.Printf("Received: %v\n", in.GetGreeting()) - - for i := 0; i < 5; i++ { - err := out.Send(&api.HelloResponse{Reply: "Hello " + in.Greeting}) - if err != nil { - return err - } - - time.Sleep(time.Duration(i*50) * time.Millisecond) - } - - return nil -} - -func (s *server) SayHelloClientStream(stream api.HelloService_SayHelloClientStreamServer) error { - i := 0 - - for { - in, err := stream.Recv() - - if err == io.EOF { - break - } else if err != nil { - log.Printf("Non EOF error: %v\n", err) - return err - } - - log.Printf("Received: %v\n", in.GetGreeting()) - i++ - } - - time.Sleep(50 * time.Millisecond) - - return stream.SendAndClose(&api.HelloResponse{Reply: fmt.Sprintf("Hello (%v times)", i)}) -} - -func (s *server) SayHelloBidiStream(stream api.HelloService_SayHelloBidiStreamServer) error { - for { - in, err := stream.Recv() - - if err == io.EOF { - break - } else if err != nil { - log.Printf("Non EOF error: %v\n", err) - return err - } - - time.Sleep(50 * time.Millisecond) - - log.Printf("Received: %v\n", in.GetGreeting()) - err = stream.Send(&api.HelloResponse{Reply: "Hello " + in.Greeting}) - - if err != nil { - return err - } - } - - return nil -} - -func main() { - config.Init() - - lis, err := net.Listen("tcp", port) - if err != nil { - log.Fatalf("failed to listen: %v", err) - } - - s := grpc.NewServer( - grpc.UnaryInterceptor(grpctrace.UnaryServerInterceptor(global.Tracer(""))), - grpc.StreamInterceptor(grpctrace.StreamServerInterceptor(global.Tracer(""))), - ) - - api.RegisterHelloServiceServer(s, &server{}) - if err := s.Serve(lis); err != nil { - log.Fatalf("failed to serve: %v", err) - } -} diff --git a/instrumentation/grpctrace/example_interceptor_test.go b/instrumentation/grpctrace/example_interceptor_test.go deleted file mode 100644 index 7310483d..00000000 --- a/instrumentation/grpctrace/example_interceptor_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package grpctrace - -import ( - "google.golang.org/grpc" - - "go.opentelemetry.io/otel/api/global" -) - -func ExampleStreamClientInterceptor() { - tracer := global.Tracer("client-instrumentation") - _, _ = grpc.Dial( - "localhost", - grpc.WithStreamInterceptor(StreamClientInterceptor(tracer)), - ) -} - -func ExampleUnaryClientInterceptor() { - tracer := global.Tracer("client-instrumentation") - _, _ = grpc.Dial( - "localhost", - grpc.WithUnaryInterceptor(UnaryClientInterceptor(tracer)), - ) -} - -func ExampleStreamServerInterceptor() { - tracer := global.Tracer("server-instrumentation") - _ = grpc.NewServer( - grpc.StreamInterceptor(StreamServerInterceptor(tracer)), - ) -} - -func ExampleUnaryServerInterceptor() { - tracer := global.Tracer("server-instrumentation") - _ = grpc.NewServer( - grpc.UnaryInterceptor(UnaryServerInterceptor(tracer)), - ) -} diff --git a/instrumentation/grpctrace/grpctrace.go b/instrumentation/grpctrace/grpctrace.go deleted file mode 100644 index 3b536fad..00000000 --- a/instrumentation/grpctrace/grpctrace.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package grpctrace - -import ( - "context" - - "google.golang.org/grpc/metadata" - - "go.opentelemetry.io/otel/api/correlation" - "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/kv" - "go.opentelemetry.io/otel/api/propagation" - "go.opentelemetry.io/otel/api/trace" -) - -// Option is a function that allows configuration of the grpctrace Extract() -// and Inject() functions -type Option func(*config) - -type config struct { - propagators propagation.Propagators -} - -func newConfig(opts []Option) *config { - c := &config{propagators: global.Propagators()} - for _, o := range opts { - o(c) - } - return c -} - -// WithPropagators sets the propagators to use for Extraction and Injection -func WithPropagators(props propagation.Propagators) Option { - return func(c *config) { - c.propagators = props - } -} - -type metadataSupplier struct { - metadata *metadata.MD -} - -func (s *metadataSupplier) Get(key string) string { - values := s.metadata.Get(key) - if len(values) == 0 { - return "" - } - return values[0] -} - -func (s *metadataSupplier) Set(key string, value string) { - s.metadata.Set(key, value) -} - -// Inject injects correlation context and span context into the gRPC -// metadata object. This function is meant to be used on outgoing -// requests. -func Inject(ctx context.Context, metadata *metadata.MD, opts ...Option) { - c := newConfig(opts) - propagation.InjectHTTP(ctx, c.propagators, &metadataSupplier{ - metadata: metadata, - }) -} - -// Extract returns the correlation context and span context that -// another service encoded in the gRPC metadata object with Inject. -// This function is meant to be used on incoming requests. -func Extract(ctx context.Context, metadata *metadata.MD, opts ...Option) ([]kv.KeyValue, trace.SpanContext) { - c := newConfig(opts) - ctx = propagation.ExtractHTTP(ctx, c.propagators, &metadataSupplier{ - metadata: metadata, - }) - - spanContext := trace.RemoteSpanContextFromContext(ctx) - var correlationCtxKVs []kv.KeyValue - correlation.MapFromContext(ctx).Foreach(func(kv kv.KeyValue) bool { - correlationCtxKVs = append(correlationCtxKVs, kv) - return true - }) - - return correlationCtxKVs, spanContext -} diff --git a/instrumentation/grpctrace/interceptor.go b/instrumentation/grpctrace/interceptor.go deleted file mode 100644 index 7e6df7fb..00000000 --- a/instrumentation/grpctrace/interceptor.go +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package grpctrace - -// gRPC tracing middleware -// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/rpc.md -import ( - "context" - "io" - "net" - "strings" - - "go.opentelemetry.io/otel/semconv" - - "github.com/golang/protobuf/proto" //nolint:staticcheck - - "google.golang.org/grpc" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/peer" - "google.golang.org/grpc/status" - - "go.opentelemetry.io/otel/api/correlation" - "go.opentelemetry.io/otel/api/kv" - "go.opentelemetry.io/otel/api/trace" -) - -type messageType kv.KeyValue - -// Event adds an event of the messageType to the span associated with the -// passed context with id and size (if message is a proto message). -func (m messageType) Event(ctx context.Context, id int, message interface{}) { - span := trace.SpanFromContext(ctx) - if p, ok := message.(proto.Message); ok { - span.AddEvent(ctx, "message", - kv.KeyValue(m), - semconv.RPCMessageIDKey.Int(id), - semconv.RPCMessageUncompressedSizeKey.Int(proto.Size(p)), - ) - } else { - span.AddEvent(ctx, "message", - kv.KeyValue(m), - semconv.RPCMessageIDKey.Int(id), - ) - } -} - -var ( - messageSent = messageType(semconv.RPCMessageTypeSent) - messageReceived = messageType(semconv.RPCMessageTypeReceived) -) - -// UnaryClientInterceptor returns a grpc.UnaryClientInterceptor suitable -// for use in a grpc.Dial call. -func UnaryClientInterceptor(tracer trace.Tracer, opts ...Option) grpc.UnaryClientInterceptor { - return func( - ctx context.Context, - method string, - req, reply interface{}, - cc *grpc.ClientConn, - invoker grpc.UnaryInvoker, - callOpts ...grpc.CallOption, - ) error { - requestMetadata, _ := metadata.FromOutgoingContext(ctx) - metadataCopy := requestMetadata.Copy() - - name, attr := spanInfo(method, cc.Target()) - var span trace.Span - ctx, span = tracer.Start( - ctx, - name, - trace.WithSpanKind(trace.SpanKindClient), - trace.WithAttributes(attr...), - ) - defer span.End() - - Inject(ctx, &metadataCopy, opts...) - ctx = metadata.NewOutgoingContext(ctx, metadataCopy) - - messageSent.Event(ctx, 1, req) - - err := invoker(ctx, method, req, reply, cc, callOpts...) - - messageReceived.Event(ctx, 1, reply) - - if err != nil { - s, _ := status.FromError(err) - span.SetStatus(s.Code(), s.Message()) - } - - return err - } -} - -type streamEventType int - -type streamEvent struct { - Type streamEventType - Err error -} - -const ( - closeEvent streamEventType = iota - receiveEndEvent - errorEvent -) - -// clientStream wraps around the embedded grpc.ClientStream, and intercepts the RecvMsg and -// SendMsg method call. -type clientStream struct { - grpc.ClientStream - - desc *grpc.StreamDesc - events chan streamEvent - eventsDone chan struct{} - finished chan error - - receivedMessageID int - sentMessageID int -} - -var _ = proto.Marshal - -func (w *clientStream) RecvMsg(m interface{}) error { - err := w.ClientStream.RecvMsg(m) - - if err == nil && !w.desc.ServerStreams { - w.sendStreamEvent(receiveEndEvent, nil) - } else if err == io.EOF { - w.sendStreamEvent(receiveEndEvent, nil) - } else if err != nil { - w.sendStreamEvent(errorEvent, err) - } else { - w.receivedMessageID++ - messageReceived.Event(w.Context(), w.receivedMessageID, m) - } - - return err -} - -func (w *clientStream) SendMsg(m interface{}) error { - err := w.ClientStream.SendMsg(m) - - w.sentMessageID++ - messageSent.Event(w.Context(), w.sentMessageID, m) - - if err != nil { - w.sendStreamEvent(errorEvent, err) - } - - return err -} - -func (w *clientStream) Header() (metadata.MD, error) { - md, err := w.ClientStream.Header() - - if err != nil { - w.sendStreamEvent(errorEvent, err) - } - - return md, err -} - -func (w *clientStream) CloseSend() error { - err := w.ClientStream.CloseSend() - - if err != nil { - w.sendStreamEvent(errorEvent, err) - } else { - w.sendStreamEvent(closeEvent, nil) - } - - return err -} - -const ( - clientClosedState byte = 1 << iota - receiveEndedState -) - -func wrapClientStream(s grpc.ClientStream, desc *grpc.StreamDesc) *clientStream { - events := make(chan streamEvent) - eventsDone := make(chan struct{}) - finished := make(chan error) - - go func() { - defer close(eventsDone) - - // Both streams have to be closed - state := byte(0) - - for event := range events { - switch event.Type { - case closeEvent: - state |= clientClosedState - case receiveEndEvent: - state |= receiveEndedState - case errorEvent: - finished <- event.Err - return - } - - if state == clientClosedState|receiveEndedState { - finished <- nil - return - } - } - }() - - return &clientStream{ - ClientStream: s, - desc: desc, - events: events, - eventsDone: eventsDone, - finished: finished, - } -} - -func (w *clientStream) sendStreamEvent(eventType streamEventType, err error) { - select { - case <-w.eventsDone: - case w.events <- streamEvent{Type: eventType, Err: err}: - } -} - -// StreamClientInterceptor returns a grpc.StreamClientInterceptor suitable -// for use in a grpc.Dial call. -func StreamClientInterceptor(tracer trace.Tracer, opts ...Option) grpc.StreamClientInterceptor { - return func( - ctx context.Context, - desc *grpc.StreamDesc, - cc *grpc.ClientConn, - method string, - streamer grpc.Streamer, - callOpts ...grpc.CallOption, - ) (grpc.ClientStream, error) { - requestMetadata, _ := metadata.FromOutgoingContext(ctx) - metadataCopy := requestMetadata.Copy() - - name, attr := spanInfo(method, cc.Target()) - var span trace.Span - ctx, span = tracer.Start( - ctx, - name, - trace.WithSpanKind(trace.SpanKindClient), - trace.WithAttributes(attr...), - ) - - Inject(ctx, &metadataCopy, opts...) - ctx = metadata.NewOutgoingContext(ctx, metadataCopy) - - s, err := streamer(ctx, desc, cc, method, callOpts...) - stream := wrapClientStream(s, desc) - - go func() { - if err == nil { - err = <-stream.finished - } - - if err != nil { - s, _ := status.FromError(err) - span.SetStatus(s.Code(), s.Message()) - } - - span.End() - }() - - return stream, err - } -} - -// UnaryServerInterceptor returns a grpc.UnaryServerInterceptor suitable -// for use in a grpc.NewServer call. -func UnaryServerInterceptor(tracer trace.Tracer, opts ...Option) grpc.UnaryServerInterceptor { - return func( - ctx context.Context, - req interface{}, - info *grpc.UnaryServerInfo, - handler grpc.UnaryHandler, - ) (interface{}, error) { - requestMetadata, _ := metadata.FromIncomingContext(ctx) - metadataCopy := requestMetadata.Copy() - - entries, spanCtx := Extract(ctx, &metadataCopy, opts...) - ctx = correlation.ContextWithMap(ctx, correlation.NewMap(correlation.MapUpdate{ - MultiKV: entries, - })) - - name, attr := spanInfo(info.FullMethod, peerFromCtx(ctx)) - ctx, span := tracer.Start( - trace.ContextWithRemoteSpanContext(ctx, spanCtx), - name, - trace.WithSpanKind(trace.SpanKindServer), - trace.WithAttributes(attr...), - ) - defer span.End() - - messageReceived.Event(ctx, 1, req) - - resp, err := handler(ctx, req) - if err != nil { - s, _ := status.FromError(err) - span.SetStatus(s.Code(), s.Message()) - messageSent.Event(ctx, 1, s.Proto()) - } else { - messageSent.Event(ctx, 1, resp) - } - - return resp, err - } -} - -// serverStream wraps around the embedded grpc.ServerStream, and intercepts the RecvMsg and -// SendMsg method call. -type serverStream struct { - grpc.ServerStream - ctx context.Context - - receivedMessageID int - sentMessageID int -} - -func (w *serverStream) Context() context.Context { - return w.ctx -} - -func (w *serverStream) RecvMsg(m interface{}) error { - err := w.ServerStream.RecvMsg(m) - - if err == nil { - w.receivedMessageID++ - messageReceived.Event(w.Context(), w.receivedMessageID, m) - } - - return err -} - -func (w *serverStream) SendMsg(m interface{}) error { - err := w.ServerStream.SendMsg(m) - - w.sentMessageID++ - messageSent.Event(w.Context(), w.sentMessageID, m) - - return err -} - -func wrapServerStream(ctx context.Context, ss grpc.ServerStream) *serverStream { - return &serverStream{ - ServerStream: ss, - ctx: ctx, - } -} - -// StreamServerInterceptor returns a grpc.StreamServerInterceptor suitable -// for use in a grpc.NewServer call. -func StreamServerInterceptor(tracer trace.Tracer, opts ...Option) grpc.StreamServerInterceptor { - return func( - srv interface{}, - ss grpc.ServerStream, - info *grpc.StreamServerInfo, - handler grpc.StreamHandler, - ) error { - ctx := ss.Context() - - requestMetadata, _ := metadata.FromIncomingContext(ctx) - metadataCopy := requestMetadata.Copy() - - entries, spanCtx := Extract(ctx, &metadataCopy, opts...) - ctx = correlation.ContextWithMap(ctx, correlation.NewMap(correlation.MapUpdate{ - MultiKV: entries, - })) - - name, attr := spanInfo(info.FullMethod, peerFromCtx(ctx)) - ctx, span := tracer.Start( - trace.ContextWithRemoteSpanContext(ctx, spanCtx), - name, - trace.WithSpanKind(trace.SpanKindServer), - trace.WithAttributes(attr...), - ) - defer span.End() - - err := handler(srv, wrapServerStream(ctx, ss)) - - if err != nil { - s, _ := status.FromError(err) - span.SetStatus(s.Code(), s.Message()) - } - - return err - } -} - -// spanInfo returns a span name and all appropriate attributes from the gRPC -// method and peer address. -func spanInfo(fullMethod, peerAddress string) (string, []kv.KeyValue) { - attrs := []kv.KeyValue{semconv.RPCSystemGRPC} - name, mAttrs := parseFullMethod(fullMethod) - attrs = append(attrs, mAttrs...) - attrs = append(attrs, peerAttr(peerAddress)...) - return name, attrs -} - -// peerAttr returns attributes about the peer address. -func peerAttr(addr string) []kv.KeyValue { - host, port, err := net.SplitHostPort(addr) - if err != nil { - return []kv.KeyValue(nil) - } - - if host == "" { - host = "127.0.0.1" - } - - return []kv.KeyValue{ - semconv.NetPeerIPKey.String(host), - semconv.NetPeerPortKey.String(port), - } -} - -// peerFromCtx returns a peer address from a context, if one exists. -func peerFromCtx(ctx context.Context) string { - p, ok := peer.FromContext(ctx) - if !ok { - return "" - } - return p.Addr.String() -} - -// parseFullMethod returns a span name following the OpenTelemetry semantic -// conventions as well as all applicable span kv.KeyValue attributes based -// on a gRPC's FullMethod. -func parseFullMethod(fullMethod string) (string, []kv.KeyValue) { - name := strings.TrimLeft(fullMethod, "/") - parts := strings.SplitN(name, "/", 2) - if len(parts) != 2 { - // Invalid format, does not follow `/package.service/method`. - return name, []kv.KeyValue(nil) - } - - var attrs []kv.KeyValue - if service := parts[0]; service != "" { - attrs = append(attrs, semconv.RPCServiceKey.String(service)) - } - if method := parts[1]; method != "" { - attrs = append(attrs, semconv.RPCMethodKey.String(method)) - } - return name, attrs -} diff --git a/instrumentation/grpctrace/interceptor_test.go b/instrumentation/grpctrace/interceptor_test.go deleted file mode 100644 index 3b5d29fb..00000000 --- a/instrumentation/grpctrace/interceptor_test.go +++ /dev/null @@ -1,428 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -package grpctrace - -import ( - "context" - "sync" - "testing" - "time" - - "go.opentelemetry.io/otel/api/trace/testtrace" - "go.opentelemetry.io/otel/semconv" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/golang/protobuf/proto" //nolint:staticcheck - - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/status" - - "go.opentelemetry.io/otel/api/kv" -) - -type SpanRecorder struct { - mu sync.RWMutex - spans map[string]*testtrace.Span -} - -func NewSpanRecorder() *SpanRecorder { - return &SpanRecorder{spans: make(map[string]*testtrace.Span)} -} - -func (sr *SpanRecorder) OnStart(span *testtrace.Span) {} - -func (sr *SpanRecorder) OnEnd(span *testtrace.Span) { - sr.mu.Lock() - defer sr.mu.Unlock() - sr.spans[span.Name()] = span -} - -func (sr *SpanRecorder) Get(name string) (*testtrace.Span, bool) { - sr.mu.RLock() - defer sr.mu.RUnlock() - s, ok := sr.spans[name] - return s, ok -} - -type mockUICInvoker struct { - ctx context.Context -} - -func (mcuici *mockUICInvoker) invoker(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, opts ...grpc.CallOption) error { - mcuici.ctx = ctx - return nil -} - -type mockProtoMessage struct{} - -func (mm *mockProtoMessage) Reset() { -} - -func (mm *mockProtoMessage) String() string { - return "mock" -} - -func (mm *mockProtoMessage) ProtoMessage() { -} - -func TestUnaryClientInterceptor(t *testing.T) { - clientConn, err := grpc.Dial("fake:connection", grpc.WithInsecure()) - if err != nil { - t.Fatalf("failed to create client connection: %v", err) - } - - sr := NewSpanRecorder() - tp := testtrace.NewProvider(testtrace.WithSpanRecorder(sr)) - tracer := tp.Tracer("grpctrace/client") - unaryInterceptor := UnaryClientInterceptor(tracer) - - req := &mockProtoMessage{} - reply := &mockProtoMessage{} - uniInterceptorInvoker := &mockUICInvoker{} - - checks := []struct { - method string - name string - expectedAttr map[kv.Key]kv.Value - eventsAttr []map[kv.Key]kv.Value - }{ - { - method: "/github.com.serviceName/bar", - name: "github.com.serviceName/bar", - expectedAttr: map[kv.Key]kv.Value{ - semconv.RPCSystemKey: kv.StringValue("grpc"), - semconv.RPCServiceKey: kv.StringValue("github.com.serviceName"), - semconv.RPCMethodKey: kv.StringValue("bar"), - semconv.NetPeerIPKey: kv.StringValue("fake"), - semconv.NetPeerPortKey: kv.StringValue("connection"), - }, - eventsAttr: []map[kv.Key]kv.Value{ - { - semconv.RPCMessageTypeKey: kv.StringValue("SENT"), - semconv.RPCMessageIDKey: kv.IntValue(1), - semconv.RPCMessageUncompressedSizeKey: kv.IntValue(proto.Size(proto.Message(req))), - }, - { - semconv.RPCMessageTypeKey: kv.StringValue("RECEIVED"), - semconv.RPCMessageIDKey: kv.IntValue(1), - semconv.RPCMessageUncompressedSizeKey: kv.IntValue(proto.Size(proto.Message(reply))), - }, - }, - }, - { - method: "/serviceName/bar", - name: "serviceName/bar", - expectedAttr: map[kv.Key]kv.Value{ - semconv.RPCSystemKey: kv.StringValue("grpc"), - semconv.RPCServiceKey: kv.StringValue("serviceName"), - semconv.RPCMethodKey: kv.StringValue("bar"), - semconv.NetPeerIPKey: kv.StringValue("fake"), - semconv.NetPeerPortKey: kv.StringValue("connection"), - }, - eventsAttr: []map[kv.Key]kv.Value{ - { - semconv.RPCMessageTypeKey: kv.StringValue("SENT"), - semconv.RPCMessageIDKey: kv.IntValue(1), - semconv.RPCMessageUncompressedSizeKey: kv.IntValue(proto.Size(proto.Message(req))), - }, - { - semconv.RPCMessageTypeKey: kv.StringValue("RECEIVED"), - semconv.RPCMessageIDKey: kv.IntValue(1), - semconv.RPCMessageUncompressedSizeKey: kv.IntValue(proto.Size(proto.Message(reply))), - }, - }, - }, - { - method: "serviceName/bar", - name: "serviceName/bar", - expectedAttr: map[kv.Key]kv.Value{ - semconv.RPCSystemKey: kv.StringValue("grpc"), - semconv.RPCServiceKey: kv.StringValue("serviceName"), - semconv.RPCMethodKey: kv.StringValue("bar"), - semconv.NetPeerIPKey: kv.StringValue("fake"), - semconv.NetPeerPortKey: kv.StringValue("connection"), - }, - eventsAttr: []map[kv.Key]kv.Value{ - { - semconv.RPCMessageTypeKey: kv.StringValue("SENT"), - semconv.RPCMessageIDKey: kv.IntValue(1), - semconv.RPCMessageUncompressedSizeKey: kv.IntValue(proto.Size(proto.Message(req))), - }, - { - semconv.RPCMessageTypeKey: kv.StringValue("RECEIVED"), - semconv.RPCMessageIDKey: kv.IntValue(1), - semconv.RPCMessageUncompressedSizeKey: kv.IntValue(proto.Size(proto.Message(reply))), - }, - }, - }, - { - method: "invalidName", - name: "invalidName", - expectedAttr: map[kv.Key]kv.Value{ - semconv.RPCSystemKey: kv.StringValue("grpc"), - semconv.NetPeerIPKey: kv.StringValue("fake"), - semconv.NetPeerPortKey: kv.StringValue("connection"), - }, - eventsAttr: []map[kv.Key]kv.Value{ - { - semconv.RPCMessageTypeKey: kv.StringValue("SENT"), - semconv.RPCMessageIDKey: kv.IntValue(1), - semconv.RPCMessageUncompressedSizeKey: kv.IntValue(proto.Size(proto.Message(req))), - }, - { - semconv.RPCMessageTypeKey: kv.StringValue("RECEIVED"), - semconv.RPCMessageIDKey: kv.IntValue(1), - semconv.RPCMessageUncompressedSizeKey: kv.IntValue(proto.Size(proto.Message(reply))), - }, - }, - }, - { - method: "/github.com.foo.serviceName_123/method", - name: "github.com.foo.serviceName_123/method", - expectedAttr: map[kv.Key]kv.Value{ - semconv.RPCSystemKey: kv.StringValue("grpc"), - semconv.RPCServiceKey: kv.StringValue("github.com.foo.serviceName_123"), - semconv.RPCMethodKey: kv.StringValue("method"), - semconv.NetPeerIPKey: kv.StringValue("fake"), - semconv.NetPeerPortKey: kv.StringValue("connection"), - }, - eventsAttr: []map[kv.Key]kv.Value{ - { - semconv.RPCMessageTypeKey: kv.StringValue("SENT"), - semconv.RPCMessageIDKey: kv.IntValue(1), - semconv.RPCMessageUncompressedSizeKey: kv.IntValue(proto.Size(proto.Message(req))), - }, - { - semconv.RPCMessageTypeKey: kv.StringValue("RECEIVED"), - semconv.RPCMessageIDKey: kv.IntValue(1), - semconv.RPCMessageUncompressedSizeKey: kv.IntValue(proto.Size(proto.Message(reply))), - }, - }, - }, - } - - for _, check := range checks { - if !assert.NoError(t, unaryInterceptor(context.Background(), check.method, req, reply, clientConn, uniInterceptorInvoker.invoker)) { - continue - } - span, ok := sr.Get(check.name) - if !assert.True(t, ok, "missing span %q", check.name) { - continue - } - assert.Equal(t, check.expectedAttr, span.Attributes()) - assert.Equal(t, check.eventsAttr, eventAttrMap(span.Events())) - } -} - -func eventAttrMap(events []testtrace.Event) []map[kv.Key]kv.Value { - maps := make([]map[kv.Key]kv.Value, len(events)) - for i, event := range events { - maps[i] = event.Attributes - } - return maps -} - -type mockClientStream struct { - Desc *grpc.StreamDesc - Ctx context.Context -} - -func (mockClientStream) SendMsg(m interface{}) error { return nil } -func (mockClientStream) RecvMsg(m interface{}) error { return nil } -func (mockClientStream) CloseSend() error { return nil } -func (c mockClientStream) Context() context.Context { return c.Ctx } -func (mockClientStream) Header() (metadata.MD, error) { return nil, nil } -func (mockClientStream) Trailer() metadata.MD { return nil } - -func TestStreamClientInterceptor(t *testing.T) { - clientConn, err := grpc.Dial("fake:connection", grpc.WithInsecure()) - if err != nil { - t.Fatalf("failed to create client connection: %v", err) - } - - // tracer - sr := NewSpanRecorder() - tp := testtrace.NewProvider(testtrace.WithSpanRecorder(sr)) - tracer := tp.Tracer("grpctrace/Server") - streamCI := StreamClientInterceptor(tracer) - - var mockClStr mockClientStream - method := "/github.com.serviceName/bar" - name := "github.com.serviceName/bar" - - streamClient, err := streamCI( - context.Background(), - &grpc.StreamDesc{ServerStreams: true}, - clientConn, - method, - func(ctx context.Context, - desc *grpc.StreamDesc, - cc *grpc.ClientConn, - method string, - opts ...grpc.CallOption) (grpc.ClientStream, error) { - mockClStr = mockClientStream{Desc: desc, Ctx: ctx} - return mockClStr, nil - }, - ) - require.NoError(t, err, "initialize grpc stream client") - _, ok := sr.Get(name) - require.False(t, ok, "span should ended while stream is open") - - req := &mockProtoMessage{} - reply := &mockProtoMessage{} - - // send and receive fake data - for i := 0; i < 10; i++ { - _ = streamClient.SendMsg(req) - _ = streamClient.RecvMsg(reply) - } - - // close client and server stream - _ = streamClient.CloseSend() - mockClStr.Desc.ServerStreams = false - _ = streamClient.RecvMsg(reply) - - // added retry because span end is called in separate go routine - var span *testtrace.Span - for retry := 0; retry < 5; retry++ { - span, ok = sr.Get(name) - if ok { - break - } - time.Sleep(time.Second * 1) - } - require.True(t, ok, "missing span %s", name) - - expectedAttr := map[kv.Key]kv.Value{ - semconv.RPCSystemKey: kv.StringValue("grpc"), - semconv.RPCServiceKey: kv.StringValue("github.com.serviceName"), - semconv.RPCMethodKey: kv.StringValue("bar"), - semconv.NetPeerIPKey: kv.StringValue("fake"), - semconv.NetPeerPortKey: kv.StringValue("connection"), - } - assert.Equal(t, expectedAttr, span.Attributes()) - - events := span.Events() - require.Len(t, events, 20) - for i := 0; i < 20; i += 2 { - msgID := i/2 + 1 - validate := func(eventName string, attrs map[kv.Key]kv.Value) { - for k, v := range attrs { - if k == semconv.RPCMessageTypeKey && v.AsString() != eventName { - t.Errorf("invalid event on index: %d expecting %s event, receive %s event", i, eventName, v.AsString()) - } - if k == semconv.RPCMessageIDKey && v != kv.IntValue(msgID) { - t.Errorf("invalid id for message event expected %d received %d", msgID, v.AsInt32()) - } - } - } - validate("SENT", events[i].Attributes) - validate("RECEIVED", events[i+1].Attributes) - } - - // ensure CloseSend can be subsequently called - _ = streamClient.CloseSend() -} - -func TestServerInterceptorError(t *testing.T) { - sr := NewSpanRecorder() - tp := testtrace.NewProvider(testtrace.WithSpanRecorder(sr)) - tracer := tp.Tracer("grpctrace/Server") - usi := UnaryServerInterceptor(tracer) - deniedErr := status.Error(codes.PermissionDenied, "PERMISSION_DENIED_TEXT") - handler := func(_ context.Context, _ interface{}) (interface{}, error) { - return nil, deniedErr - } - _, err := usi(context.Background(), &mockProtoMessage{}, &grpc.UnaryServerInfo{}, handler) - require.Error(t, err) - assert.Equal(t, err, deniedErr) - - span, ok := sr.Get("") - if !ok { - t.Fatalf("failed to export error span") - } - assert.Equal(t, span.StatusCode(), codes.PermissionDenied) - assert.Contains(t, deniedErr.Error(), span.StatusMessage()) - assert.Len(t, span.Events(), 2) - assert.Equal(t, map[kv.Key]kv.Value{ - kv.Key("message.type"): kv.StringValue("SENT"), - kv.Key("message.id"): kv.IntValue(1), - kv.Key("message.uncompressed_size"): kv.IntValue(26), - }, span.Events()[1].Attributes) -} - -func TestParseFullMethod(t *testing.T) { - tests := []struct { - fullMethod string - name string - attr []kv.KeyValue - }{ - { - fullMethod: "/grpc.test.EchoService/Echo", - name: "grpc.test.EchoService/Echo", - attr: []kv.KeyValue{ - semconv.RPCServiceKey.String("grpc.test.EchoService"), - semconv.RPCMethodKey.String("Echo"), - }, - }, { - fullMethod: "/com.example.ExampleRmiService/exampleMethod", - name: "com.example.ExampleRmiService/exampleMethod", - attr: []kv.KeyValue{ - semconv.RPCServiceKey.String("com.example.ExampleRmiService"), - semconv.RPCMethodKey.String("exampleMethod"), - }, - }, { - fullMethod: "/MyCalcService.Calculator/Add", - name: "MyCalcService.Calculator/Add", - attr: []kv.KeyValue{ - semconv.RPCServiceKey.String("MyCalcService.Calculator"), - semconv.RPCMethodKey.String("Add"), - }, - }, { - fullMethod: "/MyServiceReference.ICalculator/Add", - name: "MyServiceReference.ICalculator/Add", - attr: []kv.KeyValue{ - semconv.RPCServiceKey.String("MyServiceReference.ICalculator"), - semconv.RPCMethodKey.String("Add"), - }, - }, { - fullMethod: "/MyServiceWithNoPackage/theMethod", - name: "MyServiceWithNoPackage/theMethod", - attr: []kv.KeyValue{ - semconv.RPCServiceKey.String("MyServiceWithNoPackage"), - semconv.RPCMethodKey.String("theMethod"), - }, - }, { - fullMethod: "/pkg.srv", - name: "pkg.srv", - attr: []kv.KeyValue(nil), - }, { - fullMethod: "/pkg.srv/", - name: "pkg.srv/", - attr: []kv.KeyValue{ - semconv.RPCServiceKey.String("pkg.srv"), - }, - }, - } - - for _, test := range tests { - n, a := parseFullMethod(test.fullMethod) - assert.Equal(t, test.name, n) - assert.Equal(t, test.attr, a) - } -}