Adding 'namespace' for prometheus metrics (#13738)

* Updating prometheus client version

* Using `entity_filter` as filter mechanism

* New optional `namespace` configuration
This commit is contained in:
Alex Barcelo 2018-06-28 16:49:33 +02:00 committed by Pascal Vizeli
parent 19f2bbf52f
commit a277470363
4 changed files with 28 additions and 27 deletions

View File

@ -11,16 +11,15 @@ import voluptuous as vol
from aiohttp import web from aiohttp import web
from homeassistant.components.http import HomeAssistantView from homeassistant.components.http import HomeAssistantView
from homeassistant.components import recorder
from homeassistant.const import ( from homeassistant.const import (
CONF_DOMAINS, CONF_ENTITIES, CONF_EXCLUDE, CONF_INCLUDE,
EVENT_STATE_CHANGED, TEMP_FAHRENHEIT, CONTENT_TYPE_TEXT_PLAIN, EVENT_STATE_CHANGED, TEMP_FAHRENHEIT, CONTENT_TYPE_TEXT_PLAIN,
ATTR_TEMPERATURE, ATTR_UNIT_OF_MEASUREMENT) ATTR_TEMPERATURE, ATTR_UNIT_OF_MEASUREMENT)
from homeassistant import core as hacore from homeassistant import core as hacore
from homeassistant.helpers import state as state_helper import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import entityfilter, state as state_helper
from homeassistant.util.temperature import fahrenheit_to_celsius from homeassistant.util.temperature import fahrenheit_to_celsius
REQUIREMENTS = ['prometheus_client==0.1.0'] REQUIREMENTS = ['prometheus_client==0.2.0']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -29,8 +28,14 @@ API_ENDPOINT = '/api/prometheus'
DOMAIN = 'prometheus' DOMAIN = 'prometheus'
DEPENDENCIES = ['http'] DEPENDENCIES = ['http']
CONF_FILTER = 'filter'
CONF_PROM_NAMESPACE = 'namespace'
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: recorder.FILTER_SCHEMA, DOMAIN: vol.All({
vol.Optional(CONF_FILTER, default={}): entityfilter.FILTER_SCHEMA,
vol.Optional(CONF_PROM_NAMESPACE): cv.string,
})
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)
@ -40,25 +45,26 @@ def setup(hass, config):
hass.http.register_view(PrometheusView(prometheus_client)) hass.http.register_view(PrometheusView(prometheus_client))
conf = config.get(DOMAIN, {}) conf = config[DOMAIN]
exclude = conf.get(CONF_EXCLUDE, {}) entity_filter = conf[CONF_FILTER]
include = conf.get(CONF_INCLUDE, {}) namespace = conf.get(CONF_PROM_NAMESPACE)
metrics = Metrics(prometheus_client, exclude, include) metrics = PrometheusMetrics(prometheus_client, entity_filter, namespace)
hass.bus.listen(EVENT_STATE_CHANGED, metrics.handle_event) hass.bus.listen(EVENT_STATE_CHANGED, metrics.handle_event)
return True return True
class Metrics(object): class PrometheusMetrics(object):
"""Model all of the metrics which should be exposed to Prometheus.""" """Model all of the metrics which should be exposed to Prometheus."""
def __init__(self, prometheus_client, exclude, include): def __init__(self, prometheus_client, entity_filter, namespace):
"""Initialize Prometheus Metrics.""" """Initialize Prometheus Metrics."""
self.prometheus_client = prometheus_client self.prometheus_client = prometheus_client
self.exclude = exclude.get(CONF_ENTITIES, []) + \ self._filter = entity_filter
exclude.get(CONF_DOMAINS, []) if namespace:
self.include_domains = include.get(CONF_DOMAINS, []) self.metrics_prefix = "{}_".format(namespace)
self.include_entities = include.get(CONF_ENTITIES, []) else:
self.metrics_prefix = ""
self._metrics = {} self._metrics = {}
def handle_event(self, event): def handle_event(self, event):
@ -71,14 +77,7 @@ class Metrics(object):
_LOGGER.debug("Handling state update for %s", entity_id) _LOGGER.debug("Handling state update for %s", entity_id)
domain, _ = hacore.split_entity_id(entity_id) domain, _ = hacore.split_entity_id(entity_id)
if entity_id in self.exclude: if not self._filter(state.entity_id):
return
if domain in self.exclude and entity_id not in self.include_entities:
return
if self.include_domains and domain not in self.include_domains:
return
if not self.exclude and (self.include_entities and
entity_id not in self.include_entities):
return return
handler = '_handle_{}'.format(domain) handler = '_handle_{}'.format(domain)
@ -100,7 +99,9 @@ class Metrics(object):
try: try:
return self._metrics[metric] return self._metrics[metric]
except KeyError: except KeyError:
self._metrics[metric] = factory(metric, documentation, labels) full_metric_name = "{}{}".format(self.metrics_prefix, metric)
self._metrics[metric] = factory(
full_metric_name, documentation, labels)
return self._metrics[metric] return self._metrics[metric]
@staticmethod @staticmethod

View File

@ -674,7 +674,7 @@ postnl_api==1.0.2
proliphix==0.4.1 proliphix==0.4.1
# homeassistant.components.prometheus # homeassistant.components.prometheus
prometheus_client==0.1.0 prometheus_client==0.2.0
# homeassistant.components.sensor.systemmonitor # homeassistant.components.sensor.systemmonitor
psutil==5.4.6 psutil==5.4.6

View File

@ -120,7 +120,7 @@ pilight==0.1.1
pmsensor==0.4 pmsensor==0.4
# homeassistant.components.prometheus # homeassistant.components.prometheus
prometheus_client==0.1.0 prometheus_client==0.2.0
# homeassistant.components.notify.pushbullet # homeassistant.components.notify.pushbullet
# homeassistant.components.sensor.pushbullet # homeassistant.components.sensor.pushbullet

View File

@ -12,7 +12,7 @@ def prometheus_client(loop, hass, aiohttp_client):
assert loop.run_until_complete(async_setup_component( assert loop.run_until_complete(async_setup_component(
hass, hass,
prometheus.DOMAIN, prometheus.DOMAIN,
{}, {prometheus.DOMAIN: {}},
)) ))
return loop.run_until_complete(aiohttp_client(hass.http.app)) return loop.run_until_complete(aiohttp_client(hass.http.app))