Skip to content

Commit

Permalink
lxd/api_metrics: Filter query for Warnings appropriately
Browse files Browse the repository at this point in the history
Filters query for Warnings on the metrics handler by Node. Since some
Warnings do not have a node, nodeless Warnings are only being included
if querying the metrics from the leader node.

Signed-off-by: hamistao <[email protected]>
  • Loading branch information
hamistao committed Nov 12, 2024
1 parent 0cc6c7f commit e24204d
Showing 1 changed file with 34 additions and 4 deletions.
38 changes: 34 additions & 4 deletions lxd/api_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/canonical/lxd/lxd/auth"
"github.com/canonical/lxd/lxd/db"
dbCluster "github.com/canonical/lxd/lxd/db/cluster"
"github.com/canonical/lxd/lxd/db/warningtype"
"github.com/canonical/lxd/lxd/instance"
instanceDrivers "github.com/canonical/lxd/lxd/instance/drivers"
"github.com/canonical/lxd/lxd/instance/instancetype"
Expand Down Expand Up @@ -129,7 +130,7 @@ func metricsGet(d *Daemon, r *http.Request) response.Response {
}

// Register internal metrics.
intMetrics = internalMetrics(ctx, s.StartTime, tx)
intMetrics = internalMetrics(ctx, s, tx)
return nil
})
if err != nil {
Expand Down Expand Up @@ -378,10 +379,39 @@ func getFilteredMetrics(s *state.State, r *http.Request, compress bool, metricSe
return response.SyncResponsePlain(true, compress, metricSet.String())
}

func internalMetrics(ctx context.Context, daemonStartTime time.Time, tx *db.ClusterTx) *metrics.MetricSet {
// clusterMemberWarnings returns the list of unresolved warnings related to this cluster member.
// If this member is the leader, also include nodeless warnings.
// This way we include them while avoiding counting them redundantly across cluster members.
func clusterMemberWarnings(ctx context.Context, s *state.State, tx *db.ClusterTx) ([]dbCluster.Warning, error) {
var filters []dbCluster.WarningFilter

leaderInfo, err := s.LeaderInfo()
if err != nil {
return nil, err
}

// Use local variable to get pointer.
emptyNode := ""

for status := range warningtype.Statuses {
// Do not include resolved warnings that are resolved but not yet pruned.
if status != warningtype.StatusResolved {
filters = append(filters, dbCluster.WarningFilter{Node: &s.ServerName, Status: &status})
if leaderInfo.Leader {
// Count the nodeless warnings as belonging to the leader node.
filters = append(filters, dbCluster.WarningFilter{Node: &emptyNode, Status: &status})
}
}
}

return dbCluster.GetWarnings(ctx, tx.Tx(), filters...)
}

func internalMetrics(ctx context.Context, s *state.State, tx *db.ClusterTx) *metrics.MetricSet {
out := metrics.NewMetricSet(nil)

warnings, err := dbCluster.GetWarnings(ctx, tx.Tx())
warnings, err := clusterMemberWarnings(ctx, s, tx)

if err != nil {
logger.Warn("Failed to get warnings", logger.Ctx{"err": err})
} else {
Expand Down Expand Up @@ -421,7 +451,7 @@ func internalMetrics(ctx context.Context, daemonStartTime time.Time, tx *db.Clus
}

// Daemon uptime
out.AddSamples(metrics.UptimeSeconds, metrics.Sample{Value: time.Since(daemonStartTime).Seconds()})
out.AddSamples(metrics.UptimeSeconds, metrics.Sample{Value: time.Since(s.StartTime).Seconds()})

// Number of goroutines
out.AddSamples(metrics.GoGoroutines, metrics.Sample{Value: float64(runtime.NumGoroutine())})
Expand Down

0 comments on commit e24204d

Please sign in to comment.