Skip to content

Commit 1a4d836

Browse files
committed
feat: implement metrics for Image Factory
Fixes #14 This adds "standard" HTTP metrics for the frontend, and also three kinds of custom metrics: * schematic get/create * system extension popularity score * asset build metrics: cached/not cached, bytes, requests, in dimension of asset kind Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
1 parent 661dc70 commit 1a4d836

13 files changed

Lines changed: 328 additions & 69 deletions

File tree

cmd/image-factory/cmd/options.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ type Options struct { //nolint:govet
5353
CacheRepository string
5454
// Allow insecure connection to the cache repository.
5555
InsecureCacheRepository bool
56+
57+
// Bind address for Prometheus metrics.
58+
//
59+
// Leave empty to disable.
60+
MetricsListenAddr string
5661
}
5762

5863
// DefaultOptions are the default options.
@@ -77,4 +82,6 @@ var DefaultOptions = Options{
7782
TalosVersionRecheckInterval: 15 * time.Minute,
7883

7984
CacheRepository: "ghcr.io/siderolabs/image-factory/cache",
85+
86+
MetricsListenAddr: ":2122",
8087
}

cmd/image-factory/cmd/service.go

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"github.com/google/go-containerregistry/pkg/authn/github"
2121
"github.com/google/go-containerregistry/pkg/name"
2222
"github.com/google/go-containerregistry/pkg/v1/remote"
23+
"github.com/prometheus/client_golang/prometheus"
24+
"github.com/prometheus/client_golang/prometheus/promhttp"
2325
"github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio"
2426
"github.com/sigstore/cosign/v2/pkg/cosign"
2527
"github.com/sigstore/sigstore/pkg/cryptoutils"
@@ -121,9 +123,44 @@ func RunFactory(ctx context.Context, logger *zap.Logger, opts Options) error {
121123
return httpServer.Shutdown(shutdownCtx) //nolint:contextcheck
122124
})
123125

126+
if opts.MetricsListenAddr != "" {
127+
runMetricsServer(ctx, logger, eg, opts)
128+
}
129+
124130
return eg.Wait()
125131
}
126132

