feat: add Prometheus metric for volume creation operations (#10026)

* feat: add Prometheus metric for volume creation operations

Add VolumeServerVolumeCreationCounter metric to track volume creation
attempts by result (success/failure).

Changes:
- Add VolumeServerVolumeCreationCounter in weed/stats/metrics.go
- Instrument GrowByCountAndType in weed/topology/volume_growth.go
- Add unit tests in weed/stats/metrics_volume_creation_test.go
- Add Grafana dashboard panel for volume creation rate

This metric enables monitoring volume creation success/failure rates
in SeaweedFS clusters.

* fix: address CodeRabbit review - move failure counter before early return

- Move failure counter into loop else block before return statement
- Move success counter to after loop completion
- Strengthen test assertion from count < 1 to count != 2
- Add t.Cleanup() for test isolation in TestVolumeCreationCounterIncrement

* fix: count each volume create attempt and move metric to master subsystem

- topology runs on the master, so move volume_creation_total from the
  volumeServer subsystem to master (SeaweedFS_master_volume_creation_total);
  rename the var to MasterVolumeCreationCounter and group it with the other
  master metrics.
- increment the counter per findAndGrow iteration instead of once per
  GrowByCountAndType call: each logical volume is now counted, partial
  successes before a failure are credited, and a targetCount==0 call no
  longer records a spurious success.
- update the Grafana panel query and the unit tests; the registration test
  now asserts via the shared Gather registry under the fully-qualified name.

* test: drop volume_creation metric tests

They only exercised the Prometheus client library (CounterVec increment and
registry collection), not any SeaweedFS behavior, so they carried maintenance
cost without verifying anything in this codebase.

---------

Co-authored-by: Ubuntu User <ubuntu@example.com>
Co-authored-by: Chris Lu <chris.lu@gmail.com>
This commit is contained in:
Rushikesh Deshpande 2026-06-21 23:26:03 +05:30 committed by GitHub
parent ee8742f393
commit e2a17a76fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 110 additions and 0 deletions

View File

@ -4266,6 +4266,102 @@
}
],
"pluginVersion": "10.3.1"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"title": "Volume Creation Rate",
"description": "Rate of volume creation operations by result",
"type": "timeseries",
"id": 216,
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 118
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 4,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"unit": "ops",
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
}
},
"overrides": []
},
"options": {
"legend": {
"calcs": [
"lastNotNull",
"max"
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "rate(SeaweedFS_master_volume_creation_total{cluster=~\"$cluster\"}[5m])",
"range": true,
"refId": "A",
"legendFormat": "{{result}}"
}
],
"pluginVersion": "10.3.1"
}
]
},

View File

@ -128,6 +128,16 @@ var (
Help: "Current number of volumes that do not have enough replicas per collection/layout. 0 = healthy.",
}, []string{"collection", "disk", "rp", "ttl"})
// MasterVolumeCreationCounter counts volume creation (growth) operations by result (success, failure).
// Volume growth is orchestrated by the master, so this metric is exported by the master process.
MasterVolumeCreationCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: "master",
Name: "volume_creation_total",
Help: "Counter of volume creation operations by result (success, failure).",
}, []string{"result"})
MasterPickForWriteErrorCounter = prometheus.NewCounter(
prometheus.CounterOpts{
Namespace: Namespace,
@ -863,6 +873,7 @@ func init() {
Gather.MustRegister(VolumeServerReplicationTargets)
Gather.MustRegister(VolumeServerReplicationFailures)
Gather.MustRegister(MasterUnderReplicatedVolumes)
Gather.MustRegister(MasterVolumeCreationCounter)
Gather.MustRegister(S3RequestCounter)
Gather.MustRegister(S3HandlerCounter)

View File

@ -13,6 +13,7 @@ import (
"google.golang.org/grpc"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/stats"
"github.com/seaweedfs/seaweedfs/weed/storage"
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
"github.com/seaweedfs/seaweedfs/weed/storage/super_block"
@ -136,8 +137,10 @@ func (vg *VolumeGrowth) GrowByCountAndType(grpcDialOption grpc.DialOption, targe
for i := uint32(0); i < targetCount; i++ {
if res, e := vg.findAndGrow(grpcDialOption, topo, option); e == nil {
result = append(result, res...)
stats.MasterVolumeCreationCounter.WithLabelValues("success").Inc()
} else {
glog.V(0).Infof("create %d volume, created %d: %v", targetCount, len(result), e)
stats.MasterVolumeCreationCounter.WithLabelValues("failure").Inc()
return result, e
}
}