diff --git a/src/pybind/mgr/dashboard/module.py b/src/pybind/mgr/dashboard/module.py
index de9b889a2ee..257abfed05c 100644
--- a/src/pybind/mgr/dashboard/module.py
+++ b/src/pybind/mgr/dashboard/module.py
@@ -776,6 +776,7 @@ class Module(MgrModule):
mon_status = global_instance().get_sync_object(MonStatus).data
for mon in mon_status["monmap"]["mons"]:
mon["stats"] = {}
+ mon["url_perf"] = "/perf_counters/mon/" + mon["name"]
for counter in counters:
data = global_instance().get_counter("mon", mon["name"], counter)
if data is not None:
@@ -803,6 +804,43 @@ class Module(MgrModule):
def servers_data(self):
return self._servers()
+ @cherrypy.expose
+ def perf_counters(self, service_type, service_id):
+ template = env.get_template("perf_counters.html")
+ toplevel_data = self._toplevel_data()
+
+ return template.render(
+ url_prefix = global_instance().url_prefix,
+ ceph_version=global_instance().version,
+ path_info=cherrypy.request.path_info,
+ toplevel_data=json.dumps(toplevel_data, indent=2),
+ content_data=json.dumps(self.perf_counters_data(service_type, service_id), indent=2)
+ )
+
+ @cherrypy.expose
+ @cherrypy.tools.json_out()
+ def perf_counters_data(self, service_type, service_id):
+ schema = global_instance().get_perf_schema(service_type, str(service_id)).values()[0]
+ counters = []
+
+ for key, value in sorted(schema.items()):
+ counter = dict()
+ counter["name"] = str(key)
+ counter["description"] = value["description"]
+ if global_instance()._stattype_to_str(value["type"]) == 'counter':
+ counter["value"] = global_instance().get_rate(service_type, service_id, key)
+ counter["unit"] = "/s"
+ else:
+ counter["value"] = global_instance().get_latest(service_type, service_id, key)
+ counter["unit"] = ""
+ counters.append(counter)
+
+ return {
+ 'service_type': service_type,
+ 'service_id': service_id,
+ 'counters': counters,
+ }
+
def _health(self):
# Fuse osdmap with pg_summary to get description of pools
# including their PG states
@@ -1022,7 +1060,8 @@ class Module(MgrModule):
return {
"osd": osd,
"osd_metadata": osd_metadata,
- "osd_histogram": histogram
+ "osd_histogram": histogram,
+ "url_perf": "/perf_counters/osd/" + str(osd_id)
}
@cherrypy.expose
@@ -1196,6 +1235,7 @@ class Module(MgrModule):
return {
"rgw_id": rgw_id,
+ "url_perf": "/perf_counters/rgw/" + str(rgw_id),
"rgw_metadata": to_sorted_array(rgw_metadata),
"rgw_status": to_sorted_array(rgw_status),
}
diff --git a/src/pybind/mgr/dashboard/monitors.html b/src/pybind/mgr/dashboard/monitors.html
index 40a26551d4c..60b34ad62c5 100644
--- a/src/pybind/mgr/dashboard/monitors.html
+++ b/src/pybind/mgr/dashboard/monitors.html
@@ -67,7 +67,7 @@
Open Sessions |
- {mon.name} |
+ {mon.name} |
{mon.rank} |
{mon.public_addr} |
{ mon.stats.num_sessions | sparkline_data } |
@@ -87,7 +87,7 @@
Public Addr |
- {mon.name} |
+ {mon.name} |
{mon.rank} |
{mon.public_addr} |
diff --git a/src/pybind/mgr/dashboard/osd_perf.html b/src/pybind/mgr/dashboard/osd_perf.html
index b13ad17e1fd..2c36613517f 100644
--- a/src/pybind/mgr/dashboard/osd_perf.html
+++ b/src/pybind/mgr/dashboard/osd_perf.html
@@ -104,11 +104,12 @@
post_load();
setTimeout(refresh, 3000);
});
- };
+ };
// Wait 1s to load irrespective of normal frequency,
// to promptly load our first delta
- setTimeout(refresh, 1000);
+ setTimeout(refresh, 1000);
+
});
@@ -116,11 +117,12 @@
-
+
@@ -150,7 +152,7 @@
|
{item.key} |
- {item.value} |
+ {item.value} |
diff --git a/src/pybind/mgr/dashboard/perf_counters.html b/src/pybind/mgr/dashboard/perf_counters.html
new file mode 100644
index 00000000000..40638b6b2d8
--- /dev/null
+++ b/src/pybind/mgr/dashboard/perf_counters.html
@@ -0,0 +1,58 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name |
+ Description |
+ Value |
+
+
+
+
+ {item.name} |
+ {item.description} |
+ {item.value | dimless} {item.unit} |
+
+
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/src/pybind/mgr/dashboard/rgw_detail.html b/src/pybind/mgr/dashboard/rgw_detail.html
index 986dc90da07..3f224ac4c59 100644
--- a/src/pybind/mgr/dashboard/rgw_detail.html
+++ b/src/pybind/mgr/dashboard/rgw_detail.html
@@ -20,6 +20,7 @@
diff --git a/src/pybind/mgr/dashboard/servers.html b/src/pybind/mgr/dashboard/servers.html
index 421d3389c35..dcecac40943 100644
--- a/src/pybind/mgr/dashboard/servers.html
+++ b/src/pybind/mgr/dashboard/servers.html
@@ -16,11 +16,12 @@
setTimeout(refresh, 5000);
rivets.formatters.service_list = function(services) {
- var strings = [];
+ var result = ""
$.each(services, function(i, svc) {
- strings.push(svc.type + "." + svc.id);
+ result += "" + svc.type + "." + svc.id + ", " ;
});
- return strings.join(", ");
+ result = result.slice(0, -2);
+ return result;
};
rivets.bind($("#content"), content_data);
@@ -55,8 +56,7 @@
{server.hostname}
|
-
- {server.services | service_list}
+ |
|
{server.ceph_version | short_version}
diff --git a/src/pybind/mgr/mgr_module.py b/src/pybind/mgr/mgr_module.py
index ea72df830a0..60cc2202847 100644
--- a/src/pybind/mgr/mgr_module.py
+++ b/src/pybind/mgr/mgr_module.py
@@ -308,6 +308,21 @@ class MgrModule(ceph_module.BaseMgrModule):
"""
return self._ceph_get(data_name)
+ def _stattype_to_str(self, stattype):
+
+ typeonly = stattype & self.PERFCOUNTER_TYPE_MASK
+ if typeonly == 0:
+ return 'gauge'
+ if typeonly == self.PERFCOUNTER_LONGRUNAVG:
+ # this lie matches the DaemonState decoding: only val, no counts
+ return 'counter'
+ if typeonly == self.PERFCOUNTER_COUNTER:
+ return 'counter'
+ if typeonly == self.PERFCOUNTER_HISTOGRAM:
+ return 'histogram'
+
+ return ''
+
def get_server(self, hostname):
"""
Called by the plugin to fetch metadata about a particular hostname from
diff --git a/src/pybind/mgr/prometheus/module.py b/src/pybind/mgr/prometheus/module.py
index 5396d685175..74aceeaad44 100644
--- a/src/pybind/mgr/prometheus/module.py
+++ b/src/pybind/mgr/prometheus/module.py
@@ -144,21 +144,6 @@ class Module(MgrModule):
self.schema = OrderedDict()
_global_instance['plugin'] = self
- def _stattype_to_str(self, stattype):
-
- typeonly = stattype & self.PERFCOUNTER_TYPE_MASK
- if typeonly == 0:
- return 'gauge'
- if typeonly == self.PERFCOUNTER_LONGRUNAVG:
- # this lie matches the DaemonState decoding: only val, no counts
- return 'counter'
- if typeonly == self.PERFCOUNTER_COUNTER:
- return 'counter'
- if typeonly == self.PERFCOUNTER_HISTOGRAM:
- return 'histogram'
-
- return ''
-
def _setup_static_metrics(self):
metrics = {}
metrics['health_status'] = Metric(
|