133+
func runMetricsServer(ctx context.Context, logger *zap.Logger, eg *errgroup.Group, opts Options) {
134+
var metricsMux http.ServeMux
135+
136+
metricsMux.Handle("/metrics", promhttp.Handler())
137+
138+
metricsServer := &http.Server{
139+
Addr: opts.MetricsListenAddr,
140+
Handler: &metricsMux,
141+
}
142+
143+
eg.Go(func() error {
144+
logger.Info("serving metrics", zap.String("listen_addr", opts.MetricsListenAddr))
145+
146+
err := metricsServer.ListenAndServe()
147+
if errors.Is(err, http.ErrServerClosed) {
148+
err = nil
149+
}
150+
151+
return err
152+
})
153+
154+
eg.Go(func() error {
155+
<-ctx.Done()
156+
157+
shutdownCtx, shutdownCtxCancel := context.WithTimeout(context.Background(), 5*time.Second)
158+
defer shutdownCtxCancel()
159+
160+
return metricsServer.Shutdown(shutdownCtx) //nolint:contextcheck
161+
})
162+
}
163+
127164
func buildArtifactsManager(ctx context.Context, logger *zap.Logger, opts Options) (*artifacts.Manager, error) {
128165
rootCerts, err := fulcio.GetRoots()
129166
if err != nil {
@@ -197,7 +234,14 @@ func buildAssetBuilder(logger *zap.Logger, artifactsManager *artifacts.Manager,
197234
return nil, fmt.Errorf("failed to parse cache repository: %w", err)
198235
}
199236

200-
return asset.NewBuilder(logger, artifactsManager, builderOptions)
237+
builder, err := asset.NewBuilder(logger, artifactsManager, builderOptions)
238+
if err != nil {
239+
return nil, err
240+
}
241+
242+
prometheus.MustRegister(builder)
243+
244+
return builder, nil
201245
}
202246

203247
func buildSchematicFactory(logger *zap.Logger, opts Options) (*schematic.Factory, error) {
@@ -211,7 +255,11 @@ func buildSchematicFactory(logger *zap.Logger, opts Options) (*schematic.Factory
211255
return nil, fmt.Errorf("failed to initialize storage: %w", err)
212256
}
213257

214-
return schematic.NewFactory(logger, cache.NewCache(storage), schematic.Options{}), nil
258+
factory := schematic.NewFactory(logger, cache.NewCache(storage), schematic.Options{})
259+
260+
prometheus.MustRegister(factory)
261+
262+
return factory, nil
215263
}
216264

217265
// remoteOptions returns options for remote registry access.

cmd/image-factory/flags.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ func initFlags() cmd.Options {
5050
"allow an insecure connection to the cache repository",
5151
)
5252

53+
flag.StringVar(&opts.MetricsListenAddr, "metrics-listen-addr", cmd.DefaultOptions.MetricsListenAddr, "metrics listen address (set empty to disable)")
54+
5355
flag.Parse()
5456

5557
return opts

go.mod

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ require (
1616
github.com/h2non/filetype v1.1.3
1717
github.com/julienschmidt/httprouter v1.3.0
1818
github.com/opencontainers/go-digest v1.0.0
19+
github.com/prometheus/client_golang v1.17.0
1920
github.com/siderolabs/gen v0.4.7
2021
github.com/siderolabs/go-pointer v1.0.0
2122
github.com/siderolabs/talos v1.6.0-alpha.1.0.20231030094658-cbe6e7622d01
2223
github.com/siderolabs/talos/pkg/machinery v1.6.0-alpha.1.0.20231030094658-cbe6e7622d01
2324
github.com/sigstore/cosign/v2 v2.2.0
24-
github.com/sigstore/sigstore v1.7.2
25+
github.com/sigstore/sigstore v1.7.5
26+
github.com/slok/go-http-metrics v0.11.0
2527
github.com/stretchr/testify v1.8.4
2628
github.com/u-root/u-root v0.11.0
2729
github.com/ulikunitz/xz v0.5.11
@@ -105,7 +107,7 @@ require (
105107
github.com/containerd/ttrpc v1.2.2 // indirect
106108
github.com/containerd/typeurl/v2 v2.1.1 // indirect
107109
github.com/containernetworking/cni v1.1.2 // indirect
108-
github.com/coreos/go-oidc/v3 v3.6.0 // indirect
110+
github.com/coreos/go-oidc/v3 v3.7.0 // indirect
109111
github.com/coreos/go-semver v0.3.1 // indirect
110112
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
111113
github.com/cosi-project/runtime v0.3.13 // indirect
@@ -145,7 +147,7 @@ require (
145147
github.com/go-openapi/validate v0.22.1 // indirect
146148
github.com/go-playground/locales v0.14.1 // indirect
147149
github.com/go-playground/universal-translator v0.18.1 // indirect
148-
github.com/go-playground/validator/v10 v10.15.1 // indirect
150+
github.com/go-playground/validator/v10 v10.15.5 // indirect
149151
github.com/gogo/protobuf v1.3.2 // indirect
150152
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
151153
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
@@ -183,15 +185,15 @@ require (
183185
github.com/josharian/native v1.1.0 // indirect
184186
github.com/jsimonetti/rtnetlink v1.3.5 // indirect
185187
github.com/json-iterator/go v1.1.12 // indirect
186-
github.com/klauspost/compress v1.16.7 // indirect
188+
github.com/klauspost/compress v1.17.1 // indirect
187189
github.com/leodido/go-urn v1.2.4 // indirect
188190
github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf // indirect
189191
github.com/magiconair/properties v1.8.7 // indirect
190192
github.com/mailru/easyjson v0.7.7 // indirect
191193
github.com/martinlindhe/base36 v1.1.1 // indirect
192194
github.com/mattn/go-colorable v0.1.13 // indirect
193-
github.com/mattn/go-isatty v0.0.19 // indirect
194-
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
195+
github.com/mattn/go-isatty v0.0.20 // indirect
196+
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
195197
github.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875 // indirect
196198
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 // indirect
197199
github.com/mdlayher/ethtool v0.1.0 // indirect
@@ -221,16 +223,15 @@ require (
221223
github.com/opentracing/opentracing-go v1.2.0 // indirect
222224
github.com/packethost/packngo v0.30.0 // indirect
223225
github.com/pelletier/go-toml v1.9.5 // indirect
224-
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
226+
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
225227
github.com/pierrec/lz4/v4 v4.1.14 // indirect
226228
github.com/pin/tftp v2.1.0+incompatible // indirect
227229
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
228230
github.com/pkg/errors v0.9.1 // indirect
229231
github.com/pmezard/go-difflib v1.0.0 // indirect
230232
github.com/pmorjan/kmod v1.1.0 // indirect
231-
github.com/prometheus/client_golang v1.17.0 // indirect
232-
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
233-
github.com/prometheus/common v0.44.0 // indirect
233+
github.com/prometheus/client_model v0.5.0 // indirect
234+
github.com/prometheus/common v0.45.0 // indirect
234235
github.com/prometheus/procfs v0.12.0 // indirect
235236
github.com/rs/xid v1.5.0 // indirect
236237
github.com/ryanuber/go-glob v1.0.0 // indirect
@@ -300,16 +301,16 @@ require (
300301
go.uber.org/multierr v1.11.0 // indirect
301302
go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect
302303
golang.org/x/crypto v0.14.0 // indirect
303-
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
304+
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
304305
golang.org/x/mod v0.12.0 // indirect
305-
golang.org/x/oauth2 v0.12.0 // indirect
306+
golang.org/x/oauth2 v0.13.0 // indirect
306307
golang.org/x/term v0.13.0 // indirect
307308
golang.org/x/text v0.13.0 // indirect
308309
golang.org/x/time v0.3.0 // indirect
309-
golang.org/x/tools v0.12.0 // indirect
310+
golang.org/x/tools v0.13.0 // indirect
310311
golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect
311312
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 // indirect
312-
google.golang.org/appengine v1.6.7 // indirect
313+
google.golang.org/appengine v1.6.8 // indirect
313314
google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a // indirect
314315
google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect
315316
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect

0 commit comments

Comments
 (0)