Browse Source

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
tags/1.0.0^0
Ilya Etingof 5 months ago
parent
commit
0ded99ebc9
7 changed files with 159 additions and 8 deletions
  1. +39
    -0
      ironic_prometheus_exporter/parsers/descriptions.py
  2. +10
    -2
      ironic_prometheus_exporter/parsers/header.py
  3. +5
    -5
      ironic_prometheus_exporter/parsers/ipmi.py
  4. +4
    -0
      ironic_prometheus_exporter/parsers/metrics_information/header.json
  5. +54
    -0
      ironic_prometheus_exporter/parsers/metrics_information/redfish.json
  6. +5
    -1
      ironic_prometheus_exporter/parsers/redfish.py
  7. +42
    -0
      ironic_prometheus_exporter/tests/test_descriptions.py

+ 39
- 0
ironic_prometheus_exporter/parsers/descriptions.py 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, '')

+ 10
- 2
ironic_prometheus_exporter/parsers/header.py View File

@@ -11,8 +11,11 @@
# under the License.

from datetime import datetime

from prometheus_client import Gauge

from ironic_prometheus_exporter.parsers import descriptions


def timestamp_registry(node_information, ipmi_metric_registry):
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'],
'%Y-%m-%dT%H:%M:%S.%f')
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)

+ 5
- 5
ironic_prometheus_exporter/parsers/ipmi.py View File

@@ -17,6 +17,9 @@ import re

from prometheus_client import Gauge

from ironic_prometheus_exporter.parsers import descriptions


# 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
# (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)
if all(v is None for v in values.values()):
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])),
registry=ipmi_metric_registry)
for e in entries:
@@ -240,7 +244,3 @@ def category_registry(node_message, ipmi_metric_registry):
available_metrics = metric_names(category_dict)
prometheus_format(category_dict, ipmi_metric_registry,
available_metrics)


def get_metric_description(metric_name):
return IPMI_METRICS_DESCRIPTION.get(metric_name, '')

+ 4
- 0
ironic_prometheus_exporter/parsers/metrics_information/header.json View File

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

+ 54
- 0
ironic_prometheus_exporter/parsers/metrics_information/redfish.json 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)"
}

+ 5
- 1
ironic_prometheus_exporter/parsers/redfish.py View File

@@ -15,6 +15,8 @@ import logging

from prometheus_client import Gauge

from ironic_prometheus_exporter.parsers import descriptions


LOG = logging.getLogger(__name__)

@@ -250,7 +252,9 @@ def category_registry(node_message, metrics_registry):

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)

gauge.labels(**labels).set(value)

+ 42
- 0
ironic_prometheus_exporter/tests/test_descriptions.py 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)

Loading…
Cancel
Save