Skip to content

Commit 9fe0950

Browse files
Added new Messages page to Monitor (#6346)
This change adds a new Messages menu item that takes the users to a new Messages page. The new page will display items from the messages endpoint. The messages have a priority and category associated with them. The page has switches for enabling / disabling the inclusion of high and info priority messages and messages from different categories. Messages with a priority of critical are always shown. Closes #6185 Co-authored-by: Dom G. <domgarguilo@apache.org>
1 parent 1773204 commit 9fe0950

9 files changed

Lines changed: 417 additions & 30 deletions

File tree

server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@
2323
import java.lang.annotation.RetentionPolicy;
2424
import java.lang.annotation.Target;
2525
import java.lang.reflect.Method;
26+
import java.util.ArrayList;
2627
import java.util.Collection;
28+
import java.util.EnumSet;
2729
import java.util.List;
2830
import java.util.Map;
31+
import java.util.Map.Entry;
2932
import java.util.Set;
3033
import java.util.TreeMap;
3134
import java.util.stream.Collectors;
@@ -39,6 +42,7 @@
3942
import jakarta.ws.rs.Path;
4043
import jakarta.ws.rs.PathParam;
4144
import jakarta.ws.rs.Produces;
45+
import jakarta.ws.rs.QueryParam;
4246
import jakarta.ws.rs.core.Context;
4347
import jakarta.ws.rs.core.MediaType;
4448

@@ -53,6 +57,8 @@
5357
import org.apache.accumulo.monitor.next.InformationFetcher.InstanceSummary;
5458
import org.apache.accumulo.monitor.next.SystemInformation.CompactionGroupSummary;
5559
import org.apache.accumulo.monitor.next.SystemInformation.CompactionTableSummary;
60+
import org.apache.accumulo.monitor.next.SystemInformation.MessageCategory;
61+
import org.apache.accumulo.monitor.next.SystemInformation.MessagePriority;
5662
import org.apache.accumulo.monitor.next.SystemInformation.TableSummary;
5763
import org.apache.accumulo.monitor.next.SystemInformation.TimeOrderedRunningCompactionSet;
5864
import org.apache.accumulo.monitor.next.deployment.DeploymentOverview;
@@ -423,11 +429,62 @@ public DeploymentOverview getDeploymentOverview() {
423429
}
424430

425431
@GET
426-
@Path("suggestions")
432+
@Path("message/categories")
427433
@Produces(MediaType.APPLICATION_JSON)
428-
@Description("Returns a list of suggestions")
429-
public Set<String> getSuggestions() {
430-
return monitor.getInformationFetcher().getSummaryForEndpoint().getSuggestions();
434+
@Description("Returns a list of message categories")
435+
public Set<MessageCategory> getMessageCategories() {
436+
return EnumSet.allOf(SystemInformation.MessageCategory.class);
437+
}
438+
439+
public record Message(String priority, String category, String message) {
440+
}
441+
442+
@GET
443+
@Path("messages")
444+
@Produces(MediaType.APPLICATION_JSON)
445+
@Description("Returns a list of messages")
446+
public List<Message> getMessages(@QueryParam("high") boolean includeHigh,
447+
@QueryParam("info") boolean includeInfo, @QueryParam("category") List<String> categories) {
448+
List<Message> results = new ArrayList<>();
449+
450+
Map<MessagePriority,Map<MessageCategory,Set<String>>> messages =
451+
monitor.getInformationFetcher().getSummaryForEndpoint().getMessages();
452+
453+
for (Entry<MessagePriority,Map<MessageCategory,Set<String>>> e : messages.entrySet()) {
454+
MessagePriority prio = e.getKey();
455+
Map<MessageCategory,Set<String>> value = e.getValue();
456+
switch (prio) {
457+
case Critical:
458+
// Always include critical messages
459+
value.forEach((cat, msgs) -> {
460+
msgs.forEach(m -> results.add(new Message(prio.name(), cat.name(), m)));
461+
});
462+
break;
463+
case High:
464+
if (!includeHigh) {
465+
break;
466+
}
467+
value.forEach((cat, msgs) -> {
468+
if (categories.contains(cat.name())) {
469+
msgs.forEach(m -> results.add(new Message(prio.name(), cat.name(), m)));
470+
}
471+
});
472+
break;
473+
case Info:
474+
if (!includeInfo) {
475+
break;
476+
}
477+
value.forEach((cat, msgs) -> {
478+
if (categories.contains(cat.name())) {
479+
msgs.forEach(m -> results.add(new Message(prio.name(), cat.name(), m)));
480+
}
481+
});
482+
break;
483+
default:
484+
break;
485+
}
486+
}
487+
return results;
431488
}
432489

433490
@GET

server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020

2121
import static com.google.common.base.Suppliers.memoize;
2222
import static org.apache.accumulo.core.metrics.MetricsInfo.QUEUE_TAG_KEY;
23+
import static org.apache.accumulo.monitor.next.SystemInformation.MessageCategory.Configuration;
24+
import static org.apache.accumulo.monitor.next.SystemInformation.MessageCategory.Table;
25+
import static org.apache.accumulo.monitor.next.SystemInformation.MessagePriority.Critical;
26+
import static org.apache.accumulo.monitor.next.SystemInformation.MessagePriority.High;
27+
import static org.apache.accumulo.monitor.next.SystemInformation.MessagePriority.Info;
2328

2429
import java.nio.ByteBuffer;
2530
import java.time.Duration;
@@ -36,6 +41,7 @@
3641
import java.util.Objects;
3742
import java.util.Optional;
3843
import java.util.Set;
44+
import java.util.TreeSet;
3945
import java.util.concurrent.ConcurrentHashMap;
4046
import java.util.concurrent.ConcurrentSkipListSet;
4147
import java.util.concurrent.atomic.AtomicInteger;
@@ -365,6 +371,14 @@ public record CompactionTableSummary(String tableId, String tableName, long runn
365371
public record CompactionGroupSummary(String groupId, long running) {
366372
}
367373

374+
public enum MessagePriority {
375+
Critical, High, Info;
376+
}
377+
378+
public enum MessageCategory {
379+
Configuration, Table;
380+
}
381+
368382
private static final Logger LOG = LoggerFactory.getLogger(SystemInformation.class);
369383

370384
private final DistributionStatisticConfig DSC =
@@ -426,7 +440,8 @@ public record CompactionGroupSummary(String groupId, long running) {
426440
private final Map<ResourceGroupId,Map<ServerId.Type,ProcessSummary>> deployment =
427441
new ConcurrentHashMap<>();
428442

429-
private final Set<String> suggestions = new ConcurrentSkipListSet<>();
443+
private final Map<MessagePriority,Map<MessageCategory,Set<String>>> messages =
444+
new EnumMap<>(MessagePriority.class);
430445

431446
private final Set<String> configuredCompactionResourceGroups = ConcurrentHashMap.newKeySet();
432447

@@ -467,7 +482,7 @@ public void clear() {
467482
tables.clear();
468483
tablets.clear();
469484
deployment.clear();
470-
suggestions.clear();
485+
messages.clear();
471486
runningCompactionsPerGroup.clear();
472487
runningCompactionsPerTable.clear();
473488
tableCompactions.clear();
@@ -478,6 +493,11 @@ public void clear() {
478493
serverMetricsView.clear();
479494
}
480495

496+
private void addMessage(MessagePriority pri, MessageCategory cat, String msg) {
497+
messages.computeIfAbsent(pri, k -> new EnumMap<>(MessageCategory.class))
498+
.computeIfAbsent(cat, k -> new TreeSet<>()).add(msg);
499+
}
500+
481501
private void updateAggregates(final MetricResponse response,
482502
final Map<Id,CumulativeDistributionSummary> total,
483503
final Map<String,Map<Id,CumulativeDistributionSummary>> rg) {
@@ -657,7 +677,7 @@ public void processTabletInformation(TableId tableId, String tableName, TabletIn
657677
.add(sti);
658678
tables.computeIfAbsent(tableId, (t) -> new TableSummary(tableName)).addTablet(sti);
659679
if (sti.getEstimatedEntries() == 0) {
660-
suggestions.add("Tablet " + sti.getTabletId().toString() + " (tid: "
680+
addMessage(Info, Table, "Tablet " + sti.getTabletId().toString() + " (tid: "
661681
+ sti.getTabletId().getTable() + ") may have zero entries and could be merged.");
662682
}
663683
}
@@ -695,8 +715,9 @@ public void finish() {
695715
String balancerRG = tconf.get(TableLoadBalancer.TABLE_ASSIGNMENT_GROUP_PROPERTY);
696716
balancerRG = balancerRG == null ? Constants.DEFAULT_RESOURCE_GROUP_NAME : balancerRG;
697717
if (!tservers.containsKey(balancerRG)) {
698-
suggestions.add("Table " + table.tableName() + " configured to balance tablets in resource"
699-
+ " group " + balancerRG + ", but there are no TabletServers.");
718+
addMessage(Critical, Table,
719+
"Table " + table.tableName() + " configured to balance tablets in resource group "
720+
+ balancerRG + ", but there are no TabletServers.");
700721
}
701722
}
702723

@@ -713,8 +734,8 @@ public void finish() {
713734
Number numQueued = getMetricValue(queued.orElseThrow());
714735
if (numQueued.longValue() > 0) {
715736
if (rgCompactors == null || rgCompactors.size() == 0) {
716-
suggestions.add("Compactor group " + rg + " has " + numQueued.longValue()
717-
+ " queued compactions but no running compactors");
737+
addMessage(Critical, Configuration, "Compactor group " + rg + " has "
738+
+ numQueued.longValue() + " queued compactions but no running compactors");
718739
} else {
719740
// Check for idle compactors.
720741
Map<Id,CumulativeDistributionSummary> rgMetrics =
@@ -728,7 +749,8 @@ public void finish() {
728749
if (idleMetric.isPresent()) {
729750
var metric = idleMetric.orElseThrow().getValue();
730751
if (metric.max() == 1.0D) {
731-
suggestions.add("Compactor group " + rg + " has queued jobs and idle compactors.");
752+
addMessage(High, Configuration,
753+
"Compactor group " + rg + " has queued jobs and idle compactors.");
732754
}
733755
}
734756

@@ -739,7 +761,7 @@ public void finish() {
739761

740762
for (var compactorGroup : compactors.keySet()) {
741763
if (!configuredCompactionResourceGroups.contains(compactorGroup)) {
742-
suggestions.add("Compactor group " + compactorGroup
764+
addMessage(High, Configuration, "Compactor group " + compactorGroup
743765
+ " has running compactors, but no configuration uses them.");
744766
}
745767
}
@@ -953,8 +975,8 @@ public DeploymentOverview getDeploymentView() {
953975
return this.deploymentOverview;
954976
}
955977

956-
public Set<String> getSuggestions() {
957-
return this.suggestions;
978+
public Map<MessagePriority,Map<MessageCategory,Set<String>>> getMessages() {
979+
return this.messages;
958980
}
959981

960982
public long getTimestamp() {

server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,24 @@ public Map<String,Object> getManager() {
162162
return model;
163163
}
164164

165+
/**
166+
* Returns the messages template
167+
*
168+
* @return Messages model
169+
*/
170+
@GET
171+
@Path("messages")
172+
@Template(name = "/default.ftl")
173+
public Map<String,Object> getMessages() {
174+
175+
Map<String,Object> model = getModel();
176+
model.put("title", "Messages"); // Need this for the browser tab title
177+
model.put("tablesTitle", "Messages");
178+
model.put("template", "messages.ftl");
179+
model.put("js", "messages.js");
180+
return model;
181+
}
182+
165183
/**
166184
* Returns the tservers templates
167185
*

server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/coordinator.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,6 @@ const runningQueueHtmlTable = '#queue_running';
2626
var tableRunning;
2727
var queueRunning;
2828

29-
function getStoredArray(storageKey) {
30-
if (!sessionStorage[storageKey]) {
31-
return [];
32-
}
33-
return JSON.parse(sessionStorage[storageKey]);
34-
}
35-
3629
function refresh() {
3730
$.when(getRunningCompactionsByTable(), getRunningCompactionsByGroup(), getCoordinatorQueueView(), getManagersCompactionView()).then(function () {
3831
refreshTable(coordinatorHtmlTable, MANAGER_COMPACTION_SERVER_PROCESS_VIEW);

server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ const TABLET_SERVER_PROCESS_VIEW = 'tserversView';
3737
var STATUS_REQUEST = null;
3838
const RUNNING_COMPACTIONS_BY_TABLE = 'runningCompactionsByTable';
3939
const RUNNING_COMPACTIONS_BY_GROUP = 'runningCompactionsByGroup';
40+
const MESSAGE_CATEGORIES = 'messageCategories';
41+
const MESSAGES = 'messages';
4042

4143
// Override Length Menu options for dataTables
4244
if ($.fn && $.fn.dataTable) {
@@ -372,6 +374,20 @@ function getJSONForTable(call, sessionDataVar) {
372374
});
373375
}
374376

377+
function getStoredJson(storageKey, defaultValue) {
378+
var storedValue = sessionStorage.getItem(storageKey);
379+
if (!storedValue) {
380+
return defaultValue;
381+
}
382+
383+
return JSON.parse(storedValue);
384+
}
385+
386+
function getStoredArray(storageKey) {
387+
var storedValue = getStoredJson(storageKey, []);
388+
return Array.isArray(storedValue) ? storedValue : [];
389+
}
390+
375391
/**
376392
* Performs POST call and builds console logging message if successful
377393
* @param {string} call REST url called
@@ -540,11 +556,30 @@ function getTserversSummary(group) {
540556
}
541557

542558
/**
543-
* REST GET call for /suggestions,
544-
* stores it on a sessionStorage variable
559+
* REST GET call for /message/categories
560+
* store it on a sessionStorage variable
545561
*/
546-
function getSuggestions() {
547-
return getJSONForTable(REST_V2_PREFIX + '/suggestions', 'suggestions');
562+
function getMessageCategories() {
563+
return getJSONForTable(REST_V2_PREFIX + '/message/categories', MESSAGE_CATEGORIES);
564+
}
565+
566+
/**
567+
* REST GET call for /messages,
568+
* results are not stored in session as this
569+
* function takes parameters driven by toggles
570+
* in the UI.
571+
*/
572+
function getMessages(high, info, cats) {
573+
574+
const params = new URLSearchParams();
575+
params.append('high', high);
576+
params.append('info', info);
577+
$.each(cats, function (index, cat) {
578+
params.append('category', cat);
579+
});
580+
581+
var call = REST_V2_PREFIX + '/messages?' + params.toString();
582+
return getJSONForTable(call, MESSAGES);
548583
}
549584

550585
/**

0 commit comments

Comments
 (0)