@@ -20,14 +20,17 @@ import (
20
20
"errors"
21
21
"fmt"
22
22
"net"
23
+ "net/http"
23
24
"net/url"
24
25
"os"
25
26
"os/signal"
26
27
"strconv"
27
28
"strings"
28
29
"syscall"
30
+ "time"
29
31
30
32
"cloud.google.com/go/alloydbconn"
33
+ "contrib.go.opencensus.io/exporter/prometheus"
31
34
"github.com/GoogleCloudPlatform/alloydb-auth-proxy/alloydb"
32
35
"github.com/GoogleCloudPlatform/alloydb-auth-proxy/internal/gcloud"
33
36
"github.com/GoogleCloudPlatform/alloydb-auth-proxy/internal/proxy"
@@ -75,6 +78,9 @@ func Execute() {
75
78
type Command struct {
76
79
* cobra.Command
77
80
conf * proxy.Config
81
+
82
+ prometheusNamespace string
83
+ httpPort string
78
84
}
79
85
80
86
// Option is a function that configures a Command.
@@ -126,6 +132,10 @@ without having to manage any client SSL certificates.`,
126
132
"Path to a service account key to use for authentication." )
127
133
cmd .PersistentFlags ().BoolVarP (& c .conf .GcloudAuth , "gcloud-auth" , "g" , false ,
128
134
"Use gcloud's user configuration to retrieve a token for authentication." )
135
+ cmd .PersistentFlags ().StringVar (& c .prometheusNamespace , "prometheus-namespace" , "" ,
136
+ "Enable Prometheus for metric collection using the provided namespace" )
137
+ cmd .PersistentFlags ().StringVar (& c .httpPort , "http-port" , "9090" ,
138
+ "Port for the Prometheus server to use" )
129
139
130
140
// Global and per instance flags
131
141
cmd .PersistentFlags ().StringVarP (& c .conf .Addr , "address" , "a" , "127.0.0.1" ,
@@ -194,6 +204,10 @@ func parseConfig(cmd *cobra.Command, conf *proxy.Config, args []string) error {
194
204
}
195
205
conf .DialerOpts = opts
196
206
207
+ if userHasSet ("http-port" ) && ! userHasSet ("prometheus-namespace" ) {
208
+ return newBadCommandError ("cannot specify --http-port without --prometheus-namespace" )
209
+ }
210
+
197
211
var ics []proxy.InstanceConnConfig
198
212
for _ , a := range args {
199
213
// Assume no query params initially
@@ -268,14 +282,46 @@ func runSignalWrapper(cmd *Command) error {
268
282
269
283
shutdownCh := make (chan error )
270
284
285
+ if cmd .prometheusNamespace != "" {
286
+ e , err := prometheus .NewExporter (prometheus.Options {
287
+ Namespace : cmd .prometheusNamespace ,
288
+ })
289
+ if err != nil {
290
+ return err
291
+ }
292
+ mux := http .NewServeMux ()
293
+ mux .Handle ("/metrics" , e )
294
+ addr := fmt .Sprintf ("localhost:%s" , cmd .httpPort )
295
+ server := & http.Server {Addr : addr , Handler : mux }
296
+ go func () {
297
+ select {
298
+ case <- ctx .Done ():
299
+ // Give the HTTP server a second to shutdown cleanly.
300
+ ctx2 , _ := context .WithTimeout (context .Background (), time .Second )
301
+ if err := server .Shutdown (ctx2 ); err != nil {
302
+ cmd .Printf ("failed to shutdown Prometheus HTTP server: %v\n " , err )
303
+ }
304
+ }
305
+ }()
306
+ go func () {
307
+ err := server .ListenAndServe ()
308
+ if err == http .ErrServerClosed {
309
+ return
310
+ }
311
+ if err != nil {
312
+ shutdownCh <- fmt .Errorf ("failed to start prometheus HTTP server: %v" , err )
313
+ }
314
+ }()
315
+ }
316
+
271
317
// watch for sigterm / sigint signals
272
318
signals := make (chan os.Signal , 1 )
273
319
signal .Notify (signals , syscall .SIGTERM , syscall .SIGINT )
274
320
go func () {
275
321
var s os.Signal
276
322
select {
277
323
case s = <- signals :
278
- case <- cmd . Context () .Done ():
324
+ case <- ctx .Done ():
279
325
// this should only happen when the context supplied in tests in canceled
280
326
s = syscall .SIGINT
281
327
}
0 commit comments