2019-02-14 04:35:12 +00:00
|
|
|
"""Support for Prometheus metrics export."""
|
2017-07-11 04:20:17 +00:00
|
|
|
import logging
|
2019-09-19 10:51:49 +00:00
|
|
|
import string
|
2017-07-11 04:20:17 +00:00
|
|
|
|
|
|
|
from aiohttp import web
|
2019-10-22 05:35:43 +00:00
|
|
|
import prometheus_client
|
2019-02-14 04:35:12 +00:00
|
|
|
import voluptuous as vol
|
2017-07-11 04:20:17 +00:00
|
|
|
|
2019-02-14 04:35:12 +00:00
|
|
|
from homeassistant import core as hacore
|
2019-02-14 19:34:43 +00:00
|
|
|
from homeassistant.components.climate.const import ATTR_CURRENT_TEMPERATURE
|
2017-07-11 04:20:17 +00:00
|
|
|
from homeassistant.components.http import HomeAssistantView
|
2017-08-25 11:30:00 +00:00
|
|
|
from homeassistant.const import (
|
2019-10-22 05:35:43 +00:00
|
|
|
ATTR_DEVICE_CLASS,
|
2019-07-31 19:25:30 +00:00
|
|
|
ATTR_TEMPERATURE,
|
|
|
|
ATTR_UNIT_OF_MEASUREMENT,
|
|
|
|
CONTENT_TYPE_TEXT_PLAIN,
|
|
|
|
EVENT_STATE_CHANGED,
|
2019-08-10 12:35:04 +00:00
|
|
|
TEMP_CELSIUS,
|
2019-10-22 05:35:43 +00:00
|
|
|
TEMP_FAHRENHEIT,
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2018-06-28 14:49:33 +00:00
|
|
|
from homeassistant.helpers import entityfilter, state as state_helper
|
2019-02-14 04:35:12 +00:00
|
|
|
import homeassistant.helpers.config_validation as cv
|
2019-08-10 12:35:04 +00:00
|
|
|
from homeassistant.helpers.entity_values import EntityValues
|
2019-10-22 05:35:43 +00:00
|
|
|
from homeassistant.util.temperature import fahrenheit_to_celsius
|
2017-07-11 04:20:17 +00:00
|
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
API_ENDPOINT = "/api/prometheus"
|
2017-07-11 04:20:17 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
DOMAIN = "prometheus"
|
|
|
|
CONF_FILTER = "filter"
|
|
|
|
CONF_PROM_NAMESPACE = "namespace"
|
2019-08-10 12:35:04 +00:00
|
|
|
CONF_COMPONENT_CONFIG = "component_config"
|
|
|
|
CONF_COMPONENT_CONFIG_GLOB = "component_config_glob"
|
|
|
|
CONF_COMPONENT_CONFIG_DOMAIN = "component_config_domain"
|
|
|
|
CONF_DEFAULT_METRIC = "default_metric"
|
|
|
|
CONF_OVERRIDE_METRIC = "override_metric"
|
|
|
|
COMPONENT_CONFIG_SCHEMA_ENTRY = vol.Schema(
|
|
|
|
{vol.Optional(CONF_OVERRIDE_METRIC): cv.string}
|
|
|
|
)
|
2018-06-28 14:49:33 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
CONFIG_SCHEMA = vol.Schema(
|
|
|
|
{
|
|
|
|
DOMAIN: vol.All(
|
|
|
|
{
|
|
|
|
vol.Optional(CONF_FILTER, default={}): entityfilter.FILTER_SCHEMA,
|
|
|
|
vol.Optional(CONF_PROM_NAMESPACE): cv.string,
|
2019-08-10 12:35:04 +00:00
|
|
|
vol.Optional(CONF_DEFAULT_METRIC): cv.string,
|
|
|
|
vol.Optional(CONF_OVERRIDE_METRIC): cv.string,
|
|
|
|
vol.Optional(CONF_COMPONENT_CONFIG, default={}): vol.Schema(
|
|
|
|
{cv.entity_id: COMPONENT_CONFIG_SCHEMA_ENTRY}
|
|
|
|
),
|
|
|
|
vol.Optional(CONF_COMPONENT_CONFIG_GLOB, default={}): vol.Schema(
|
|
|
|
{cv.string: COMPONENT_CONFIG_SCHEMA_ENTRY}
|
|
|
|
),
|
|
|
|
vol.Optional(CONF_COMPONENT_CONFIG_DOMAIN, default={}): vol.Schema(
|
|
|
|
{cv.string: COMPONENT_CONFIG_SCHEMA_ENTRY}
|
|
|
|
),
|
2019-07-31 19:25:30 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
},
|
|
|
|
extra=vol.ALLOW_EXTRA,
|
|
|
|
)
|
2017-07-11 04:20:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
def setup(hass, config):
|
|
|
|
"""Activate Prometheus component."""
|
|
|
|
hass.http.register_view(PrometheusView(prometheus_client))
|
|
|
|
|
2018-06-28 14:49:33 +00:00
|
|
|
conf = config[DOMAIN]
|
|
|
|
entity_filter = conf[CONF_FILTER]
|
|
|
|
namespace = conf.get(CONF_PROM_NAMESPACE)
|
2018-08-22 07:17:29 +00:00
|
|
|
climate_units = hass.config.units.temperature_unit
|
2019-08-10 12:35:04 +00:00
|
|
|
override_metric = conf.get(CONF_OVERRIDE_METRIC)
|
|
|
|
default_metric = conf.get(CONF_DEFAULT_METRIC)
|
|
|
|
component_config = EntityValues(
|
|
|
|
conf[CONF_COMPONENT_CONFIG],
|
|
|
|
conf[CONF_COMPONENT_CONFIG_DOMAIN],
|
|
|
|
conf[CONF_COMPONENT_CONFIG_GLOB],
|
|
|
|
)
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
metrics = PrometheusMetrics(
|
2019-08-10 12:35:04 +00:00
|
|
|
prometheus_client,
|
|
|
|
entity_filter,
|
|
|
|
namespace,
|
|
|
|
climate_units,
|
|
|
|
component_config,
|
|
|
|
override_metric,
|
|
|
|
default_metric,
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2017-07-11 04:20:17 +00:00
|
|
|
|
|
|
|
hass.bus.listen(EVENT_STATE_CHANGED, metrics.handle_event)
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2018-07-20 08:45:20 +00:00
|
|
|
class PrometheusMetrics:
|
2017-07-11 04:20:17 +00:00
|
|
|
"""Model all of the metrics which should be exposed to Prometheus."""
|
|
|
|
|
2019-08-10 12:35:04 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
2019-10-22 05:35:43 +00:00
|
|
|
prometheus_cli,
|
2019-08-10 12:35:04 +00:00
|
|
|
entity_filter,
|
|
|
|
namespace,
|
|
|
|
climate_units,
|
|
|
|
component_config,
|
|
|
|
override_metric,
|
|
|
|
default_metric,
|
|
|
|
):
|
2017-07-11 04:20:17 +00:00
|
|
|
"""Initialize Prometheus Metrics."""
|
2019-10-22 05:35:43 +00:00
|
|
|
self.prometheus_cli = prometheus_cli
|
2019-08-10 12:35:04 +00:00
|
|
|
self._component_config = component_config
|
|
|
|
self._override_metric = override_metric
|
|
|
|
self._default_metric = default_metric
|
2018-06-28 14:49:33 +00:00
|
|
|
self._filter = entity_filter
|
2019-08-10 12:35:04 +00:00
|
|
|
self._sensor_metric_handlers = [
|
|
|
|
self._sensor_override_component_metric,
|
|
|
|
self._sensor_override_metric,
|
|
|
|
self._sensor_attribute_metric,
|
|
|
|
self._sensor_default_metric,
|
|
|
|
self._sensor_fallback_metric,
|
|
|
|
]
|
|
|
|
|
2018-06-28 14:49:33 +00:00
|
|
|
if namespace:
|
2019-08-10 12:35:04 +00:00
|
|
|
self.metrics_prefix = f"{namespace}_"
|
2018-06-28 14:49:33 +00:00
|
|
|
else:
|
|
|
|
self.metrics_prefix = ""
|
2017-07-11 04:20:17 +00:00
|
|
|
self._metrics = {}
|
2018-08-22 07:17:29 +00:00
|
|
|
self._climate_units = climate_units
|
2017-07-11 04:20:17 +00:00
|
|
|
|
|
|
|
def handle_event(self, event):
|
|
|
|
"""Listen for new messages on the bus, and add them to Prometheus."""
|
2019-07-31 19:25:30 +00:00
|
|
|
state = event.data.get("new_state")
|
2017-07-11 04:20:17 +00:00
|
|
|
if state is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
entity_id = state.entity_id
|
|
|
|
_LOGGER.debug("Handling state update for %s", entity_id)
|
|
|
|
domain, _ = hacore.split_entity_id(entity_id)
|
|
|
|
|
2018-06-28 14:49:33 +00:00
|
|
|
if not self._filter(state.entity_id):
|
2017-07-11 04:20:17 +00:00
|
|
|
return
|
|
|
|
|
2019-08-10 12:35:04 +00:00
|
|
|
handler = f"_handle_{domain}"
|
2017-07-11 04:20:17 +00:00
|
|
|
|
|
|
|
if hasattr(self, handler):
|
|
|
|
getattr(self, handler)(state)
|
|
|
|
|
2018-05-05 14:23:01 +00:00
|
|
|
metric = self._metric(
|
2019-10-22 05:35:43 +00:00
|
|
|
"state_change", self.prometheus_cli.Counter, "The number of state changes"
|
2018-05-05 14:23:01 +00:00
|
|
|
)
|
|
|
|
metric.labels(**self._labels(state)).inc()
|
|
|
|
|
2017-07-11 04:20:17 +00:00
|
|
|
def _metric(self, metric, factory, documentation, labels=None):
|
|
|
|
if labels is None:
|
2019-07-31 19:25:30 +00:00
|
|
|
labels = ["entity", "friendly_name", "domain"]
|
2017-07-11 04:20:17 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
return self._metrics[metric]
|
|
|
|
except KeyError:
|
2019-09-19 10:51:49 +00:00
|
|
|
full_metric_name = self._sanitize_metric_name(
|
|
|
|
f"{self.metrics_prefix}{metric}"
|
|
|
|
)
|
2019-07-31 19:25:30 +00:00
|
|
|
self._metrics[metric] = factory(full_metric_name, documentation, labels)
|
2017-07-11 04:20:17 +00:00
|
|
|
return self._metrics[metric]
|
|
|
|
|
2019-09-19 10:51:49 +00:00
|
|
|
@staticmethod
|
|
|
|
def _sanitize_metric_name(metric: str) -> str:
|
|
|
|
return "".join(
|
|
|
|
[
|
|
|
|
c
|
|
|
|
if c in string.ascii_letters or c.isdigit() or c == "_" or c == ":"
|
|
|
|
else f"u{hex(ord(c))}"
|
|
|
|
for c in metric
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
2019-03-22 20:16:17 +00:00
|
|
|
@staticmethod
|
|
|
|
def state_as_number(state):
|
|
|
|
"""Return a state casted to a float."""
|
|
|
|
try:
|
|
|
|
value = state_helper.state_as_number(state)
|
|
|
|
except ValueError:
|
|
|
|
_LOGGER.warning("Could not convert %s to float", state)
|
|
|
|
value = 0
|
|
|
|
return value
|
|
|
|
|
2017-07-11 04:20:17 +00:00
|
|
|
@staticmethod
|
|
|
|
def _labels(state):
|
|
|
|
return {
|
2019-07-31 19:25:30 +00:00
|
|
|
"entity": state.entity_id,
|
|
|
|
"domain": state.domain,
|
|
|
|
"friendly_name": state.attributes.get("friendly_name"),
|
2017-07-11 04:20:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def _battery(self, state):
|
2019-07-31 19:25:30 +00:00
|
|
|
if "battery_level" in state.attributes:
|
2017-07-11 04:20:17 +00:00
|
|
|
metric = self._metric(
|
2019-07-31 19:25:30 +00:00
|
|
|
"battery_level_percent",
|
2019-10-22 05:35:43 +00:00
|
|
|
self.prometheus_cli.Gauge,
|
2019-07-31 19:25:30 +00:00
|
|
|
"Battery level as a percentage of its capacity",
|
2017-07-11 04:20:17 +00:00
|
|
|
)
|
|
|
|
try:
|
2019-07-31 19:25:30 +00:00
|
|
|
value = float(state.attributes["battery_level"])
|
2017-07-11 04:20:17 +00:00
|
|
|
metric.labels(**self._labels(state)).set(value)
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
def _handle_binary_sensor(self, state):
|
|
|
|
metric = self._metric(
|
2019-07-31 19:25:30 +00:00
|
|
|
"binary_sensor_state",
|
2019-10-22 05:35:43 +00:00
|
|
|
self.prometheus_cli.Gauge,
|
2019-07-31 19:25:30 +00:00
|
|
|
"State of the binary sensor (0/1)",
|
2017-07-11 04:20:17 +00:00
|
|
|
)
|
2019-03-22 20:16:17 +00:00
|
|
|
value = self.state_as_number(state)
|
2017-07-11 04:20:17 +00:00
|
|
|
metric.labels(**self._labels(state)).set(value)
|
|
|
|
|
2018-11-06 12:19:36 +00:00
|
|
|
def _handle_input_boolean(self, state):
|
|
|
|
metric = self._metric(
|
2019-07-31 19:25:30 +00:00
|
|
|
"input_boolean_state",
|
2019-10-22 05:35:43 +00:00
|
|
|
self.prometheus_cli.Gauge,
|
2019-07-31 19:25:30 +00:00
|
|
|
"State of the input boolean (0/1)",
|
2018-11-06 12:19:36 +00:00
|
|
|
)
|
2019-03-22 20:16:17 +00:00
|
|
|
value = self.state_as_number(state)
|
2018-11-06 12:19:36 +00:00
|
|
|
metric.labels(**self._labels(state)).set(value)
|
|
|
|
|
2017-07-11 04:20:17 +00:00
|
|
|
def _handle_device_tracker(self, state):
|
|
|
|
metric = self._metric(
|
2019-07-31 19:25:30 +00:00
|
|
|
"device_tracker_state",
|
2019-10-22 05:35:43 +00:00
|
|
|
self.prometheus_cli.Gauge,
|
2019-07-31 19:25:30 +00:00
|
|
|
"State of the device tracker (0/1)",
|
2017-07-11 04:20:17 +00:00
|
|
|
)
|
2019-03-22 20:16:17 +00:00
|
|
|
value = self.state_as_number(state)
|
2017-07-11 04:20:17 +00:00
|
|
|
metric.labels(**self._labels(state)).set(value)
|
2019-02-23 17:13:27 +00:00
|
|
|
|
|
|
|
def _handle_person(self, state):
|
|
|
|
metric = self._metric(
|
2019-10-22 05:35:43 +00:00
|
|
|
"person_state", self.prometheus_cli.Gauge, "State of the person (0/1)"
|
2019-02-23 17:13:27 +00:00
|
|
|
)
|
2019-03-22 20:16:17 +00:00
|
|
|
value = self.state_as_number(state)
|
2019-02-23 17:13:27 +00:00
|
|
|
metric.labels(**self._labels(state)).set(value)
|
2017-07-11 04:20:17 +00:00
|
|
|
|
|
|
|
def _handle_light(self, state):
|
|
|
|
metric = self._metric(
|
2019-10-22 05:35:43 +00:00
|
|
|
"light_state", self.prometheus_cli.Gauge, "Load level of a light (0..1)"
|
2017-07-11 04:20:17 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
try:
|
2019-07-31 19:25:30 +00:00
|
|
|
if "brightness" in state.attributes:
|
|
|
|
value = state.attributes["brightness"] / 255.0
|
2017-07-11 04:20:17 +00:00
|
|
|
else:
|
2019-03-22 20:16:17 +00:00
|
|
|
value = self.state_as_number(state)
|
2017-07-11 04:20:17 +00:00
|
|
|
value = value * 100
|
|
|
|
metric.labels(**self._labels(state)).set(value)
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
def _handle_lock(self, state):
|
|
|
|
metric = self._metric(
|
2019-10-22 05:35:43 +00:00
|
|
|
"lock_state", self.prometheus_cli.Gauge, "State of the lock (0/1)"
|
2017-07-11 04:20:17 +00:00
|
|
|
)
|
2019-03-22 20:16:17 +00:00
|
|
|
value = self.state_as_number(state)
|
2017-07-11 04:20:17 +00:00
|
|
|
metric.labels(**self._labels(state)).set(value)
|
|
|
|
|
2017-12-04 12:39:26 +00:00
|
|
|
def _handle_climate(self, state):
|
|
|
|
temp = state.attributes.get(ATTR_TEMPERATURE)
|
|
|
|
if temp:
|
2018-08-22 07:17:29 +00:00
|
|
|
if self._climate_units == TEMP_FAHRENHEIT:
|
2017-12-04 12:39:26 +00:00
|
|
|
temp = fahrenheit_to_celsius(temp)
|
|
|
|
metric = self._metric(
|
2019-07-31 19:25:30 +00:00
|
|
|
"temperature_c",
|
2019-10-22 05:35:43 +00:00
|
|
|
self.prometheus_cli.Gauge,
|
2019-07-31 19:25:30 +00:00
|
|
|
"Temperature in degrees Celsius",
|
|
|
|
)
|
2017-12-04 12:39:26 +00:00
|
|
|
metric.labels(**self._labels(state)).set(temp)
|
|
|
|
|
2018-07-02 22:03:46 +00:00
|
|
|
current_temp = state.attributes.get(ATTR_CURRENT_TEMPERATURE)
|
|
|
|
if current_temp:
|
2018-08-22 07:17:29 +00:00
|
|
|
if self._climate_units == TEMP_FAHRENHEIT:
|
2018-07-02 22:03:46 +00:00
|
|
|
current_temp = fahrenheit_to_celsius(current_temp)
|
|
|
|
metric = self._metric(
|
2019-07-31 19:25:30 +00:00
|
|
|
"current_temperature_c",
|
2019-10-22 05:35:43 +00:00
|
|
|
self.prometheus_cli.Gauge,
|
2019-07-31 19:25:30 +00:00
|
|
|
"Current Temperature in degrees Celsius",
|
|
|
|
)
|
2018-07-02 22:03:46 +00:00
|
|
|
metric.labels(**self._labels(state)).set(current_temp)
|
|
|
|
|
2017-07-11 04:20:17 +00:00
|
|
|
def _handle_sensor(self, state):
|
2019-08-10 12:35:04 +00:00
|
|
|
unit = self._unit_string(state.attributes.get(ATTR_UNIT_OF_MEASUREMENT))
|
2017-07-11 04:20:17 +00:00
|
|
|
|
2019-08-10 12:35:04 +00:00
|
|
|
for metric_handler in self._sensor_metric_handlers:
|
|
|
|
metric = metric_handler(state, unit)
|
|
|
|
if metric is not None:
|
|
|
|
break
|
2017-07-11 04:20:17 +00:00
|
|
|
|
2019-08-10 12:35:04 +00:00
|
|
|
if metric is not None:
|
|
|
|
_metric = self._metric(
|
2019-10-22 05:35:43 +00:00
|
|
|
metric, self.prometheus_cli.Gauge, f"Sensor data measured in {unit}"
|
2019-08-10 12:35:04 +00:00
|
|
|
)
|
2018-04-10 06:20:47 +00:00
|
|
|
|
2019-08-10 12:35:04 +00:00
|
|
|
try:
|
|
|
|
value = self.state_as_number(state)
|
|
|
|
if unit == TEMP_FAHRENHEIT:
|
|
|
|
value = fahrenheit_to_celsius(value)
|
|
|
|
_metric.labels(**self._labels(state)).set(value)
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
self._battery(state)
|
2018-01-08 16:11:45 +00:00
|
|
|
|
2019-08-10 12:35:04 +00:00
|
|
|
def _sensor_default_metric(self, state, unit):
|
|
|
|
"""Get default metric."""
|
|
|
|
return self._default_metric
|
2018-01-08 16:11:45 +00:00
|
|
|
|
2019-08-10 12:35:04 +00:00
|
|
|
@staticmethod
|
|
|
|
def _sensor_attribute_metric(state, unit):
|
|
|
|
"""Get metric based on device class attribute."""
|
|
|
|
metric = state.attributes.get(ATTR_DEVICE_CLASS)
|
|
|
|
if metric is not None:
|
|
|
|
return f"{metric}_{unit}"
|
|
|
|
return None
|
|
|
|
|
|
|
|
def _sensor_override_metric(self, state, unit):
|
|
|
|
"""Get metric from override in configuration."""
|
|
|
|
if self._override_metric:
|
|
|
|
return self._override_metric
|
|
|
|
return None
|
|
|
|
|
|
|
|
def _sensor_override_component_metric(self, state, unit):
|
|
|
|
"""Get metric from override in component confioguration."""
|
|
|
|
return self._component_config.get(state.entity_id).get(CONF_OVERRIDE_METRIC)
|
2017-07-11 04:20:17 +00:00
|
|
|
|
2019-08-10 12:35:04 +00:00
|
|
|
@staticmethod
|
|
|
|
def _sensor_fallback_metric(state, unit):
|
|
|
|
"""Get metric from fallback logic for compatability."""
|
|
|
|
if unit in (None, ""):
|
|
|
|
_LOGGER.debug("Unsupported sensor: %s", state.entity_id)
|
|
|
|
return None
|
|
|
|
return f"sensor_unit_{unit}"
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _unit_string(unit):
|
|
|
|
"""Get a formatted string of the unit."""
|
|
|
|
if unit is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
units = {
|
|
|
|
TEMP_CELSIUS: "c",
|
|
|
|
TEMP_FAHRENHEIT: "c", # F should go into C metric
|
|
|
|
"%": "percent",
|
|
|
|
}
|
|
|
|
default = unit.replace("/", "_per_")
|
|
|
|
default = default.lower()
|
|
|
|
return units.get(unit, default)
|
2017-07-11 04:20:17 +00:00
|
|
|
|
|
|
|
def _handle_switch(self, state):
|
|
|
|
metric = self._metric(
|
2019-10-22 05:35:43 +00:00
|
|
|
"switch_state", self.prometheus_cli.Gauge, "State of the switch (0/1)"
|
2017-07-11 04:20:17 +00:00
|
|
|
)
|
2017-12-03 22:39:54 +00:00
|
|
|
|
|
|
|
try:
|
2019-03-22 20:16:17 +00:00
|
|
|
value = self.state_as_number(state)
|
2017-12-03 22:39:54 +00:00
|
|
|
metric.labels(**self._labels(state)).set(value)
|
|
|
|
except ValueError:
|
|
|
|
pass
|
2017-07-11 04:20:17 +00:00
|
|
|
|
2017-07-24 06:49:03 +00:00
|
|
|
def _handle_zwave(self, state):
|
|
|
|
self._battery(state)
|
|
|
|
|
2017-12-03 22:39:54 +00:00
|
|
|
def _handle_automation(self, state):
|
|
|
|
metric = self._metric(
|
2019-07-31 19:25:30 +00:00
|
|
|
"automation_triggered_count",
|
2019-10-22 05:35:43 +00:00
|
|
|
self.prometheus_cli.Counter,
|
2019-07-31 19:25:30 +00:00
|
|
|
"Count of times an automation has been triggered",
|
2017-12-03 22:39:54 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
metric.labels(**self._labels(state)).inc()
|
|
|
|
|
2017-07-11 04:20:17 +00:00
|
|
|
|
|
|
|
class PrometheusView(HomeAssistantView):
|
|
|
|
"""Handle Prometheus requests."""
|
|
|
|
|
|
|
|
url = API_ENDPOINT
|
2019-07-31 19:25:30 +00:00
|
|
|
name = "api:prometheus"
|
2017-07-11 04:20:17 +00:00
|
|
|
|
2019-10-22 05:35:43 +00:00
|
|
|
def __init__(self, prometheus_cli):
|
2017-07-11 04:20:17 +00:00
|
|
|
"""Initialize Prometheus view."""
|
2019-10-22 05:35:43 +00:00
|
|
|
self.prometheus_cli = prometheus_cli
|
2017-07-11 04:20:17 +00:00
|
|
|
|
2018-10-01 06:52:42 +00:00
|
|
|
async def get(self, request):
|
2017-07-11 04:20:17 +00:00
|
|
|
"""Handle request for Prometheus metrics."""
|
2017-08-25 11:30:00 +00:00
|
|
|
_LOGGER.debug("Received Prometheus metrics request")
|
2017-07-11 04:20:17 +00:00
|
|
|
|
|
|
|
return web.Response(
|
2019-10-22 05:35:43 +00:00
|
|
|
body=self.prometheus_cli.generate_latest(),
|
2019-07-31 19:25:30 +00:00
|
|
|
content_type=CONTENT_TYPE_TEXT_PLAIN,
|
|
|
|
)
|