-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
223fce4
commit a92ec65
Showing
7 changed files
with
456 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# DMCache Input Plugin | ||
|
||
This plugin provide a native collection for dmsetup based statistics for dm-cache. | ||
|
||
This plugin requires sudo, that is why you should setup and be sure that the telegraf is able to execute sudo without a password. | ||
|
||
`sudo /sbin/dmsetup status --target cache` is the full command that telegraf will run for debugging purposes. | ||
|
||
### Configuration | ||
|
||
```toml | ||
[[inputs.dmcache]] | ||
## Whether to report per-device stats or not | ||
per_device = true | ||
``` | ||
|
||
### Measurements & Fields: | ||
|
||
- dmcache | ||
- length | ||
- target | ||
- metadata_blocksize | ||
- metadata_used | ||
- metadata_total | ||
- cache_blocksize | ||
- cache_used | ||
- cache_total | ||
- read_hits | ||
- read_misses | ||
- write_hits | ||
- write_misses | ||
- demotions | ||
- promotions | ||
- dirty | ||
|
||
### Tags: | ||
|
||
- All measurements have the following tags: | ||
- device | ||
|
||
### Example Output: | ||
|
||
``` | ||
$ ./telegraf --test --config /etc/telegraf/telegraf.conf --input-filter dmcache | ||
* Plugin: inputs.dmcache, Collection 1 | ||
> dmcache,device=example cache_blocksize=0i,read_hits=995134034411520i,read_misses=916807089127424i,write_hits=195107267543040i,metadata_used=12861440i,write_misses=563725346013184i,promotions=3265223720960i,dirty=0i,metadata_blocksize=0i,cache_used=1099511627776ii,cache_total=0i,length=0i,metadata_total=1073741824i,demotions=3265223720960i 1491482035000000000 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package dmcache | ||
|
||
import ( | ||
"github.com/influxdata/telegraf" | ||
"github.com/influxdata/telegraf/plugins/inputs" | ||
) | ||
|
||
type DMCache struct { | ||
PerDevice bool `toml:"per_device"` | ||
getCurrentStatus func() ([]string, error) | ||
} | ||
|
||
var sampleConfig = ` | ||
## Whether to report per-device stats or not | ||
per_device = true | ||
` | ||
|
||
func (c *DMCache) SampleConfig() string { | ||
return sampleConfig | ||
} | ||
|
||
func (c *DMCache) Description() string { | ||
return "Provide a native collection for dmsetup based statistics for dm-cache" | ||
} | ||
|
||
func init() { | ||
inputs.Add("dmcache", func() telegraf.Input { | ||
return &DMCache{ | ||
PerDevice: true, | ||
getCurrentStatus: dmSetupStatus, | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
// +build linux | ||
|
||
package dmcache | ||
|
||
import ( | ||
"os/exec" | ||
"strconv" | ||
"strings" | ||
|
||
"errors" | ||
|
||
"github.com/influxdata/telegraf" | ||
) | ||
|
||
const metricName = "dmcache" | ||
|
||
type cacheStatus struct { | ||
device string | ||
length int | ||
target string | ||
metadataBlocksize int | ||
metadataUsed int | ||
metadataTotal int | ||
cacheBlocksize int | ||
cacheUsed int | ||
cacheTotal int | ||
readHits int | ||
readMisses int | ||
writeHits int | ||
writeMisses int | ||
demotions int | ||
promotions int | ||
dirty int | ||
} | ||
|
||
func (c *DMCache) Gather(acc telegraf.Accumulator) error { | ||
outputLines, err := c.getCurrentStatus() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
totalStatus := cacheStatus{} | ||
|
||
for _, s := range outputLines { | ||
status, err := parseDMSetupStatus(s) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if c.PerDevice { | ||
tags := map[string]string{"device": status.device} | ||
acc.AddFields(metricName, toFields(status), tags) | ||
} | ||
aggregateStats(&totalStatus, status) | ||
} | ||
|
||
acc.AddFields(metricName, toFields(totalStatus), map[string]string{"device": "all"}) | ||
|
||
return nil | ||
} | ||
|
||
func parseDMSetupStatus(line string) (cacheStatus, error) { | ||
var err error | ||
parseError := errors.New("Output from dmsetup could not be parsed") | ||
status := cacheStatus{} | ||
values := strings.Fields(line) | ||
if len(values) < 15 { | ||
return cacheStatus{}, parseError | ||
} | ||
|
||
status.device = strings.TrimRight(values[0], ":") | ||
status.length, err = strconv.Atoi(values[2]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
status.target = values[3] | ||
status.metadataBlocksize, err = strconv.Atoi(values[4]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
metadata := strings.Split(values[5], "/") | ||
if len(metadata) != 2 { | ||
return cacheStatus{}, parseError | ||
} | ||
status.metadataUsed, err = strconv.Atoi(metadata[0]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
status.metadataTotal, err = strconv.Atoi(metadata[1]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
status.cacheBlocksize, err = strconv.Atoi(values[6]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
cache := strings.Split(values[7], "/") | ||
if len(cache) != 2 { | ||
return cacheStatus{}, parseError | ||
} | ||
status.cacheUsed, err = strconv.Atoi(cache[0]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
status.cacheTotal, err = strconv.Atoi(cache[1]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
status.readHits, err = strconv.Atoi(values[8]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
status.readMisses, err = strconv.Atoi(values[9]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
status.writeHits, err = strconv.Atoi(values[10]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
status.writeMisses, err = strconv.Atoi(values[11]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
status.demotions, err = strconv.Atoi(values[12]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
status.promotions, err = strconv.Atoi(values[13]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
status.dirty, err = strconv.Atoi(values[14]) | ||
if err != nil { | ||
return cacheStatus{}, err | ||
} | ||
|
||
return status, nil | ||
} | ||
|
||
func aggregateStats(totalStatus *cacheStatus, status cacheStatus) { | ||
totalStatus.length += status.length | ||
totalStatus.metadataBlocksize += status.metadataBlocksize | ||
totalStatus.metadataUsed += status.metadataUsed | ||
totalStatus.metadataTotal += status.metadataTotal | ||
totalStatus.cacheBlocksize += status.cacheBlocksize | ||
totalStatus.cacheUsed += status.cacheUsed | ||
totalStatus.cacheTotal += status.cacheTotal | ||
totalStatus.readHits += status.readHits | ||
totalStatus.readMisses += status.readMisses | ||
totalStatus.writeHits += status.writeHits | ||
totalStatus.writeMisses += status.writeMisses | ||
totalStatus.demotions += status.demotions | ||
totalStatus.promotions += status.promotions | ||
totalStatus.dirty += status.dirty | ||
} | ||
|
||
func toFields(status cacheStatus) map[string]interface{} { | ||
fields := make(map[string]interface{}) | ||
fields["length"] = status.length | ||
fields["metadata_blocksize"] = status.metadataBlocksize | ||
fields["metadata_used"] = status.metadataUsed | ||
fields["metadata_total"] = status.metadataTotal | ||
fields["cache_blocksize"] = status.cacheBlocksize | ||
fields["cache_used"] = status.cacheUsed | ||
fields["cache_total"] = status.cacheTotal | ||
fields["read_hits"] = status.readHits | ||
fields["read_misses"] = status.readMisses | ||
fields["write_hits"] = status.writeHits | ||
fields["write_misses"] = status.writeMisses | ||
fields["demotions"] = status.demotions | ||
fields["promotions"] = status.promotions | ||
fields["dirty"] = status.dirty | ||
return fields | ||
} | ||
|
||
func dmSetupStatus() ([]string, error) { | ||
out, err := exec.Command("/bin/sh", "-c", "sudo /sbin/dmsetup status --target cache").Output() | ||
if err != nil { | ||
return nil, err | ||
} | ||
if string(out) == "No devices found\n" { | ||
return []string{}, nil | ||
} | ||
|
||
outString := strings.TrimRight(string(out), "\n") | ||
status := strings.Split(outString, "\n") | ||
|
||
return status, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// +build !linux | ||
|
||
package dmcache | ||
|
||
import ( | ||
"github.com/influxdata/telegraf" | ||
) | ||
|
||
func (c *DMCache) Gather(acc telegraf.Accumulator) error { | ||
return nil | ||
} | ||
|
||
func dmSetupStatus() ([]string, error) { | ||
return []string{}, nil | ||
} |
Oops, something went wrong.