aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tolchanov <1687799+knyar@users.noreply.github.com>2018-12-21 13:10:03 +0000
committerBen Kochie <superq@gmail.com>2018-12-21 14:10:03 +0100
commitcf8b29d1fb8be541fc2b4cafe531a0f8abdd2bab (patch)
tree0cf8993b646849ac876b83a89f8b9092a6254751
parent97dab59e18c575d1384a9afd54e9f30473f34322 (diff)
downloadprometheus_node_collector-cf8b29d1fb8be541fc2b4cafe531a0f8abdd2bab.tar.bz2
prometheus_node_collector-cf8b29d1fb8be541fc2b4cafe531a0f8abdd2bab.tar.xz
prometheus_node_collector-cf8b29d1fb8be541fc2b4cafe531a0f8abdd2bab.zip
Add a sample btrfs stats collector script (#1200)
Signed-off-by: Anton Tolchanov <commits@knyar.net>
-rwxr-xr-xtext_collector_examples/btrfs_stats.py112
1 files changed, 112 insertions, 0 deletions
diff --git a/text_collector_examples/btrfs_stats.py b/text_collector_examples/btrfs_stats.py
new file mode 100755
index 0000000..b26bfd2
--- /dev/null
+++ b/text_collector_examples/btrfs_stats.py
@@ -0,0 +1,112 @@
1#!/usr/bin/env python
2
3# Collect per-device btrfs filesystem errors.
4# Designed to work on Debian and Centos 6 (with python2.6).
5
6import collections
7import glob
8import os
9import re
10import subprocess
11
12def get_btrfs_mount_points():
13 """List all btrfs mount points.
14
15 Yields:
16 (string) filesystem mount points.
17 """
18 with open("/proc/mounts") as f:
19 for line in f:
20 parts = line.split()
21 if parts[2] == "btrfs":
22 yield parts[1]
23
24def get_btrfs_errors(mountpoint):
25 """Get per-device errors for a btrfs mount point.
26
27 Args:
28 mountpoint: (string) path to a mount point.
29
30 Yields:
31 (device, error_type, error_count) tuples, where:
32 device: (string) path to block device.
33 error_type: (string) type of btrfs error.
34 error_count: (int) number of btrfs errors of a given type.
35 """
36 p = subprocess.Popen(["btrfs", "device", "stats", mountpoint],
37 stdout=subprocess.PIPE)
38 (stdout, stderr) = p.communicate()
39 if p.returncode != 0:
40 raise RuntimeError("btrfs returned exit code %d" % p.returncode)
41 for line in stdout.splitlines():
42 if line == '':
43 continue
44 # Sample line:
45 # [/dev/vdb1].flush_io_errs 0
46 m = re.search(r"^\[([^\]]+)\]\.(\S+)\s+(\d+)$", line.decode("utf-8"))
47 if not m:
48 raise RuntimeError("unexpected output from btrfs: '%s'" % line)
49 yield m.group(1), m.group(2), int(m.group(3))
50
51def btrfs_error_metrics():
52 """Collect btrfs error metrics.
53
54 Returns:
55 a list of strings to be exposed as Prometheus metrics.
56 """
57 metric = "node_btrfs_errors_total"
58 contents = [
59 "# TYPE %s counter" % metric,
60 "# HELP %s number of btrfs errors" % metric,
61 ]
62 errors_by_device = collections.defaultdict(dict)
63 for mountpoint in get_btrfs_mount_points():
64 for device, error_type, error_count in get_btrfs_errors(mountpoint):
65 contents.append(
66 '%s{mountpoint="%s",device="%s",type="%s"} %d' %
67 (metric, mountpoint, device, error_type, error_count))
68
69 if len(contents) > 2:
70 # return metrics if there are actual btrfs filesystems found
71 # (i.e. `contents` contains more than just TYPE and HELP).
72 return contents
73
74def btrfs_allocation_metrics():
75 """Collect btrfs allocation metrics.
76
77 Returns:
78 a list of strings to be exposed as Prometheus metrics.
79 """
80 prefix = 'node_btrfs_allocation'
81 metric_to_filename = {
82 'size_bytes': 'total_bytes',
83 'used_bytes': 'bytes_used',
84 'reserved_bytes': 'bytes_reserved',
85 'pinned_bytes': 'bytes_pinned',
86 'disk_size_bytes': 'disk_total',
87 'disk_used_bytes': 'disk_used',
88 }
89 contents = []
90 for m, f in metric_to_filename.items():
91 contents += [
92 "# TYPE %s_%s gauge" % (prefix, m),
93 "# HELP %s_%s btrfs allocation data (%s)" % (prefix, m, f),
94 ]
95
96 for alloc in glob.glob("/sys/fs/btrfs/*/allocation"):
97 fs = alloc.split('/')[4]
98 for type_ in ('data', 'metadata', 'system'):
99 for m, f in metric_to_filename.items():
100 filename = os.path.join(alloc, type_, f)
101 with open(filename) as f:
102 value = int(f.read().strip())
103 contents.append('%s_%s{fs="%s",type="%s"} %d' % (
104 prefix, m, fs, type_, value))
105 if len(contents) > 2*len(metric_to_filename):
106 return contents
107
108if __name__ == "__main__":
109 contents = ((btrfs_error_metrics() or []) +
110 (btrfs_allocation_metrics() or []))
111
112 print("\n".join(contents))