add cmd flags, listen to signals, and use kit/log for logging
Marcel Hauf
8 years ago
2 | 2 | import ( |
3 | 3 | "bytes" |
4 | 4 | "encoding/json" |
5 | "flag" | |
6 | "fmt" | |
5 | 7 | "io" |
6 | 8 | "io/ioutil" |
7 | "log" | |
9 | stdlog "log" | |
8 | 10 | "net/http" |
9 | 11 | "net/url" |
12 | "os" | |
13 | "os/signal" | |
10 | 14 | "strings" |
15 | "syscall" | |
11 | 16 | |
12 | 17 | "golang.org/x/net/context" |
13 | 18 | |
16 | 21 | "github.com/go-kit/kit/endpoint" |
17 | 22 | "github.com/go-kit/kit/loadbalancer" |
18 | 23 | "github.com/go-kit/kit/loadbalancer/consul" |
19 | klog "github.com/go-kit/kit/log" | |
24 | log "github.com/go-kit/kit/log" | |
20 | 25 | httptransport "github.com/go-kit/kit/transport/http" |
21 | 26 | |
22 | 27 | "github.com/hashicorp/consul/api" |
25 | 30 | var ( |
26 | 31 | discoveryClient consul.Client |
27 | 32 | ctx = context.Background() |
33 | logger log.Logger | |
28 | 34 | ) |
29 | 35 | |
30 | 36 | func main() { |
37 | fs := flag.NewFlagSet("", flag.ExitOnError) | |
38 | var ( | |
39 | httpAddr = fs.String("http.addr", ":8000", "Address for HTTP (JSON) server") | |
40 | consulAddr = fs.String("consul.addr", "", "Consul agent address") | |
41 | ) | |
42 | flag.Usage = fs.Usage | |
43 | if err := fs.Parse(os.Args[1:]); err != nil { | |
44 | fmt.Fprintf(os.Stderr, "%v", err) | |
45 | os.Exit(1) | |
46 | } | |
31 | 47 | |
48 | // log | |
49 | logger = log.NewLogfmtLogger(os.Stderr) | |
50 | logger = log.NewContext(logger).With("ts", log.DefaultTimestampUTC).With("caller", log.DefaultCaller) | |
51 | stdlog.SetFlags(0) // flags are handled by Go kit's logger | |
52 | stdlog.SetOutput(log.NewStdlibAdapter(logger)) // redirect anything using stdlib log to us | |
53 | ||
54 | // errors | |
55 | errc := make(chan error) | |
56 | go func() { | |
57 | errc <- interrupt() | |
58 | }() | |
59 | ||
60 | // consul | |
32 | 61 | consulConfig := api.DefaultConfig() |
62 | if len(*consulAddr) > 0 { | |
63 | consulConfig.Address = *consulAddr | |
64 | } | |
33 | 65 | consulClient, err := api.NewClient(consulConfig) |
34 | 66 | if err != nil { |
35 | log.Fatal(err) | |
67 | logger.Log("fatal", err) | |
36 | 68 | } |
37 | 69 | discoveryClient = consul.NewClient(consulClient) |
38 | 70 | |
39 | r := mux.NewRouter() | |
40 | r.HandleFunc("/api/{service}/{method}", apiGateway) | |
71 | // apigateway | |
72 | go func() { | |
73 | r := mux.NewRouter() | |
74 | r.HandleFunc("/api/{service}/{method}", apiGateway) | |
75 | errc <- http.ListenAndServe(*httpAddr, r) | |
76 | }() | |
41 | 77 | |
42 | http.ListenAndServe(":8000", r) | |
78 | // wait for interrupt/error | |
79 | logger.Log("fatal", <-errc) | |
80 | } | |
81 | ||
82 | func interrupt() error { | |
83 | c := make(chan os.Signal) | |
84 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) | |
85 | return fmt.Errorf("%s", <-c) | |
43 | 86 | } |
44 | 87 | |
45 | 88 | func apiGateway(w http.ResponseWriter, r *http.Request) { |
48 | 91 | method := vars["method"] |
49 | 92 | e, err := getEndpoint(service, method) |
50 | 93 | if err != nil { |
51 | log.Print(err) | |
94 | logger.Log("error", err) | |
52 | 95 | return |
53 | 96 | } |
54 | 97 | |
56 | 99 | dec := json.NewDecoder(r.Body) |
57 | 100 | err = dec.Decode(&val) |
58 | 101 | if err != nil { |
59 | log.Print(err) | |
102 | logger.Log("warning", err) | |
103 | fmt.Fprint(w, err) | |
60 | 104 | return |
61 | 105 | } |
62 | 106 | |
63 | 107 | resp, err := e(ctx, val) |
64 | 108 | if err != nil { |
65 | log.Print(err) | |
109 | logger.Log("warning", err) | |
110 | fmt.Fprint(w, err) | |
66 | 111 | return |
67 | 112 | } |
68 | 113 | enc := json.NewEncoder(w) |
69 | 114 | err = enc.Encode(resp) |
70 | 115 | if err != nil { |
71 | log.Print(err) | |
116 | logger.Log("warning", err) | |
117 | fmt.Fprint(w, err) | |
72 | 118 | return |
73 | 119 | } |
74 | 120 | } |
84 | 130 | } |
85 | 131 | } |
86 | 132 | |
87 | publisher, err := consul.NewPublisher(discoveryClient, factory(ctx, method), klog.NewLogfmtLogger(&klog.StdlibWriter{}), se) | |
133 | publisher, err := consul.NewPublisher(discoveryClient, factory(ctx, method), log.NewLogfmtLogger(&log.StdlibWriter{}), se) | |
134 | publisher.Endpoints() | |
88 | 135 | if err != nil { |
89 | 136 | return nil, err |
90 | 137 | } |
128 | 175 | } |
129 | 176 | |
130 | 177 | func encodeRequest(r *http.Request, request interface{}) error { |
131 | log.Printf("encode req: %v", request) | |
132 | 178 | var buf bytes.Buffer |
133 | 179 | if err := json.NewEncoder(&buf).Encode(request); err != nil { |
134 | log.Print(err) | |
135 | 180 | return err |
136 | 181 | } |
137 | 182 | r.Body = ioutil.NopCloser(&buf) |