Migrate custom collector for kubelet

This commit is contained in:
RainbowMango 2019-11-06 20:38:36 +08:00
parent 1016b8b58a
commit ee4394a306
9 changed files with 100 additions and 84 deletions

View File

@ -17,14 +17,13 @@ limitations under the License.
package collectors package collectors
import ( import (
"github.com/prometheus/client_golang/prometheus" "k8s.io/component-base/metrics"
"k8s.io/klog" "k8s.io/klog"
statsapi "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1" statsapi "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1"
) )
var ( var (
descLogSize = prometheus.NewDesc( descLogSize = metrics.NewDesc(
"kubelet_container_log_filesystem_used_bytes", "kubelet_container_log_filesystem_used_bytes",
"Bytes used by the container's logs on the filesystem.", "Bytes used by the container's logs on the filesystem.",
[]string{ []string{
@ -33,28 +32,35 @@ var (
"pod", "pod",
"container", "container",
}, nil, }, nil,
metrics.ALPHA,
"",
) )
) )
type logMetricsCollector struct { type logMetricsCollector struct {
metrics.BaseStableCollector
podStats func() ([]statsapi.PodStats, error) podStats func() ([]statsapi.PodStats, error)
} }
// NewLogMetricsCollector implements the prometheus.Collector interface and // Check if logMetricsCollector implements necessary interface
var _ metrics.StableCollector = &logMetricsCollector{}
// NewLogMetricsCollector implements the metrics.StableCollector interface and
// exposes metrics about container's log volume size. // exposes metrics about container's log volume size.
func NewLogMetricsCollector(podStats func() ([]statsapi.PodStats, error)) prometheus.Collector { func NewLogMetricsCollector(podStats func() ([]statsapi.PodStats, error)) metrics.StableCollector {
return &logMetricsCollector{ return &logMetricsCollector{
podStats: podStats, podStats: podStats,
} }
} }
// Describe implements the prometheus.Collector interface. // DescribeWithStability implements the metrics.StableCollector interface.
func (c *logMetricsCollector) Describe(ch chan<- *prometheus.Desc) { func (c *logMetricsCollector) DescribeWithStability(ch chan<- *metrics.Desc) {
ch <- descLogSize ch <- descLogSize
} }
// Collect implements the prometheus.Collector interface. // CollectWithStability implements the metrics.StableCollector interface.
func (c *logMetricsCollector) Collect(ch chan<- prometheus.Metric) { func (c *logMetricsCollector) CollectWithStability(ch chan<- metrics.Metric) {
podStats, err := c.podStats() podStats, err := c.podStats()
if err != nil { if err != nil {
klog.Errorf("failed to get pod stats: %v", err) klog.Errorf("failed to get pod stats: %v", err)
@ -64,9 +70,9 @@ func (c *logMetricsCollector) Collect(ch chan<- prometheus.Metric) {
for _, ps := range podStats { for _, ps := range podStats {
for _, c := range ps.Containers { for _, c := range ps.Containers {
if c.Logs != nil && c.Logs.UsedBytes != nil { if c.Logs != nil && c.Logs.UsedBytes != nil {
ch <- prometheus.MustNewConstMetric( ch <- metrics.NewLazyConstMetric(
descLogSize, descLogSize,
prometheus.GaugeValue, metrics.GaugeValue,
float64(*c.Logs.UsedBytes), float64(*c.Logs.UsedBytes),
ps.PodRef.UID, ps.PodRef.UID,
ps.PodRef.Namespace, ps.PodRef.Namespace,

View File

@ -25,18 +25,24 @@ import (
) )
func TestNoMetricsCollected(t *testing.T) { func TestNoMetricsCollected(t *testing.T) {
// Refresh Desc to share with different registry
descLogSize = descLogSize.GetRawDesc()
collector := &logMetricsCollector{ collector := &logMetricsCollector{
podStats: func() ([]statsapi.PodStats, error) { podStats: func() ([]statsapi.PodStats, error) {
return []statsapi.PodStats{}, nil return []statsapi.PodStats{}, nil
}, },
} }
if err := testutil.CollectAndCompare(collector, strings.NewReader(""), ""); err != nil { if err := testutil.CustomCollectAndCompare(collector, strings.NewReader(""), ""); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestMetricsCollected(t *testing.T) { func TestMetricsCollected(t *testing.T) {
// Refresh Desc to share with different registry
descLogSize = descLogSize.GetRawDesc()
size := uint64(18) size := uint64(18)
collector := &logMetricsCollector{ collector := &logMetricsCollector{
podStats: func() ([]statsapi.PodStats, error) { podStats: func() ([]statsapi.PodStats, error) {
@ -60,8 +66,8 @@ func TestMetricsCollected(t *testing.T) {
}, },
} }
err := testutil.CollectAndCompare(collector, strings.NewReader(` err := testutil.CustomCollectAndCompare(collector, strings.NewReader(`
# HELP kubelet_container_log_filesystem_used_bytes Bytes used by the container's logs on the filesystem. # HELP kubelet_container_log_filesystem_used_bytes [ALPHA] Bytes used by the container's logs on the filesystem.
# TYPE kubelet_container_log_filesystem_used_bytes gauge # TYPE kubelet_container_log_filesystem_used_bytes gauge
kubelet_container_log_filesystem_used_bytes{container="containerName1",namespace="some-namespace",pod="podName1",uid="UID_some_id"} 18 kubelet_container_log_filesystem_used_bytes{container="containerName1",namespace="some-namespace",pod="podName1",uid="UID_some_id"} 18
`), "kubelet_container_log_filesystem_used_bytes") `), "kubelet_container_log_filesystem_used_bytes")

View File

@ -17,58 +17,68 @@ limitations under the License.
package collectors package collectors
import ( import (
"github.com/prometheus/client_golang/prometheus"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog" "k8s.io/component-base/metrics"
stats "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1" stats "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1"
"k8s.io/kubernetes/pkg/kubelet/metrics" kubeletmetrics "k8s.io/kubernetes/pkg/kubelet/metrics"
serverstats "k8s.io/kubernetes/pkg/kubelet/server/stats" serverstats "k8s.io/kubernetes/pkg/kubelet/server/stats"
) )
var ( var (
volumeStatsCapacityBytesDesc = prometheus.NewDesc( volumeStatsCapacityBytesDesc = metrics.NewDesc(
prometheus.BuildFQName("", metrics.KubeletSubsystem, metrics.VolumeStatsCapacityBytesKey), metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsCapacityBytesKey),
"Capacity in bytes of the volume", "Capacity in bytes of the volume",
[]string{"namespace", "persistentvolumeclaim"}, nil, []string{"namespace", "persistentvolumeclaim"}, nil,
metrics.ALPHA, "",
) )
volumeStatsAvailableBytesDesc = prometheus.NewDesc( volumeStatsAvailableBytesDesc = metrics.NewDesc(
prometheus.BuildFQName("", metrics.KubeletSubsystem, metrics.VolumeStatsAvailableBytesKey), metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsAvailableBytesKey),
"Number of available bytes in the volume", "Number of available bytes in the volume",
[]string{"namespace", "persistentvolumeclaim"}, nil, []string{"namespace", "persistentvolumeclaim"}, nil,
metrics.ALPHA, "",
) )
volumeStatsUsedBytesDesc = prometheus.NewDesc( volumeStatsUsedBytesDesc = metrics.NewDesc(
prometheus.BuildFQName("", metrics.KubeletSubsystem, metrics.VolumeStatsUsedBytesKey), metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsUsedBytesKey),
"Number of used bytes in the volume", "Number of used bytes in the volume",
[]string{"namespace", "persistentvolumeclaim"}, nil, []string{"namespace", "persistentvolumeclaim"}, nil,
metrics.ALPHA, "",
) )
volumeStatsInodesDesc = prometheus.NewDesc( volumeStatsInodesDesc = metrics.NewDesc(
prometheus.BuildFQName("", metrics.KubeletSubsystem, metrics.VolumeStatsInodesKey), metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsInodesKey),
"Maximum number of inodes in the volume", "Maximum number of inodes in the volume",
[]string{"namespace", "persistentvolumeclaim"}, nil, []string{"namespace", "persistentvolumeclaim"}, nil,
metrics.ALPHA, "",
) )
volumeStatsInodesFreeDesc = prometheus.NewDesc( volumeStatsInodesFreeDesc = metrics.NewDesc(
prometheus.BuildFQName("", metrics.KubeletSubsystem, metrics.VolumeStatsInodesFreeKey), metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsInodesFreeKey),
"Number of free inodes in the volume", "Number of free inodes in the volume",
[]string{"namespace", "persistentvolumeclaim"}, nil, []string{"namespace", "persistentvolumeclaim"}, nil,
metrics.ALPHA, "",
) )
volumeStatsInodesUsedDesc = prometheus.NewDesc( volumeStatsInodesUsedDesc = metrics.NewDesc(
prometheus.BuildFQName("", metrics.KubeletSubsystem, metrics.VolumeStatsInodesUsedKey), metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsInodesUsedKey),
"Number of used inodes in the volume", "Number of used inodes in the volume",
[]string{"namespace", "persistentvolumeclaim"}, nil, []string{"namespace", "persistentvolumeclaim"}, nil,
metrics.ALPHA, "",
) )
) )
type volumeStatsCollector struct { type volumeStatsCollector struct {
metrics.BaseStableCollector
statsProvider serverstats.Provider statsProvider serverstats.Provider
} }
// NewVolumeStatsCollector creates a volume stats prometheus collector. // Check if volumeStatsCollector implements necessary interface
func NewVolumeStatsCollector(statsProvider serverstats.Provider) prometheus.Collector { var _ metrics.StableCollector = &volumeStatsCollector{}
// NewVolumeStatsCollector creates a volume stats metrics.StableCollector.
func NewVolumeStatsCollector(statsProvider serverstats.Provider) metrics.StableCollector {
return &volumeStatsCollector{statsProvider: statsProvider} return &volumeStatsCollector{statsProvider: statsProvider}
} }
// Describe implements the prometheus.Collector interface. // DescribeWithStability implements the metrics.StableCollector interface.
func (collector *volumeStatsCollector) Describe(ch chan<- *prometheus.Desc) { func (collector *volumeStatsCollector) DescribeWithStability(ch chan<- *metrics.Desc) {
ch <- volumeStatsCapacityBytesDesc ch <- volumeStatsCapacityBytesDesc
ch <- volumeStatsAvailableBytesDesc ch <- volumeStatsAvailableBytesDesc
ch <- volumeStatsUsedBytesDesc ch <- volumeStatsUsedBytesDesc
@ -77,20 +87,16 @@ func (collector *volumeStatsCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- volumeStatsInodesUsedDesc ch <- volumeStatsInodesUsedDesc
} }
// Collect implements the prometheus.Collector interface. // CollectWithStability implements the metrics.StableCollector interface.
func (collector *volumeStatsCollector) Collect(ch chan<- prometheus.Metric) { func (collector *volumeStatsCollector) CollectWithStability(ch chan<- metrics.Metric) {
podStats, err := collector.statsProvider.ListPodStats() podStats, err := collector.statsProvider.ListPodStats()
if err != nil { if err != nil {
return return
} }
addGauge := func(desc *prometheus.Desc, pvcRef *stats.PVCReference, v float64, lv ...string) { addGauge := func(desc *metrics.Desc, pvcRef *stats.PVCReference, v float64, lv ...string) {
lv = append([]string{pvcRef.Namespace, pvcRef.Name}, lv...) lv = append([]string{pvcRef.Namespace, pvcRef.Name}, lv...)
metric, err := prometheus.NewConstMetric(desc, prometheus.GaugeValue, v, lv...)
if err != nil { ch <- metrics.NewLazyConstMetric(desc, metrics.GaugeValue, v, lv...)
klog.Warningf("Failed to generate metric: %v", err)
return
}
ch <- metric
} }
allPVCs := sets.String{} allPVCs := sets.String{}
for _, podStat := range podStats { for _, podStat := range podStats {

View File

@ -34,17 +34,17 @@ func TestVolumeStatsCollector(t *testing.T) {
// Fixed metadata on type and help text. We prepend this to every expected // Fixed metadata on type and help text. We prepend this to every expected
// output so we only have to modify a single place when doing adjustments. // output so we only have to modify a single place when doing adjustments.
const metadata = ` const metadata = `
# HELP kubelet_volume_stats_available_bytes Number of available bytes in the volume # HELP kubelet_volume_stats_available_bytes [ALPHA] Number of available bytes in the volume
# TYPE kubelet_volume_stats_available_bytes gauge # TYPE kubelet_volume_stats_available_bytes gauge
# HELP kubelet_volume_stats_capacity_bytes Capacity in bytes of the volume # HELP kubelet_volume_stats_capacity_bytes [ALPHA] Capacity in bytes of the volume
# TYPE kubelet_volume_stats_capacity_bytes gauge # TYPE kubelet_volume_stats_capacity_bytes gauge
# HELP kubelet_volume_stats_inodes Maximum number of inodes in the volume # HELP kubelet_volume_stats_inodes [ALPHA] Maximum number of inodes in the volume
# TYPE kubelet_volume_stats_inodes gauge # TYPE kubelet_volume_stats_inodes gauge
# HELP kubelet_volume_stats_inodes_free Number of free inodes in the volume # HELP kubelet_volume_stats_inodes_free [ALPHA] Number of free inodes in the volume
# TYPE kubelet_volume_stats_inodes_free gauge # TYPE kubelet_volume_stats_inodes_free gauge
# HELP kubelet_volume_stats_inodes_used Number of used inodes in the volume # HELP kubelet_volume_stats_inodes_used [ALPHA] Number of used inodes in the volume
# TYPE kubelet_volume_stats_inodes_used gauge # TYPE kubelet_volume_stats_inodes_used gauge
# HELP kubelet_volume_stats_used_bytes Number of used bytes in the volume # HELP kubelet_volume_stats_used_bytes [ALPHA] Number of used bytes in the volume
# TYPE kubelet_volume_stats_used_bytes gauge # TYPE kubelet_volume_stats_used_bytes gauge
` `
@ -132,7 +132,7 @@ func TestVolumeStatsCollector(t *testing.T) {
mockStatsProvider := new(statstest.StatsProvider) mockStatsProvider := new(statstest.StatsProvider)
mockStatsProvider.On("ListPodStats").Return(podStats, nil) mockStatsProvider.On("ListPodStats").Return(podStats, nil)
mockStatsProvider.On("ListPodStatsAndUpdateCPUNanoCoreUsage").Return(podStats, nil) mockStatsProvider.On("ListPodStatsAndUpdateCPUNanoCoreUsage").Return(podStats, nil)
if err := testutil.CollectAndCompare(&volumeStatsCollector{statsProvider: mockStatsProvider}, strings.NewReader(want), metrics...); err != nil { if err := testutil.CustomCollectAndCompare(&volumeStatsCollector{statsProvider: mockStatsProvider}, strings.NewReader(want), metrics...); err != nil {
t.Errorf("unexpected collecting result:\n%s", err) t.Errorf("unexpected collecting result:\n%s", err)
} }
} }

View File

@ -499,7 +499,7 @@ var (
var registerMetrics sync.Once var registerMetrics sync.Once
// Register registers all metrics. // Register registers all metrics.
func Register(containerCache kubecontainer.RuntimeCache, collectors ...metrics.Collector) { func Register(containerCache kubecontainer.RuntimeCache, collectors ...metrics.StableCollector) {
// Register the metrics. // Register the metrics.
registerMetrics.Do(func() { registerMetrics.Do(func() {
legacyregistry.MustRegister(NodeName) legacyregistry.MustRegister(NodeName)
@ -540,7 +540,7 @@ func Register(containerCache kubecontainer.RuntimeCache, collectors ...metrics.C
legacyregistry.MustRegister(ConfigError) legacyregistry.MustRegister(ConfigError)
} }
for _, collector := range collectors { for _, collector := range collectors {
legacyregistry.RawMustRegister(collector) legacyregistry.CustomMustRegister(collector)
} }
}) })
} }

View File

@ -19,8 +19,8 @@ package metrics
import ( import (
"sync" "sync"
"github.com/prometheus/client_golang/prometheus" "k8s.io/component-base/metrics"
"k8s.io/klog" "k8s.io/component-base/metrics/legacyregistry"
"k8s.io/kubernetes/pkg/kubelet/pluginmanager/cache" "k8s.io/kubernetes/pkg/kubelet/pluginmanager/cache"
) )
@ -32,11 +32,13 @@ const (
var ( var (
registerMetrics sync.Once registerMetrics sync.Once
totalPluginsDesc = prometheus.NewDesc( totalPluginsDesc = metrics.NewDesc(
pluginManagerTotalPlugins, pluginManagerTotalPlugins,
"Number of plugins in Plugin Manager", "Number of plugins in Plugin Manager",
[]string{"socket_path", "state"}, []string{"socket_path", "state"},
nil, nil,
metrics.ALPHA,
"",
) )
) )
@ -55,35 +57,33 @@ func (pc pluginCount) add(state, pluginName string) {
// Register registers Plugin Manager metrics. // Register registers Plugin Manager metrics.
func Register(asw cache.ActualStateOfWorld, dsw cache.DesiredStateOfWorld) { func Register(asw cache.ActualStateOfWorld, dsw cache.DesiredStateOfWorld) {
registerMetrics.Do(func() { registerMetrics.Do(func() {
prometheus.MustRegister(&totalPluginsCollector{asw, dsw}) legacyregistry.CustomMustRegister(&totalPluginsCollector{asw: asw, dsw: dsw})
}) })
} }
type totalPluginsCollector struct { type totalPluginsCollector struct {
metrics.BaseStableCollector
asw cache.ActualStateOfWorld asw cache.ActualStateOfWorld
dsw cache.DesiredStateOfWorld dsw cache.DesiredStateOfWorld
} }
var _ prometheus.Collector = &totalPluginsCollector{} var _ metrics.StableCollector = &totalPluginsCollector{}
// Describe implements the prometheus.Collector interface. // DescribeWithStability implements the metrics.StableCollector interface.
func (c *totalPluginsCollector) Describe(ch chan<- *prometheus.Desc) { func (c *totalPluginsCollector) DescribeWithStability(ch chan<- *metrics.Desc) {
ch <- totalPluginsDesc ch <- totalPluginsDesc
} }
// Collect implements the prometheus.Collector interface. // CollectWithStability implements the metrics.StableCollector interface.
func (c *totalPluginsCollector) Collect(ch chan<- prometheus.Metric) { func (c *totalPluginsCollector) CollectWithStability(ch chan<- metrics.Metric) {
for stateName, pluginCount := range c.getPluginCount() { for stateName, pluginCount := range c.getPluginCount() {
for socketPath, count := range pluginCount { for socketPath, count := range pluginCount {
metric, err := prometheus.NewConstMetric(totalPluginsDesc, ch <- metrics.NewLazyConstMetric(totalPluginsDesc,
prometheus.GaugeValue, metrics.GaugeValue,
float64(count), float64(count),
socketPath, socketPath,
stateName) stateName)
if err != nil {
klog.Warningf("Failed to create metric : %v", err)
}
ch <- metric
} }
} }
} }

View File

@ -42,7 +42,7 @@ func TestMetricCollection(t *testing.T) {
t.Fatalf("AddOrUpdatePlugin failed. Expected: <no error> Actual: <%v>", err) t.Fatalf("AddOrUpdatePlugin failed. Expected: <no error> Actual: <%v>", err)
} }
metricCollector := &totalPluginsCollector{asw, dsw} metricCollector := &totalPluginsCollector{asw: asw, dsw: dsw}
// Check if getPluginCount returns correct data // Check if getPluginCount returns correct data
count := metricCollector.getPluginCount() count := metricCollector.getPluginCount()

View File

@ -17,11 +17,10 @@ limitations under the License.
package metrics package metrics
import ( import (
"k8s.io/component-base/metrics/legacyregistry"
"sync" "sync"
"github.com/prometheus/client_golang/prometheus" "k8s.io/component-base/metrics"
"k8s.io/klog" "k8s.io/component-base/metrics/legacyregistry"
"k8s.io/kubernetes/pkg/kubelet/volumemanager/cache" "k8s.io/kubernetes/pkg/kubelet/volumemanager/cache"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
volumeutil "k8s.io/kubernetes/pkg/volume/util" volumeutil "k8s.io/kubernetes/pkg/volume/util"
@ -37,11 +36,12 @@ const (
var ( var (
registerMetrics sync.Once registerMetrics sync.Once
totalVolumesDesc = prometheus.NewDesc( totalVolumesDesc = metrics.NewDesc(
volumeManagerTotalVolumes, volumeManagerTotalVolumes,
"Number of volumes in Volume Manager", "Number of volumes in Volume Manager",
[]string{"plugin_name", "state"}, []string{"plugin_name", "state"},
nil, nil,
metrics.ALPHA, "",
) )
) )
@ -60,36 +60,34 @@ func (v volumeCount) add(state, plugin string) {
// Register registers Volume Manager metrics. // Register registers Volume Manager metrics.
func Register(asw cache.ActualStateOfWorld, dsw cache.DesiredStateOfWorld, pluginMgr *volume.VolumePluginMgr) { func Register(asw cache.ActualStateOfWorld, dsw cache.DesiredStateOfWorld, pluginMgr *volume.VolumePluginMgr) {
registerMetrics.Do(func() { registerMetrics.Do(func() {
legacyregistry.RawMustRegister(&totalVolumesCollector{asw, dsw, pluginMgr}) legacyregistry.CustomMustRegister(&totalVolumesCollector{asw: asw, dsw: dsw, pluginMgr: pluginMgr})
}) })
} }
type totalVolumesCollector struct { type totalVolumesCollector struct {
metrics.BaseStableCollector
asw cache.ActualStateOfWorld asw cache.ActualStateOfWorld
dsw cache.DesiredStateOfWorld dsw cache.DesiredStateOfWorld
pluginMgr *volume.VolumePluginMgr pluginMgr *volume.VolumePluginMgr
} }
var _ prometheus.Collector = &totalVolumesCollector{} var _ metrics.StableCollector = &totalVolumesCollector{}
// Describe implements the prometheus.Collector interface. // DescribeWithStability implements the metrics.StableCollector interface.
func (c *totalVolumesCollector) Describe(ch chan<- *prometheus.Desc) { func (c *totalVolumesCollector) DescribeWithStability(ch chan<- *metrics.Desc) {
ch <- totalVolumesDesc ch <- totalVolumesDesc
} }
// Collect implements the prometheus.Collector interface. // CollectWithStability implements the metrics.StableCollector interface.
func (c *totalVolumesCollector) Collect(ch chan<- prometheus.Metric) { func (c *totalVolumesCollector) CollectWithStability(ch chan<- metrics.Metric) {
for stateName, pluginCount := range c.getVolumeCount() { for stateName, pluginCount := range c.getVolumeCount() {
for pluginName, count := range pluginCount { for pluginName, count := range pluginCount {
metric, err := prometheus.NewConstMetric(totalVolumesDesc, ch <- metrics.NewLazyConstMetric(totalVolumesDesc,
prometheus.GaugeValue, metrics.GaugeValue,
float64(count), float64(count),
pluginName, pluginName,
stateName) stateName)
if err != nil {
klog.Warningf("Failed to create metric : %v", err)
}
ch <- metric
} }
} }
} }

View File

@ -83,7 +83,7 @@ func TestMetricCollection(t *testing.T) {
t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
} }
metricCollector := &totalVolumesCollector{asw, dsw, volumePluginMgr} metricCollector := &totalVolumesCollector{asw: asw, dsw: dsw, pluginMgr: volumePluginMgr}
// Check if getVolumeCount returns correct data // Check if getVolumeCount returns correct data
count := metricCollector.getVolumeCount() count := metricCollector.getVolumeCount()