forked from go-kit/kit
/
addcli.go
210 lines (197 loc) · 7.18 KB
/
addcli.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
package main
import (
"context"
"flag"
"fmt"
"os"
"strconv"
"text/tabwriter"
"time"
"google.golang.org/grpc"
"github.com/apache/thrift/lib/go/thrift"
lightstep "github.com/lightstep/lightstep-tracer-go"
stdopentracing "github.com/opentracing/opentracing-go"
zipkinot "github.com/openzipkin-contrib/zipkin-go-opentracing"
zipkin "github.com/openzipkin/zipkin-go"
zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
"sourcegraph.com/sourcegraph/appdash"
appdashot "sourcegraph.com/sourcegraph/appdash/opentracing"
"github.com/chadgrant/kit/log"
"github.com/chadgrant/kit/examples/addsvc/pkg/addservice"
"github.com/chadgrant/kit/examples/addsvc/pkg/addtransport"
addthrift "github.com/chadgrant/kit/examples/addsvc/thrift/gen-go/addsvc"
)
func main() {
// The addcli presumes no service discovery system, and expects users to
// provide the direct address of an addsvc. This presumption is reflected in
// the addcli binary and the client packages: the -transport.addr flags
// and various client constructors both expect host:port strings. For an
// example service with a client built on top of a service discovery system,
// see profilesvc.
fs := flag.NewFlagSet("addcli", flag.ExitOnError)
var (
httpAddr = fs.String("http-addr", "", "HTTP address of addsvc")
grpcAddr = fs.String("grpc-addr", "", "gRPC address of addsvc")
thriftAddr = fs.String("thrift-addr", "", "Thrift address of addsvc")
jsonRPCAddr = fs.String("jsonrpc-addr", "", "JSON RPC address of addsvc")
thriftProtocol = fs.String("thrift-protocol", "binary", "binary, compact, json, simplejson")
thriftBuffer = fs.Int("thrift-buffer", 0, "0 for unbuffered")
thriftFramed = fs.Bool("thrift-framed", false, "true to enable framing")
zipkinURL = fs.String("zipkin-url", "", "Enable Zipkin tracing via HTTP reporter URL e.g. http://localhost:9411/api/v2/spans")
zipkinBridge = fs.Bool("zipkin-ot-bridge", false, "Use Zipkin OpenTracing bridge instead of native implementation")
lightstepToken = fs.String("lightstep-token", "", "Enable LightStep tracing via a LightStep access token")
appdashAddr = fs.String("appdash-addr", "", "Enable Appdash tracing via an Appdash server host:port")
method = fs.String("method", "sum", "sum, concat")
)
fs.Usage = usageFor(fs, os.Args[0]+" [flags] <a> <b>")
fs.Parse(os.Args[1:])
if len(fs.Args()) != 2 {
fs.Usage()
os.Exit(1)
}
// This is a demonstration of the native Zipkin tracing client. If using
// Zipkin this is the more idiomatic client over OpenTracing.
var zipkinTracer *zipkin.Tracer
{
if *zipkinURL != "" {
var (
err error
hostPort = "" // if host:port is unknown we can keep this empty
serviceName = "addsvc-cli"
reporter = zipkinhttp.NewReporter(*zipkinURL)
)
defer reporter.Close()
zEP, _ := zipkin.NewEndpoint(serviceName, hostPort)
zipkinTracer, err = zipkin.NewTracer(reporter, zipkin.WithLocalEndpoint(zEP))
if err != nil {
fmt.Fprintf(os.Stderr, "unable to create zipkin tracer: %s\n", err.Error())
os.Exit(1)
}
}
}
// This is a demonstration client, which supports multiple tracers.
// Your clients will probably just use one tracer.
var otTracer stdopentracing.Tracer
{
if *zipkinBridge && zipkinTracer != nil {
otTracer = zipkinot.Wrap(zipkinTracer)
zipkinTracer = nil // do not instrument with both native and ot bridge
} else if *lightstepToken != "" {
otTracer = lightstep.NewTracer(lightstep.Options{
AccessToken: *lightstepToken,
})
defer lightstep.FlushLightStepTracer(otTracer)
} else if *appdashAddr != "" {
otTracer = appdashot.NewTracer(appdash.NewRemoteCollector(*appdashAddr))
} else {
otTracer = stdopentracing.GlobalTracer() // no-op
}
}
// This is a demonstration client, which supports multiple transports.
// Your clients will probably just define and stick with 1 transport.
var (
svc addservice.Service
err error
)
if *httpAddr != "" {
svc, err = addtransport.NewHTTPClient(*httpAddr, otTracer, zipkinTracer, log.NewNopLogger())
} else if *grpcAddr != "" {
conn, err := grpc.Dial(*grpcAddr, grpc.WithInsecure(), grpc.WithTimeout(time.Second))
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v", err)
os.Exit(1)
}
defer conn.Close()
svc = addtransport.NewGRPCClient(conn, otTracer, zipkinTracer, log.NewNopLogger())
} else if *jsonRPCAddr != "" {
svc, err = addtransport.NewJSONRPCClient(*jsonRPCAddr, otTracer, log.NewNopLogger())
} else if *thriftAddr != "" {
// It's necessary to do all of this construction in the func main,
// because (among other reasons) we need to control the lifecycle of the
// Thrift transport, i.e. close it eventually.
var protocolFactory thrift.TProtocolFactory
switch *thriftProtocol {
case "compact":
protocolFactory = thrift.NewTCompactProtocolFactory()
case "simplejson":
protocolFactory = thrift.NewTSimpleJSONProtocolFactory()
case "json":
protocolFactory = thrift.NewTJSONProtocolFactory()
case "binary", "":
protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
default:
fmt.Fprintf(os.Stderr, "error: invalid protocol %q\n", *thriftProtocol)
os.Exit(1)
}
var transportFactory thrift.TTransportFactory
if *thriftBuffer > 0 {
transportFactory = thrift.NewTBufferedTransportFactory(*thriftBuffer)
} else {
transportFactory = thrift.NewTTransportFactory()
}
if *thriftFramed {
transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
}
transportSocket, err := thrift.NewTSocket(*thriftAddr)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
transport, err := transportFactory.GetTransport(transportSocket)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
if err := transport.Open(); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
defer transport.Close()
client := addthrift.NewAddServiceClientFactory(transport, protocolFactory)
svc = addtransport.NewThriftClient(client)
} else {
fmt.Fprintf(os.Stderr, "error: no remote address specified\n")
os.Exit(1)
}
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
switch *method {
case "sum":
a, _ := strconv.ParseInt(fs.Args()[0], 10, 64)
b, _ := strconv.ParseInt(fs.Args()[1], 10, 64)
v, err := svc.Sum(context.Background(), int(a), int(b))
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
fmt.Fprintf(os.Stdout, "%d + %d = %d\n", a, b, v)
case "concat":
a := fs.Args()[0]
b := fs.Args()[1]
v, err := svc.Concat(context.Background(), a, b)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
fmt.Fprintf(os.Stdout, "%q + %q = %q\n", a, b, v)
default:
fmt.Fprintf(os.Stderr, "error: invalid method %q\n", *method)
os.Exit(1)
}
}
func usageFor(fs *flag.FlagSet, short string) func() {
return func() {
fmt.Fprintf(os.Stderr, "USAGE\n")
fmt.Fprintf(os.Stderr, " %s\n", short)
fmt.Fprintf(os.Stderr, "\n")
fmt.Fprintf(os.Stderr, "FLAGS\n")
w := tabwriter.NewWriter(os.Stderr, 0, 2, 2, ' ', 0)
fs.VisitAll(func(f *flag.Flag) {
fmt.Fprintf(w, "\t-%s %s\t%s\n", f.Name, f.DefValue, f.Usage)
})
w.Flush()
fmt.Fprintf(os.Stderr, "\n")
}
}