├── barman_exporter ├── __init__.py └── barman_exporter.py ├── grafana-screenshot.png ├── setup.py ├── LICENSE ├── .gitignore ├── README.md └── grafana-dashboard.json /barman_exporter/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /grafana-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcinhlybin/prometheus-barman-exporter/HEAD/grafana-screenshot.png -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup(name='barman_exporter', 4 | version='1.0.10', 5 | description='Barman exporter for Prometheus', 6 | long_description='Barman exporter for Prometheus. Full description at https://github.com/ahes/prometheus-barman-exporter', 7 | url='https://github.com/ahes/prometheus-barman-exporter', 8 | author='Marcin Hlybin', 9 | author_email='marcin.hlybin@gmail.com', 10 | license='MIT', 11 | packages=['barman_exporter'], 12 | keywords='prometheus barman exporter barman-exporter', 13 | entry_points={ 14 | 'console_scripts': ['barman-exporter=barman_exporter.barman_exporter:main'], 15 | }, 16 | install_requires=[ 17 | 'prometheus-client', 18 | 'sh' 19 | ], 20 | zip_safe=False) 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019, 2020 Marcin Onufry Hlybin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | # vscode 107 | .vscode 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Barman exporter for Prometheus 2 | 3 | The barman exporter runs `barman` shell command with _experimental_ JSON output. I am the author of JSON output in Barman so it should work fine until somebody else changes output format which may happen in the future. 4 | 5 | By default `barman-exporter` runs as a service and binds to 127.0.0.1:9780. Metrics are cached and refreshed every hour. 6 | 7 | You can run `barman-exporter` from cron using `-f` argument to output results to a textfile: 8 | 9 | ``` 10 | /usr/local/bin/barman-exporter -f /var/lib/prometheus/node_exporter/barman.prom 11 | ``` 12 | 13 | In such case the `node_exporter` must point to this path with `--collector.textfile.directory` option. 14 | 15 | ## Grafana dashboard 16 | 17 | You can find basic grafana dashboard in `grafana-dashboard.json`. It is open for improvements. 18 | 19 | ![Grafana screenshot](grafana-screenshot.png?raw=true "Grafana screenshot") 20 | 21 | ## Usage 22 | 23 | ``` 24 | usage: barman-exporter [-h] [-u USER] [-g GROUP] [-m MODE] [-c SECONDS] [-v] [-f TEXTFILE_PATH | -l HOST:PORT | -d] 25 | [servers [servers ...]] 26 | 27 | Barman exporter 28 | 29 | positional arguments: 30 | servers Space separated list of servers to check (default: ['all']) 31 | 32 | optional arguments: 33 | -h, --help show this help message and exit 34 | -u USER, --user USER Textfile owner (default: prometheus) 35 | -g GROUP, --group GROUP 36 | Textfile group (default: prometheus) 37 | -m MODE, --mode MODE Textfile mode (default: 0644) 38 | -c SECONDS, --cache-time SECONDS 39 | Number of seconds to cache barman output for (default: 3600) 40 | -v, --version Show barman exporter version (default: False) 41 | -f TEXTFILE_PATH, --file TEXTFILE_PATH 42 | Save output to textfile (default: None) 43 | -l HOST:PORT, --listen-address HOST:PORT 44 | Address to listen on (default: 127.0.0.1:9780) 45 | -d, --debug Print output to stdout (default: False) 46 | ``` 47 | 48 | Examples: 49 | 50 | - `$ /usr/local/bin/barman-exporter postgres-01` 51 | - `$ /usr/local/bin/barman-exporter postgres-01 postgres-02` 52 | - `$ /usr/local/bin/barman-exporter all` 53 | - `$ /usr/local/bin/barman-exporter -l 10.10.10.10:9780 -c 900` 54 | - `$ /usr/local/bin/barman-exporter -f /var/lib/prometheus/node_exporter/barman.prom -u prometheus -g prometheus -m 0640 all` 55 | 56 | ## Requirements 57 | 58 | Python3 and following modules are required to run it: 59 | 60 | - prometheus_client 61 | - sh 62 | 63 | All dependencies will be installed automatically with pip command (see Installation). 64 | 65 | ## Installation 66 | 67 | ``` 68 | pip3 install barman-exporter 69 | ``` 70 | 71 | ### Systemd service file to run barman-exporter as a service 72 | 73 | ``` 74 | [Unit] 75 | Description=Barman Exporter 76 | After=network-online.target 77 | 78 | [Service] 79 | Type=simple 80 | User=barman 81 | Group=barman 82 | ExecStart=/usr/local/bin/barman-exporter -l 10.10.10.10:9780 -c 3600 83 | SyslogIdentifier=barman_exporter 84 | Restart=always 85 | 86 | [Install] 87 | WantedBy=multi-user.target 88 | ``` 89 | 90 | ### Cron job to run barman-exporter with textfile output 91 | 92 | If you don't want to use barman exporter as a service you can run it with `-f` argument from the cron job. To run it every hour: 93 | 94 | ``` 95 | 0 * * * * /usr/local/bin/barman-exporter -f /var/lib/prometheus/node_exporter/barman.prom 96 | ``` 97 | 98 | In this mode barman exporter does not require any Prometheus configuration because it uses **node-exporter** to parse the metrics from a textfile. Remember to use `--collector.textfile.directory` in `node-exporter` to define a directory with textfiles. 99 | 100 | ## Prometheus configuration 101 | 102 | Please note that `barman-exporter` is listing all backups which is quite heavy operation to perform and it takes some time. Barman exporter caches its results because execution every 5 seconds would be impossible. 103 | 104 | ``` 105 | scrape_configs: 106 | - job_name: barman 107 | static_configs: 108 | - targets: 109 | - 10.10.10.10:9780' 110 | ``` 111 | 112 | ## Metrics 113 | 114 | - `number=1` label indicates the newest backup 115 | - `barman_backups_size` and `barman_backup_wal_size` show successful backups only. Failed backups will not be listed here. 116 | - `barman_backups_total` includes failed backups 117 | - `barman_backups_failed`exposes the number of failed backups. 118 | - `barman_last_backup_copy_time` shows how long it takes to make a backup 119 | - `barman_up` shows all checks from `barman check SERVER_NAME` command. Output `OK` is `1.0`, `FAILED` is `0.0`. 120 | - `barman_metrics_update` shows a timestamp when barman metrics has been last updated 121 | 122 | With `barman_last_backup` and `barman_first_backup` you can easily calculate when the latest backup was completed: 123 | 124 | ``` 125 | time() - barman_last_backup{instance="$instance", server="$server"} 126 | ``` 127 | 128 | ### Raw metrics 129 | 130 | ``` 131 | # HELP barman_backup_size Size of available backups 132 | # TYPE barman_backup_size gauge 133 | barman_backup_size{number="1",server="postgres-01"} 1.429365116108e+012 134 | barman_backup_size{number="2",server="postgres-01"} 1.429365116108e+012 135 | barman_backup_size{number="3",server="postgres-01"} 1.429365116108e+012 136 | barman_backup_size{number="4",server="postgres-01"} 1.429365116108e+012 137 | barman_backup_size{number="5",server="postgres-01"} 1.429365116108e+012 138 | barman_backup_size{number="6",server="postgres-01"} 1.429365116108e+012 139 | barman_backup_size{number="7",server="postgres-01"} 1.429365116108e+012 140 | barman_backup_size{number="8",server="postgres-01"} 1.429365116108e+012 141 | 142 | # HELP barman_backup_wal_size WAL size of available backups 143 | # TYPE barman_backup_wal_size gauge 144 | barman_backup_wal_size{number="1",server="postgres-01"} 1.94347270144e+011 145 | barman_backup_wal_size{number="2",server="postgres-01"} 3.06553290752e+011 146 | barman_backup_wal_size{number="3",server="postgres-01"} 3.05479548928e+011 147 | barman_backup_wal_size{number="4",server="postgres-01"} 4.79318350233e+011 148 | barman_backup_wal_size{number="5",server="postgres-01"} 2.87333312102e+011 149 | barman_backup_wal_size{number="6",server="postgres-01"} 2.73267294208e+011 150 | barman_backup_wal_size{number="7",server="postgres-01"} 3.65501716889e+011 151 | barman_backup_wal_size{number="8",server="postgres-01"} 2.34075717632e+011 152 | 153 | # HELP barman_backups_total Total number of backups 154 | # TYPE barman_backups_total gauge 155 | barman_backups_total{server="postgres-01"} 9.0 156 | 157 | # HELP barman_backups_failed Number of failed backups 158 | # TYPE barman_backups_failed gauge 159 | barman_backups_failed{server="postgres-01"} 1.0 160 | 161 | # HELP barman_last_backup Last successful backup timestamp 162 | # TYPE barman_last_backup gauge 163 | barman_last_backup{server="postgres-01"} 1.562537102e+09 164 | 165 | # HELP barman_last_backup_copy_time Last successful backup copy time 166 | # TYPE barman_last_backup_copy_time gauge 167 | barman_last_backup_copy_time{server="postgres-01"} 18706.918297 168 | 169 | # HELP barman_first_backup First successful backup timestamp 170 | # TYPE barman_first_backup gauge 171 | barman_first_backup{server="postgres-01"} 1.561154701e+09 172 | 173 | # HELP barman_up Barman status checks 174 | # TYPE barman_up gauge 175 | barman_up{check="archiver_errors",server="postgres-01"} 1.0 176 | barman_up{check="backup_maximum_age",server="postgres-01"} 1.0 177 | barman_up{check="compression_settings",server="postgres-01"} 1.0 178 | barman_up{check="directories",server="postgres-01"} 1.0 179 | barman_up{check="failed_backups",server="postgres-01"} 1.0 180 | barman_up{check="is_superuser",server="postgres-01"} 1.0 181 | barman_up{check="minimum_redundancy_requirements",server="postgres-01"} 1.0 182 | barman_up{check="pg_basebackup",server="postgres-01"} 1.0 183 | barman_up{check="pg_basebackup_compatible",server="postgres-01"} 1.0 184 | barman_up{check="pg_basebackup_supports_tablespaces_mapping",server="postgres-01"} 1.0 185 | barman_up{check="pg_receivexlog",server="postgres-01"} 1.0 186 | barman_up{check="pg_receivexlog_compatible",server="postgres-01"} 1.0 187 | barman_up{check="postgresql",server="postgres-01"} 1.0 188 | barman_up{check="postgresql_streaming",server="postgres-01"} 1.0 189 | barman_up{check="receive_wal_running",server="postgres-01"} 1.0 190 | barman_up{check="replication_slot",server="postgres-01"} 1.0 191 | barman_up{check="retention_policy_settings",server="postgres-01"} 1.0 192 | barman_up{check="systemid_coherence",server="postgres-01"} 1.0 193 | barman_up{check="wal_level",server="postgres-01"} 1.0 194 | 195 | # HELP barman_metrics_update Barman metrics update timestamp 196 | # TYPE barman_metrics_update gauge 197 | barman_metrics_update{server="autouncle"} 1.580485601e+09 198 | ``` 199 | 200 | ## Development 201 | 202 | Upload to PyPi: 203 | 204 | ``` 205 | source venv/bin/activate 206 | rm -f dist/* 207 | python3 setup.py sdist 208 | twine upload dist/* 209 | ``` 210 | -------------------------------------------------------------------------------- /barman_exporter/barman_exporter.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import argparse 4 | import time 5 | import json 6 | import shutil 7 | import threading 8 | import prometheus_client 9 | from prometheus_client import core 10 | from datetime import datetime 11 | 12 | BARMAN_EXPORTER_VERSION = '1.0.10' 13 | sys.tracebacklimit = 0 14 | 15 | try: 16 | from sh import barman as barman_cli 17 | except ImportError as e: 18 | raise ImportError('ERROR: Barman binary not found!') from e 19 | 20 | 21 | class Barman: 22 | def __init__(self): 23 | self.check_barman_version() 24 | 25 | def check_barman_version(self): 26 | barman_version = tuple(int(v) for v in self.version().split('.')) 27 | if barman_version < (2, 9): 28 | raise ValueError("Barman version 2.9+ required") 29 | 30 | @staticmethod 31 | def cli(*args, **kwargs): 32 | output = barman_cli('-f', 'json', *args, **kwargs) 33 | output = json.loads(str(output)) 34 | return output 35 | 36 | def version(self): 37 | version = barman_cli('-v', _err_to_out=True).split() 38 | return version[0] 39 | 40 | def servers(self): 41 | servers = self.cli('list-server') 42 | return list(servers.keys()) 43 | 44 | def server_status(self, server_name): 45 | status = self.cli('status', server_name) 46 | status = {k: v['message'] for k, v in status[server_name].items()} 47 | return status 48 | 49 | def server_check(self, server_name): 50 | check = self.cli('check', server_name, _ok_code=[0, 1]) 51 | check = {k: 1 if v['status'] == "OK" else 0 for k, 52 | v in check[server_name].items()} 53 | return check 54 | 55 | def list_backup(self, server_name): 56 | backups = self.cli('list-backup', server_name) 57 | backups_done = [backup for backup in backups[server_name] 58 | if backup['status'] == 'DONE'] 59 | backups_failed = [ 60 | backup for backup in backups[server_name] if backup['status'] == 'FAILED'] 61 | return backups_done, backups_failed 62 | 63 | def show_backup(self, server_name, backup_id): 64 | backup = self.cli('show-backup', server_name, backup_id) 65 | return backup[server_name] 66 | 67 | 68 | class BarmanServer: 69 | 70 | def __init__(self, barman, server_name): 71 | self.barman = barman 72 | self.name = server_name 73 | self.status = barman.server_status(server_name) 74 | self.checks = barman.server_check(server_name) 75 | self.backups_done, self.backups_failed = barman.list_backup( 76 | server_name) 77 | 78 | def backup(self, backup_id): 79 | return self.barman.show_backup(self.name, backup_id) 80 | 81 | 82 | class BarmanCollector: 83 | 84 | def __init__(self, barman, servers): 85 | self.barman = barman 86 | self.servers = servers 87 | self.collectors = dict( 88 | barman_backup_size=core.GaugeMetricFamily( 89 | 'barman_backup_size', "Size of available backups", 90 | labels=['server', 'number']), 91 | barman_backup_wal_size=core.GaugeMetricFamily( 92 | 'barman_backup_wal_size', "WAL size of available backups", 93 | labels=['server', 'number']), 94 | barman_backups_total=core.GaugeMetricFamily( 95 | "barman_backups_total", "Total number of backups", 96 | labels=["server"]), 97 | barman_backups_failed=core.GaugeMetricFamily( 98 | "barman_backups_failed", "Number of failed backups", 99 | labels=["server"]), 100 | barman_last_backup=core.GaugeMetricFamily( 101 | "barman_last_backup", "Last successful backup timestamp", 102 | labels=["server"]), 103 | barman_last_backup_copy_time=core.GaugeMetricFamily( 104 | "barman_last_backup_copy_time", "Last successful backup copy time", 105 | labels=["server"]), 106 | barman_first_backup=core.GaugeMetricFamily( 107 | "barman_first_backup", "First successful backup timestamp", 108 | labels=["server"]), 109 | barman_up=core.GaugeMetricFamily( 110 | "barman_up", "Barman status checks", 111 | labels=["server", "check"]), 112 | barman_metrics_update=core.GaugeMetricFamily( 113 | "barman_metrics_update", "Barman metrics update timestamp", 114 | labels=["server"]) 115 | ) 116 | 117 | def collect(self): 118 | for server_name in self.barman_servers(): 119 | barman_server = BarmanServer(self.barman, server_name) 120 | self.collect_first_backup(barman_server) 121 | self.collect_last_backup(barman_server) 122 | self.collect_backups_total(barman_server) 123 | self.collect_backups_failed(barman_server) 124 | self.collect_last_backup_copy_time(barman_server) 125 | self.collect_barman_backup_size(barman_server) 126 | self.collect_barman_backup_wal_size(barman_server) 127 | self.collect_barman_up(barman_server) 128 | self.collect_barman_metrics_update(barman_server) 129 | 130 | for collector in self.collectors.values(): 131 | yield collector 132 | 133 | def barman_servers(self): 134 | if self.servers[0] == "all": 135 | return self.barman.servers() 136 | else: 137 | return self.servers 138 | 139 | def collect_first_backup(self, barman_server): 140 | if barman_server.status['first_backup'] and barman_server.status['first_backup'] != 'None': 141 | first_backup = datetime.strptime( 142 | barman_server.status['first_backup'], "%Y%m%dT%H%M%S") 143 | self.collectors['barman_first_backup'].add_metric( 144 | [barman_server.name], first_backup.strftime("%s")) 145 | 146 | def collect_last_backup(self, barman_server): 147 | if barman_server.status['last_backup'] and barman_server.status['last_backup'] != 'None': 148 | last_backup = datetime.strptime( 149 | barman_server.status['last_backup'], "%Y%m%dT%H%M%S") 150 | self.collectors['barman_last_backup'].add_metric( 151 | [barman_server.name], last_backup.strftime("%s")) 152 | 153 | def collect_backups_total(self, barman_server): 154 | self.collectors['barman_backups_total'].add_metric([barman_server.name], len( 155 | barman_server.backups_done) + len(barman_server.backups_failed)) 156 | 157 | def collect_backups_failed(self, barman_server): 158 | self.collectors['barman_backups_failed'].add_metric( 159 | [barman_server.name], len(barman_server.backups_failed)) 160 | 161 | def collect_last_backup_copy_time(self, barman_server): 162 | last_backup_copy_time = 0 163 | if len(barman_server.backups_done) > 0: 164 | backup_id = barman_server.backups_done[0]['backup_id'] 165 | last_backup = barman_server.backup(backup_id) 166 | last_backup_copy_time = last_backup['base_backup_information']['copy_time_seconds'] 167 | 168 | self.collectors['barman_last_backup_copy_time'].add_metric( 169 | [barman_server.name], last_backup_copy_time) 170 | 171 | def collect_barman_backup_size(self, barman_server): 172 | for number, backup in enumerate(barman_server.backups_done, 1): 173 | self.collectors['barman_backup_size'].add_metric( 174 | [barman_server.name, str(number)], backup['size_bytes']) 175 | 176 | def collect_barman_backup_wal_size(self, barman_server): 177 | for number, backup in enumerate(barman_server.backups_done, 1): 178 | self.collectors['barman_backup_wal_size'].add_metric( 179 | [barman_server.name, str(number)], backup['wal_size_bytes']) 180 | 181 | def collect_barman_up(self, barman_server): 182 | for check_name, check_value in barman_server.checks.items(): 183 | self.collectors['barman_up'].add_metric( 184 | [barman_server.name, check_name], check_value) 185 | 186 | def collect_barman_metrics_update(self, barman_server): 187 | self.collectors['barman_metrics_update'].add_metric( 188 | [barman_server.name], int(time.time())) 189 | 190 | 191 | class BarmanCollectorCache: 192 | def __init__(self, barman, servers, cache_time): 193 | self.barman = barman 194 | self.servers = servers 195 | self.cache_time = cache_time 196 | self._collect = [] 197 | self.start_collect_thread() 198 | 199 | def start_collect_thread(self): 200 | t = threading.Thread(target=self.collect_loop) 201 | t.daemon = True 202 | t.start() 203 | 204 | def collect_loop(self): 205 | while True: 206 | barman_collector = BarmanCollector(self.barman, self.servers) 207 | self._collect = list(barman_collector.collect()) 208 | time.sleep(self.cache_time) 209 | 210 | def collect(self): 211 | return self._collect 212 | 213 | 214 | def main(): 215 | args = parse_args() 216 | 217 | if args.version: 218 | show_version() 219 | elif args.debug: 220 | sys.tracebacklimit = 1 221 | print_metrics_to_stdout(args) 222 | elif args.file: 223 | write_metrics_to_file(args) 224 | else: 225 | start_exporter_service(args) 226 | 227 | 228 | def parse_args(): 229 | parser = argparse.ArgumentParser( 230 | description="Barman exporter", 231 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) 232 | 233 | parser.add_argument('servers', nargs="*", default=['all'], 234 | help="Space separated list of " 235 | "servers to check") 236 | parser.add_argument('-u', '--user', metavar='USER', 237 | default='prometheus', help="Textfile owner") 238 | parser.add_argument('-g', '--group', metavar='GROUP', 239 | default='prometheus', help="Textfile group") 240 | parser.add_argument('-m', '--mode', metavar='MODE', 241 | default='0644', help="Textfile mode") 242 | parser.add_argument('-c', '--cache-time', metavar='SECONDS', type=int, 243 | default=3600, help='Number of seconds to cache barman output for') 244 | parser.add_argument('-v', '--version', action='store_true', 245 | help='Show barman exporter version') 246 | 247 | group = parser.add_mutually_exclusive_group() 248 | group.add_argument('-f', '--file', 249 | metavar="TEXTFILE_PATH", 250 | help="Save output to textfile") 251 | group.add_argument('-l', '--listen-address', 252 | default='127.0.0.1:9780', 253 | metavar="HOST:PORT", 254 | help="Address to listen on") 255 | group.add_argument('-d', '--debug', 256 | action='store_true', 257 | help="Print output to stdout") 258 | 259 | return parser.parse_args() 260 | 261 | 262 | def show_version(): 263 | print(BARMAN_EXPORTER_VERSION) 264 | sys.exit(0) 265 | 266 | 267 | def write_metrics_to_file(args): 268 | registry = BarmanCollector(Barman(), args.servers) 269 | prometheus_client.write_to_textfile(args.file, registry) 270 | shutil.chown(args.file, user=args.user, group=args.group) 271 | os.chmod(args.file, mode=int(args.mode, 8)) 272 | 273 | 274 | def start_exporter_service(args): 275 | try: 276 | addr, port = args.listen_address.split(":") 277 | except ValueError as e: 278 | raise ValueError("Incorrect '--listen-address' value: '{}'.".format( 279 | args.listen_address), "Use HOST:PORT.") from e 280 | 281 | registry = BarmanCollectorCache(Barman(), args.servers, args.cache_time) 282 | core.REGISTRY.register(registry) 283 | 284 | print("Listening on " + args.listen_address) 285 | prometheus_client.start_http_server(int(port), addr) 286 | 287 | while True: 288 | time.sleep(1) 289 | 290 | 291 | def print_metrics_to_stdout(args): 292 | registry = BarmanCollector(Barman(), args.servers) 293 | print(prometheus_client.generate_latest(registry).decode()) 294 | 295 | 296 | if __name__ == "__main__": 297 | main() 298 | -------------------------------------------------------------------------------- /grafana-dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": "-- Grafana --", 7 | "enable": true, 8 | "hide": true, 9 | "iconColor": "rgba(0, 211, 255, 1)", 10 | "name": "Annotations & Alerts", 11 | "type": "dashboard" 12 | } 13 | ] 14 | }, 15 | "editable": true, 16 | "gnetId": null, 17 | "graphTooltip": 0, 18 | "id": 40, 19 | "iteration": 1614250514469, 20 | "links": [], 21 | "panels": [ 22 | { 23 | "datasource": null, 24 | "gridPos": { 25 | "h": 1, 26 | "w": 24, 27 | "x": 0, 28 | "y": 0 29 | }, 30 | "id": 29, 31 | "panels": [], 32 | "repeat": "instance", 33 | "scopedVars": { 34 | "instance": { 35 | "selected": true, 36 | "text": "barman-02", 37 | "value": "barman-02" 38 | } 39 | }, 40 | "title": "Barman instance", 41 | "type": "row" 42 | }, 43 | { 44 | "cacheTimeout": null, 45 | "datasource": null, 46 | "fieldConfig": { 47 | "defaults": { 48 | "color": { 49 | "mode": "thresholds" 50 | }, 51 | "custom": {}, 52 | "displayName": "", 53 | "mappings": [], 54 | "max": 100, 55 | "min": 0, 56 | "thresholds": { 57 | "mode": "absolute", 58 | "steps": [ 59 | { 60 | "color": "green", 61 | "value": null 62 | }, 63 | { 64 | "color": "red", 65 | "value": 90 66 | } 67 | ] 68 | }, 69 | "unit": "percent" 70 | }, 71 | "overrides": [] 72 | }, 73 | "gridPos": { 74 | "h": 10, 75 | "w": 4, 76 | "x": 0, 77 | "y": 1 78 | }, 79 | "id": 14, 80 | "links": [], 81 | "options": { 82 | "orientation": "auto", 83 | "reduceOptions": { 84 | "calcs": [ 85 | "last" 86 | ], 87 | "fields": "", 88 | "values": false 89 | }, 90 | "showThresholdLabels": false, 91 | "showThresholdMarkers": true 92 | }, 93 | "pluginVersion": "7.3.7", 94 | "scopedVars": { 95 | "instance": { 96 | "selected": true, 97 | "text": "barman-02", 98 | "value": "barman-02" 99 | } 100 | }, 101 | "targets": [ 102 | { 103 | "expr": "(node_filesystem_size_bytes{instance=~\"$instance.*\",mountpoint=\"/var/lib/barman\"} - node_filesystem_avail_bytes{instance=~\"$instance.*\",mountpoint=\"/var/lib/barman\"}) / node_filesystem_size_bytes{instance=~\"$instance.*\",mountpoint=~\"/var/lib/barman\"} * 100", 104 | "format": "time_series", 105 | "interval": "", 106 | "intervalFactor": 1, 107 | "legendFormat": "{{ mountpoint }}", 108 | "refId": "A" 109 | } 110 | ], 111 | "timeFrom": null, 112 | "timeShift": null, 113 | "title": "Storage usage", 114 | "type": "gauge" 115 | }, 116 | { 117 | "aliasColors": {}, 118 | "bars": false, 119 | "dashLength": 10, 120 | "dashes": false, 121 | "datasource": null, 122 | "fieldConfig": { 123 | "defaults": { 124 | "custom": {}, 125 | "links": [] 126 | }, 127 | "overrides": [] 128 | }, 129 | "fill": 0, 130 | "fillGradient": 0, 131 | "gridPos": { 132 | "h": 10, 133 | "w": 12, 134 | "x": 4, 135 | "y": 1 136 | }, 137 | "hiddenSeries": false, 138 | "id": 16, 139 | "legend": { 140 | "avg": false, 141 | "current": false, 142 | "max": false, 143 | "min": false, 144 | "show": true, 145 | "total": false, 146 | "values": false 147 | }, 148 | "lines": true, 149 | "linewidth": 2, 150 | "links": [], 151 | "nullPointMode": "null", 152 | "options": { 153 | "alertThreshold": true 154 | }, 155 | "percentage": false, 156 | "pluginVersion": "7.3.7", 157 | "pointradius": 2, 158 | "points": false, 159 | "renderer": "flot", 160 | "scopedVars": { 161 | "instance": { 162 | "selected": true, 163 | "text": "barman-02", 164 | "value": "barman-02" 165 | } 166 | }, 167 | "seriesOverrides": [ 168 | { 169 | "alias": "available disk space", 170 | "color": "#F2495C", 171 | "dashes": true, 172 | "spaceLength": 3 173 | } 174 | ], 175 | "spaceLength": 10, 176 | "stack": false, 177 | "steppedLine": false, 178 | "targets": [ 179 | { 180 | "expr": "node_filesystem_size_bytes{instance=~\"$instance.*\",mountpoint=\"/var/lib/barman\"} - node_filesystem_avail_bytes{instance=~\"$instance.*\",mountpoint=\"/var/lib/barman\"}", 181 | "format": "time_series", 182 | "interval": "", 183 | "intervalFactor": 1, 184 | "legendFormat": "$instance: used disk space", 185 | "refId": "A" 186 | }, 187 | { 188 | "expr": "node_filesystem_size_bytes{instance=~\"$instance.*\",mountpoint=\"/var/lib/barman\"}", 189 | "format": "time_series", 190 | "interval": "", 191 | "intervalFactor": 1, 192 | "legendFormat": "$instance: available disk space", 193 | "refId": "B" 194 | } 195 | ], 196 | "thresholds": [], 197 | "timeFrom": null, 198 | "timeRegions": [], 199 | "timeShift": null, 200 | "title": "Backup partition (/var/lib/barman)", 201 | "tooltip": { 202 | "shared": true, 203 | "sort": 0, 204 | "value_type": "individual" 205 | }, 206 | "type": "graph", 207 | "xaxis": { 208 | "buckets": null, 209 | "mode": "time", 210 | "name": null, 211 | "show": true, 212 | "values": [] 213 | }, 214 | "yaxes": [ 215 | { 216 | "format": "decbytes", 217 | "label": null, 218 | "logBase": 1, 219 | "max": null, 220 | "min": "0", 221 | "show": true 222 | }, 223 | { 224 | "format": "short", 225 | "label": null, 226 | "logBase": 1, 227 | "max": null, 228 | "min": null, 229 | "show": false 230 | } 231 | ], 232 | "yaxis": { 233 | "align": false, 234 | "alignLevel": null 235 | } 236 | }, 237 | { 238 | "cacheTimeout": null, 239 | "colorBackground": false, 240 | "colorValue": true, 241 | "colors": [ 242 | "#299c46", 243 | "#AD0317", 244 | "#AD0317" 245 | ], 246 | "datasource": null, 247 | "fieldConfig": { 248 | "defaults": { 249 | "custom": {} 250 | }, 251 | "overrides": [] 252 | }, 253 | "format": "none", 254 | "gauge": { 255 | "maxValue": 100, 256 | "minValue": 0, 257 | "show": false, 258 | "thresholdLabels": false, 259 | "thresholdMarkers": true 260 | }, 261 | "gridPos": { 262 | "h": 10, 263 | "w": 4, 264 | "x": 16, 265 | "y": 1 266 | }, 267 | "id": 2, 268 | "interval": null, 269 | "links": [], 270 | "mappingType": 1, 271 | "mappingTypes": [ 272 | { 273 | "name": "value to text", 274 | "value": 1 275 | }, 276 | { 277 | "name": "range to text", 278 | "value": 2 279 | } 280 | ], 281 | "maxDataPoints": 100, 282 | "nullPointMode": "connected", 283 | "nullText": null, 284 | "pluginVersion": "6.2.5", 285 | "postfix": "", 286 | "postfixFontSize": "50%", 287 | "prefix": "", 288 | "prefixFontSize": "50%", 289 | "rangeMaps": [ 290 | { 291 | "from": "null", 292 | "text": "N/A", 293 | "to": "null" 294 | } 295 | ], 296 | "scopedVars": { 297 | "instance": { 298 | "selected": true, 299 | "text": "barman-02", 300 | "value": "barman-02" 301 | } 302 | }, 303 | "sparkline": { 304 | "fillColor": "rgba(31, 118, 189, 0.18)", 305 | "full": false, 306 | "lineColor": "rgb(31, 120, 193)", 307 | "show": false 308 | }, 309 | "tableColumn": "", 310 | "targets": [ 311 | { 312 | "expr": "count(barman_up{instance=~\"$instance.*\"}) - sum(barman_up{instance=~\"$instance.*\"})", 313 | "format": "time_series", 314 | "interval": "", 315 | "intervalFactor": 1, 316 | "legendFormat": "", 317 | "refId": "A" 318 | } 319 | ], 320 | "thresholds": "1", 321 | "timeFrom": null, 322 | "timeShift": null, 323 | "title": "Barman errors", 324 | "type": "singlestat", 325 | "valueFontSize": "150%", 326 | "valueMaps": [ 327 | { 328 | "op": "=", 329 | "text": "N/A", 330 | "value": "null" 331 | } 332 | ], 333 | "valueName": "current" 334 | }, 335 | { 336 | "cacheTimeout": null, 337 | "colorBackground": false, 338 | "colorValue": true, 339 | "colors": [ 340 | "#299c46", 341 | "#AD0317", 342 | "#AD0317" 343 | ], 344 | "datasource": null, 345 | "fieldConfig": { 346 | "defaults": { 347 | "custom": {} 348 | }, 349 | "overrides": [] 350 | }, 351 | "format": "none", 352 | "gauge": { 353 | "maxValue": 100, 354 | "minValue": 0, 355 | "show": false, 356 | "thresholdLabels": false, 357 | "thresholdMarkers": true 358 | }, 359 | "gridPos": { 360 | "h": 5, 361 | "w": 4, 362 | "x": 20, 363 | "y": 1 364 | }, 365 | "id": 30, 366 | "interval": null, 367 | "links": [], 368 | "mappingType": 1, 369 | "mappingTypes": [ 370 | { 371 | "name": "value to text", 372 | "value": 1 373 | }, 374 | { 375 | "name": "range to text", 376 | "value": 2 377 | } 378 | ], 379 | "maxDataPoints": 100, 380 | "nullPointMode": "connected", 381 | "nullText": null, 382 | "pluginVersion": "6.2.5", 383 | "postfix": "", 384 | "postfixFontSize": "50%", 385 | "prefix": "", 386 | "prefixFontSize": "50%", 387 | "rangeMaps": [ 388 | { 389 | "from": "null", 390 | "text": "N/A", 391 | "to": "null" 392 | } 393 | ], 394 | "scopedVars": { 395 | "instance": { 396 | "selected": true, 397 | "text": "barman-02", 398 | "value": "barman-02" 399 | } 400 | }, 401 | "sparkline": { 402 | "fillColor": "rgba(31, 118, 189, 0.18)", 403 | "full": false, 404 | "lineColor": "rgb(31, 120, 193)", 405 | "show": false 406 | }, 407 | "tableColumn": "", 408 | "targets": [ 409 | { 410 | "expr": "count(barman_backups_total{instance=~\"$instance.*\"}) by (server)", 411 | "format": "time_series", 412 | "interval": "", 413 | "intervalFactor": 1, 414 | "legendFormat": "", 415 | "refId": "A" 416 | } 417 | ], 418 | "thresholds": "", 419 | "timeFrom": null, 420 | "timeShift": null, 421 | "title": "Number of servers", 422 | "type": "singlestat", 423 | "valueFontSize": "150%", 424 | "valueMaps": [ 425 | { 426 | "op": "=", 427 | "text": "N/A", 428 | "value": "null" 429 | } 430 | ], 431 | "valueName": "current" 432 | }, 433 | { 434 | "cacheTimeout": null, 435 | "colorBackground": false, 436 | "colorValue": true, 437 | "colors": [ 438 | "#299c46", 439 | "#AD0317", 440 | "#AD0317" 441 | ], 442 | "datasource": null, 443 | "fieldConfig": { 444 | "defaults": { 445 | "custom": {} 446 | }, 447 | "overrides": [] 448 | }, 449 | "format": "none", 450 | "gauge": { 451 | "maxValue": 100, 452 | "minValue": 0, 453 | "show": false, 454 | "thresholdLabels": false, 455 | "thresholdMarkers": true 456 | }, 457 | "gridPos": { 458 | "h": 5, 459 | "w": 4, 460 | "x": 20, 461 | "y": 6 462 | }, 463 | "id": 31, 464 | "interval": null, 465 | "links": [], 466 | "mappingType": 1, 467 | "mappingTypes": [ 468 | { 469 | "name": "value to text", 470 | "value": 1 471 | }, 472 | { 473 | "name": "range to text", 474 | "value": 2 475 | } 476 | ], 477 | "maxDataPoints": 100, 478 | "nullPointMode": "connected", 479 | "nullText": null, 480 | "pluginVersion": "6.2.5", 481 | "postfix": "", 482 | "postfixFontSize": "50%", 483 | "prefix": "", 484 | "prefixFontSize": "50%", 485 | "rangeMaps": [ 486 | { 487 | "from": "null", 488 | "text": "N/A", 489 | "to": "null" 490 | } 491 | ], 492 | "scopedVars": { 493 | "instance": { 494 | "selected": true, 495 | "text": "barman-02", 496 | "value": "barman-02" 497 | } 498 | }, 499 | "sparkline": { 500 | "fillColor": "rgba(31, 118, 189, 0.18)", 501 | "full": false, 502 | "lineColor": "rgb(31, 120, 193)", 503 | "show": false 504 | }, 505 | "tableColumn": "", 506 | "targets": [ 507 | { 508 | "expr": "sum(barman_backups_total{instance=~\"$instance.*\"})", 509 | "format": "time_series", 510 | "interval": "", 511 | "intervalFactor": 1, 512 | "legendFormat": "", 513 | "refId": "A" 514 | } 515 | ], 516 | "thresholds": "", 517 | "timeFrom": null, 518 | "timeShift": null, 519 | "title": "Total number of backups", 520 | "type": "singlestat", 521 | "valueFontSize": "150%", 522 | "valueMaps": [ 523 | { 524 | "op": "=", 525 | "text": "N/A", 526 | "value": "null" 527 | } 528 | ], 529 | "valueName": "current" 530 | }, 531 | { 532 | "collapsed": false, 533 | "datasource": null, 534 | "gridPos": { 535 | "h": 1, 536 | "w": 24, 537 | "x": 0, 538 | "y": 11 539 | }, 540 | "id": 27, 541 | "panels": [], 542 | "repeat": "server", 543 | "scopedVars": { 544 | "server": { 545 | "selected": true, 546 | "text": "psql-cluster-02", 547 | "value": "psql-cluster-02" 548 | } 549 | }, 550 | "title": "Server $server", 551 | "type": "row" 552 | }, 553 | { 554 | "cacheTimeout": null, 555 | "colorBackground": false, 556 | "colorValue": true, 557 | "colors": [ 558 | "#299c46", 559 | "rgba(237, 129, 40, 0.89)", 560 | "#d44a3a" 561 | ], 562 | "datasource": null, 563 | "fieldConfig": { 564 | "defaults": { 565 | "custom": {} 566 | }, 567 | "overrides": [] 568 | }, 569 | "format": "h", 570 | "gauge": { 571 | "maxValue": 120, 572 | "minValue": 0, 573 | "show": true, 574 | "thresholdLabels": false, 575 | "thresholdMarkers": true 576 | }, 577 | "gridPos": { 578 | "h": 10, 579 | "w": 4, 580 | "x": 0, 581 | "y": 12 582 | }, 583 | "id": 8, 584 | "interval": null, 585 | "links": [], 586 | "mappingType": 1, 587 | "mappingTypes": [ 588 | { 589 | "name": "value to text", 590 | "value": 1 591 | }, 592 | { 593 | "name": "range to text", 594 | "value": 2 595 | } 596 | ], 597 | "maxDataPoints": 100, 598 | "nullPointMode": "connected", 599 | "nullText": null, 600 | "pluginVersion": "6.2.5", 601 | "postfix": "", 602 | "postfixFontSize": "50%", 603 | "prefix": "", 604 | "prefixFontSize": "50%", 605 | "rangeMaps": [ 606 | { 607 | "from": "null", 608 | "text": "N/A", 609 | "to": "null" 610 | } 611 | ], 612 | "repeat": null, 613 | "scopedVars": { 614 | "server": { 615 | "selected": true, 616 | "text": "psql-cluster-02", 617 | "value": "psql-cluster-02" 618 | } 619 | }, 620 | "sparkline": { 621 | "fillColor": "rgba(31, 118, 189, 0.18)", 622 | "full": false, 623 | "lineColor": "rgb(31, 120, 193)", 624 | "show": false 625 | }, 626 | "tableColumn": "", 627 | "targets": [ 628 | { 629 | "expr": "hour(time()- barman_last_backup{instance=~\"$instance.*\", server=\"$server\"})", 630 | "format": "time_series", 631 | "interval": "", 632 | "intervalFactor": 1, 633 | "legendFormat": "$instance: {{ server }}", 634 | "refId": "A" 635 | } 636 | ], 637 | "thresholds": "48", 638 | "timeFrom": null, 639 | "timeShift": null, 640 | "title": "Last backup age", 641 | "type": "singlestat", 642 | "valueFontSize": "80%", 643 | "valueMaps": [ 644 | { 645 | "op": "=", 646 | "text": "N/A", 647 | "value": "null" 648 | } 649 | ], 650 | "valueName": "current" 651 | }, 652 | { 653 | "cacheTimeout": null, 654 | "colorBackground": false, 655 | "colorValue": false, 656 | "colors": [ 657 | "#299c46", 658 | "rgba(237, 129, 40, 0.89)", 659 | "#d44a3a" 660 | ], 661 | "datasource": null, 662 | "decimals": 1, 663 | "fieldConfig": { 664 | "defaults": { 665 | "custom": {} 666 | }, 667 | "overrides": [] 668 | }, 669 | "format": "s", 670 | "gauge": { 671 | "maxValue": 120, 672 | "minValue": 0, 673 | "show": false, 674 | "thresholdLabels": false, 675 | "thresholdMarkers": true 676 | }, 677 | "gridPos": { 678 | "h": 5, 679 | "w": 4, 680 | "x": 4, 681 | "y": 12 682 | }, 683 | "id": 24, 684 | "interval": null, 685 | "links": [], 686 | "mappingType": 1, 687 | "mappingTypes": [ 688 | { 689 | "name": "value to text", 690 | "value": 1 691 | }, 692 | { 693 | "name": "range to text", 694 | "value": 2 695 | } 696 | ], 697 | "maxDataPoints": 100, 698 | "nullPointMode": "connected", 699 | "nullText": null, 700 | "pluginVersion": "6.2.5", 701 | "postfix": "", 702 | "postfixFontSize": "50%", 703 | "prefix": "", 704 | "prefixFontSize": "50%", 705 | "rangeMaps": [ 706 | { 707 | "from": "null", 708 | "text": "N/A", 709 | "to": "null" 710 | } 711 | ], 712 | "scopedVars": { 713 | "server": { 714 | "selected": true, 715 | "text": "psql-cluster-02", 716 | "value": "psql-cluster-02" 717 | } 718 | }, 719 | "sparkline": { 720 | "fillColor": "rgba(31, 118, 189, 0.18)", 721 | "full": false, 722 | "lineColor": "rgb(31, 120, 193)", 723 | "show": false 724 | }, 725 | "tableColumn": "", 726 | "targets": [ 727 | { 728 | "expr": "time() - barman_first_backup{instance=~\"$instance.*\", server=\"$server\"}", 729 | "format": "time_series", 730 | "interval": "", 731 | "intervalFactor": 1, 732 | "legendFormat": "", 733 | "refId": "A" 734 | } 735 | ], 736 | "thresholds": "48", 737 | "timeFrom": null, 738 | "timeShift": null, 739 | "title": "First backup age", 740 | "type": "singlestat", 741 | "valueFontSize": "80%", 742 | "valueMaps": [ 743 | { 744 | "op": "=", 745 | "text": "N/A", 746 | "value": "null" 747 | } 748 | ], 749 | "valueName": "current" 750 | }, 751 | { 752 | "cacheTimeout": null, 753 | "colorBackground": true, 754 | "colorPrefix": false, 755 | "colorValue": false, 756 | "colors": [ 757 | "#299c46", 758 | "#F2495C", 759 | "#F2495C" 760 | ], 761 | "datasource": null, 762 | "decimals": null, 763 | "fieldConfig": { 764 | "defaults": { 765 | "custom": {} 766 | }, 767 | "overrides": [] 768 | }, 769 | "format": "none", 770 | "gauge": { 771 | "maxValue": 100, 772 | "minValue": 0, 773 | "show": false, 774 | "thresholdLabels": false, 775 | "thresholdMarkers": true 776 | }, 777 | "gridPos": { 778 | "h": 5, 779 | "w": 4, 780 | "x": 8, 781 | "y": 12 782 | }, 783 | "id": 23, 784 | "interval": null, 785 | "links": [], 786 | "mappingType": 1, 787 | "mappingTypes": [ 788 | { 789 | "name": "value to text", 790 | "value": 1 791 | }, 792 | { 793 | "name": "range to text", 794 | "value": 2 795 | } 796 | ], 797 | "maxDataPoints": 100, 798 | "nullPointMode": "connected", 799 | "nullText": null, 800 | "pluginVersion": "6.2.5", 801 | "postfix": "", 802 | "postfixFontSize": "50%", 803 | "prefix": "", 804 | "prefixFontSize": "50%", 805 | "rangeMaps": [ 806 | { 807 | "from": "null", 808 | "text": "N/A", 809 | "to": "null" 810 | } 811 | ], 812 | "scopedVars": { 813 | "server": { 814 | "selected": true, 815 | "text": "psql-cluster-02", 816 | "value": "psql-cluster-02" 817 | } 818 | }, 819 | "sparkline": { 820 | "fillColor": "rgba(31, 118, 189, 0.18)", 821 | "full": false, 822 | "lineColor": "rgb(31, 120, 193)", 823 | "show": false 824 | }, 825 | "tableColumn": "", 826 | "targets": [ 827 | { 828 | "expr": "barman_backups_failed{instance=~\"$instance.*\", server=\"$server\"}", 829 | "format": "time_series", 830 | "instant": false, 831 | "interval": "", 832 | "intervalFactor": 1, 833 | "legendFormat": "", 834 | "refId": "A" 835 | } 836 | ], 837 | "thresholds": "1", 838 | "timeFrom": null, 839 | "timeShift": null, 840 | "title": "Failed backups", 841 | "type": "singlestat", 842 | "valueFontSize": "100%", 843 | "valueMaps": [ 844 | { 845 | "op": "=", 846 | "text": "N/A", 847 | "value": "null" 848 | } 849 | ], 850 | "valueName": "current" 851 | }, 852 | { 853 | "aliasColors": {}, 854 | "bars": false, 855 | "dashLength": 10, 856 | "dashes": false, 857 | "datasource": null, 858 | "fieldConfig": { 859 | "defaults": { 860 | "custom": {}, 861 | "links": [] 862 | }, 863 | "overrides": [] 864 | }, 865 | "fill": 0, 866 | "fillGradient": 0, 867 | "gridPos": { 868 | "h": 10, 869 | "w": 12, 870 | "x": 12, 871 | "y": 12 872 | }, 873 | "hiddenSeries": false, 874 | "id": 6, 875 | "legend": { 876 | "avg": false, 877 | "current": false, 878 | "max": false, 879 | "min": false, 880 | "show": true, 881 | "total": false, 882 | "values": false 883 | }, 884 | "lines": true, 885 | "linewidth": 2, 886 | "links": [], 887 | "nullPointMode": "null", 888 | "options": { 889 | "alertThreshold": true 890 | }, 891 | "percentage": false, 892 | "pluginVersion": "7.3.7", 893 | "pointradius": 2, 894 | "points": false, 895 | "renderer": "flot", 896 | "scopedVars": { 897 | "server": { 898 | "selected": true, 899 | "text": "psql-cluster-02", 900 | "value": "psql-cluster-02" 901 | } 902 | }, 903 | "seriesOverrides": [ 904 | { 905 | "alias": "" 906 | } 907 | ], 908 | "spaceLength": 10, 909 | "stack": false, 910 | "steppedLine": false, 911 | "targets": [ 912 | { 913 | "expr": "time() - barman_last_backup{instance=~\"$instance.*\", server=\"$server\"}", 914 | "format": "time_series", 915 | "instant": false, 916 | "interval": "15m", 917 | "intervalFactor": 1, 918 | "legendFormat": "$instance: {{ server }}", 919 | "refId": "A" 920 | } 921 | ], 922 | "thresholds": [], 923 | "timeFrom": null, 924 | "timeRegions": [], 925 | "timeShift": null, 926 | "title": "Time since last backup", 927 | "tooltip": { 928 | "shared": true, 929 | "sort": 0, 930 | "value_type": "individual" 931 | }, 932 | "type": "graph", 933 | "xaxis": { 934 | "buckets": null, 935 | "mode": "time", 936 | "name": null, 937 | "show": true, 938 | "values": [] 939 | }, 940 | "yaxes": [ 941 | { 942 | "decimals": 1, 943 | "format": "s", 944 | "label": null, 945 | "logBase": 1, 946 | "max": null, 947 | "min": null, 948 | "show": true 949 | }, 950 | { 951 | "format": "short", 952 | "label": null, 953 | "logBase": 1, 954 | "max": null, 955 | "min": null, 956 | "show": true 957 | } 958 | ], 959 | "yaxis": { 960 | "align": false, 961 | "alignLevel": null 962 | } 963 | }, 964 | { 965 | "cacheTimeout": null, 966 | "colorBackground": false, 967 | "colorValue": false, 968 | "colors": [ 969 | "#299c46", 970 | "rgba(237, 129, 40, 0.89)", 971 | "#d44a3a" 972 | ], 973 | "datasource": null, 974 | "decimals": 1, 975 | "fieldConfig": { 976 | "defaults": { 977 | "custom": {} 978 | }, 979 | "overrides": [] 980 | }, 981 | "format": "s", 982 | "gauge": { 983 | "maxValue": 120, 984 | "minValue": 0, 985 | "show": false, 986 | "thresholdLabels": false, 987 | "thresholdMarkers": true 988 | }, 989 | "gridPos": { 990 | "h": 5, 991 | "w": 4, 992 | "x": 4, 993 | "y": 17 994 | }, 995 | "id": 25, 996 | "interval": null, 997 | "links": [], 998 | "mappingType": 1, 999 | "mappingTypes": [ 1000 | { 1001 | "name": "value to text", 1002 | "value": 1 1003 | }, 1004 | { 1005 | "name": "range to text", 1006 | "value": 2 1007 | } 1008 | ], 1009 | "maxDataPoints": 100, 1010 | "nullPointMode": "connected", 1011 | "nullText": null, 1012 | "pluginVersion": "6.2.5", 1013 | "postfix": "", 1014 | "postfixFontSize": "50%", 1015 | "prefix": "", 1016 | "prefixFontSize": "50%", 1017 | "rangeMaps": [ 1018 | { 1019 | "from": "null", 1020 | "text": "N/A", 1021 | "to": "null" 1022 | } 1023 | ], 1024 | "scopedVars": { 1025 | "server": { 1026 | "selected": true, 1027 | "text": "psql-cluster-02", 1028 | "value": "psql-cluster-02" 1029 | } 1030 | }, 1031 | "sparkline": { 1032 | "fillColor": "rgba(31, 118, 189, 0.18)", 1033 | "full": false, 1034 | "lineColor": "rgb(31, 120, 193)", 1035 | "show": false 1036 | }, 1037 | "tableColumn": "", 1038 | "targets": [ 1039 | { 1040 | "expr": "barman_last_backup_copy_time{instance=~\"$instance.*\", server=\"$server\"}", 1041 | "format": "time_series", 1042 | "interval": "", 1043 | "intervalFactor": 1, 1044 | "legendFormat": "", 1045 | "refId": "A" 1046 | } 1047 | ], 1048 | "thresholds": "48", 1049 | "timeFrom": null, 1050 | "timeShift": null, 1051 | "title": "Last backup copy time", 1052 | "type": "singlestat", 1053 | "valueFontSize": "80%", 1054 | "valueMaps": [ 1055 | { 1056 | "op": "=", 1057 | "text": "N/A", 1058 | "value": "null" 1059 | } 1060 | ], 1061 | "valueName": "current" 1062 | }, 1063 | { 1064 | "cacheTimeout": null, 1065 | "colorBackground": false, 1066 | "colorValue": true, 1067 | "colors": [ 1068 | "#AD0317", 1069 | "#37872D", 1070 | "#299c46" 1071 | ], 1072 | "datasource": null, 1073 | "fieldConfig": { 1074 | "defaults": { 1075 | "custom": {} 1076 | }, 1077 | "overrides": [] 1078 | }, 1079 | "format": "none", 1080 | "gauge": { 1081 | "maxValue": 100, 1082 | "minValue": 0, 1083 | "show": false, 1084 | "thresholdLabels": false, 1085 | "thresholdMarkers": true 1086 | }, 1087 | "gridPos": { 1088 | "h": 5, 1089 | "w": 4, 1090 | "x": 8, 1091 | "y": 17 1092 | }, 1093 | "id": 19, 1094 | "interval": null, 1095 | "links": [], 1096 | "mappingType": 1, 1097 | "mappingTypes": [ 1098 | { 1099 | "name": "value to text", 1100 | "value": 1 1101 | }, 1102 | { 1103 | "name": "range to text", 1104 | "value": 2 1105 | } 1106 | ], 1107 | "maxDataPoints": 100, 1108 | "nullPointMode": "connected", 1109 | "nullText": null, 1110 | "pluginVersion": "6.2.5", 1111 | "postfix": "", 1112 | "postfixFontSize": "50%", 1113 | "prefix": "", 1114 | "prefixFontSize": "50%", 1115 | "rangeMaps": [ 1116 | { 1117 | "from": "null", 1118 | "text": "N/A", 1119 | "to": "null" 1120 | } 1121 | ], 1122 | "scopedVars": { 1123 | "server": { 1124 | "selected": true, 1125 | "text": "psql-cluster-02", 1126 | "value": "psql-cluster-02" 1127 | } 1128 | }, 1129 | "sparkline": { 1130 | "fillColor": "rgba(31, 118, 189, 0.18)", 1131 | "full": false, 1132 | "lineColor": "rgb(31, 120, 193)", 1133 | "show": false 1134 | }, 1135 | "tableColumn": "", 1136 | "targets": [ 1137 | { 1138 | "expr": "barman_backups_total{instance=~\"$instance.*\", server=\"$server\"} - barman_backups_failed{instance=~\"$instance.*\", server=\"$server\"}", 1139 | "format": "time_series", 1140 | "interval": "", 1141 | "intervalFactor": 1, 1142 | "legendFormat": "", 1143 | "refId": "A" 1144 | } 1145 | ], 1146 | "thresholds": "4", 1147 | "timeFrom": null, 1148 | "timeShift": null, 1149 | "title": "Available backups", 1150 | "type": "singlestat", 1151 | "valueFontSize": "100%", 1152 | "valueMaps": [ 1153 | { 1154 | "op": "=", 1155 | "text": "N/A", 1156 | "value": "null" 1157 | } 1158 | ], 1159 | "valueName": "current" 1160 | }, 1161 | { 1162 | "aliasColors": {}, 1163 | "bars": false, 1164 | "dashLength": 10, 1165 | "dashes": false, 1166 | "datasource": null, 1167 | "fieldConfig": { 1168 | "defaults": { 1169 | "custom": {}, 1170 | "links": [] 1171 | }, 1172 | "overrides": [] 1173 | }, 1174 | "fill": 0, 1175 | "fillGradient": 0, 1176 | "gridPos": { 1177 | "h": 10, 1178 | "w": 12, 1179 | "x": 0, 1180 | "y": 22 1181 | }, 1182 | "hiddenSeries": false, 1183 | "id": 20, 1184 | "legend": { 1185 | "alignAsTable": true, 1186 | "avg": true, 1187 | "current": true, 1188 | "max": true, 1189 | "min": true, 1190 | "show": true, 1191 | "total": false, 1192 | "values": true 1193 | }, 1194 | "lines": true, 1195 | "linewidth": 2, 1196 | "links": [], 1197 | "nullPointMode": "null", 1198 | "options": { 1199 | "alertThreshold": true 1200 | }, 1201 | "percentage": false, 1202 | "pluginVersion": "7.3.7", 1203 | "pointradius": 2, 1204 | "points": false, 1205 | "renderer": "flot", 1206 | "scopedVars": { 1207 | "server": { 1208 | "selected": true, 1209 | "text": "psql-cluster-02", 1210 | "value": "psql-cluster-02" 1211 | } 1212 | }, 1213 | "seriesOverrides": [ 1214 | { 1215 | "alias": "" 1216 | } 1217 | ], 1218 | "spaceLength": 10, 1219 | "stack": false, 1220 | "steppedLine": false, 1221 | "targets": [ 1222 | { 1223 | "expr": "barman_backup_size{instance=~\"$instance.*\", server=\"$server\", number=\"1\"}", 1224 | "format": "time_series", 1225 | "hide": false, 1226 | "interval": "15m", 1227 | "intervalFactor": 1, 1228 | "legendFormat": "$instance: {{ server }} backup size", 1229 | "refId": "A" 1230 | }, 1231 | { 1232 | "expr": "barman_backup_wal_size{instance=~\"$instance.*\", server=\"$server\", number=\"1\"}", 1233 | "format": "time_series", 1234 | "interval": "15m", 1235 | "intervalFactor": 1, 1236 | "legendFormat": "$instance: {{ server }} WAL size", 1237 | "refId": "B" 1238 | } 1239 | ], 1240 | "thresholds": [], 1241 | "timeFrom": null, 1242 | "timeRegions": [], 1243 | "timeShift": null, 1244 | "title": "Last backup size", 1245 | "tooltip": { 1246 | "shared": true, 1247 | "sort": 0, 1248 | "value_type": "individual" 1249 | }, 1250 | "type": "graph", 1251 | "xaxis": { 1252 | "buckets": null, 1253 | "mode": "time", 1254 | "name": null, 1255 | "show": true, 1256 | "values": [] 1257 | }, 1258 | "yaxes": [ 1259 | { 1260 | "format": "decbytes", 1261 | "label": null, 1262 | "logBase": 1, 1263 | "max": null, 1264 | "min": "0", 1265 | "show": true 1266 | }, 1267 | { 1268 | "format": "short", 1269 | "label": null, 1270 | "logBase": 1, 1271 | "max": null, 1272 | "min": null, 1273 | "show": false 1274 | } 1275 | ], 1276 | "yaxis": { 1277 | "align": false, 1278 | "alignLevel": null 1279 | } 1280 | } 1281 | ], 1282 | "refresh": "", 1283 | "schemaVersion": 26, 1284 | "style": "dark", 1285 | "tags": [], 1286 | "templating": { 1287 | "list": [ 1288 | { 1289 | "allValue": null, 1290 | "current": { 1291 | "selected": false, 1292 | "text": "barman-02", 1293 | "value": "barman-02" 1294 | }, 1295 | "datasource": "Prometheus", 1296 | "definition": "label_values(barman_up, instance)", 1297 | "error": null, 1298 | "hide": 0, 1299 | "includeAll": false, 1300 | "label": "Instance", 1301 | "multi": false, 1302 | "name": "instance", 1303 | "options": [], 1304 | "query": "label_values(barman_up, instance)", 1305 | "refresh": 1, 1306 | "regex": "/^(barman-\\d+)/", 1307 | "skipUrlSync": false, 1308 | "sort": 1, 1309 | "tagValuesQuery": "", 1310 | "tags": [], 1311 | "tagsQuery": "", 1312 | "type": "query", 1313 | "useTags": false 1314 | }, 1315 | { 1316 | "allValue": ".*", 1317 | "current": { 1318 | "selected": true, 1319 | "text": "psql-cluster-02", 1320 | "value": [ 1321 | "psql-cluster-02" 1322 | ] 1323 | }, 1324 | "datasource": "Prometheus", 1325 | "definition": "label_values(barman_up, server)", 1326 | "error": null, 1327 | "hide": 0, 1328 | "includeAll": false, 1329 | "label": "Server", 1330 | "multi": false, 1331 | "name": "server", 1332 | "options": [ 1333 | { 1334 | "selected": true, 1335 | "text": "psql-cluster-02", 1336 | "value": "psql-cluster-02" 1337 | } 1338 | ], 1339 | "query": "label_values(barman_up, server)", 1340 | "refresh": 0, 1341 | "regex": "", 1342 | "skipUrlSync": false, 1343 | "sort": 0, 1344 | "tagValuesQuery": "", 1345 | "tags": [], 1346 | "tagsQuery": "", 1347 | "type": "query", 1348 | "useTags": false 1349 | } 1350 | ] 1351 | }, 1352 | "time": { 1353 | "from": "now-6h", 1354 | "to": "now" 1355 | }, 1356 | "timepicker": { 1357 | "refresh_intervals": [ 1358 | "10s", 1359 | "30s", 1360 | "1m", 1361 | "5m", 1362 | "15m", 1363 | "30m", 1364 | "1h", 1365 | "2h", 1366 | "1d" 1367 | ], 1368 | "time_options": [ 1369 | "5m", 1370 | "15m", 1371 | "1h", 1372 | "6h", 1373 | "12h", 1374 | "24h", 1375 | "2d", 1376 | "7d", 1377 | "30d" 1378 | ] 1379 | }, 1380 | "timezone": "", 1381 | "title": "Barman", 1382 | "uid": "Jb2lonIWk", 1383 | "version": 48 1384 | } 1385 | --------------------------------------------------------------------------------