Skip to content

Commit

Permalink
add bcache plugin
Browse files Browse the repository at this point in the history
Closes #286
  • Loading branch information
Roman Statsevich authored and sparrc committed Oct 20, 2015
1 parent c26ce9c commit 499b5be
Show file tree
Hide file tree
Showing 6 changed files with 389 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ of metrics collected and from how many plugins.
- [#273](https://github.com/influxdb/telegraf/pull/273): puppet agent plugin, thats @jrxFive!
- [#280](https://github.com/influxdb/telegraf/issues/280): Use InfluxDB client v2.
- [#281](https://github.com/influxdb/telegraf/issues/281): Eliminate need to deep copy Batch Points.
- [#286](https://github.com/influxdb/telegraf/issues/286): bcache plugin, thanks @cornerot!

### Bugfixes
- [#228](https://github.com/influxdb/telegraf/pull/228): New version of package will replace old one. Thanks @ekini!
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ Below is how to configure `tagpass` and `tagdrop` parameters (added in 0.1.5)
Telegraf currently has support for collecting metrics from

* apache
* bcache
* disque
* elasticsearch
* exec (generic JSON-emitting executable plugin)
Expand Down
1 change: 1 addition & 0 deletions plugins/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package all

import (
_ "github.com/influxdb/telegraf/plugins/apache"
_ "github.com/influxdb/telegraf/plugins/bcache"
_ "github.com/influxdb/telegraf/plugins/disque"
_ "github.com/influxdb/telegraf/plugins/elasticsearch"
_ "github.com/influxdb/telegraf/plugins/exec"
Expand Down
89 changes: 89 additions & 0 deletions plugins/bcache/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Telegraf plugin: bcache

Get bcache stat from stats_total directory and dirty_data file.

# Measurements

Meta:

- tags: `backing_dev=dev bcache_dev=dev`

Measurement names:

- dirty_data
- bypassed
- cache_bypass_hits
- cache_bypass_misses
- cache_hit_ratio
- cache_hits
- cache_miss_collisions
- cache_misses
- cache_readaheads

### Description

```
dirty_data
Amount of dirty data for this backing device in the cache. Continuously
updated unlike the cache set's version, but may be slightly off.
bypassed
Amount of IO (both reads and writes) that has bypassed the cache
cache_bypass_hits
cache_bypass_misses
Hits and misses for IO that is intended to skip the cache are still counted,
but broken out here.
cache_hits
cache_misses
cache_hit_ratio
Hits and misses are counted per individual IO as bcache sees them; a
partial hit is counted as a miss.
cache_miss_collisions
Counts instances where data was going to be inserted into the cache from a
cache miss, but raced with a write and data was already present (usually 0
since the synchronization for cache misses was rewritten)
cache_readaheads
Count of times readahead occurred.
```

# Example output

Using this configuration:

```
[bcache]
# Bcache sets path
# If not specified, then default is:
# bcachePath = "/sys/fs/bcache"
#
# By default, telegraf gather stats for all bcache devices
# Setting devices will restrict the stats to the specified
# bcache devices.
# bcacheDevs = ["bcache0", ...]
```

When run with:

```
./telegraf -config telegraf.conf -filter bcache -test
```

It produces:

```
* Plugin: bcache, Collection 1
> [backing_dev="md10" bcache_dev="bcache0"] bcache_dirty_data value=11639194
> [backing_dev="md10" bcache_dev="bcache0"] bcache_bypassed value=5167704440832
> [backing_dev="md10" bcache_dev="bcache0"] bcache_cache_bypass_hits value=146270986
> [backing_dev="md10" bcache_dev="bcache0"] bcache_cache_bypass_misses value=0
> [backing_dev="md10" bcache_dev="bcache0"] bcache_cache_hit_ratio value=90
> [backing_dev="md10" bcache_dev="bcache0"] bcache_cache_hits value=511941651
> [backing_dev="md10" bcache_dev="bcache0"] bcache_cache_miss_collisions value=157678
> [backing_dev="md10" bcache_dev="bcache0"] bcache_cache_misses value=50647396
> [backing_dev="md10" bcache_dev="bcache0"] bcache_cache_readaheads value=0
```
144 changes: 144 additions & 0 deletions plugins/bcache/bcache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package bcache

import (
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/influxdb/telegraf/plugins"
)

type Bcache struct {
BcachePath string
BcacheDevs []string
}

var sampleConfig = `
# Bcache sets path
# If not specified, then default is:
# bcachePath = "/sys/fs/bcache"
#
# By default, telegraf gather stats for all bcache devices
# Setting devices will restrict the stats to the specified
# bcache devices.
# bcacheDevs = ["bcache0", ...]
`

func (b *Bcache) SampleConfig() string {
return sampleConfig
}

func (b *Bcache) Description() string {
return "Read metrics of bcache from stats_total and dirty_data"
}

func getBackingDevs(bcachePath string) []string {
bdevs, err := filepath.Glob(bcachePath + "/*/bdev*")
if len(bdevs) < 1 {
panic("Can't found any bcache device")
}
if err != nil {
panic(err)
}
return bdevs
}

func getTags(bdev string) map[string]string {
backingDevFile, _ := os.Readlink(bdev)
backingDevPath := strings.Split(backingDevFile, "/")
backingDev := backingDevPath[len(backingDevPath)-2]

bcacheDevFile, _ := os.Readlink(bdev + "/dev")
bcacheDevPath := strings.Split(bcacheDevFile, "/")
bcacheDev := bcacheDevPath[len(bcacheDevPath)-1]

return map[string]string{"backing_dev": backingDev, "bcache_dev": bcacheDev}
}

func prettyToBytes(v string) uint64 {
var factors = map[string]uint64{
"k": 1 << 10,
"M": 1 << 20,
"G": 1 << 30,
"T": 1 << 40,
"P": 1 << 50,
"E": 1 << 60,
}
var factor uint64
factor = 1
prefix := v[len(v)-1 : len(v)]
if factors[prefix] != 0 {
v = v[:len(v)-1]
factor = factors[prefix]
}
result, _ := strconv.ParseFloat(v, 32)
result = result * float64(factor)

return uint64(result)
}

func (b *Bcache) gatherBcache(bdev string, acc plugins.Accumulator) error {
tags := getTags(bdev)
metrics, err := filepath.Glob(bdev + "/stats_total/*")
if len(metrics) < 0 {
panic("Can't read any stats file")
}
file, err := ioutil.ReadFile(bdev + "/dirty_data")
if err != nil {
panic(err)
}
rawValue := strings.TrimSpace(string(file))
value := prettyToBytes(rawValue)
acc.Add("dirty_data", value, tags)

for _, path := range metrics {
key := filepath.Base(path)
file, err := ioutil.ReadFile(path)
rawValue := strings.TrimSpace(string(file))
if err != nil {
panic(err)
}
if key == "bypassed" {
value := prettyToBytes(rawValue)
acc.Add(key, value, tags)
} else {
value, _ := strconv.ParseUint(rawValue, 10, 64)
acc.Add(key, value, tags)
}
}
return nil
}

func (b *Bcache) Gather(acc plugins.Accumulator) error {
bcacheDevsChecked := make(map[string]bool)
var restrictDevs bool
if len(b.BcacheDevs) != 0 {
restrictDevs = true
for _, bcacheDev := range b.BcacheDevs {
bcacheDevsChecked[bcacheDev] = true
}
}

bcachePath := b.BcachePath
if len(bcachePath) == 0 {
bcachePath = "/sys/fs/bcache"
}
for _, bdev := range getBackingDevs(bcachePath) {
if restrictDevs {
bcacheDev := getTags(bdev)["bcache_dev"]
if !bcacheDevsChecked[bcacheDev] {
continue
}
}
b.gatherBcache(bdev, acc)
}
return nil
}

func init() {
plugins.Add("bcache", func() plugins.Plugin {
return &Bcache{}
})
}
Loading

0 comments on commit 499b5be

Please sign in to comment.