-
Notifications
You must be signed in to change notification settings - Fork 37
/
example_test.go
120 lines (101 loc) · 3.54 KB
/
example_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// (c) Copyright IBM Corp. 2021
// (c) Copyright Instana Inc. 2020
//go:build go1.19
// +build go1.19
package instagrpc_test
import (
"context"
"fmt"
"log"
"net"
"time"
instana "github.com/instana/go-sensor"
"github.com/instana/go-sensor/instrumentation/instagrpc"
"github.com/opentracing/opentracing-go/ext"
"google.golang.org/grpc"
grpctest "google.golang.org/grpc/interop/grpc_testing"
)
// EchoServer is an implementation of GRPC server
type TestServiceServer struct {
grpctest.UnimplementedTestServiceServer
}
// UnaryCall responds with a static greeting from server
func (s TestServiceServer) UnaryCall(ctx context.Context, req *grpctest.SimpleRequest) (*grpctest.SimpleResponse, error) {
// Extract the parent span and use its tracer to initialize any child spans to trace the calls
// inside the handler, e.g. database queries, 3rd-party API requests, etc.
if parent, ok := instana.SpanFromContext(ctx); ok {
sp := parent.Tracer().StartSpan("unary-call")
defer sp.Finish()
}
time.Sleep(100 * time.Microsecond)
return &grpctest.SimpleResponse{
Payload: &grpctest.Payload{
Body: []byte("hello from server"),
},
}, nil
}
// setupServer starts a new instrumented GRPC server instance and returns
// the server address
func setupServer() (net.Addr, error) {
// Initialize server sensor to instrument request handlers
sensor := instana.NewSensor("grpc-server")
ln, err := net.Listen("tcp", ":0")
if err != nil {
return nil, fmt.Errorf("failed to start listener: %s", err)
}
// To instrument server calls add instagrpc.UnaryServerInterceptor(sensor) and
// instagrpc.StreamServerInterceptor(sensor) to the list of server options when
// initializing the server
srv := grpc.NewServer(
grpc.UnaryInterceptor(instagrpc.UnaryServerInterceptor(sensor)),
grpc.StreamInterceptor(instagrpc.StreamServerInterceptor(sensor)),
)
grpctest.RegisterTestServiceServer(srv, &TestServiceServer{})
go func() {
if err := srv.Serve(ln); err != nil {
log.Fatalf("failed to start server: %s", err)
}
}()
return ln.Addr(), nil
}
func Example() {
serverAddr, err := setupServer()
if err != nil {
log.Fatalf("failed to setup a server: %s", err)
}
// Initialize client tracer
sensor := instana.NewSensor("grpc-client")
// To instrument client calls add instagrpc.UnaryClientInterceptor(sensor) and
// instagrpc.StringClientInterceptor(sensor) to the DialOption list while dialing
// the GRPC server.
conn, err := grpc.Dial(
serverAddr.String(),
grpc.WithInsecure(),
grpc.WithUnaryInterceptor(instagrpc.UnaryClientInterceptor(sensor)),
grpc.WithStreamInterceptor(instagrpc.StreamClientInterceptor(sensor)),
)
if err != nil {
log.Fatalf("failed to dial server on %s: %s", serverAddr.String(), err)
}
defer conn.Close()
c := grpctest.NewTestServiceClient(conn)
// The call should always start with an entry span (https://www.instana.com/docs/tracing/custom-best-practices/#start-new-traces-with-entry-spans)
// Normally this would be your HTTP/GRPC/message queue request span, but here we need to
// create it explicitly.
sp := sensor.Tracer().StartSpan("client-call")
sp.SetTag(string(ext.SpanKind), "entry")
// Create a context that holds the parent entry span and pass it to the GRPC call
resp, err := c.UnaryCall(
instana.ContextWithSpan(context.Background(), sp),
&grpctest.SimpleRequest{
Payload: &grpctest.Payload{
Body: []byte("hello from client"),
},
},
)
if err != nil {
log.Fatalf("server responded with an error: %s", err)
}
fmt.Println(string(resp.GetPayload().GetBody()))
// Output: hello from server
}