package com.jivesoftware.os.amza.sync.deployable.region;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jivesoftware.os.amza.sync.api.AmzaSyncSenderConfig;
import com.jivesoftware.os.amza.sync.deployable.AmzaSyncSender;
import com.jivesoftware.os.amza.sync.deployable.AmzaSyncSenders;
import com.jivesoftware.os.amza.sync.deployable.AmzaSyncStats;
import com.jivesoftware.os.amza.ui.region.PageRegion;
import com.jivesoftware.os.amza.ui.soy.SoyRenderer;
import com.jivesoftware.os.mlogger.core.LoggerSummary;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
*
*/
public class AmzaAdminRegion implements PageRegion<Void> {
private final String template;
private final SoyRenderer renderer;
private final AmzaSyncStats stats;
private final boolean senderEnabled;
private final boolean receiverEnabled;
private final AmzaSyncSenders syncSenders;
public AmzaAdminRegion(String template,
SoyRenderer renderer,
AmzaSyncStats stats,
boolean senderEnabled,
boolean receiverEnabled,
AmzaSyncSenders syncSenders) {
this.template = template;
this.renderer = renderer;
this.stats = stats;
this.senderEnabled = senderEnabled;
this.receiverEnabled = receiverEnabled;
this.syncSenders = syncSenders;
}
@Override
public String render(Void input) {
HashMap<String, Object> data = Maps.newHashMap();
data.put("sender", senderEnabled);
data.put("receiver", receiverEnabled);
if (senderEnabled) {
Collection<AmzaSyncSender> senders = syncSenders.getActiveSenders();
List<Map<String, Object>> senderData = Lists.newArrayList();
for (AmzaSyncSender sender : senders) {
AmzaSyncSenderConfig config = sender.getConfig();
senderData.add(ImmutableMap.<String, Object>builder()
.put("name", config.name)
.put("enabled", config.enabled)
.put("senderScheme", config.senderScheme)
.put("senderHost", config.senderHost)
.put("senderPort", config.senderPort)
.put("allowSelfSignedCerts", config.allowSelfSignedCerts)
.put("syncIntervalMillis", String.valueOf(config.syncIntervalMillis))
.put("batchSize", config.batchSize)
.build());
}
data.put("senders", senderData);
}
data.put("errors", String.valueOf(LoggerSummary.INSTANCE.errors.longValue() + LoggerSummary.INSTANCE_EXTERNAL_INTERACTIONS.errors.longValue()));
data.put("recentErrors", recentLogs(LoggerSummary.INSTANCE.lastNErrors.get(), LoggerSummary.INSTANCE_EXTERNAL_INTERACTIONS.lastNErrors.get()));
data.put("warns", String.valueOf(LoggerSummary.INSTANCE.warns.longValue() + LoggerSummary.INSTANCE_EXTERNAL_INTERACTIONS.warns.longValue()));
data.put("recentWarns", recentLogs(LoggerSummary.INSTANCE.lastNWarns.get(), LoggerSummary.INSTANCE_EXTERNAL_INTERACTIONS.lastNWarns.get()));
data.put("infos", String.valueOf(LoggerSummary.INSTANCE.infos.longValue() + LoggerSummary.INSTANCE_EXTERNAL_INTERACTIONS.infos.longValue()));
data.put("recentInfos", recentLogs(LoggerSummary.INSTANCE.lastNInfos.get(), LoggerSummary.INSTANCE_EXTERNAL_INTERACTIONS.lastNInfos.get()));
ingressed(data);
egressed(data);
return renderer.render(template, data);
}
private List<String> recentLogs(String[] internal, String[] external) {
List<String> log = new ArrayList<>();
if (internal != null) {
for (String i : internal) {
if (i != null) {
log.add(i);
}
}
}
if (external != null) {
for (String e : external) {
if (e != null) {
log.add(e);
}
}
}
return log;
}
private void ingressed(Map<String, Object> data) {
List<Map<String, String>> rows = new ArrayList<>();
Map<String, AmzaSyncStats.Stat> map = stats.ingressedMap();
List<Map.Entry<String, AmzaSyncStats.Stat>> sortedEntries = new ArrayList<>(map.entrySet());
Collections.sort(sortedEntries,
(o1, o2) -> Long.compare(o2.getValue().count.longValue(), o1.getValue().count.longValue()));
long grandTotal = 0;
long mostRecentUpdateTimestamp = 0;
long worstLatency = 0;
for (Map.Entry<String, AmzaSyncStats.Stat> e : sortedEntries) {
Map<String, String> status = new HashMap<>();
String key = e.getKey();
status.put("context", key);
AmzaSyncStats.Stat value = e.getValue();
status.put("count", String.valueOf(value.count.get()));
status.put("recency", humanReadableUptime(System.currentTimeMillis() - value.timestamp.get()));
status.put("latency", humanReadableLatency(value.latency.get()));
rows.add(status);
if (value.timestamp.get() > mostRecentUpdateTimestamp) {
mostRecentUpdateTimestamp = value.timestamp.get();
}
if (value.latency.get() > worstLatency) {
worstLatency = value.latency.get();
}
grandTotal += value.count.get();
}
data.put("ingressedRecency", mostRecentUpdateTimestamp == 0 ? "" : humanReadableUptime(System.currentTimeMillis() - mostRecentUpdateTimestamp));
data.put("ingressedLatency", humanReadableLatency(worstLatency));
data.put("ingressedTotal", String.valueOf(grandTotal));
data.put("ingressedStatus", rows);
}
private void egressed(Map<String, Object> data) {
List<Map<String, String>> rows = new ArrayList<>();
Map<String, AmzaSyncStats.Stat> map = stats.egressedMap();
List<Map.Entry<String, AmzaSyncStats.Stat>> sortedEntries = new ArrayList<>(map.entrySet());
Collections.sort(sortedEntries,
(o1, o2) -> Long.compare(o2.getValue().count.longValue(), o1.getValue().count.longValue()));
long grandTotal = 0;
long mostRecentUpdateTimestamp = 0;
long worstLatency = 0;
for (Map.Entry<String, AmzaSyncStats.Stat> e : sortedEntries) {
Map<String, String> status = new HashMap<>();
String key = e.getKey();
status.put("context", key);
AmzaSyncStats.Stat value = e.getValue();
status.put("count", String.valueOf(value.count.get()));
status.put("recency", humanReadableUptime(System.currentTimeMillis() - value.timestamp.get()));
status.put("latency", humanReadableLatency(value.latency.get()));
rows.add(status);
if (value.timestamp.get() > mostRecentUpdateTimestamp) {
mostRecentUpdateTimestamp = value.timestamp.get();
}
if (value.latency.get() > worstLatency) {
worstLatency = value.latency.get();
}
grandTotal += value.count.get();
}
data.put("egressedRecency", mostRecentUpdateTimestamp == 0 ? "" : humanReadableUptime(System.currentTimeMillis() - mostRecentUpdateTimestamp));
data.put("egressedLatency", humanReadableLatency(worstLatency));
data.put("egressedTotal", String.valueOf(grandTotal));
data.put("egressedStatus", rows);
}
@Override
public String getTitle() {
return "Sync";
}
public static String humanReadableLatency(long millis) {
if (millis < 0) {
return String.valueOf(millis);
}
long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
millis -= TimeUnit.SECONDS.toMillis(seconds);
StringBuilder sb = new StringBuilder(64);
sb.append(seconds);
sb.append(".");
if (millis < 100) {
sb.append('0');
}
if (millis < 10) {
sb.append('0');
}
sb.append(millis);
return (sb.toString());
}
public static String humanReadableUptime(long millis) {
if (millis < 0) {
return String.valueOf(millis);
}
long hours = TimeUnit.MILLISECONDS.toHours(millis);
millis -= TimeUnit.HOURS.toMillis(hours);
long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
millis -= TimeUnit.MINUTES.toMillis(minutes);
long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
millis -= TimeUnit.SECONDS.toMillis(seconds);
StringBuilder sb = new StringBuilder(64);
if (hours < 10) {
sb.append('0');
}
sb.append(hours);
sb.append(":");
if (minutes < 10) {
sb.append('0');
}
sb.append(minutes);
sb.append(":");
if (seconds < 10) {
sb.append('0');
}
sb.append(seconds);
return (sb.toString());
}
}