Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added extra metrics + no crash when scraped node has no disks #3

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include prometheus-swift-exporter.service
include post.sh
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Install prometheus_client:
pip install prometheus_client
```

## Installation
## Manual Installation

```
# Copy example config in place, edit to your needs
Expand Down Expand Up @@ -42,6 +42,13 @@ Or to run interactively:

Configuration options are documented in prometheus-swift-exporter.yaml shipped with this project

# To build rpm

```
python setup.py bdist_rpm --post-install post.sh
```

This installs the systemd service file but not the prometheus-swift-exporter.yaml
# FAQ

## Why hardcode swift host list?
Expand Down
4 changes: 4 additions & 0 deletions post.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

touch /etc/default/prometheus-swift-exporter
/usr/bin/systemctl enable prometheus-swift-exporter.service
121 changes: 89 additions & 32 deletions prometheus-swift-exporter
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ from os import path
import traceback
import urlparse
import requests
import json as simplejson
from BaseHTTPServer import BaseHTTPRequestHandler
from BaseHTTPServer import HTTPServer
from SocketServer import ForkingMixIn
from prometheus_client import CollectorRegistry, generate_latest, Gauge, CONTENT_TYPE_LATEST
from prometheus_client import CollectorRegistry, generate_latest, \
Gauge, CONTENT_TYPE_LATEST

import logging
import logging.handlers
Expand All @@ -40,88 +42,142 @@ log = logging.getLogger('poe-logger')
class Swift():
def __init__(self):
self.registry = CollectorRegistry()
self.baseurl = 'http://{{}}:{}/recon/{{}}'.format(config.get('swift_port','6000'))
self.baseurl = 'http://{{}}:{}/recon/{{}}'.format(
config.get('swift_port', '9002'))
self.swift_hosts = config.get('swift_hosts', [])

def gen_get(self, h, p):
r = requests.get(self.baseurl.format(h, 'diskusage'))
if r.status_code != 200:
raise requests.exceptions.RequestException
return r

def gen_up_stats(self):
labels = ['cloud', 'hostname']
swift_up = Gauge('swift_host_up', 'Swift host reachability',
labels, registry=self.registry)
for h in self.swift_hosts:
try:
requests.get(self.baseurl.format(h, 'diskusage'))
r = self.gen_get(h, 'diskusage')
swift_up.labels(config['cloud'], h).set(1)
except requests.exceptions.RequestException:
swift_up.labels(config['cloud'], h).set(0)

def gen_disk_usage_stats(self):
labels = ['cloud', 'hostname', 'device', 'type']
swift_disk = Gauge('swift_disk_usage_bytes', 'Swift disk usage in bytes',
labels, registry=self.registry)
swift_disk = Gauge(
'swift_disk_usage_bytes',
'Swift disk usage in bytes',
labels,
registry=self.registry)
for h in self.swift_hosts:
try:
r = requests.get(self.baseurl.format(h, 'diskusage'))
except requests.exceptions.RequestException:
r = self.gen_get(h, 'diskusage')
except requests.exceptions.RequestException as ValueError:
continue
for disk in r.json():
if not all([disk.get(i, False) for i in ['size', 'used', 'device']]):
if not all([disk.get(i, False)
for i in ['size', 'used', 'device']]):
continue
swift_disk.labels(config['cloud'], h, disk['device'], 'size').set(int(disk['size']))
swift_disk.labels(config['cloud'], h, disk['device'], 'used').set(int(disk['used']))
swift_disk.labels(config['cloud'],
h, disk['device'],
'size').set(int(disk['size']))
swift_disk.labels(config['cloud'],
h, disk['device'],
'used').set(int(disk['used']))

def gen_quarantine_stats(self):
labels = ['cloud', 'hostname', 'ring']
swift_quarantine = Gauge('swift_quarantined_objects', 'Number of quarantined objects',
labels, registry=self.registry)
swift_quarantine = Gauge(
'swift_quarantined_objects',
'Number of quarantined objects',
labels,
registry=self.registry)
for h in self.swift_hosts:
try:
r = requests.get(self.baseurl.format(h, 'quarantined'))
r = self.gen_get(h, 'quarantined')
except requests.exceptions.RequestException:
continue
for ring in ['accounts', 'objects', 'containers']:
swift_quarantine.labels(config['cloud'], h, ring).set(r.json().get(ring))
if (isinstance(r.json(), dict)):
swift_quarantine.labels(
config['cloud'], h, ring).set(
r.json().get(ring))

def gen_unmounted_stats(self):
labels = ['cloud', 'hostname', 'device']
swift_unmounted = Gauge('swift_umounted_disks', 'Disk is unmounted',
labels, registry=self.registry)
for h in self.swift_hosts:
try:
r = self.gen_get(h, 'unmounted')
except requests.exceptions.RequestException:
continue
for disk in r.json():
if disk.get('mounted', True) is False:
swift_unmounted.labels(config['cloud'],
h, disk['device']).set(1)

