Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

frontend: refactor metrics #1413

Merged
merged 1 commit into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions frontend/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,6 @@ func (opts *FrontendOpts) Run() error {
logger := util.DefaultLogger()
logger.Info(fmt.Sprintf("%s (%s) started", frontend.ProgramName, util.Version()))

// Initialize the Prometheus emitter.
prometheusEmitter := frontend.NewPrometheusEmitter(prometheus.DefaultRegisterer)

// Initialize the global OpenTelemetry tracer.
otelShutdown, err := frontend.ConfigureOpenTelemetryTracer(ctx, logger, semconv.CloudRegion(opts.location))
if err != nil {
Expand Down Expand Up @@ -179,7 +176,7 @@ func (opts *FrontendOpts) Run() error {
}
logger.Info(fmt.Sprintf("Application running in %s", opts.location))

f := frontend.NewFrontend(logger, listener, metricsListener, prometheusEmitter, dbClient, opts.location, &csClient)
f := frontend.NewFrontend(logger, listener, metricsListener, prometheus.DefaultRegisterer, dbClient, opts.location, &csClient)

stop := make(chan struct{})
signalChannel := make(chan os.Signal, 1)
Expand Down
3 changes: 1 addition & 2 deletions frontend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ require (
go.opentelemetry.io/otel/sdk v1.34.0
go.opentelemetry.io/otel/trace v1.34.0
go.uber.org/mock v0.5.0
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
golang.org/x/sync v0.11.0
)

Expand Down Expand Up @@ -86,7 +85,7 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openshift/api v0.0.0-20240429104249-ac9356ba1784
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/client_model v0.6.1
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
Expand Down
2 changes: 0 additions & 2 deletions frontend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
Expand Down
7 changes: 7 additions & 0 deletions frontend/pkg/frontend/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,11 @@ const (
PathSegmentResourceGroupName = "resourcegroupname"
PathSegmentResourceName = "resourcename"
PathSegmentSubscriptionID = "subscriptionid"

healthGaugeName = "frontend_health"
requestCounterName = "frontend_http_requests_total"
requestDurationName = "frontend_http_requests_duration_seconds"

noMatchRouteLabel = "<no match>"
unknownVersionLabel = "<unknown>"
)
46 changes: 45 additions & 1 deletion frontend/pkg/frontend/context.go
Copy link
Collaborator

@mbarnes mbarnes Feb 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appreciate the refactoring of the context API. I won't ask for it this time but in the future it would be good to split refactoring into one or more focused commits for easier review. There's a lot packed into this one commit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I got a bit too enthusiastic here.

Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,43 @@ import (

type ContextError struct {
got any
key contextKey
}

func (c *ContextError) Error() string {
return fmt.Sprintf(
"error retrieving value from context, value obtained was '%v' and type obtained was '%T'",
"error retrieving value for key %q from context, value obtained was '%v' and type obtained was '%T'",
c.key,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice.

c.got,
c.got)
}

type contextKey int

func (c contextKey) String() string {
switch c {
case contextKeyOriginalPath:
return "originalPath"
case contextKeyBody:
return "body"
case contextKeyLogger:
return "logger"
case contextKeyVersion:
return "version"
case contextKeyDBClient:
return "dbClient"
case contextKeyResourceID:
return "resourceID"
case contextKeyCorrelationData:
return "correlationData"
case contextKeySystemData:
return "systemData"
case contextKeyPattern:
return "pattern"
}
return "<unknown>"
}

const (
// Keys for request-scoped data in http.Request contexts
contextKeyOriginalPath contextKey = iota
Expand All @@ -36,6 +62,7 @@ const (
contextKeyResourceID
contextKeyCorrelationData
contextKeySystemData
contextKeyPattern
)

func ContextWithOriginalPath(ctx context.Context, originalPath string) context.Context {
Expand All @@ -47,6 +74,7 @@ func OriginalPathFromContext(ctx context.Context) (string, error) {
if !ok {
err := &ContextError{
got: originalPath,
key: contextKeyOriginalPath,
}
return originalPath, err
}
Expand All @@ -62,6 +90,7 @@ func BodyFromContext(ctx context.Context) ([]byte, error) {
if !ok {
err := &ContextError{
got: body,
key: contextKeyBody,
}
return body, err
}
Expand All @@ -77,6 +106,7 @@ func LoggerFromContext(ctx context.Context) *slog.Logger {
if !ok {
err := &ContextError{
got: logger,
key: contextKeyLogger,
}
// Return the default logger as a fail-safe, but log
// the failure to obtain the logger from the context.
Expand All @@ -95,6 +125,7 @@ func VersionFromContext(ctx context.Context) (api.Version, error) {
if !ok {
err := &ContextError{
got: version,
key: contextKeyVersion,
}
return version, err
}
Expand All @@ -110,6 +141,7 @@ func DBClientFromContext(ctx context.Context) (database.DBClient, error) {
if !ok {
err := &ContextError{
got: dbClient,
key: contextKeyDBClient,
}
return dbClient, err
}
Expand All @@ -125,6 +157,7 @@ func ResourceIDFromContext(ctx context.Context) (*azcorearm.ResourceID, error) {
if !ok {
err := &ContextError{
got: resourceID,
key: contextKeyResourceID,
}
return resourceID, err
}
Expand All @@ -140,6 +173,7 @@ func CorrelationDataFromContext(ctx context.Context) (*arm.CorrelationData, erro
if !ok {
err := &ContextError{
got: correlationData,
key: contextKeyCorrelationData,
}
return correlationData, err
}
Expand All @@ -155,8 +189,18 @@ func SystemDataFromContext(ctx context.Context) (*arm.SystemData, error) {
if !ok {
err := &ContextError{
got: systemData,
key: contextKeySystemData,
}
return systemData, err
}
return systemData, nil
}

func ContextWithPattern(ctx context.Context, pattern *string) context.Context {
return context.WithValue(ctx, contextKeyPattern, pattern)
}

func PatternFromContext(ctx context.Context) *string {
pattern, _ := ctx.Value(contextKeyPattern).(*string)
return pattern
}
46 changes: 28 additions & 18 deletions frontend/pkg/frontend/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
azcorearm "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
arohcpv1alpha1 "github.com/openshift-online/ocm-sdk-go/arohcp/v1alpha1"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"golang.org/x/sync/errgroup"

"github.com/Azure/ARO-HCP/frontend/pkg/metrics"
Expand All @@ -39,16 +40,24 @@ type Frontend struct {
dbClient database.DBClient
ready atomic.Value
done chan struct{}
metrics Emitter
location string
collector *metrics.SubscriptionCollector
healthGauge prometheus.Gauge
}

func NewFrontend(logger *slog.Logger, listener net.Listener, metricsListener net.Listener, emitter Emitter, dbClient database.DBClient, location string, csClient ocm.ClusterServiceClientSpec) *Frontend {
func NewFrontend(
logger *slog.Logger,
listener net.Listener,
metricsListener net.Listener,
reg prometheus.Registerer,
dbClient database.DBClient,
location string,
csClient ocm.ClusterServiceClientSpec,
) *Frontend {
f := &Frontend{
clusterServiceClient: csClient,
listener: listener,
metricsListener: metricsListener,
metrics: emitter,
server: http.Server{
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
BaseContext: func(net.Listener) context.Context {
Expand All @@ -64,12 +73,19 @@ func NewFrontend(logger *slog.Logger, listener net.Listener, metricsListener net
return ContextWithLogger(context.Background(), logger)
},
},
dbClient: dbClient,
done: make(chan struct{}),
location: strings.ToLower(location),
dbClient: dbClient,
done: make(chan struct{}),
location: strings.ToLower(location),
collector: metrics.NewSubscriptionCollector(reg, dbClient, location),
healthGauge: promauto.With(reg).NewGauge(
prometheus.GaugeOpts{
Name: healthGaugeName,
Help: "Reports the health status of the service (0: not healthy, 1: healthy).",
},
),
}

f.server.Handler = f.routes()
f.server.Handler = f.routes(reg)
f.metricsServer.Handler = f.metricsRoutes()

return f
Expand Down Expand Up @@ -101,8 +117,7 @@ func (f *Frontend) Run(ctx context.Context, stop <-chan struct{}) {
return f.metricsServer.Serve(f.metricsListener)
})
errs.Go(func() error {
collector := metrics.NewSubscriptionCollector(prometheus.DefaultRegisterer, f.dbClient, f.location)
collector.Run(logger, stop)
f.collector.Run(logger, stop)
return nil
})

Expand Down Expand Up @@ -137,19 +152,14 @@ func (f *Frontend) NotFound(writer http.ResponseWriter, request *http.Request) {
}

func (f *Frontend) Healthz(writer http.ResponseWriter, request *http.Request) {
var healthStatus float64

if f.CheckReady(request.Context()) {
writer.WriteHeader(http.StatusOK)
healthStatus = 1.0
} else {
arm.WriteInternalServerError(writer)
healthStatus = 0.0
f.healthGauge.Set(1.0)
return
}

f.metrics.EmitGauge("frontend_health", healthStatus, map[string]string{
"endpoint": "/healthz",
})
arm.WriteInternalServerError(writer)
f.healthGauge.Set(0.0)
}

func (f *Frontend) ArmResourceList(writer http.ResponseWriter, request *http.Request) {
Expand Down
Loading
Loading