diff --git a/examples/prometheus/btrfs_error_exporter b/examples/prometheus/btrfs_error_exporter new file mode 100755 index 0000000..bfb9ca8 --- /dev/null +++ b/examples/prometheus/btrfs_error_exporter @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 + +# Collect per-device btrfs filesystem errors. +# Based on btrfs_stats.py (https://git.io/JkTIi) but rewritten to use +# python-btrfs and not shell out multiple times to 'btrfs stats'. +# +# Written by Holger Hoffstätte +# +# This file is part of python-btrfs. +# +# python-btrfs is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# python-btrfs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with python-btrfs. If not, see . + +import btrfs + +def get_btrfs_errors(mountpoint): + """Get per-device errors for a btrfs mount point. + + Args: + mountpoint: (string) path to a mount point. + + Yields: + (device, error_type, error_count, fsid) tuples, where: + device: (string) path to block device. + error_type: (string) type of btrfs error. + error_count: (int) number of btrfs errors of a given type. + fsid: (string) filesystem UUID. + """ + fs = btrfs.FileSystem(mountpoint) + for dev in fs.devices(): + devname = fs.dev_info(dev.devid).path.strip("/dev/") + error_counters = fs.dev_stats(dev.devid).counters + for error_name in error_counters.keys(): + yield devname, error_name, error_counters[error_name], fs.fsid + +def btrfs_error_metrics(): + """Collect btrfs error metrics. + + Returns: + a list of strings to be exposed as Prometheus metrics or None. + """ + metric = "node_btrfs_errors_total" + contents = [ + "# TYPE %s counter" % metric, + "# HELP %s number of btrfs errors" % metric, + ] + + for mountpoint in btrfs.utils.mounted_filesystem_paths(): + for device, error_type, error_count, fsid in get_btrfs_errors(mountpoint): + contents.append('%s{device="%s",mountpoint="%s",type="%s",uuid="%s"} %d' % + (metric, device, mountpoint, error_type, fsid, error_count)) + + if len(contents) > 2: + # return metrics if there are actual btrfs filesystems found + # (i.e. `contents` contains more than just TYPE and HELP). + return contents + +if __name__ == "__main__": + contents = btrfs_error_metrics() + if contents is not None: + print("\n".join(contents)) +