@@ -18,6 +18,7 @@ import (
18
18
"cloud.google.com/go/compute/metadata"
19
19
"golang.org/x/xerrors"
20
20
"gopkg.in/natefinch/lumberjack.v2"
21
+ "tailscale.com/util/clientmetric"
21
22
22
23
"cdr.dev/slog"
23
24
"cdr.dev/slog/sloggers/sloghuman"
@@ -36,6 +37,7 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
36
37
noReap bool
37
38
sshMaxTimeout time.Duration
38
39
tailnetListenPort int64
40
+ prometheusAddress string
39
41
)
40
42
cmd := & clibase.Cmd {
41
43
Use : "agent" ,
@@ -126,6 +128,13 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
126
128
agentPorts [port ] = "pprof"
127
129
}
128
130
131
+ prometheusSrvClose := ServeHandler (ctx , logger , prometheusMetricsHandler (), prometheusAddress , "prometheus" )
132
+ defer prometheusSrvClose ()
133
+ // Do a best effort here. If this fails, it's not a big deal.
134
+ if port , err := urlPort (prometheusAddress ); err == nil {
135
+ agentPorts [port ] = "prometheus"
136
+ }
137
+
129
138
// exchangeToken returns a session token.
130
139
// This is abstracted to allow for the same looping condition
131
140
// regardless of instance identity auth type.
@@ -257,6 +266,13 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
257
266
Description : "Specify a static port for Tailscale to use for listening." ,
258
267
Value : clibase .Int64Of (& tailnetListenPort ),
259
268
},
269
+ {
270
+ Flag : "prometheus-address" ,
271
+ Default : "127.0.0.1:2112" ,
272
+ Env : "CODER_AGENT_PROMETHEUS_ADDRESS" ,
273
+ Value : clibase .StringOf (& prometheusAddress ),
274
+ Description : "The bind address to serve Prometheus metrics." ,
275
+ },
260
276
}
261
277
262
278
return cmd
@@ -343,3 +359,12 @@ func urlPort(u string) (int, error) {
343
359
}
344
360
return - 1 , xerrors .Errorf ("invalid port: %s" , u )
345
361
}
362
+
363
+ func prometheusMetricsHandler () http.Handler {
364
+ // We don't have any other internal metrics so far, so it's safe to expose metrics this way.
365
+ // Based on: https://github.com/tailscale/tailscale/blob/280255acae604796a1113861f5a84e6fa2dc6121/ipn/localapi/localapi.go#L489
366
+ return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
367
+ w .Header ().Set ("Content-Type" , "text/plain" )
368
+ clientmetric .WritePrometheusExpositionFormat (w )
369
+ })
370
+ }
0 commit comments