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:
parent
9959cf36bc
commit
0ded99ebc9
|
@ -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, '')
|
|
@ -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)
|
||||||
|
|
|
@ -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, '')
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"baremetal_last_payload_timestamp_seconds":
|
||||||
|
"Timestamp of the last received payload"
|
||||||
|
}
|
|
@ -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)"
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
Loading…
Reference in New Issue