Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JSON-style reports #18047

Merged
merged 21 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package alluxio.wire;

import alluxio.util.FormatUtils;
import com.amazonaws.util.StringUtils;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;

public class FileSizeSerializer extends JsonSerializer<Long> {
@Override
public void serialize(Long value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
String formattedSize = FormatUtils.getSizeFromBytes(value);
jsonGenerator.writeString(StringUtils.upperCase(formattedSize));
}
}
13 changes: 12 additions & 1 deletion dora/core/common/src/main/java/alluxio/wire/MountPointInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

import alluxio.annotation.PublicApi;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;

Expand All @@ -27,19 +30,27 @@
@NotThreadSafe
@PublicApi
public class MountPointInfo implements Serializable {
@JsonIgnore
twalluxio marked this conversation as resolved.
Show resolved Hide resolved
private static final long serialVersionUID = -2912330427506888886L;

@JsonIgnore
private static final long UNKNOWN_CAPACITY_BYTES = -1;
@JsonIgnore
private static final long UNKNOWN_USED_BYTES = -1;

private String mUfsUri = "";
private String mUfsType = "";
@JsonIgnore
private long mMountId = 0;
@JsonSerialize(using = FileSizeSerializer.class)
@JsonProperty("ufsCapacity")
private long mUfsCapacityBytes = UNKNOWN_CAPACITY_BYTES;
@JsonSerialize(using = FileSizeSerializer.class)
@JsonProperty("ufsUsed")
private long mUfsUsedBytes = UNKNOWN_USED_BYTES;
private boolean mReadOnly;
private HashMap<String, String> mProperties = new HashMap<>();
private boolean mShared;
private HashMap<String, String> mProperties = new HashMap<>();

/**
* Creates a new instance of {@link MountPointInfo}.
Expand Down
189 changes: 83 additions & 106 deletions dora/shell/src/main/java/alluxio/cli/fsadmin/report/CapacityCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
import alluxio.util.FormatUtils;
import alluxio.wire.WorkerInfo;

import com.google.common.base.Strings;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.cli.CommandLine;

import java.io.IOException;
Expand All @@ -51,18 +54,17 @@
* Prints Alluxio capacity information.
*/
public class CapacityCommand {
private static final int INDENT_SIZE = 4;

private BlockMasterClient mBlockMasterClient;
private PrintStream mPrintStream;
private int mIndentationLevel = 0;
private long mSumCapacityBytes;
private long mSumUsedBytes;
private Map<String, Long> mSumCapacityBytesOnTierMap;
private Map<String, Long> mSumUsedBytesOnTierMap;
private TreeMap<String, Map<String, String>> mCapacityTierInfoMap;
private Map<String, Map<String, String>> mUsedTierInfoMap;

private ObjectMapper mMapper;
private ObjectNode mCapacityInfo;
private static final String LIVE_WORKER_STATE = "In Service";
private static final String LOST_WORKER_STATE = "Out of Service";

Expand Down Expand Up @@ -118,17 +120,20 @@ public void generateCapacityReport(GetWorkerReportOptions options, AlluxioConfig
workerInfoList = mBlockMasterClient.getWorkerReport(options);
}
if (workerInfoList.size() == 0) {
print("No workers found.");
mPrintStream.println("No workers found.");
return;
}
Collections.sort(workerInfoList, new WorkerInfo.LastContactSecComparator());

collectWorkerInfo(workerInfoList);
printAggregatedInfo(options);
printWorkerInfo(workerInfoList);
generateAggregatedInfo(options);
generateWorkerInfo(workerInfoList);
if (workerRegisterToAllMasters) {
printWorkerAllMasterConnectionInfo(allMastersWorkerInfo);
}
mPrintStream.printf("Capacity information for %s workers:%n",
twalluxio marked this conversation as resolved.
Show resolved Hide resolved
options.getWorkerRange().toString().toLowerCase());
mPrintStream.println(mMapper.writerWithDefaultPrettyPrinter().writeValueAsString(mCapacityInfo));
}

/**
Expand Down Expand Up @@ -177,36 +182,44 @@ private void collectWorkerInfo(List<WorkerInfo> workerInfoList) {
*
* @param options GetWorkerReportOptions to check if input is invalid
*/
private void printAggregatedInfo(GetWorkerReportOptions options) {
mIndentationLevel = 0;
print(String.format("Capacity information for %s workers: ",
options.getWorkerRange().toString().toLowerCase()));

mIndentationLevel++;
print("Total Capacity: " + FormatUtils.getSizeFromBytes(mSumCapacityBytes));
mIndentationLevel++;
private void generateAggregatedInfo(GetWorkerReportOptions options) throws JsonProcessingException {
ObjectNode capacityMetrics = mMapper.createObjectNode();
ObjectNode totalCapacity = mMapper.createObjectNode();
ObjectNode usedCapacity = mMapper.createObjectNode();

ArrayNode totalCapacityTiers = mMapper.createArrayNode();
for (Map.Entry<String, Long> totalBytesTier : mSumCapacityBytesOnTierMap.entrySet()) {
long value = totalBytesTier.getValue();
print("Tier: " + totalBytesTier.getKey()
+ " Size: " + FormatUtils.getSizeFromBytes(value));
ObjectNode totalCapacityPerTier = mMapper.createObjectNode();
totalCapacityPerTier.put("Tier", totalBytesTier.getKey());
totalCapacityPerTier.put("Size", FormatUtils.getSizeFromBytes(value));
totalCapacityTiers.add(totalCapacityPerTier);
}
mIndentationLevel--;

print("Used Capacity: "
+ FormatUtils.getSizeFromBytes(mSumUsedBytes));
mIndentationLevel++;
ArrayNode usedCapacityTiers = mMapper.createArrayNode();
for (Map.Entry<String, Long> usedBytesTier : mSumUsedBytesOnTierMap.entrySet()) {
long value = usedBytesTier.getValue();
print("Tier: " + usedBytesTier.getKey()
+ " Size: " + FormatUtils.getSizeFromBytes(value));
ObjectNode usedCapacityPerTier = mMapper.createObjectNode();
usedCapacityPerTier.put("Tier", usedBytesTier.getKey());
usedCapacityPerTier.put("Size", FormatUtils.getSizeFromBytes(value));
usedCapacityTiers.add(usedCapacityPerTier);
}
mIndentationLevel--;

totalCapacity.put("All", FormatUtils.getSizeFromBytes(mSumCapacityBytes));
totalCapacity.set("Tiers", totalCapacityTiers);
usedCapacity.put("All", FormatUtils.getSizeFromBytes(mSumUsedBytes));
usedCapacity.set("Tiers", usedCapacityTiers);

capacityMetrics.set("Total Capacity", totalCapacity);
capacityMetrics.set("Used Capacity", usedCapacity);

if (mSumCapacityBytes != 0) {
int usedPercentage = (int) (100L * mSumUsedBytes / mSumCapacityBytes);
print(String.format("Used Percentage: " + "%s%%", usedPercentage));
print(String.format("Free Percentage: " + "%s%%", 100 - usedPercentage));
capacityMetrics.put("Used Percentage", String.format("%s%%", usedPercentage));
capacityMetrics.put("Free Percentage", String.format("%s%%", 100 - usedPercentage));
}

mCapacityInfo.set("Capacity Metrics", capacityMetrics);
}

private String getMasterAddressesString(Set<java.net.InetSocketAddress> addresses) {
Expand Down Expand Up @@ -296,96 +309,58 @@ private void printWorkerAllMasterConnectionInfo(
*
* @param workerInfoList the worker info list to get info from
*/
private void printWorkerInfo(List<WorkerInfo> workerInfoList) {
mIndentationLevel = 0;
private void generateWorkerInfo(List<WorkerInfo> workerInfoList) {
boolean isShort = false;
if (mCapacityTierInfoMap.size() == 0) {
return;
} else if (mCapacityTierInfoMap.size() == 1) {
// TODO(jiacheng): test BOTH long and short output
// Do not print Total value when only one tier exists
printShortWorkerInfo(workerInfoList);
return;
isShort = true;
}

ArrayNode workerInfo = mMapper.createArrayNode();
Set<String> tiers = mCapacityTierInfoMap.keySet();
String tiersInfo = String.format(Strings.repeat("%-14s", tiers.size()), tiers.toArray());
String longInfoFormat = getInfoFormat(workerInfoList, false);
print(String.format("%n" + longInfoFormat,
"Worker Name", "State", "Last Heartbeat", "Storage", "Total", tiersInfo,
"Version", "Revision"));

for (WorkerInfo info : workerInfoList) {
String workerName = info.getAddress().getHost();

long usedBytes = info.getUsedBytes();
long capacityBytes = info.getCapacityBytes();

String usedPercentageInfo = "";
if (capacityBytes != 0) {
int usedPercentage = (int) (100L * usedBytes / capacityBytes);
usedPercentageInfo = String.format(" (%s%%)", usedPercentage);
ObjectNode infoPerWorker = mMapper.createObjectNode();

ArrayNode tiersInfo = mMapper.createArrayNode();

if (isShort) {
// TODO(jiacheng): test BOTH long and short output
twalluxio marked this conversation as resolved.
Show resolved Hide resolved
// Do not print Total value when only one tier exists
ObjectNode tierInfo = mMapper.createObjectNode();
tierInfo.put("Tier", mCapacityTierInfoMap.firstKey());
tierInfo.put("Capacity", FormatUtils.getSizeFromBytes(info.getCapacityBytes()));
tierInfo.put("Used", FormatUtils.getSizeFromBytes(info.getUsedBytes()));
if (info.getCapacityBytes() != 0) {
tierInfo.put("Used percentage", String.format(" %s%%", (int) (100L * info.getUsedBytes() / info.getCapacityBytes())));
twalluxio marked this conversation as resolved.
Show resolved Hide resolved
}
tiersInfo.add(tierInfo);
} else {
for (String tier : tiers){
ObjectNode tierInfo = mMapper.createObjectNode();
tierInfo.put("Tier", tier);
tierInfo.put("Capacity", getWorkerFormattedTierValues(mCapacityTierInfoMap, info.getAddress().getHost()));
tierInfo.put("Used", getWorkerFormattedTierValues(mUsedTierInfoMap, info.getAddress().getHost()));
if (info.getCapacityBytes() != 0) {
tierInfo.put("Used percentage",
String.format("%s%%", (int) (100L * info.getUsedBytes() / info.getCapacityBytes())));
}
tiersInfo.add(tierInfo);
}
twalluxio marked this conversation as resolved.
Show resolved Hide resolved
}

String capacityTierInfo = getWorkerFormattedTierValues(mCapacityTierInfoMap, workerName);
String usedTierInfo = getWorkerFormattedTierValues(mUsedTierInfoMap, workerName);

print(String.format(longInfoFormat, workerName, info.getState(),
info.getLastContactSec(), "capacity",
FormatUtils.getSizeFromBytes(capacityBytes), capacityTierInfo,
info.getVersion(), info.getRevision()));
print(String.format(longInfoFormat, "", "", "", "used",
FormatUtils.getSizeFromBytes(usedBytes) + usedPercentageInfo, usedTierInfo,
"", ""));
}
}

/**
* Prints worker information when only one tier exists.
*
* @param workerInfoList the worker info list to get info from
*/
private void printShortWorkerInfo(List<WorkerInfo> workerInfoList) {
String tier = String.format("%-16s", mCapacityTierInfoMap.firstKey());
String shortInfoFormat = getInfoFormat(workerInfoList, true);
print(String.format("%n" + shortInfoFormat,
"Worker Name", "State", "Last Heartbeat", "Storage", tier, "Version", "Revision"));

for (WorkerInfo info : workerInfoList) {
long capacityBytes = info.getCapacityBytes();
long usedBytes = info.getUsedBytes();
infoPerWorker.put("Worker Name", info.getAddress().getHost());
twalluxio marked this conversation as resolved.
Show resolved Hide resolved
infoPerWorker.put("State", info.getState());
infoPerWorker.put("Last Heartbeat", info.getLastContactSec());
infoPerWorker.set("tiers", tiersInfo);
infoPerWorker.put("Version", info.getVersion());
infoPerWorker.put("Revision", info.getRevision());

String usedPercentageInfo = "";
if (capacityBytes != 0) {
int usedPercentage = (int) (100L * usedBytes / capacityBytes);
usedPercentageInfo = String.format(" (%s%%)", usedPercentage);
}
print(String.format(shortInfoFormat, info.getAddress().getHost(), info.getState(),
info.getLastContactSec(), "capacity",
String.format("%-16s", FormatUtils.getSizeFromBytes(capacityBytes)),
info.getVersion(), info.getRevision()));
print(String.format(shortInfoFormat, "", "", "", "used",
String.format("%-16s", FormatUtils.getSizeFromBytes(usedBytes) + usedPercentageInfo),
"", ""));
workerInfo.add(infoPerWorker);
}
}

/**
* Gets the info format according to the longest worker name.
* @param workerInfoList the worker info list to get info from
* @param isShort whether exists only one tier
* @return the info format for printing long/short worker info
*/
private String getInfoFormat(List<WorkerInfo> workerInfoList, boolean isShort) {
int maxWorkerNameLength = workerInfoList.stream().map(w -> w.getAddress().getHost().length())
.max(Comparator.comparing(Integer::intValue)).get();
int firstIndent = 16;
if (firstIndent <= maxWorkerNameLength) {
// extend first indent according to the longest worker name by default 5
firstIndent = maxWorkerNameLength + 5;
}
if (isShort) {
return "%-" + firstIndent + "s %-15s %-16s %-13s %s %-16s %-40s";
}
return "%-" + firstIndent + "s %-15s %-16s %-13s %-16s %s %-16s %-40s";
mCapacityInfo.set("Worker Information", workerInfo);
}

/**
Expand Down Expand Up @@ -450,6 +425,9 @@ private void initVariables() {
// TierInfoMap is of form Map<Tier_Name, Map<Worker_Name, Worker_Tier_Value>>
mCapacityTierInfoMap = new TreeMap<>(FileSystemAdminShellUtils::compareTierNames);
mUsedTierInfoMap = new TreeMap<>(FileSystemAdminShellUtils::compareTierNames);

mMapper = new ObjectMapper();
mCapacityInfo = mMapper.createObjectNode();
}

/**
Expand All @@ -458,8 +436,7 @@ private void initVariables() {
* @param text information to print
*/
private void print(String text) {
String indent = Strings.repeat(" ", mIndentationLevel * INDENT_SIZE);
mPrintStream.println(indent + text);
mPrintStream.println(text);
}

/**
Expand Down
Loading