This is an automated email from the ASF dual-hosted git repository.
DomGarguilo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git
The following commit(s) were added to refs/heads/main by this push:
new a273a41e7d Add per-server metrics page (#6429)
a273a41e7d is described below
commit a273a41e7d917ce7ef42358ac951b87411bcbc28
Author: Dom G. <[email protected]>
AuthorDate: Tue Jun 23 11:09:21 2026 -0400
Add per-server metrics page (#6429)
* Add per-server metrics page
* Require server identity in monitor detail route
---
.../apache/accumulo/monitor/next/Endpoints.java | 31 +++
.../accumulo/monitor/next/SystemInformation.java | 14 +-
.../monitor/next/views/TableDataFactory.java | 60 ++++-
.../org/apache/accumulo/monitor/view/WebViews.java | 32 +++
.../accumulo/monitor/resources/js/compactions.js | 2 +-
.../accumulo/monitor/resources/js/functions.js | 32 +++
.../apache/accumulo/monitor/resources/js/server.js | 291 +++------------------
.../monitor/resources/js/server_process_common.js | 11 +-
.../apache/accumulo/monitor/templates/server.ftl | 103 ++------
9 files changed, 235 insertions(+), 341 deletions(-)
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
index 68d4d5627d..c72a55cc04 100644
---
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
@@ -50,6 +50,7 @@ import org.apache.accumulo.core.Constants;
import org.apache.accumulo.core.client.admin.TabletInformation;
import org.apache.accumulo.core.client.admin.servers.ServerId;
import org.apache.accumulo.core.data.TableId;
+import org.apache.accumulo.core.process.thrift.MetricResponse;
import org.apache.accumulo.core.util.compaction.RunningCompactionInfo;
import org.apache.accumulo.monitor.Monitor;
import org.apache.accumulo.monitor.next.InformationFetcher.InstanceSummary;
@@ -185,6 +186,36 @@ public class Endpoints {
return view;
}
+ @GET
+ @Path("servers/detail/{type}/{resourceGroup}/{server}")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Description("Returns a UI-ready metric table for one server process")
+ public TableData getServerDetail(@PathParam("type") ServerId.Type type,
+ @PathParam("resourceGroup") String resourceGroup, @PathParam("server")
String server) {
+ if (type == null) {
+ throw new BadRequestException("A 'type' parameter is required");
+ }
+ if (resourceGroup == null || resourceGroup.isBlank()) {
+ throw new BadRequestException("A 'resourceGroup' parameter is required");
+ }
+ if (server == null || server.isBlank()) {
+ throw new BadRequestException("A 'server' parameter is required");
+ }
+
+ MetricResponse response;
+ try {
+ response = monitor.getInformationFetcher().getSummaryForEndpoint()
+ .getServerMetricResponse(type, resourceGroup, server);
+ } catch (IllegalArgumentException e) {
+ throw new BadRequestException("Invalid server metrics parameters", e);
+ }
+ if (response == null) {
+ throw new NotFoundException("Server " + type.name() + " " + server + "
in resource group "
+ + resourceGroup + " not found");
+ }
+ return TableDataFactory.forServer(response);
+ }
+
@GET
@Path("compactions/running")
@Produces(MediaType.APPLICATION_JSON)
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
index d786fdcf96..70dfe828cf 100644
---
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
@@ -889,7 +889,9 @@ public class SystemInformation {
if (!qm.isEmpty()) {
// Create a ServersView object from the MetricResponse for each queue
- return TableDataFactory.forColumns(qm.keySet(), qm, cols);
+ TableData tableData = TableDataFactory.forColumns(qm.keySet(), qm, cols);
+ tableData.data().forEach(row ->
row.put(TableDataFactory.LINK_RG_COL_KEY, ""));
+ return tableData;
}
return TableDataFactory.forColumns(Set.of(), Map.of(), cols);
}
@@ -1639,6 +1641,16 @@ public class SystemInformation {
return null;
}
+ public MetricResponse getServerMetricResponse(ServerId.Type type, String
resourceGroup,
+ String serverAddress) {
+ HostAndPort address = HostAndPort.fromString(serverAddress);
+ if (!address.hasPort()) {
+ throw new IllegalArgumentException("Server address must be host:port");
+ }
+ return allMetrics.getIfPresent(new ServerId(type,
ResourceGroupId.of(resourceGroup),
+ address.getHost(), address.getPort()));
+ }
+
public static Number getMetricValue(FMetric metric) {
if (metric.ivalue() != 0) {
return metric.ivalue();
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/views/TableDataFactory.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/views/TableDataFactory.java
index a16cb13063..859bca36cf 100644
---
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/views/TableDataFactory.java
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/views/TableDataFactory.java
@@ -39,6 +39,7 @@ import org.apache.accumulo.core.metrics.flatbuffers.FMetric;
import org.apache.accumulo.core.metrics.flatbuffers.FTag;
import org.apache.accumulo.core.process.thrift.MetricResponse;
import org.apache.accumulo.core.util.threads.ThreadPoolNames;
+import org.apache.accumulo.monitor.next.SystemInformation;
import org.apache.accumulo.monitor.next.views.TableData.Column;
import org.apache.accumulo.server.metrics.MetricResponseWrapper;
@@ -53,14 +54,30 @@ public class TableDataFactory {
public static final String RG_COL_KEY = "resourceGroup";
public static final String ADDR_COL_KEY = "serverAddress";
+ public static final String TYPE_COL_KEY = "serverType";
+ public static final String LINK_RG_COL_KEY = "serverLinkResourceGroup";
public static final String TIME_COL_KEY = "lastContact";
+ public static final String METRIC_NAME_COL_KEY = "metricName";
+ public static final String METRIC_VALUE_COL_KEY = "metricValue";
+ public static final String METRIC_TYPE_COL_KEY = "metricType";
+ public static final String METRIC_TAGS_COL_KEY = "metricTags";
+ public static final String METRIC_DESCRIPTION_COL_KEY = "metricDescription";
+ public static final String METRIC_SECTION_COL_KEY = "metricSection";
public static final Column LAST_CONTACT_COLUMN = new Column(TIME_COL_KEY,
"Last Contact",
"Time since the server last responded to the monitor", "duration");
public static final Column RG_COLUMN =
new Column(RG_COL_KEY, "Resource Group", "Resource Group", "");
public static final Column ADDR_COLUMN =
- new Column(ADDR_COL_KEY, "Server Address", "Server address", "");
+ new Column(ADDR_COL_KEY, "Server Address", "Server address",
"server-address");
+
+ private static final List<Column> SERVER_DETAIL_COLUMNS =
+ List.of(new Column(METRIC_NAME_COL_KEY, "Metric", "Metric name", ""),
+ new Column(METRIC_VALUE_COL_KEY, "Value", "Metric value", ""),
+ new Column(METRIC_TYPE_COL_KEY, "Type", "Metric type", ""),
+ new Column(METRIC_TAGS_COL_KEY, "Tags", "Metric tags", ""),
+ new Column(METRIC_SECTION_COL_KEY, "Section", "Metric documentation
section", ""),
+ new Column(METRIC_DESCRIPTION_COL_KEY, "Description", "Metric
description", ""));
/**
* Server-process table identifiers accepted by /rest-v2/servers/view. These
enum names are used
@@ -146,6 +163,8 @@ public class TableDataFactory {
List<Map<String,Object>> data = new ArrayList<>();
serverMetricRows.forEach(serverMetricRow -> {
Map<String,Object> row = new LinkedHashMap<>();
+ row.put(TYPE_COL_KEY, serverMetricRow.server().getType().name());
+ row.put(LINK_RG_COL_KEY,
serverMetricRow.server().getResourceGroup().canonical());
for (ColumnFactory colf : requestedColumns) {
row.put(colf.getColumn().key(),
colf.getRowData(serverMetricRow.server(),
serverMetricRow.response(), serverMetricRow.metrics()));
@@ -157,6 +176,45 @@ public class TableDataFactory {
}
+ public static TableData forServer(final MetricResponse metricResponse) {
+ if (!hasMetricData(metricResponse)) {
+ return new TableData(SERVER_DETAIL_COLUMNS, List.of());
+ }
+
+ List<Map<String,Object>> data = new ArrayList<>();
+ FMetric metric = new FMetric();
+ for (var binary : metricResponse.getMetrics()) {
+ metric = FMetric.getRootAsFMetric(binary, metric);
+ Map<String,Object> row = new LinkedHashMap<>();
+ row.put(METRIC_NAME_COL_KEY, metric.name());
+ row.put(METRIC_VALUE_COL_KEY, SystemInformation.getMetricValue(metric));
+ row.put(METRIC_TYPE_COL_KEY, metric.type());
+ row.put(METRIC_TAGS_COL_KEY, formatTags(metric));
+
+ try {
+ Metric metricDefinition = Metric.fromName(metric.name());
+ row.put(METRIC_SECTION_COL_KEY,
metricDefinition.getDocSection().getSectionTitle());
+ row.put(METRIC_DESCRIPTION_COL_KEY, metricDefinition.getDescription());
+ } catch (IllegalArgumentException e) {
+ row.put(METRIC_SECTION_COL_KEY, "");
+ row.put(METRIC_DESCRIPTION_COL_KEY, "");
+ }
+ data.add(row);
+ }
+
+ return new TableData(SERVER_DETAIL_COLUMNS, data);
+ }
+
+ private static String formatTags(FMetric metric) {
+ List<String> tags = new ArrayList<>();
+ FTag tag = new FTag();
+ for (int i = 0; i < metric.tagsLength(); i++) {
+ tag = metric.tags(tag, i);
+ tags.add(tag.key() + "=" + tag.value());
+ }
+ return String.join(", ", tags);
+ }
+
public static TableData forTable(final TableName table, final Set<ServerId>
servers,
final Map<ServerId,MetricResponse> allMetrics) {
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
index 55e1e90efa..2dafa85d67 100644
---
a/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
@@ -77,6 +77,10 @@ public class WebViews {
*/
private static final String TSERVER_PARAM_KEY = "s";
+ private static final String SERVER_TYPE_PARAM_KEY = "type";
+
+ private static final String RESOURCE_GROUP_PARAM_KEY = "resourceGroup";
+
private static final Logger log = LoggerFactory.getLogger(WebViews.class);
@Inject
@@ -195,9 +199,12 @@ public class WebViews {
Map<String,Object> model = getModel();
model.put("title", "Tablet Server Status");
if (server != null && !server.isBlank()) {
+ model.put("title", "Server Metrics");
model.put("template", "server.ftl");
model.put("js", "server.js");
model.put("server", server);
+ model.put("serverType", "TABLET_SERVER");
+ model.put("resourceGroup", "");
return model;
}
model.put("template", "tservers.ftl");
@@ -205,6 +212,31 @@ public class WebViews {
return model;
}
+ /**
+ * Returns the server metrics template
+ *
+ * @param serverType Accumulo server process type
+ * @param resourceGroup server resource group
+ * @param server server address
+ * @return server metrics model
+ */
+ @GET
+ @Path("server")
+ @Template(name = "/default.ftl")
+ public Map<String,Object>
getServerMetrics(@QueryParam(SERVER_TYPE_PARAM_KEY) String serverType,
+ @QueryParam(RESOURCE_GROUP_PARAM_KEY) String resourceGroup,
+ @QueryParam(TSERVER_PARAM_KEY) @Pattern(regexp = HOSTNAME_PORT_REGEX)
String server) {
+
+ Map<String,Object> model = getModel();
+ model.put("title", "Server Metrics");
+ model.put("template", "server.ftl");
+ model.put("js", "server.js");
+ model.put("server", server);
+ model.put("serverType", serverType);
+ model.put("resourceGroup", resourceGroup == null ? "" : resourceGroup);
+ return model;
+ }
+
/**
* Returns the scan servers template
*
diff --git
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/compactions.js
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/compactions.js
index 37ec085371..62d1a45bcf 100644
---
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/compactions.js
+++
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/compactions.js
@@ -51,7 +51,7 @@ $(function () {
"type": "html",
"render": function (data, type, row, meta) {
if (type === 'display') {
- data = '<a class="link-body-emphasis" href="tservers?s=' +
row.server + '">' + row.server + '</a>';
+ data = renderServerMetricsLink('COMPACTOR', '', row.server);
}
return data;
}
diff --git
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
index 597144a211..bbe619a5c0 100644
---
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
+++
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
@@ -44,6 +44,7 @@ const ALERT_COUNTS = 'alertCounts';
const RECOVERY = 'recovery';
const INSTANCE_OVERVIEW = 'instanceOverview';
const SCANS = 'scans';
+const SERVER_METRICS = 'serverMetrics';
const LAST_UPDATE = 'lastUpdate';
var STATUS_REQUEST = null;
@@ -311,6 +312,31 @@ function sanitize(url) {
return url.split('+').join('%2B');
}
+function escapeHtml(value) {
+ if (value === null || value === undefined) {
+ return '';
+ }
+ return $('<div>').text(value).html();
+}
+
+function serverMetricsHref(serverType, resourceGroup, serverAddress) {
+ var href = 'server?type=' + encodeURIComponent(serverType) +
+ '&s=' + encodeURIComponent(serverAddress);
+ if (resourceGroup !== null && resourceGroup !== undefined && resourceGroup
!== '') {
+ href += '&resourceGroup=' + encodeURIComponent(resourceGroup);
+ }
+ return href;
+}
+
+function renderServerMetricsLink(serverType, resourceGroup, serverAddress) {
+ if (!serverType || !resourceGroup || !serverAddress) {
+ return escapeHtml(serverAddress);
+ }
+ return '<a class="link-body-emphasis" href="' +
+ serverMetricsHref(serverType, resourceGroup, serverAddress) + '">' +
+ escapeHtml(serverAddress) + '</a>';
+}
+
/**
* Creates a string with the value to sort and the value to display
* Options are 0 = firstcell left, 1 = right, 2 = center, 3 = left
@@ -606,6 +632,12 @@ function getServerProcessView(table, storageKey) {
return getJSONForTable(url, storageKey);
}
+function getServerMetrics(serverType, resourceGroup, serverAddress) {
+ var url = REST_V2_PREFIX + '/servers/detail/' +
encodeURIComponent(serverType) + '/' +
+ encodeURIComponent(resourceGroup) + '/' +
encodeURIComponent(serverAddress);
+ return getJSONForTable(url, SERVER_METRICS);
+}
+
function getCompactorsView() {
return getServerProcessView('COMPACTORS', COMPACTOR_SERVER_PROCESS_VIEW);
}
diff --git
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/server.js
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/server.js
index f995a2fc85..2d17d13712 100644
---
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/server.js
+++
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/server.js
@@ -18,264 +18,45 @@
*/
"use strict";
-var detailTable, historyTable, currentTable, resultsTable;
-
-/**
- * Makes the REST calls, generates the tables with the new information
- */
-function refreshServer() {
- ajaxReloadTable(detailTable);
- ajaxReloadTable(historyTable);
- ajaxReloadTable(currentTable);
- ajaxReloadTable(resultsTable);
+const htmlServerMetricsTable = '#serverMetrics';
+const htmlServerMetricsBanner = '#serverMetricsStatusBanner';
+const htmlServerMetricsBannerMessage = '#server-metrics-banner-message';
+
+function refreshServerMetrics() {
+ if (!serverMetricsType || !serverMetricsResourceGroup ||
!serverMetricsAddress) {
+ sessionStorage[SERVER_METRICS] = JSON.stringify({
+ data: [],
+ columns: []
+ });
+ refreshTable(htmlServerMetricsTable, SERVER_METRICS);
+ $(htmlServerMetricsBannerMessage).text('ERROR: missing server metrics
parameters.');
+ $(htmlServerMetricsBanner).show();
+ return;
+ }
+
+ getServerMetrics(serverMetricsType, serverMetricsResourceGroup,
serverMetricsAddress).then(
+ function () {
+ refreshTable(htmlServerMetricsTable, SERVER_METRICS);
+ $(htmlServerMetricsBanner).hide();
+ }).fail(function () {
+ sessionStorage[SERVER_METRICS] = JSON.stringify({
+ data: [],
+ columns: []
+ });
+ refreshTable(htmlServerMetricsTable, SERVER_METRICS);
+ $(htmlServerMetricsBannerMessage).text('ERROR: unable to retrieve server
metrics.');
+ $(htmlServerMetricsBanner).show();
+ });
}
-/**
- * Used to redraw the page
- */
function refresh() {
- refreshServer();
+ refreshServerMetrics();
}
-/**
- * Initializes all of the DataTables for the given hostname
- *
- * @param {String} serv the tserver hostname
- */
-function initServerTables(serv) {
-
- const url = contextPath + 'rest/tservers/' + serv;
- console.debug('REST url used to fetch data for server.js DataTables: ' +
url);
-
- // Create a table for details on the current server
- detailTable = $('#tServerDetail').DataTable({
- "ajax": {
- "url": url,
- "dataSrc": function (data) {
- // the data needs to be in an array to work with DataTables
- var arr = [];
- if (data.details === undefined) {
- console.warn('the value of "details" is undefined');
- } else {
- arr = [data.details];
- }
-
- return arr;
- }
- },
- "stateSave": true,
- "searching": false,
- "paging": false,
- "info": false,
- "columnDefs": [{
- "targets": "big-num",
- "render": function (data, type) {
- if (type === 'display') {
- data = bigNumberForQuantity(data);
- }
- return data;
- }
- }],
- "columns": [{
- "data": "hostedTablets"
- },
- {
- "data": "entries"
- },
- {
- "data": "minors"
- }
- ]
+$(function () {
+ sessionStorage[SERVER_METRICS] = JSON.stringify({
+ data: [],
+ columns: []
});
-
- // Create a table for all time tablet operations
- historyTable = $('#opHistoryDetails').DataTable({
- "ajax": {
- "url": url,
- "dataSrc": "allTimeTabletResults"
- },
- "stateSave": true,
- "searching": false,
- "paging": false,
- "info": false,
- "columnDefs": [{
- "targets": "big-num",
- "render": function (data, type) {
- if (type === 'display') {
- data = bigNumberForQuantity(data);
- }
- return data;
- }
- },
- {
- "targets": "duration",
- "render": function (data, type) {
- if (type === 'display') {
- if (data === null) {
- data = '—';
- } else {
- data = timeDuration(data * 1000.0);
- }
- }
- return data;
- }
- }
- ],
- "columns": [{
- "data": "operation"
- },
- {
- "data": "success"
- },
- {
- "data": "failure"
- },
- {
- "data": "avgQueueTime"
- },
- {
- "data": "queueStdDev"
- },
- {
- "data": "avgTime"
- },
- {
- "data": "stdDev"
- },
- {
- "data": "timeSpent" // placeholder for percent column, replaced below
- }
- ],
- // calculate and fill percent column each time table is drawn
- "drawCallback": function () {
- var totalTime = 0;
- var api = this.api();
-
- // calculate total duration of all tablet operations
- api.rows().every(function () {
- totalTime += this.data().timeSpent;
- });
-
- const percentColumnIndex = 7;
- api.rows().every(function (rowIdx) {
- // calculate the percentage of time taken for each row (each tablet op)
- var currentPercent = (this.data().timeSpent / totalTime) * 100;
- currentPercent = Math.round(currentPercent);
- if (isNaN(currentPercent)) {
- currentPercent = 0;
- }
- // insert the percentage bar into the current row and percent column
- var newData = `<div class="progress"><div class="progress-bar"
role="progressbar" style="min-width: 2em;
width:${currentPercent}%;">${currentPercent}%</div></div>`
- api.cell(rowIdx, percentColumnIndex).data(newData);
- });
- }
- });
-
- // Create a table for tablet operations on the current server
- currentTable = $('#currentTabletOps').DataTable({
- "ajax": {
- "url": url,
- "dataSrc": function (data) {
- // the data needs to be in an array to work with DataTables
- var arr = [];
- if (data.currentTabletOperationResults === undefined) {
- console.warn('the value of "currentTabletOperationResults" is
undefined');
- } else {
- arr = [data.currentTabletOperationResults];
- }
-
- return arr;
- }
- },
- "stateSave": true,
- "searching": false,
- "paging": false,
- "info": false,
- "columnDefs": [{
- "targets": "duration",
- "render": function (data, type) {
- if (type === 'display') {
- data = timeDuration(data * 1000.0);
- }
- return data;
- }
- }],
- "columns": [{
- "data": "currentMinorAvg"
- },
- {
- "data": "currentMinorStdDev"
- }
- ]
- });
-
- // Create a table for detailed tablet operations
- resultsTable = $('#perTabletResults').DataTable({
- "ajax": {
- "url": url,
- "dataSrc": "currentOperations"
- },
- "stateSave": true,
- "dom": 't<"align-left"l>p',
- "columnDefs": [{
- "targets": "big-num",
- "render": function (data, type) {
- if (type === 'display') {
- data = bigNumberForQuantity(data);
- }
- return data;
- }
- },
- {
- "targets": "duration",
- "render": function (data, type) {
- if (type === 'display') {
- data = timeDuration(data);
- }
- return data;
- }
- }
- ],
- "columns": [{
- "data": "name",
- "type": "html",
- "render": function (data, type, row) {
- if (type === 'display') {
- data = `<a class="link-body-emphasis"
href="tables/${row.tableID}">${data}</a>`;
- }
- return data;
- }
- },
- {
- "data": "tablet",
- "type": "html",
- "render": function (data, type) {
- if (type === 'display') {
- data = `<code>${data}</code>`;
- }
- return data;
- }
- },
- {
- "data": "entries"
- },
- {
- "data": "ingest"
- },
- {
- "data": "query"
- },
- {
- "data": "minorAvg"
- },
- {
- "data": "minorStdDev"
- },
- {
- "data": "minorAvgES"
- }
- ]
- });
-
- refreshServer();
-}
+ refreshServerMetrics();
+});
diff --git
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/server_process_common.js
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/server_process_common.js
index bdb9361145..2952dfed5d 100644
---
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/server_process_common.js
+++
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/server_process_common.js
@@ -257,7 +257,7 @@ function createDataTable(table, storageKey) {
"text": '<i class="bi bi-gear"></i>',
"titleAttr": 'Columns'
}],
- "dom": '<"row"<"col-sm-12 col-md-4"l><"col-sm-12 col-md-6"f><"col-sm-12
col-md-2"B>>' +
+ "dom": '<"row"<"col-sm-12 col-md-4"l><"col-sm-12 col-md-6
text-md-end"f><"col-sm-12 col-md-2 text-md-end"B>>' +
'<"row dt-row"<"col-sm-12"rt>>' +
'<"row"<"col-sm-12 col-md-5"i><"col-sm-12 col-md-7"p>>',
"stateSave": true,
@@ -368,6 +368,15 @@ function createDataTable(table, storageKey) {
{
"targets": "memory-state",
"render": renderMemoryState
+ },
+ {
+ "targets": "server-address",
+ "render": function (data, type, row) {
+ if (type === 'display') {
+ return renderServerMetricsLink(row.serverType,
row.serverLinkResourceGroup, data);
+ }
+ return data;
+ }
}
],
"columns": getDataTableCols(storageKey)
diff --git
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/server.ftl
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/server.ftl
index b412b564b3..8204af61ba 100644
---
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/server.ftl
+++
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/server.ftl
@@ -18,86 +18,25 @@
under the License.
-->
- <script>
- $(function () {
- // initialize DataTables
- initServerTables('${server}');
- });
- </script>
- <div class="row">
- <div class="col-xs-12">
- <h3>${title}</h3>
- </div>
- </div>
- <div class="row">
- <div class="col-xs-12">
- <table id="tServerDetail" class="table caption-top table-bordered
table-striped table-condensed">
- <caption><span class="table-caption">${server}</span></caption>
- <thead>
- <tr>
- <th class="big-num">Hosted Tablets </th>
- <th class="big-num">Entries </th>
- <th class="big-num">Minor Compacting </th>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
- </div>
- </div>
- <br />
- <div class="row">
- <div class="col-xs-12">
- <table id="opHistoryDetails" class="table caption-top table-bordered
table-striped table-condensed">
- <caption><span
class="table-caption">All-Time Tablet Operation Results</span></caption>
- <thead>
- <tr>
- <th>Operation </th>
- <th class="big-num">Success </th>
- <th class="big-num">Failure </th>
- <th class="duration">Average<br />Queue Time </th>
- <th class="duration">Std. Dev.<br
/>Queue Time </th>
- <th class="duration">Average<br />Time </th>
- <th class="duration">Std. Dev.<br />Time </th>
- <th>Percentage Time Spent </th>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
- </div>
- </div>
- <br />
- <div class="row">
- <div class="col-xs-12">
- <table id="currentTabletOps" class="table caption-top table-bordered
table-striped table-condensed">
- <caption><span
class="table-caption">Current Tablet Operation Results</span></caption>
- <thead>
- <tr>
- <th class="duration">Minor Average </th>
- <th class="duration">Minor Std Dev </th>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
- </div>
- </div>
- <br />
- <div class="row">
- <div class="col-xs-12">
- <table id="perTabletResults" class="table caption-top table-bordered
table-striped table-condensed">
- <caption><span class="table-caption">Detailed Tablet
Operations</span></caption>
- <thead>
- <tr>
- <th>Table </th>
- <th title="Run 'getsplits -v' in the Accumulo Shell to
associate the encoded tablets with their actual splits.">Tablet </th>
- <th class="big-num">Entries </th>
- <th class="big-num">Ingest </th>
- <th class="big-num">Query </th>
- <th class="duration">Minor Avg </th>
- <th class="duration">Minor Std Dev </th>
- <th class="big-num">Minor Avg e/s </th>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
- </div>
+ <script>
+ var serverMetricsType = '${(serverType!)?js_string}';
+ var serverMetricsResourceGroup = '${(resourceGroup!)?js_string}';
+ var serverMetricsAddress = '${(server!)?js_string}';
+ </script>
+ <div id="serverMetricsStatusBanner" style="display: none;">
+ <div id="server-metrics-banner-message" class="alert alert-danger"
role="alert"></div>
+ </div>
+ <div class="row">
+ <div class="col-xs-12">
+ <span class="table-caption">Server Metrics</span>
+ <br />
+ <span class="table-subcaption">
+ ${(serverType!)?html} ${(server!)?html}<#if
resourceGroup?has_content> (${resourceGroup?html})</#if>
+ </span>
+ <br />
+ <br />
+ <table id="serverMetrics" class="table caption-top table-bordered
table-striped table-condensed">
+ <#include "table_loading.ftl" >
+ </table>
</div>
+ </div>