Skip to content

Commit

Permalink
Replace Flask with Quart
Browse files Browse the repository at this point in the history
  • Loading branch information
thenodon committed Sep 2, 2019
1 parent 33037c6 commit cd5bfea
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 77 deletions.
11 changes: 6 additions & 5 deletions icinga2_exporter/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import icinga2_exporter.fileconfiguration as config
import icinga2_exporter.proxy as proxy

from flask import Flask
from quart import Quart
import icinga2_exporter.monitorconnection as monitorconnection


Expand Down Expand Up @@ -62,9 +62,9 @@ def start():
monitorconnection.MonitorConfig(configuration)
log.info('Starting web app on port: ' + str(port))

app = Flask(__name__)
app = proxy.app #Quart(__name__)

app.register_blueprint(proxy.app, url_prefix='/')
#app.register_blueprint(proxy.app, url_prefix='/')
app.run(host='0.0.0.0', port=port)


Expand All @@ -86,8 +86,9 @@ def create_app(config_path=None):
monitorconnection.MonitorConfig(configuration)
log.info('Starting web app')

app = Flask(__name__)
app = proxy.app # Quart(__name__)

app.register_blueprint(proxy.app, url_prefix='/')
#app.register_blueprint(proxy.app, url_prefix='/')
#app.register_blueprint(proxy.app)

return app
32 changes: 32 additions & 0 deletions icinga2_exporter/monitorconnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import requests
import json
import aiohttp
from requests.auth import HTTPBasicAuth
import icinga2_exporter.log as log

Expand Down Expand Up @@ -142,3 +143,34 @@ def post(self, url, body):
log.error("{}".format(str(err)))

return data_json


async def async_get_perfdata(self, hostname):
# Get performance data from Monitor and return in json format
body = {"joins": ["host.vars"],
"attrs": ["__name", "display_name", "check_command", "last_check_result", "vars", "host_name"],
"filter": 'service.host_name==\"{}\"'.format(hostname)}

data_json = await self.async_post(self.url_query_service_perfdata, body)

if not data_json:
log.warn('Received no perfdata from Icinga2')

return data_json


async def async_post(self, url, body):
data_json = {}
try:
async with aiohttp.ClientSession() as session:
async with session.post(url, auth=aiohttp.BasicAuth(self.user, self.passwd),
verify_ssl=False,
headers={'Content-Type': 'application/json',
'X-HTTP-Method-Override': 'GET'},
data=json.dumps(body)) as response:
re = await response.text()
print(re)
print(response.status)
return json.loads(re)
finally:
pass
45 changes: 45 additions & 0 deletions icinga2_exporter/perfdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def get_perfdata(self) -> dict:
Collect icinga2 data and parse it into prometheus metrics
:return:
"""

data_json = self.monitor.get_perfdata(self.query_hostname)
if 'results' in data_json:
for serivce_attrs in data_json['results']:
Expand All @@ -60,6 +61,50 @@ def get_perfdata(self) -> dict:
# For all host custom vars add as label
labels.update(Perfdata.get_host_custom_vars(serivce_attrs))

for perf_string in serivce_attrs['attrs']['last_check_result']['performance_data']:
perf = Perfdata.parse_perfdata(perf_string)

# For each perfdata metrics
for perf_data_key, perf_data_value in perf.items():

if 'value' in perf_data_value:
prometheus_key = self.format_promethues_metrics_name(check_command, perf_data_key,
perf_data_value)

# Add more labels based on perfname
if check_command in self.perfname_to_label:
labels.update(
Perfdata.add_labels_by_items(
self.perfname_to_label[check_command]['label_name'],
perf_data_key))

prometheus_key_with_labels = Perfdata.concat_metrics_name_and_labels(labels,
prometheus_key)

self.perfdatadict.update({prometheus_key_with_labels: str(perf_data_value['value'])})

return self.perfdatadict

async def async_get_perfdata(self) -> dict:
"""
Collect icinga2 data and parse it into prometheus metrics
:return:
"""

data_json = await self.monitor.async_get_perfdata(self.query_hostname)
if 'results' in data_json:
for serivce_attrs in data_json['results']:
if 'attrs' in serivce_attrs and 'last_check_result' in serivce_attrs['attrs'] and 'performance_data' in \
serivce_attrs['attrs']['last_check_result']:
check_command = serivce_attrs['attrs']['check_command']
# Get default labels
labels = {'hostname': serivce_attrs['attrs']['host_name'],
'service': serivce_attrs['attrs']['display_name']}

# For all host custom vars add as label
labels.update(Perfdata.get_host_custom_vars(serivce_attrs))


for perf_string in serivce_attrs['attrs']['last_check_result']['performance_data']:
perf = Perfdata.parse_perfdata(perf_string)

Expand Down
95 changes: 23 additions & 72 deletions icinga2_exporter/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@
along with icinga2-exporter-exporter. If not, see <http://www.gnu.org/licenses/>.
"""
import asyncio
from quart import request, Response, jsonify, Quart

