Add metrics descriptions

Added inventories of known metrics on per-source basis to supply
along with the metric name and value to Prometheus.

Change-Id: I6ea466a332b220902071bb24e2eb1fd9c23f5aaf
This commit is contained in:
Ilya Etingof 2019-09-09 15:35:47 +02:00
parent 9959cf36bc
commit 0ded99ebc9
7 changed files with 159 additions and 8 deletions

View File

@ -0,0 +1,39 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import logging
import os
import pkg_resources
DESCRIPTIONS = {}
LOG = logging.getLogger(__name__)
def get_metric_description(source, metric_name):
if source not in DESCRIPTIONS:
try:
json_file = pkg_resources.resource_filename(
__name__, os.path.join(
'metrics_information', source + '.json'))
with open(json_file) as fl:
DESCRIPTIONS[source] = json.load(fl)
except Exception as exc:
LOG.warning(
'Failed to load metrics descriptions '
'for metrics source %s: %s', source, exc)
return DESCRIPTIONS.get(source, {}).get(metric_name, '')

View File

@ -11,8 +11,11 @@
# under the License. # under the License.
from datetime import datetime from datetime import datetime
from prometheus_client import Gauge from prometheus_client import Gauge
from ironic_prometheus_exporter.parsers import descriptions
def timestamp_registry(node_information, ipmi_metric_registry): def timestamp_registry(node_information, ipmi_metric_registry):
metric = 'baremetal_last_payload_timestamp_seconds' metric = 'baremetal_last_payload_timestamp_seconds'
@ -23,6 +26,11 @@ def timestamp_registry(node_information, ipmi_metric_registry):
dt_timestamp = datetime.strptime(node_information['timestamp'], dt_timestamp = datetime.strptime(node_information['timestamp'],
'%Y-%m-%dT%H:%M:%S.%f') '%Y-%m-%dT%H:%M:%S.%f')
value = int((dt_timestamp - dt_1970).total_seconds()) value = int((dt_timestamp - dt_1970).total_seconds())
g = Gauge(metric, 'Timestamp of the last received payload',
labelnames=labels.keys(), registry=ipmi_metric_registry) desc = descriptions.get_metric_description('header', metric)
g = Gauge(
metric, desc, labelnames=labels,
registry=ipmi_metric_registry)
g.labels(**labels).set(value) g.labels(**labels).set(value)

View File

@ -17,6 +17,9 @@ import re
from prometheus_client import Gauge from prometheus_client import Gauge
from ironic_prometheus_exporter.parsers import descriptions
# NOTE (iurygregory): most of the sensor readings come in the ipmi format # NOTE (iurygregory): most of the sensor readings come in the ipmi format
# each type of sensor consider a different range of values that aren't integers # each type of sensor consider a different range of values that aren't integers
# (eg: 0h, 2eh), 0h will be published as 0 and the other values as 1, this way # (eg: 0h, 2eh), 0h will be published as 0 and the other values as 1, this way
@ -220,7 +223,8 @@ def prometheus_format(category_info, ipmi_metric_registry, available_metrics):
values = extract_values(entries, category_info) values = extract_values(entries, category_info)
if all(v is None for v in values.values()): if all(v is None for v in values.values()):
continue continue
g = Gauge(metric, get_metric_description(metric), desc = descriptions.get_metric_description('ipmi', metric)
g = Gauge(metric, desc,
labelnames=list(labels.get(entries[0])), labelnames=list(labels.get(entries[0])),
registry=ipmi_metric_registry) registry=ipmi_metric_registry)
for e in entries: for e in entries:
@ -240,7 +244,3 @@ def category_registry(node_message, ipmi_metric_registry):
available_metrics = metric_names(category_dict) available_metrics = metric_names(category_dict)
prometheus_format(category_dict, ipmi_metric_registry, prometheus_format(category_dict, ipmi_metric_registry,
available_metrics) available_metrics)
def get_metric_description(metric_name):
return IPMI_METRICS_DESCRIPTION.get(metric_name, '')

View File

@ -0,0 +1,4 @@
{
"baremetal_last_payload_timestamp_seconds":
"Timestamp of the last received payload"
}

View File

@ -0,0 +1,54 @@
{
"baremetal_power_status":
"Power supply unit health status (0 - OK, 1 - failure)",
"baremetal_temp_room_celsius":
"Room temperature expressed in Celsius",
"baremetal_temp_intake_celsius":
"Intake air temperature expressed in Celsius",
"baremetal_temp_exhaust_celsius":
"Exhaust air temperature expressed in Celsius",
"baremetal_temp_front_celsius":
"Front chassis temperature expressed in Celsius",
"baremetal_temp_back_celsius":
"Back chassis temperature expressed in Celsius",
"baremetal_temp_upper_celsius":
"Upper chassis temperature expressed in Celsius",
"baremetal_temp_lower_celsius":
"Lower chassis temperature expressed in Celsius",
"baremetal_temp_cpu_celsius":
"CPU temperature expressed in Celsius",
"baremetal_temp_gpu_celsius":
"GPU temperature expressed in Celsius",
"baremetal_temp_backplane_celsius":
"Backplane temperature expressed in Celsius",
"baremetal_temp_systemboard_celsius":
"System Board temperature expressed in Celsius",
"baremetal_temp_powersupply_celsius":
"Power Supply temperature expressed in Celsius",
"baremetal_temp_voltageregulator_celsius":
"Voltage Regulator temperature expressed in Celsius",
"baremetal_temp_storagedevice_celsius":
"Storage Device temperature expressed in Celsius",
"baremetal_temp_networkingdevice_celsius":
"Networking Device temperature expressed in Celsius",
"baremetal_temp_computebay_celsius":
"Compute Bay temperature expressed in Celsius",
"baremetal_temp_storagebay_celsius":
"Storage Bay temperature expressed in Celsius",
"baremetal_temp_networkbay_celsius":
"Network Bay temperature expressed in Celsius",
"baremetal_temp_expansionbay_celsius":
"Expansion Bay temperature expressed in Celsius",
"baremetal_temp_powersupplybay_celsius":
"Power Supply Bay temperature expressed in Celsius",
"baremetal_temp_memory_celsius":
"Memory unit temperature expressed in Celsius",
"baremetal_temp_chassis_celsius":
"Chassis temperature expressed in Celsius",
"baremetal_temp_fan_celsius":
"Cooling fan temperature expressed in Celsius",
"baremetal_fan_status":
"Cooling fan health status (0 - OK, 1 - failure)",
"baremetal_drive_status":
"Storage drive health status (0 - OK, 1 - failure)"
}

View File

@ -15,6 +15,8 @@ import logging
from prometheus_client import Gauge from prometheus_client import Gauge
from ironic_prometheus_exporter.parsers import descriptions
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -250,7 +252,9 @@ def category_registry(node_message, metrics_registry):
for value, labels in details: for value, labels in details:
gauge = Gauge(metric, '', labelnames=labels, desc = descriptions.get_metric_description('redfish', metric)
gauge = Gauge(metric, desc, labelnames=labels,
registry=metrics_registry) registry=metrics_registry)
gauge.labels(**labels).set(value) gauge.labels(**labels).set(value)

View File

@ -0,0 +1,42 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from ironic_prometheus_exporter.parsers import descriptions
from oslo_messaging.tests import utils as test_utils
class TestMetricsDescriptions(test_utils.BaseTestCase):
def test_good_source_good_metrics(self):
desc = descriptions.get_metric_description(
'header', 'baremetal_last_payload_timestamp_seconds')
expected = 'Timestamp of the last received payload'
self.assertEqual(expected, desc)
def test_good_source_bad_metrics(self):
desc = descriptions.get_metric_description(
'header', 'bad_metrics')
expected = ''
self.assertEqual(expected, desc)
def test_bad_source_bad_metrics(self):
desc = descriptions.get_metric_description(
'bad_source', 'bad_metrics')
expected = ''
self.assertEqual(expected, desc)