Encode prometheus metric names per the prom spec (#26639)
Referencing issue #26418. Prometheus metric names can only contain chars a-zA-Z0-9, : and _ (https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels). HA currently generates invalid prometheus names, e.g. if the unit for a sensor is a non-ASCII character containing ° or μ. To resolve, we need to sanitize the name before creating, replacing non-valid characters with a valid representation. In this case, I've used "u{unicode-hex-code}". Also updated the test case to make sure that the ° case is handled.pull/26723/head
parent
5e15675593
commit
770eeaf82f
|
@ -1,5 +1,6 @@
|
|||
"""Support for Prometheus metrics export."""
|
||||
import logging
|
||||
import string
|
||||
|
||||
from aiohttp import web
|
||||
import voluptuous as vol
|
||||
|
@ -159,10 +160,23 @@ class PrometheusMetrics:
|
|||
try:
|
||||
return self._metrics[metric]
|
||||
except KeyError:
|
||||
full_metric_name = f"{self.metrics_prefix}{metric}"
|
||||
full_metric_name = self._sanitize_metric_name(
|
||||
f"{self.metrics_prefix}{metric}"
|
||||
)
|
||||
self._metrics[metric] = factory(full_metric_name, documentation, labels)
|
||||
return self._metrics[metric]
|
||||
|
||||
@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
|
||||
]
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def state_as_number(state):
|
||||
"""Return a state casted to a float."""
|
||||
|
|
|
@ -41,6 +41,11 @@ async def prometheus_client(loop, hass, hass_client):
|
|||
sensor3.entity_id = "sensor.electricity_price"
|
||||
await sensor3.async_update_ha_state()
|
||||
|
||||
sensor4 = DemoSensor("Wind Direction", 25, None, "°", None)
|
||||
sensor4.hass = hass
|
||||
sensor4.entity_id = "sensor.wind_direction"
|
||||
await sensor4.async_update_ha_state()
|
||||
|
||||
return await hass_client()
|
||||
|
||||
|
||||
|
@ -103,3 +108,9 @@ def test_view(prometheus_client): # pylint: disable=redefined-outer-name
|
|||
'entity="sensor.electricity_price",'
|
||||
'friendly_name="Electricity price"} 0.123' in body
|
||||
)
|
||||
|
||||
assert (
|
||||
'sensor_unit_u0xb0{domain="sensor",'
|
||||
'entity="sensor.wind_direction",'
|
||||
'friendly_name="Wind Direction"} 25.0' in body
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue