From a3e30d7c6726910cb164e5fcd05a5294bc1a70c8 Mon Sep 17 00:00:00 2001 From: Kai Storbeck Date: Tue, 31 May 2016 21:21:25 +0200 Subject: [PATCH] Expose max_avail field in pool_usage instead --- collectors/df.go | 141 ---------------------------------- collectors/df_test.go | 112 --------------------------- collectors/pool_usage.go | 16 ++++ collectors/pool_usage_test.go | 9 +++ 4 files changed, 25 insertions(+), 253 deletions(-) delete mode 100644 collectors/df.go delete mode 100644 collectors/df_test.go diff --git a/collectors/df.go b/collectors/df.go deleted file mode 100644 index 416e8fe..0000000 --- a/collectors/df.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2016 DigitalOcean -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package collectors - -import ( - "encoding/json" - "fmt" - "log" - - "github.com/prometheus/client_golang/prometheus" -) - -// DfCollector collects information about the available and used space for -// each pool. -type DfCollector struct { - // conn holds connection to the Ceph cluster - conn Conn - - // DfPoolBytesAvailable shows the current bytes available for each pool - DfPoolBytesAvailable *prometheus.GaugeVec - - // DfPoolBytesUsed shows the current bytes used for each pool - DfPoolBytesUsed *prometheus.GaugeVec -} - -// NewDfCollector creates a new instance of DfCollector to collect df -// metrics on. -func NewDfCollector(conn Conn) *DfCollector { - - return &DfCollector{ - conn: conn, - - DfPoolBytesAvailable: prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Namespace: cephNamespace, - Subsystem: "df", - Name: "pool_bytes_available", - Help: "Ceph volume available statistics", - }, - []string{"pool"}, - ), - DfPoolBytesUsed: prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Namespace: cephNamespace, - Subsystem: "df", - Name: "pool_bytes_used", - Help: "Ceph volume usage statistics", - }, - []string{"pool"}, - ), - } -} - -func (c *DfCollector) collectorList() []prometheus.Collector { - return []prometheus.Collector{ - c.DfPoolBytesAvailable, - c.DfPoolBytesUsed, - } -} - -type cephDfStats struct { - Pools []struct { - Name string - Stats struct { - BytesUsed json.Number `json:"bytes_used"` - BytesAvailable json.Number `json:"max_avail"` - } - } -} - -func (c *DfCollector) collectDfStats() (err error) { - cmd := c.cephDfCommand() - buf, _, err := c.conn.MonCommand(cmd) - if err != nil { - return err - } - - stats := &cephDfStats{} - if err := json.Unmarshal(buf, stats); err != nil { - return err - } - - for _, p := range stats.Pools { - avail, err := p.Stats.BytesAvailable.Float64() - if err != nil { - return fmt.Errorf("Cannot convert bytesavailable %s to float64: %s", p.Stats.BytesAvailable, err) - } - c.DfPoolBytesAvailable.WithLabelValues(p.Name).Set(avail) - used, err := p.Stats.BytesUsed.Float64() - if err != nil { - return fmt.Errorf("Cannot convert bytesused %s to float64: %s", p.Stats.BytesUsed, err) - } - c.DfPoolBytesUsed.WithLabelValues(p.Name).Set(used) - } - return err -} - -func (c *DfCollector) cephDfCommand() []byte { - cmd, err := json.Marshal(map[string]interface{}{ - "prefix": "df", - "format": "json", - }) - if err != nil { - // panic! because ideally in no world this hard-coded input - // should fail. - panic(err) - } - return cmd -} - -// Describe sends all the descriptions of individual metrics of DfCollector -// to the provided prometheus channel. -func (c *DfCollector) Describe(ch chan<- *prometheus.Desc) { - for _, collector := range c.collectorList() { - collector.Describe(ch) - } -} - -// Collect sends all the collected metrics to the provided prometheus channel. -// It requires the caller to handle synchronization. -func (c *DfCollector) Collect(ch chan<- prometheus.Metric) { - if err := c.collectDfStats(); err != nil { - log.Println("failed collecting df stats:", err) - } - - for _, collector := range c.collectorList() { - collector.Collect(ch) - } -} diff --git a/collectors/df_test.go b/collectors/df_test.go deleted file mode 100644 index 86f94ca..0000000 --- a/collectors/df_test.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2016 DigitalOcean -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package collectors - -import ( - "io/ioutil" - "net/http" - "net/http/httptest" - "regexp" - "testing" - - "github.com/prometheus/client_golang/prometheus" -) - -func TestDfCollector(t *testing.T) { - for _, tt := range []struct { - input string - regexes []*regexp.Regexp - }{ - { - ` -{ - "stats": { - "total_bytes": 255205081620480, - "total_used_bytes": 17850383970304, - "total_avail_bytes": 237354697650176 - }, - "pools": [ - { - "name": "rbd", - "id": 1, - "stats": { - "kb_used": 4715700422, - "bytes_used": 4828877231187, - "max_avail": 65868981633781, - "objects": 1360283 - } - }, - { - "name": "ssd", - "id": 2, - "stats": { - "kb_used": 362463233, - "bytes_used": 371162350522, - "max_avail": 4621426774653, - "objects": 89647 - } - }, - { - "name": "bench", - "id": 3, - "stats": { - "kb_used": 0, - "bytes_used": 0, - "max_avail": 4621426774653, - "objects": 0 - } - } - ] -} -`, - []*regexp.Regexp{ - regexp.MustCompile(`ceph_df_pool_bytes_used{pool="bench"} 0`), - regexp.MustCompile(`ceph_df_pool_bytes_used{pool="rbd"} 4.828877231187e\+12`), - regexp.MustCompile(`ceph_df_pool_bytes_used{pool="ssd"} 3.71162350522e\+11`), - regexp.MustCompile(`ceph_df_pool_bytes_available{pool="bench"} 4.621426774653e\+12`), - regexp.MustCompile(`ceph_df_pool_bytes_available{pool="rbd"} 6.5868981633781e\+13`), - regexp.MustCompile(`ceph_df_pool_bytes_available{pool="ssd"} 4.621426774653e\+12`), - }, - }, - } { - func() { - collector := NewDfCollector(NewNoopConn(tt.input)) - if err := prometheus.Register(collector); err != nil { - t.Fatalf("collector failed to register: %s", err) - } - defer prometheus.Unregister(collector) - - server := httptest.NewServer(prometheus.Handler()) - defer server.Close() - - resp, err := http.Get(server.URL) - if err != nil { - t.Fatalf("unexpected failed response from prometheus: %s", err) - } - defer resp.Body.Close() - - buf, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatalf("failed reading server response: %s", err) - } - - for _, re := range tt.regexes { - if !re.Match(buf) { - t.Errorf("failed matching: %q", re) - } - } - }() - } -} diff --git a/collectors/pool_usage.go b/collectors/pool_usage.go index 8cc6c9e..f027564 100644 --- a/collectors/pool_usage.go +++ b/collectors/pool_usage.go @@ -31,6 +31,10 @@ type PoolUsageCollector struct { // does not factor in the overcommitment made for individual images. UsedBytes *prometheus.GaugeVec + // MaxAvail tracks the amount of bytes currently free for the pool, + // which depends on the replication settings for the pool in question. + MaxAvail *prometheus.GaugeVec + // Objects shows the no. of RADOS objects created within the pool. Objects *prometheus.GaugeVec @@ -55,6 +59,15 @@ func NewPoolUsageCollector(conn Conn) *PoolUsageCollector { }, []string{"pool"}, ), + MaxAvail: prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: cephNamespace, + Subsystem: "df", + Name: "pool_available_bytes", + Help: "Free space for this ceph pool", + }, + []string{"pool"}, + ), Objects: prometheus.NewGaugeVec( prometheus.GaugeOpts{ Namespace: cephNamespace, @@ -85,6 +98,7 @@ func NewPoolUsageCollector(conn Conn) *PoolUsageCollector { func (p *PoolUsageCollector) collectorList() []prometheus.Collector { return []prometheus.Collector{ p.UsedBytes, + p.MaxAvail, p.Objects, p.ReadIO, p.WriteIO, @@ -97,6 +111,7 @@ type cephPoolStats struct { ID int `json:"id"` Stats struct { BytesUsed json.Number `json:"bytes_used"` + MaxAvail float64 `json:"max_avail"` Objects json.Number `json:"objects"` Read json.Number `json:"rd"` Write json.Number `json:"wr"` @@ -144,6 +159,7 @@ func (p *PoolUsageCollector) collect() error { } p.UsedBytes.WithLabelValues(pool.Name).Set(bytesUsed) + p.MaxAvail.WithLabelValues(pool.Name).Set(pool.Stats.MaxAvail) p.Objects.WithLabelValues(pool.Name).Set(objects) p.ReadIO.WithLabelValues(pool.Name).Set(read) p.WriteIO.WithLabelValues(pool.Name).Set(write) diff --git a/collectors/pool_usage_test.go b/collectors/pool_usage_test.go index a370def..4866401 100644 --- a/collectors/pool_usage_test.go +++ b/collectors/pool_usage_test.go @@ -128,6 +128,15 @@ func TestPoolUsageCollector(t *testing.T) { }, reUnmatch: []*regexp.Regexp{}, }, + { + input: ` +{"pools": [ + {"name": "ssd", "id": 11, "stats": {"max_avail": 4618201748262, "objects": 5, "rd": 4, "wr": 6}} +]}`, + reMatch: []*regexp.Regexp{ + regexp.MustCompile(`pool_available_bytes{pool="ssd"} 4.618201748262e\+12`), + }, + }, } { func() { collector := NewPoolUsageCollector(NewNoopConn(tt.input))