from flask import request, Response, jsonify, Blueprint
from prometheus_client import (CONTENT_TYPE_LATEST, Counter)

from icinga2_exporter.perfdata import Perfdata
import icinga2_exporter.monitorconnection as monitorconnection
import icinga2_exporter.log as log

app = Blueprint("prom", __name__)
app = Quart( __name__)
total_requests = Counter('requests', 'Total requests to monitor-exporter endpoint')

loop = asyncio.new_event_loop()

@app.route('/', methods=['GET'])
def hello_world():
Expand All @@ -54,13 +56,31 @@ def get_metrics():

return resp

@app.route("/ametrics", methods=['GET'])
async def get_ametrics():
log.info(request.url)
target = request.args.get('target')

log.info('Collect metrics', {'target': target})

monitor_data = Perfdata(monitorconnection.MonitorConfig(), target)

# Fetch performance data from Monitor
await asyncio.get_event_loop().create_task(monitor_data.async_get_perfdata())

target_metrics = monitor_data.prometheus_format()

resp = Response(target_metrics)
resp.headers['Content-Type'] = CONTENT_TYPE_LATEST
#after_request_func(resp)
return resp

@app.route("/health", methods=['GET'])
def get_health():
return chech_healthy()


@app.after_request
#@app.after_request
def after_request_func(response):
total_requests.inc()

Expand All @@ -75,72 +95,3 @@ def chech_healthy() -> Response:
resp = jsonify({'status': 'ok'})
resp.status_code = 200
return resp

# def read_config(config_file: str) -> dict:
# """
# Read configuration file
# :param config_file:
# :return:
# """
# config = {}
# try:
# ymlfile = open(config_file, 'r')
# config = yaml.load(ymlfile, Loader=yaml.SafeLoader)
# except (FileNotFoundError, IOError):
# print("Config file {} not found".format(config_file))
# exit(1)
# except (yaml.YAMLError, yaml.MarkedYAMLError) as err:
# print("Error will reading config file - {}".format(err))
# exit(1)
#
# return config


# def start():
# parser = argparse.ArgumentParser(description='monitor_exporter')
#
# parser.add_argument('-f', '--configfile',
# dest="configfile", help="configuration file")
#
# parser.add_argument('-p', '--port',
# dest="port", help="Server port")
#
# args = parser.parse_args()
#
# port = 5000
# if args.port:
# port = args.port
#
# config_file = 'config.yml'
# if args.configfile:
# config_file = args.configfile
#
# configuration = config.read_config(config_file)
#
# formatter = log.configure_logger(configuration)
# ##
#
# monitorconnection.MonitorConfig(configuration)
# log.info('Starting web app on port: ' + str(port))
#
#
# app.run(host='0.0.0.0', port=port)
# app.logger.handlers[0].setFormatter(formatter)


# def create_app(config_path = None):
#
# config_file = 'config.yml'
# if config_path:
# config_file = config_path
#
# config = read_config(config_file)
#
# formatter = log.configure_logger(config)
#
# monitorconnection.MonitorConfig(config)
# log.info('Starting web app')
#
# app.logger.handlers[0].setFormatter(formatter)
#
# return app

0 comments on commit cd5bfea

Please sign in to comment.