def gen_replication_stats(self):
labels = ['cloud', 'hostname', 'ring', 'type']
swift_repl = Gauge('swift_replication_stats', 'Swift replication stats', labels, registry=self.registry)
swift_repl = Gauge(
'swift_replication_stats',
'Swift replication stats',
labels,
registry=self.registry)
labels = ['cloud', 'hostname', 'ring']
swift_repl_duration = Gauge('swift_replication_duration_seconds', 'Swift replication duration in seconds',
labels, registry=self.registry)
swift_repl_duration = Gauge(
'swift_replication_duration_seconds',
'Swift replication duration in seconds',
labels,
registry=self.registry)
for h in self.swift_hosts:
metrics = ['attempted', 'diff', 'diff_capped', 'empty',
'failure', 'hashmatch', 'no_change', 'remote_merge',
'remove', 'rsync', 'success', 'ts_repl']
# Object replication is special
try:
r = requests.get(self.baseurl.format(h, 'replication/object'))
r = self.gen_get(h, 'replication/object')
except requests.exceptions.RequestException:
continue
try:
swift_repl_duration.labels(config['cloud'], h, 'object').set(r.json()['object_replication_time'])
swift_repl_duration.labels(
config['cloud'], h, 'object').set(
r.json()['object_replication_time'])
except TypeError:
print(traceback.format_exc())
continue

for ring in ['account', 'container']:
try:
r = requests.get(self.baseurl.format(h, 'replication/' + ring))
r = self.gen_get(h, 'replication/' + ring)
except requests.exceptions.RequestException:
continue
try:
swift_repl_duration.labels(config['cloud'], h, ring).set(r.json()['replication_time'])
if (r.json()['replication_time']):
swift_repl_duration.labels(
config['cloud'], h, ring).set(
r.json()['replication_time'])
except TypeError:
print(traceback.format_exc())

for metric in metrics:
try:
swift_repl.labels(config['cloud'], h, ring, metric).set(r.json()['replication_stats'][metric])
except TypeError:
print(traceback.format_exc())
if r.json().get('replication_stats'):
for metric in metrics:
try:
swift_repl.labels(
config['cloud'], h, ring, metric).set(
r.json()['replication_stats'][metric])
except TypeError:
print("M", metric)
print("C", config['cloud'], h, ring, metric)
print("R", r.json()['replication_stats'])
print(traceback.format_exc())

def get_stats(self):
self.gen_up_stats()
self.gen_disk_usage_stats()
self.gen_quarantine_stats()
self.gen_replication_stats()
self.gen_unmounted_stats()
return generate_latest(self.registry)


Expand All @@ -144,7 +200,7 @@ class OpenstackSwiftExporterHandler(BaseHTTPRequestHandler):
self.send_header('Content-Type', CONTENT_TYPE_LATEST)
self.end_headers()
self.wfile.write(output)
except:
except BaseException:
self.send_response(500)
self.end_headers()
self.wfile.write(traceback.format_exc())
Expand All @@ -168,15 +224,16 @@ def handler(*args, **kwargs):


if __name__ == '__main__':
parser = argparse.ArgumentParser(usage=__doc__,
description='Prometheus OpenStack Swift exporter',
formatter_class=argparse.RawTextHelpFormatter)
parser = argparse.ArgumentParser(
usage=__doc__,
description='Prometheus OpenStack Swift exporter',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('config_file', nargs='?',
help='Configuration file path',
default='/etc/prometheus/prometheus-swift-exporter.yaml',
type=argparse.FileType('r'))
args = parser.parse_args()
log.setLevel(logging.DEBUG)
# log.setLevel(logging.DEBUG)
for logsock in ('/dev/log', '/var/run/syslog'):
if path.exists(logsock):
log.addHandler(logging.handlers.SysLogHandler(address=logsock))
Expand Down
2 changes: 1 addition & 1 deletion prometheus-swift-exporter.service
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ After=network.target

[Service]
EnvironmentFile=/etc/default/prometheus-swift-exporter
ExecStart=/opt/prometheus-swift-exporter/prometheus-swift-exporter /etc/prometheus/prometheus-swift-exporter.yaml
ExecStart=/usr/bin/prometheus-swift-exporter
KillMode=process

[Install]
Expand Down
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ def read(fname):
description="Exposes high level OpenStack Swift metrics to Prometheus.",
license="GPLv3",
keywords=["prometheus", "openstack", "swift", "exporter"],
url="https://github.com/ilanddev/prometheus-swift-exporter",
url="https://github.com/vorsprung/prometheus-swift-exporter",
scripts=["prometheus-swift-exporter"],
data_files=[("/etc/systemd/system",["prometheus-swift-exporter.service"])],
install_requires=["prometheus_client"],
long_description=read('README.md'),
long_description="Exposes high level OpenStack Swift metrics to Prometheus.",
classifiers=[
"Development Status :: 4 - Beta",
"Topic :: System :: Networking :: Monitoring",
Expand Down