├── .gitignore ├── services ├── backend │ ├── Dockerfile │ ├── cloudbuild.yaml │ └── main.go ├── message │ ├── Dockerfile │ ├── cloudbuild.yaml │ └── main.go ├── frontend │ ├── Dockerfile │ ├── cloudbuild.yaml │ └── main.go └── message-grpc │ ├── Dockerfile │ ├── cloudbuild.yaml │ └── main.go ├── trace.png ├── proto └── message │ ├── README.md │ ├── message.proto │ └── message.pb.go ├── cloudbuild.sh ├── cluster.sh ├── README.md └── kubernetes.yaml.tmpl /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | kubernetes.yaml -------------------------------------------------------------------------------- /services/backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | ADD app /app 3 | CMD ["./app"] 4 | -------------------------------------------------------------------------------- /services/message/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | ADD app /app 3 | CMD ["./app"] 4 | -------------------------------------------------------------------------------- /services/frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | ADD app /app 3 | CMD ["./app"] 4 | -------------------------------------------------------------------------------- /services/message-grpc/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | ADD app /app 3 | CMD ["./app"] 4 | -------------------------------------------------------------------------------- /trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnksm/go-distributed-tracing/HEAD/trace.png -------------------------------------------------------------------------------- /proto/message/README.md: -------------------------------------------------------------------------------- 1 | # Message service protobuf 2 | 3 | This repository contains protobuf message service definition. 4 | 5 | To generate go package, 6 | 7 | ```bash 8 | $ protoc -I=./ --go_out=plugins=grpc:./ message.proto 9 | ``` 10 | -------------------------------------------------------------------------------- /proto/message/message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package message; 4 | 5 | service Message { 6 | rpc Hello(HelloRequest) returns (HelloResponse) {} 7 | } 8 | 9 | message HelloRequest { 10 | string name = 1; 11 | } 12 | 13 | message HelloResponse { 14 | string message = 1; 15 | } -------------------------------------------------------------------------------- /cloudbuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "${PROJECT_ID}" ]; then 4 | echo "[ERROR] Set GCP project ID by PROJECT_ID env var" 5 | exit 1 6 | fi 7 | 8 | for dir in `find services -type d -depth 1` ; do 9 | pushd $dir 10 | echo "gcloud container builds submit --config cloudbuild.yaml . --project $PROJECT_ID" 11 | popd 12 | done 13 | -------------------------------------------------------------------------------- /cluster.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "${PROJECT_ID}" ]; then 4 | echo "[ERROR] Set GCP project ID by PROJECT_ID env var" 5 | exit 1 6 | fi 7 | 8 | gcloud container clusters create test-trace-cluster \ 9 | --project $PROJECT_ID \ 10 | --zone us-west1-b \ 11 | --scopes default,bigquery,cloud-platform,compute-rw,datastore,logging-write,monitoring-write 12 | -------------------------------------------------------------------------------- /services/backend/cloudbuild.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - name: gcr.io/cloud-builders/go 3 | env: ["PROJECT_ROOT=app"] 4 | args: ["get","-v"] 5 | 6 | - name: gcr.io/cloud-builders/go 7 | env: ["PROJECT_ROOT=app"] 8 | args: ["build", "-o", "app"] 9 | 10 | - name: "gcr.io/cloud-builders/docker" 11 | args: ["build", "-t", "gcr.io/$PROJECT_ID/service-backend:latest", "." ] 12 | 13 | images: 14 | - "gcr.io/$PROJECT_ID/service-backend:latest" 15 | -------------------------------------------------------------------------------- /services/frontend/cloudbuild.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - name: gcr.io/cloud-builders/go 3 | env: ["PROJECT_ROOT=app"] 4 | args: ["get","-v"] 5 | 6 | - name: gcr.io/cloud-builders/go 7 | env: ["PROJECT_ROOT=app"] 8 | args: ["build", "-o", "app"] 9 | 10 | - name: "gcr.io/cloud-builders/docker" 11 | args: ["build", "-t", "gcr.io/$PROJECT_ID/service-frontend:latest", "." ] 12 | 13 | images: 14 | - "gcr.io/$PROJECT_ID/service-frontend:latest" 15 | -------------------------------------------------------------------------------- /services/message/cloudbuild.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - name: gcr.io/cloud-builders/go 3 | env: ["PROJECT_ROOT=app"] 4 | args: ["get","-v"] 5 | 6 | - name: gcr.io/cloud-builders/go 7 | env: ["PROJECT_ROOT=app"] 8 | args: ["build", "-o", "app"] 9 | 10 | - name: "gcr.io/cloud-builders/docker" 11 | args: ["build", "-t", "gcr.io/$PROJECT_ID/service-message:latest", "." ] 12 | 13 | images: 14 | - "gcr.io/$PROJECT_ID/service-message:latest" 15 | -------------------------------------------------------------------------------- /services/message-grpc/cloudbuild.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - name: gcr.io/cloud-builders/go 3 | env: ["PROJECT_ROOT=app"] 4 | args: ["get","-v"] 5 | 6 | - name: gcr.io/cloud-builders/go 7 | env: ["PROJECT_ROOT=app"] 8 | args: ["build", "-o", "app"] 9 | 10 | - name: "gcr.io/cloud-builders/docker" 11 | args: ["build", "-t", "gcr.io/$PROJECT_ID/service-message-grpc:latest", "." ] 12 | 13 | images: 14 | - "gcr.io/$PROJECT_ID/service-message-grpc:latest" 15 | -------------------------------------------------------------------------------- /services/message/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "log" 6 | "net/http" 7 | "time" 8 | 9 | "cloud.google.com/go/trace" 10 | ) 11 | 12 | func main() { 13 | 14 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 15 | log.Printf("[INFO] %s %s %s", r.Method, r.URL.Path, r.UserAgent()) 16 | span := trace.FromContext(r.Context()) 17 | defer span.Finish() 18 | 19 | time.Sleep(10 * time.Millisecond) 20 | 21 | response := struct { 22 | Message string `json:"message"` 23 | }{ 24 | Message: "hello, world", 25 | } 26 | 27 | w.Header().Add("Content-Type", "application/json") 28 | encoder := json.NewEncoder(w) 29 | if err := encoder.Encode(&response); err != nil { 30 | log.Printf("[ERROR] Failed to encode message: %s", err) 31 | return 32 | } 33 | }) 34 | 35 | log.Printf("[INFO] Start server") 36 | if err := http.ListenAndServe(":3002", nil); err != nil { 37 | log.Fatalf("[ERROR] Failed to start server") 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Distributed tracing for Golang 2 | 3 | This repository contains sample k8s config and golang microservices apps to try distributed tracing with GCP [Stackdriver trace](https://cloud.google.com/trace/). After setup, you can see the following tracing. This contains tracing example both HTTP and [gRPC](http://www.grpc.io/) requests. 4 | 5 | ![](/trace.png) 6 | 7 | ## Usage 8 | 9 | To create k8s cluster for this, 10 | 11 | ```bash 12 | $ ./cluster.sh 13 | ``` 14 | 15 | To build docker images on GCP Container Builder, 16 | 17 | ```bash 18 | $ ./cloudbuild.sh 19 | ``` 20 | 21 | To run apps in k8s, replace `$PROJECT_ID` with your GCP project ID in `kubernetes.yaml.tmpl`, 22 | 23 | ```bash 24 | $ kubectl apply -f kubernetes.yaml 25 | ``` 26 | 27 | ## Reference 28 | 29 | - [Google Cloud Platform Blog: Distributed tracing for Go](https://cloudplatform.googleblog.com/2017/04/distributed-tracing-for-Go.html) 30 | - [Automatic Stackdriver Tracing for gRPC · Go, the unwritten parts](https://rakyll.org/grpc-trace/) 31 | -------------------------------------------------------------------------------- /services/message-grpc/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | 8 | pb "github.com/tcnksm/go-distributed-trace/proto/message" 9 | 10 | "golang.org/x/net/context" 11 | "google.golang.org/grpc" 12 | ) 13 | 14 | const ( 15 | EnvProjectID = "PROJECT_ID" 16 | EnvMessageServiceHost = "MESSAGE_SERVICE_HOST" 17 | ) 18 | 19 | type messageServer struct { 20 | } 21 | 22 | func (s *messageServer) Hello(_ context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) { 23 | name := req.Name 24 | log.Printf("[INFO] Request: %s", name) 25 | return &pb.HelloResponse{ 26 | Message: fmt.Sprintf("hello, %s (gRPC)", name), 27 | }, nil 28 | } 29 | 30 | func main() { 31 | grpcServer := grpc.NewServer() 32 | pb.RegisterMessageServer(grpcServer, &messageServer{}) 33 | 34 | log.Println("[INFO] Listening grpc server on :4002") 35 | listener, err := net.Listen("tcp", ":4002") 36 | if err != nil { 37 | log.Fatalf("[ERROR] Failed to listen: %s", err) 38 | } 39 | 40 | if err := grpcServer.Serve(listener); err != nil { 41 | log.Fatalf("[ERROR] Failed to start server") 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /services/frontend/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "log" 7 | "net/http" 8 | "os" 9 | "time" 10 | 11 | "cloud.google.com/go/trace" 12 | ) 13 | 14 | const ( 15 | EnvProjectID = "PROJECT_ID" 16 | EnvBackendHost = "BACKEND_HOST" 17 | ) 18 | 19 | type messageClient struct{} 20 | 21 | func main() { 22 | 23 | traceClient, err := trace.NewClient(context.TODO(), os.Getenv(EnvProjectID)) 24 | if err != nil { 25 | log.Fatalf("[ERROR] Failed to create new trace client: %s", err) 26 | } 27 | 28 | http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) { 29 | username, password, ok := r.BasicAuth() 30 | if !ok || !(username == "tcnksm" && password == "ncpai4wbp948bc49qu") { 31 | w.WriteHeader(http.StatusUnauthorized) 32 | return 33 | } 34 | 35 | log.Printf("[INFO] %s %s %s", r.Method, r.URL.Path, r.UserAgent()) 36 | span := traceClient.NewSpan("/hello") 37 | defer span.Finish() 38 | 39 | heavyF := func(name string, t time.Duration) { 40 | spanC := span.NewChild(name) 41 | defer spanC.Finish() 42 | time.Sleep(t) 43 | } 44 | 45 | heavyF("frontend-process1", 40*time.Millisecond) 46 | heavyF("frontend-process2", 50*time.Millisecond) 47 | 48 | host := os.Getenv(EnvBackendHost) 49 | if len(host) == 0 { 50 | w.Header().Add("Content-Type", "text/plain") 51 | w.WriteHeader(http.StatusOK) 52 | w.Write([]byte("No backend service is working\n")) 53 | return 54 | } 55 | 56 | req, err := http.NewRequest("GET", host, nil) 57 | if err != nil { 58 | log.Printf("[ERROR] Failed to create new request: %s", err) 59 | return 60 | } 61 | 62 | remoteSpan := span.NewRemoteChild(req) 63 | defer remoteSpan.Finish() 64 | 65 | resp, err := http.DefaultClient.Do(req) 66 | if err != nil { 67 | log.Printf("[ERROR] Failed to do request: %s", err) 68 | return 69 | } 70 | 71 | w.WriteHeader(http.StatusOK) 72 | io.Copy(w, resp.Body) 73 | }) 74 | 75 | log.Printf("[INFO] Start server") 76 | if err := http.ListenAndServe(":3000", nil); err != nil { 77 | log.Fatalf("[ERROR] Failed to start server: %s", err) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /services/backend/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "log" 7 | "net/http" 8 | "os" 9 | "time" 10 | 11 | pb "github.com/tcnksm/go-distributed-trace/proto/message" 12 | 13 | "cloud.google.com/go/trace" 14 | "google.golang.org/grpc" 15 | ) 16 | 17 | const ( 18 | EnvProjectID = "PROJECT_ID" 19 | EnvMessageServiceHost = "MESSAGE_SERVICE_HOST" 20 | EnvGRPCMessageServiceHost = "GRPC_MESSAGE_SERVICE_HOST" 21 | ) 22 | 23 | func main() { 24 | 25 | traceClient, err := trace.NewClient(context.TODO(), os.Getenv(EnvProjectID)) 26 | if err != nil { 27 | log.Fatalf("[ERROR] Failed to create new trace client: %s", err) 28 | } 29 | 30 | http.HandleFunc("/message", func(w http.ResponseWriter, r *http.Request) { 31 | log.Printf("[INFO] %s %s %s", r.Method, r.URL.Path, r.UserAgent()) 32 | span := traceClient.SpanFromRequest(r) 33 | defer span.Finish() 34 | 35 | heavyF := func(name string, t time.Duration) { 36 | spanC := span.NewChild(name) 37 | defer spanC.Finish() 38 | time.Sleep(t) 39 | } 40 | 41 | // TODO(tcnksm): Does not work ..... 42 | heavyF("backend-process1", 10*time.Millisecond) 43 | heavyF("backend-process2", 30*time.Millisecond) 44 | 45 | host := os.Getenv(EnvMessageServiceHost) 46 | grpcHost := os.Getenv(EnvGRPCMessageServiceHost) 47 | 48 | if len(host) != 0 { 49 | // Do normal http request 50 | req, err := http.NewRequest("GET", host, nil) 51 | if err != nil { 52 | log.Printf("[ERROR] Failed to create new request: %s", err) 53 | return 54 | } 55 | 56 | remoteSpan := span.NewRemoteChild(req) 57 | defer remoteSpan.Finish() 58 | 59 | resp, err := http.DefaultClient.Do(req) 60 | if err != nil { 61 | log.Printf("[ERROR] Failed to do request: %s", err) 62 | return 63 | } 64 | 65 | w.Header().Add("Content-Type", "application/json") 66 | w.WriteHeader(http.StatusOK) 67 | io.Copy(w, resp.Body) 68 | 69 | } else if len(grpcHost) != 0 { 70 | // Do gRPC request 71 | conn, err := grpc.Dial(grpcHost, grpc.WithInsecure(), grpc.WithUnaryInterceptor(trace.GRPCClientInterceptor())) 72 | if err != nil { 73 | log.Fatalf("[ERROR] Faield to connect: %v", err) 74 | return 75 | } 76 | defer conn.Close() 77 | 78 | client := pb.NewMessageClient(conn) 79 | 80 | grpcSpan := span.NewChild(grpcHost) 81 | defer grpcSpan.Finish() 82 | 83 | ctx := trace.NewContext(r.Context(), grpcSpan) 84 | resp, err := client.Hello(ctx, &pb.HelloRequest{ 85 | Name: "tcnksm", 86 | }) 87 | if err != nil { 88 | log.Fatalf("[ERROR] Faield: %v", err) 89 | return 90 | } 91 | 92 | w.Header().Add("Content-Type", "text/plain") 93 | w.WriteHeader(http.StatusOK) 94 | w.Write([]byte(resp.Message + "\n")) 95 | return 96 | 97 | } else { 98 | w.WriteHeader(http.StatusInternalServerError) 99 | w.Write([]byte("No backend message service is working\n")) 100 | return 101 | } 102 | }) 103 | 104 | log.Printf("[INFO] Start server on :3001") 105 | if err := http.ListenAndServe(":3001", nil); err != nil { 106 | log.Fatalf("[ERROR] Failed to start server: %s", err) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /kubernetes.yaml.tmpl: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: frontend 5 | labels: 6 | app: frontend 7 | spec: 8 | replicas: 1 9 | template: 10 | metadata: 11 | name: frontend 12 | labels: 13 | app: frontend 14 | spec: 15 | containers: 16 | - name: frontend 17 | image: gcr.io/$PROJECT_ID/service-frontend:latest 18 | imagePullPolicy: Always 19 | ports: 20 | - name: frontend 21 | containerPort: 3000 22 | env: 23 | - name: BACKEND_HOST 24 | value: "http://backend.default.svc.cluster.local/message" 25 | - name: PROJECT_ID 26 | value: "$PROJECT_ID" 27 | 28 | 29 | --- 30 | apiVersion: extensions/v1beta1 31 | kind: Deployment 32 | metadata: 33 | name: backend 34 | labels: 35 | app: backend 36 | spec: 37 | replicas: 1 38 | template: 39 | metadata: 40 | name: backend 41 | labels: 42 | app: backend 43 | spec: 44 | containers: 45 | - name: backend 46 | image: gcr.io/$PROJECT_ID/service-backend:latest 47 | imagePullPolicy: Always 48 | ports: 49 | - name: backend 50 | containerPort: 3001 51 | env: 52 | - name: GRPC_MESSAGE_SERVICE_HOST 53 | value: "message-grpc.default.svc.cluster.local:80" 54 | - name: MESSAGE_SERVICE_HOST 55 | value: "" # "http://message.default.svc.cluster.local" 56 | - name: PROJECT_ID 57 | value: "$PROJECT_ID" 58 | 59 | --- 60 | apiVersion: extensions/v1beta1 61 | kind: Deployment 62 | metadata: 63 | name: message 64 | labels: 65 | app: message 66 | spec: 67 | replicas: 1 68 | template: 69 | metadata: 70 | name: message 71 | labels: 72 | app: message 73 | spec: 74 | containers: 75 | - name: message 76 | image: gcr.io/$PROJECT_ID/service-message:latest 77 | imagePullPolicy: Always 78 | ports: 79 | - name: message 80 | containerPort: 3002 81 | 82 | --- 83 | apiVersion: extensions/v1beta1 84 | kind: Deployment 85 | metadata: 86 | name: message-grpc 87 | labels: 88 | app: message-grpc 89 | spec: 90 | replicas: 1 91 | template: 92 | metadata: 93 | name: message-grpc 94 | labels: 95 | app: message-grpc 96 | spec: 97 | containers: 98 | - name: message-grpc 99 | image: gcr.io/$PROJECT_ID/service-message-grpc:latest 100 | imagePullPolicy: Always 101 | ports: 102 | - name: message-grpc 103 | containerPort: 4002 104 | 105 | --- 106 | apiVersion: v1 107 | kind: Service 108 | metadata: 109 | name: frontend 110 | spec: 111 | selector: 112 | app: frontend 113 | type: LoadBalancer 114 | ports: 115 | - protocol: TCP 116 | port: 80 117 | targetPort: 3000 118 | 119 | --- 120 | apiVersion: v1 121 | kind: Service 122 | metadata: 123 | name: backend 124 | spec: 125 | selector: 126 | app: backend 127 | ports: 128 | - protocol: TCP 129 | port: 80 130 | targetPort: 3001 131 | 132 | --- 133 | apiVersion: v1 134 | kind: Service 135 | metadata: 136 | name: message 137 | spec: 138 | selector: 139 | app: message 140 | ports: 141 | - protocol: TCP 142 | port: 80 143 | targetPort: 3002 144 | 145 | --- 146 | apiVersion: v1 147 | kind: Service 148 | metadata: 149 | name: message-grpc 150 | spec: 151 | selector: 152 | app: message-grpc 153 | ports: 154 | - protocol: TCP 155 | port: 80 156 | targetPort: 4002 157 | 158 | -------------------------------------------------------------------------------- /proto/message/message.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: message.proto 3 | // DO NOT EDIT! 4 | 5 | /* 6 | Package message is a generated protocol buffer package. 7 | 8 | It is generated from these files: 9 | message.proto 10 | 11 | It has these top-level messages: 12 | HelloRequest 13 | HelloResponse 14 | */ 15 | package message 16 | 17 | import proto "github.com/golang/protobuf/proto" 18 | import fmt "fmt" 19 | import math "math" 20 | 21 | import ( 22 | context "golang.org/x/net/context" 23 | grpc "google.golang.org/grpc" 24 | ) 25 | 26 | // Reference imports to suppress errors if they are not otherwise used. 27 | var _ = proto.Marshal 28 | var _ = fmt.Errorf 29 | var _ = math.Inf 30 | 31 | // This is a compile-time assertion to ensure that this generated file 32 | // is compatible with the proto package it is being compiled against. 33 | // A compilation error at this line likely means your copy of the 34 | // proto package needs to be updated. 35 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 36 | 37 | type HelloRequest struct { 38 | Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` 39 | } 40 | 41 | func (m *HelloRequest) Reset() { *m = HelloRequest{} } 42 | func (m *HelloRequest) String() string { return proto.CompactTextString(m) } 43 | func (*HelloRequest) ProtoMessage() {} 44 | func (*HelloRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 45 | 46 | func (m *HelloRequest) GetName() string { 47 | if m != nil { 48 | return m.Name 49 | } 50 | return "" 51 | } 52 | 53 | type HelloResponse struct { 54 | Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` 55 | } 56 | 57 | func (m *HelloResponse) Reset() { *m = HelloResponse{} } 58 | func (m *HelloResponse) String() string { return proto.CompactTextString(m) } 59 | func (*HelloResponse) ProtoMessage() {} 60 | func (*HelloResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } 61 | 62 | func (m *HelloResponse) GetMessage() string { 63 | if m != nil { 64 | return m.Message 65 | } 66 | return "" 67 | } 68 | 69 | func init() { 70 | proto.RegisterType((*HelloRequest)(nil), "message.HelloRequest") 71 | proto.RegisterType((*HelloResponse)(nil), "message.HelloResponse") 72 | } 73 | 74 | // Reference imports to suppress errors if they are not otherwise used. 75 | var _ context.Context 76 | var _ grpc.ClientConn 77 | 78 | // This is a compile-time assertion to ensure that this generated file 79 | // is compatible with the grpc package it is being compiled against. 80 | const _ = grpc.SupportPackageIsVersion4 81 | 82 | // Client API for Message service 83 | 84 | type MessageClient interface { 85 | Hello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) 86 | } 87 | 88 | type messageClient struct { 89 | cc *grpc.ClientConn 90 | } 91 | 92 | func NewMessageClient(cc *grpc.ClientConn) MessageClient { 93 | return &messageClient{cc} 94 | } 95 | 96 | func (c *messageClient) Hello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) { 97 | out := new(HelloResponse) 98 | err := grpc.Invoke(ctx, "/message.Message/Hello", in, out, c.cc, opts...) 99 | if err != nil { 100 | return nil, err 101 | } 102 | return out, nil 103 | } 104 | 105 | // Server API for Message service 106 | 107 | type MessageServer interface { 108 | Hello(context.Context, *HelloRequest) (*HelloResponse, error) 109 | } 110 | 111 | func RegisterMessageServer(s *grpc.Server, srv MessageServer) { 112 | s.RegisterService(&_Message_serviceDesc, srv) 113 | } 114 | 115 | func _Message_Hello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 116 | in := new(HelloRequest) 117 | if err := dec(in); err != nil { 118 | return nil, err 119 | } 120 | if interceptor == nil { 121 | return srv.(MessageServer).Hello(ctx, in) 122 | } 123 | info := &grpc.UnaryServerInfo{ 124 | Server: srv, 125 | FullMethod: "/message.Message/Hello", 126 | } 127 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 128 | return srv.(MessageServer).Hello(ctx, req.(*HelloRequest)) 129 | } 130 | return interceptor(ctx, in, info, handler) 131 | } 132 | 133 | var _Message_serviceDesc = grpc.ServiceDesc{ 134 | ServiceName: "message.Message", 135 | HandlerType: (*MessageServer)(nil), 136 | Methods: []grpc.MethodDesc{ 137 | { 138 | MethodName: "Hello", 139 | Handler: _Message_Hello_Handler, 140 | }, 141 | }, 142 | Streams: []grpc.StreamDesc{}, 143 | Metadata: "message.proto", 144 | } 145 | 146 | func init() { proto.RegisterFile("message.proto", fileDescriptor0) } 147 | 148 | var fileDescriptor0 = []byte{ 149 | // 130 bytes of a gzipped FileDescriptorProto 150 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xcd, 0x4d, 0x2d, 0x2e, 151 | 0x4e, 0x4c, 0x4f, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x87, 0x72, 0x95, 0x94, 0xb8, 152 | 0x78, 0x3c, 0x52, 0x73, 0x72, 0xf2, 0x83, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x84, 0xb8, 153 | 0x58, 0xf2, 0x12, 0x73, 0x53, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x25, 0x4d, 154 | 0x2e, 0x5e, 0xa8, 0x9a, 0xe2, 0x82, 0xfc, 0xbc, 0xe2, 0x54, 0x21, 0x09, 0x2e, 0x98, 0x7e, 0xa8, 155 | 0x3a, 0x18, 0xd7, 0xc8, 0x99, 0x8b, 0xdd, 0x17, 0xc2, 0x14, 0xb2, 0xe0, 0x62, 0x05, 0xeb, 0x12, 156 | 0x12, 0xd5, 0x83, 0xd9, 0x8d, 0x6c, 0x93, 0x94, 0x18, 0xba, 0x30, 0xc4, 0x70, 0x25, 0x86, 0x24, 157 | 0x36, 0xb0, 0x1b, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x75, 0x27, 0x77, 0x2e, 0xb4, 0x00, 158 | 0x00, 0x00, 159 | } 160 | --------------------------------------------------------------------------------