Expose max_avail field in pool_usage instead
This commit is contained in:
parent
09bbb2cb1f
commit
a3e30d7c67
141
collectors/df.go
141
collectors/df.go
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in New Issue