diff --git a/examples/addsvc2/cmd/addsvc/addsvc.go b/examples/addsvc2/cmd/addsvc/addsvc.go index 8f8f2d3..ace0619 100644 --- a/examples/addsvc2/cmd/addsvc/addsvc.go +++ b/examples/addsvc2/cmd/addsvc/addsvc.go @@ -9,6 +9,7 @@ "os" "os/signal" "syscall" + "text/tabwriter" "github.com/apache/thrift/lib/go/thrift" "github.com/oklog/oklog/pkg/group" @@ -29,18 +30,24 @@ ) func main() { + // Define our flags. Your service probably won't need to bind listeners for + // *all* supported transports, or support both Zipkin and LightStep, and so + // on, but we do it here for demonstration purposes. + fs := flag.NewFlagSet("addsvc", flag.ExitOnError) var ( - debugAddr = flag.String("debug.addr", ":8080", "Debug and metrics listen address") - httpAddr = flag.String("http-addr", ":8081", "HTTP listen address") - grpcAddr = flag.String("grpc-addr", ":8082", "gRPC listen address") - thriftAddr = flag.String("thrift-addr", ":8082", "Thrift listen address") - thriftProtocol = flag.String("thrift.protocol", "binary", "binary, compact, json, simplejson") - thriftBufferSize = flag.Int("thrift.buffer.size", 0, "0 for unbuffered") - thriftFramed = flag.Bool("thrift.framed", false, "true to enable framing") - zipkinURL = flag.String("zipkin-url", "", "Zipkin collector URL e.g. http://localhost:9411/api/v1/spans") + debugAddr = fs.String("debug.addr", ":8080", "Debug and metrics listen address") + httpAddr = fs.String("http-addr", ":8081", "HTTP listen address") + grpcAddr = fs.String("grpc-addr", ":8082", "gRPC listen address") + thriftAddr = fs.String("thrift-addr", ":8082", "Thrift listen address") + 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", "", "Zipkin collector URL e.g. http://localhost:9411/api/v1/spans") ) - flag.Parse() - + fs.Usage = usageFor(fs, os.Args[0]+" [flags]") + fs.Parse(os.Args[1:]) + + // Create a single logger, which we'll use and give to other components. var logger log.Logger { logger = log.NewLogfmtLogger(os.Stderr) @@ -48,6 +55,8 @@ logger = log.With(logger, "caller", log.DefaultCaller) } + // Determine which tracer to use. We'll pass the tracer to all the + // components that use it, as a dependency. var tracer stdopentracing.Tracer { if *zipkinURL != "" { @@ -75,7 +84,8 @@ } } - // Our metrics are dependencies, here we create them. + // Create the (sparse) metrics we'll use in the service. They, too, are + // dependencies that we pass to components that use them. var ints, chars metrics.Counter { // Business-level metrics. @@ -103,16 +113,33 @@ }, []string{"method", "success"}) } + // Build the layers of the service "onion" from the inside out. First, the + // business logic service; then, the set of endpoints that wrap the service; + // and finally, a series of concrete transport adapters. The adapters, like + // the HTTP handler or the gRPC server, are the bridge between Go kit and + // the interfaces that the transports expect. Note that we're not binding + // them to ports or anything yet; we'll do that next. var ( - service = addservice.New(logger, ints, chars) - endpoints = addendpoint.New(service, logger, duration, tracer) - httpHandler = addtransport.NewHTTPHandler(context.Background(), endpoints, logger, tracer) - grpcServer = addtransport.MakeGRPCServer(endpoints, tracer, logger) - thriftHandler = addtransport.MakeThriftHandler(context.Background(), endpoints) + service = addservice.New(logger, ints, chars) + endpoints = addendpoint.New(service, logger, duration, tracer) + httpHandler = addtransport.NewHTTPHandler(context.Background(), endpoints, logger, tracer) + grpcServer = addtransport.NewGRPCServer(endpoints, tracer, logger) + thriftServer = addtransport.NewThriftServer(context.Background(), endpoints) ) + // Now we're to the part of the func main where we want to start actually + // running things, like servers bound to listeners to receive connections. + // + // The method is the same for each component: add a new actor to the group + // struct, which is a combination of 2 anonymous functions: the first + // function actually runs the component, and the second function should + // interrupt the first function and cause it to return. + var g group.Group { + // The debug listener mounts the http.DefaultServeMux, and serves up + // stuff like the Prometheus metrics route, the Go debug and profiling + // routes, and so on. debugListener, err := net.Listen("tcp", *debugAddr) if err != nil { logger.Log("transport", "debug/HTTP", "during", "Listen", "err", err) @@ -126,6 +153,7 @@ }) } { + // The HTTP listener mounts the Go kit HTTP handler we created. httpListener, err := net.Listen("tcp", *httpAddr) if err != nil { logger.Log("transport", "HTTP", "during", "Listen", "err", err) @@ -139,6 +167,7 @@ }) } { + // The gRPC listener mounts the Go kit gRPC server we created. grpcListener, err := net.Listen("tcp", *grpcAddr) if err != nil { logger.Log("transport", "gRPC", "during", "Listen", "err", err) @@ -154,6 +183,9 @@ }) } { + // The Thrift socket mounts the Go kit Thrift server we created earlier. + // There's a lot of boilerplate involved here, related to configuring + // the protocol and transport; blame Thrift. thriftSocket, err := thrift.NewTServerSocket(*thriftAddr) if err != nil { logger.Log("transport", "Thrift", "during", "Listen", "err", err) @@ -175,8 +207,8 @@ return fmt.Errorf("invalid Thrift protocol %q", *thriftProtocol) } var transportFactory thrift.TTransportFactory - if *thriftBufferSize > 0 { - transportFactory = thrift.NewTBufferedTransportFactory(*thriftBufferSize) + if *thriftBuffer > 0 { + transportFactory = thrift.NewTBufferedTransportFactory(*thriftBuffer) } else { transportFactory = thrift.NewTTransportFactory() } @@ -184,7 +216,7 @@ transportFactory = thrift.NewTFramedTransportFactory(transportFactory) } return thrift.NewTSimpleServer4( - addthrift.NewAddServiceProcessor(thriftHandler), + addthrift.NewAddServiceProcessor(thriftServer), thriftSocket, transportFactory, protocolFactory, @@ -194,6 +226,7 @@ }) } { + // This function just sits and waits for ctrl-C. cancelInterrupt := make(chan struct{}) g.Add(func() error { c := make(chan os.Signal, 1) @@ -210,3 +243,18 @@ } logger.Log("exit", g.Run()) } + +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") + } +} diff --git a/examples/addsvc2/pkg/transport/grpc.go b/examples/addsvc2/pkg/transport/grpc.go index bbbb592..59eac93 100644 --- a/examples/addsvc2/pkg/transport/grpc.go +++ b/examples/addsvc2/pkg/transport/grpc.go @@ -15,8 +15,8 @@ "github.com/go-kit/kit/examples/addsvc2/pkg/endpoint" ) -// MakeGRPCServer makes a set of endpoints available as a gRPC AddServer. -func MakeGRPCServer(endpoints endpoint.Set, tracer stdopentracing.Tracer, logger log.Logger) pb.AddServer { +// NewGRPCServer makes a set of endpoints available as a gRPC AddServer. +func NewGRPCServer(endpoints endpoint.Set, tracer stdopentracing.Tracer, logger log.Logger) pb.AddServer { options := []grpctransport.ServerOption{ grpctransport.ServerErrorLogger(logger), } diff --git a/examples/addsvc2/pkg/transport/thrift.go b/examples/addsvc2/pkg/transport/thrift.go index 02beba5..49d99ff 100644 --- a/examples/addsvc2/pkg/transport/thrift.go +++ b/examples/addsvc2/pkg/transport/thrift.go @@ -9,8 +9,8 @@ thriftadd "github.com/go-kit/kit/examples/addsvc2/thrift/gen-go/addsvc" ) -// MakeThriftHandler makes a set of endpoints available as a Thrift service. -func MakeThriftHandler(ctx context.Context, endpoints addendpoint.Set) thriftadd.AddService { +// NewThriftServer makes a set of endpoints available as a Thrift service. +func NewThriftServer(ctx context.Context, endpoints addendpoint.Set) thriftadd.AddService { return &thriftServer{ ctx: ctx, endpoints: endpoints,