|
@@ -45,6 +45,7 @@ import org.apache.hadoop.security.UserGroupInformation;
|
|
|
import org.apache.hadoop.util.Tool;
|
|
|
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
|
|
import org.apache.hadoop.yarn.api.records.ApplicationReport;
|
|
|
+import org.apache.hadoop.yarn.api.records.ContainerId;
|
|
|
import org.apache.hadoop.yarn.api.records.ContainerReport;
|
|
|
import org.apache.hadoop.yarn.api.records.YarnApplicationState;
|
|
|
import org.apache.hadoop.yarn.client.api.YarnClient;
|
|
@@ -78,59 +79,16 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
private static final String APP_OWNER_OPTION = "appOwner";
|
|
|
private static final String AM_CONTAINER_OPTION = "am";
|
|
|
private static final String CONTAINER_LOG_FILES = "logFiles";
|
|
|
+ private static final String SHOW_META_INFO = "show_meta_info";
|
|
|
+ private static final String LIST_NODES_OPTION = "list_nodes";
|
|
|
public static final String HELP_CMD = "help";
|
|
|
|
|
|
@Override
|
|
|
public int run(String[] args) throws Exception {
|
|
|
|
|
|
- Options opts = new Options();
|
|
|
- opts.addOption(HELP_CMD, false, "Displays help for all commands.");
|
|
|
- Option appIdOpt =
|
|
|
- new Option(APPLICATION_ID_OPTION, true, "ApplicationId (required)");
|
|
|
- appIdOpt.setRequired(true);
|
|
|
- opts.addOption(appIdOpt);
|
|
|
- opts.addOption(CONTAINER_ID_OPTION, true, "ContainerId. "
|
|
|
- + "By default, it will only print syslog if the application is runing."
|
|
|
- + " Work with -logFiles to get other logs.");
|
|
|
- opts.addOption(NODE_ADDRESS_OPTION, true, "NodeAddress in the format "
|
|
|
- + "nodename:port");
|
|
|
- opts.addOption(APP_OWNER_OPTION, true,
|
|
|
- "AppOwner (assumed to be current user if not specified)");
|
|
|
- Option amOption = new Option(AM_CONTAINER_OPTION, true,
|
|
|
- "Prints the AM Container logs for this application. "
|
|
|
- + "Specify comma-separated value to get logs for related AM Container. "
|
|
|
- + "For example, If we specify -am 1,2, we will get the logs for "
|
|
|
- + "the first AM Container as well as the second AM Container. "
|
|
|
- + "To get logs for all AM Containers, use -am ALL. "
|
|
|
- + "To get logs for the latest AM Container, use -am -1. "
|
|
|
- + "By default, it will only print out syslog. Work with -logFiles "
|
|
|
- + "to get other logs");
|
|
|
- amOption.setValueSeparator(',');
|
|
|
- amOption.setArgs(Option.UNLIMITED_VALUES);
|
|
|
- amOption.setArgName("AM Containers");
|
|
|
- opts.addOption(amOption);
|
|
|
- Option logFileOpt = new Option(CONTAINER_LOG_FILES, true,
|
|
|
- "Work with -am/-containerId and specify comma-separated value "
|
|
|
- + "to get specified container log files. Use \"ALL\" to fetch all the "
|
|
|
- + "log files for the container.");
|
|
|
- logFileOpt.setValueSeparator(',');
|
|
|
- logFileOpt.setArgs(Option.UNLIMITED_VALUES);
|
|
|
- logFileOpt.setArgName("Log File Name");
|
|
|
- opts.addOption(logFileOpt);
|
|
|
-
|
|
|
- opts.getOption(APPLICATION_ID_OPTION).setArgName("Application ID");
|
|
|
- opts.getOption(CONTAINER_ID_OPTION).setArgName("Container ID");
|
|
|
- opts.getOption(NODE_ADDRESS_OPTION).setArgName("Node Address");
|
|
|
- opts.getOption(APP_OWNER_OPTION).setArgName("Application Owner");
|
|
|
- opts.getOption(AM_CONTAINER_OPTION).setArgName("AM Containers");
|
|
|
+ Options opts = createCommandOpts();
|
|
|
|
|
|
- Options printOpts = new Options();
|
|
|
- printOpts.addOption(opts.getOption(HELP_CMD));
|
|
|
- printOpts.addOption(opts.getOption(CONTAINER_ID_OPTION));
|
|
|
- printOpts.addOption(opts.getOption(NODE_ADDRESS_OPTION));
|
|
|
- printOpts.addOption(opts.getOption(APP_OWNER_OPTION));
|
|
|
- printOpts.addOption(opts.getOption(AM_CONTAINER_OPTION));
|
|
|
- printOpts.addOption(opts.getOption(CONTAINER_LOG_FILES));
|
|
|
+ Options printOpts = createPrintOpts(opts);
|
|
|
|
|
|
if (args.length < 1) {
|
|
|
printHelpMessage(printOpts);
|
|
@@ -146,6 +104,8 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
String nodeAddress = null;
|
|
|
String appOwner = null;
|
|
|
boolean getAMContainerLogs = false;
|
|
|
+ boolean showMetaInfo = false;
|
|
|
+ boolean nodesList = false;
|
|
|
String[] logFiles = null;
|
|
|
List<String> amContainersList = new ArrayList<String>();
|
|
|
try {
|
|
@@ -155,31 +115,14 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
nodeAddress = commandLine.getOptionValue(NODE_ADDRESS_OPTION);
|
|
|
appOwner = commandLine.getOptionValue(APP_OWNER_OPTION);
|
|
|
getAMContainerLogs = commandLine.hasOption(AM_CONTAINER_OPTION);
|
|
|
+ showMetaInfo = commandLine.hasOption(SHOW_META_INFO);
|
|
|
+ nodesList = commandLine.hasOption(LIST_NODES_OPTION);
|
|
|
if (getAMContainerLogs) {
|
|
|
- String[] amContainers = commandLine.getOptionValues(AM_CONTAINER_OPTION);
|
|
|
- for (String am : amContainers) {
|
|
|
- boolean errorInput = false;
|
|
|
- if (!am.trim().equalsIgnoreCase("ALL")) {
|
|
|
- try {
|
|
|
- int id = Integer.parseInt(am.trim());
|
|
|
- if (id != -1 && id <= 0) {
|
|
|
- errorInput = true;
|
|
|
- }
|
|
|
- } catch (NumberFormatException ex) {
|
|
|
- errorInput = true;
|
|
|
- }
|
|
|
- if (errorInput) {
|
|
|
- System.err.println(
|
|
|
- "Invalid input for option -am. Valid inputs are 'ALL', -1 "
|
|
|
- + "and any other integer which is larger than 0.");
|
|
|
- printHelpMessage(printOpts);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- amContainersList.add(am.trim());
|
|
|
- } else {
|
|
|
- amContainersList.add("ALL");
|
|
|
- break;
|
|
|
- }
|
|
|
+ try {
|
|
|
+ amContainersList = parseAMContainer(commandLine, printOpts);
|
|
|
+ } catch (NumberFormatException ex) {
|
|
|
+ System.err.println(ex.getMessage());
|
|
|
+ return -1;
|
|
|
}
|
|
|
}
|
|
|
if (commandLine.hasOption(CONTAINER_LOG_FILES)) {
|
|
@@ -212,138 +155,54 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
appOwner = UserGroupInformation.getCurrentUser().getShortUserName();
|
|
|
}
|
|
|
|
|
|
- boolean appStateKnown = true;
|
|
|
+ boolean appStateObtainedSuccessfully = true;
|
|
|
YarnApplicationState appState = YarnApplicationState.NEW;
|
|
|
try {
|
|
|
appState = getApplicationState(appId);
|
|
|
if (appState == YarnApplicationState.NEW
|
|
|
|| appState == YarnApplicationState.NEW_SAVING
|
|
|
|| appState == YarnApplicationState.SUBMITTED) {
|
|
|
- System.out.println("Logs are not avaiable right now.");
|
|
|
+ System.err.println("Logs are not avaiable right now.");
|
|
|
return -1;
|
|
|
}
|
|
|
} catch (IOException | YarnException e) {
|
|
|
- appStateKnown = false;
|
|
|
+ appStateObtainedSuccessfully = false;
|
|
|
System.err.println("Unable to get ApplicationState."
|
|
|
+ " Attempting to fetch logs directly from the filesystem.");
|
|
|
}
|
|
|
|
|
|
+ if (showMetaInfo) {
|
|
|
+ return showMetaInfo(appState, appStateObtainedSuccessfully,
|
|
|
+ logCliHelper, appId, containerIdStr, nodeAddress, appOwner);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nodesList) {
|
|
|
+ return showNodeLists(appState, appStateObtainedSuccessfully,
|
|
|
+ logCliHelper, appId, appOwner);
|
|
|
+ }
|
|
|
// To get am logs
|
|
|
if (getAMContainerLogs) {
|
|
|
- // if we do not specify the value for CONTAINER_LOG_FILES option,
|
|
|
- // we will only output syslog
|
|
|
- if (logFiles == null || logFiles.length == 0) {
|
|
|
- logFiles = new String[] { "syslog" };
|
|
|
- }
|
|
|
- // If the application is running, we will call the RM WebService
|
|
|
- // to get the AppAttempts which includes the nodeHttpAddress
|
|
|
- // and containerId for all the AM Containers.
|
|
|
- // After that, we will call NodeManager webService to get the
|
|
|
- // related logs
|
|
|
- if (appState == YarnApplicationState.ACCEPTED
|
|
|
- || appState == YarnApplicationState.RUNNING) {
|
|
|
- return printAMContainerLogs(getConf(), appIdStr, amContainersList,
|
|
|
- logFiles, logCliHelper, appOwner, false);
|
|
|
- } else {
|
|
|
- // If the application is in the final state, we will call RM webservice
|
|
|
- // to get all AppAttempts information first. If we get nothing,
|
|
|
- // we will try to call AHS webservice to get related AppAttempts
|
|
|
- // which includes nodeAddress for the AM Containers.
|
|
|
- // After that, we will use nodeAddress and containerId
|
|
|
- // to get logs from HDFS directly.
|
|
|
- if (getConf().getBoolean(YarnConfiguration.APPLICATION_HISTORY_ENABLED,
|
|
|
- YarnConfiguration.DEFAULT_APPLICATION_HISTORY_ENABLED)) {
|
|
|
- return printAMContainerLogs(getConf(), appIdStr, amContainersList,
|
|
|
- logFiles, logCliHelper, appOwner, true);
|
|
|
- } else {
|
|
|
- System.out
|
|
|
- .println(
|
|
|
- "Can not get AMContainers logs for the application:" + appId);
|
|
|
- System.out.println("This application:" + appId + " is finished."
|
|
|
- + " Please enable the application history service. Or Using "
|
|
|
- + "yarn logs -applicationId <appId> -containerId <containerId> "
|
|
|
- + "--nodeAddress <nodeHttpAddress> to get the container logs");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- }
|
|
|
+ return fetchAMContainerLogs(logFiles, appState, appId, appOwner,
|
|
|
+ amContainersList, logCliHelper);
|
|
|
}
|
|
|
|
|
|
int resultCode = 0;
|
|
|
if (containerIdStr != null) {
|
|
|
- // if we provide the node address and the application is in the final
|
|
|
- // state, we could directly get logs from HDFS.
|
|
|
- if (nodeAddress != null && (!appStateKnown ||
|
|
|
- isApplicationFinished(appState))) {
|
|
|
- // if user specified "ALL" as the logFiles param, pass null
|
|
|
- // to logCliHelper so that it fetches all the logs
|
|
|
- List<String> logs;
|
|
|
- if (logFiles == null) {
|
|
|
- logs = null;
|
|
|
- } else if (fetchAllLogFiles(logFiles)) {
|
|
|
- logs = null;
|
|
|
- } else {
|
|
|
- logs = Arrays.asList(logFiles);
|
|
|
- }
|
|
|
- return logCliHelper.dumpAContainersLogsForALogType(appIdStr,
|
|
|
- containerIdStr, nodeAddress, appOwner, logs);
|
|
|
- }
|
|
|
- String nodeHttpAddress = null;
|
|
|
- String nodeId = null;
|
|
|
- try {
|
|
|
- // If the nodeAddress is not provided, we will try to get
|
|
|
- // the ContainerReport. In the containerReport, we could get
|
|
|
- // nodeAddress and nodeHttpAddress
|
|
|
- ContainerReport report = getContainerReport(containerIdStr);
|
|
|
- nodeHttpAddress =
|
|
|
- report.getNodeHttpAddress().replaceFirst(
|
|
|
- WebAppUtils.getHttpSchemePrefix(getConf()), "");
|
|
|
- nodeId = report.getAssignedNode().toString();
|
|
|
- } catch (IOException | YarnException ex) {
|
|
|
- if (!appStateKnown || isApplicationFinished(appState)) {
|
|
|
- String [] requestedLogFiles = logFiles;
|
|
|
- if(fetchAllLogFiles(logFiles)) {
|
|
|
- requestedLogFiles = null;
|
|
|
- }
|
|
|
- return printContainerLogsForFinishedApplicationWithoutNodeId(
|
|
|
- appIdStr, containerIdStr, requestedLogFiles, logCliHelper,
|
|
|
- appOwner);
|
|
|
- } else if (!isApplicationFinished(appState)) {
|
|
|
- System.err.println("Unable to get logs for this container:"
|
|
|
- + containerIdStr + "for the application:" + appId);
|
|
|
- System.out.println("The application: " + appId + " is still running, "
|
|
|
- + "and we can not get Container report for the container: "
|
|
|
- + containerIdStr +". Please try later or after the application "
|
|
|
- + "finishes.");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- }
|
|
|
- // If the application is not in the final state,
|
|
|
- // we will provide the NodeHttpAddress and get the container logs
|
|
|
- // by calling NodeManager webservice.
|
|
|
- if (!isApplicationFinished(appState)) {
|
|
|
- if (logFiles == null || logFiles.length == 0) {
|
|
|
- logFiles = new String[] {"syslog"};
|
|
|
- }
|
|
|
- printContainerLogsFromRunningApplication(getConf(), appIdStr,
|
|
|
- containerIdStr, nodeHttpAddress, nodeId, logFiles, logCliHelper,
|
|
|
- appOwner);
|
|
|
- } else {
|
|
|
- String[] requestedLogFiles = logFiles;
|
|
|
- if(fetchAllLogFiles(logFiles)) {
|
|
|
- requestedLogFiles = null;
|
|
|
- }
|
|
|
- // If the application is in the final state, we will directly
|
|
|
- // get the container logs from HDFS.
|
|
|
- printContainerLogsForFinishedApplication(appIdStr, containerIdStr,
|
|
|
- nodeId, requestedLogFiles, logCliHelper, appOwner);
|
|
|
+ ContainerId containerId = ContainerId.fromString(containerIdStr);
|
|
|
+ if (!containerId.getApplicationAttemptId().getApplicationId()
|
|
|
+ .equals(appId)) {
|
|
|
+ System.err.println("The Application:" + appId
|
|
|
+ + " does not have the container:" + containerId);
|
|
|
+ return -1;
|
|
|
}
|
|
|
- return resultCode;
|
|
|
+ return fetchContainerLogs(appState, appStateObtainedSuccessfully,
|
|
|
+ logFiles, appOwner, nodeAddress, containerId, logCliHelper);
|
|
|
} else {
|
|
|
if (nodeAddress == null) {
|
|
|
resultCode =
|
|
|
logCliHelper.dumpAllContainersLogs(appId, appOwner, System.out);
|
|
|
} else {
|
|
|
- System.out.println("Should at least provide ContainerId!");
|
|
|
+ System.err.println("Should at least provide ContainerId!");
|
|
|
printHelpMessage(printOpts);
|
|
|
resultCode = -1;
|
|
|
}
|
|
@@ -382,7 +241,8 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
private void printHelpMessage(Options options) {
|
|
|
System.out.println("Retrieve logs for completed YARN applications.");
|
|
|
HelpFormatter formatter = new HelpFormatter();
|
|
|
- formatter.printHelp("yarn logs -applicationId <application ID> [OPTIONS]", new Options());
|
|
|
+ formatter.printHelp("yarn logs -applicationId <application ID> [OPTIONS]",
|
|
|
+ new Options());
|
|
|
formatter.setSyntaxPrefix("");
|
|
|
formatter.printHelp("general options are:", options);
|
|
|
}
|
|
@@ -410,9 +270,9 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
return amContainersList;
|
|
|
}
|
|
|
|
|
|
- private List<JSONObject> getAMContainerInfoForAHSWebService(Configuration conf,
|
|
|
- String appId) throws ClientHandlerException, UniformInterfaceException,
|
|
|
- JSONException {
|
|
|
+ private List<JSONObject> getAMContainerInfoForAHSWebService(
|
|
|
+ Configuration conf, String appId) throws ClientHandlerException,
|
|
|
+ UniformInterfaceException, JSONException {
|
|
|
Client webServiceClient = Client.create();
|
|
|
String webAppAddress =
|
|
|
WebAppUtils.getHttpSchemePrefix(conf)
|
|
@@ -420,8 +280,9 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
WebResource webResource = webServiceClient.resource(webAppAddress);
|
|
|
|
|
|
ClientResponse response =
|
|
|
- webResource.path("ws").path("v1").path("applicationhistory").path("apps")
|
|
|
- .path(appId).path("appattempts").accept(MediaType.APPLICATION_JSON)
|
|
|
+ webResource.path("ws").path("v1").path("applicationhistory")
|
|
|
+ .path("apps").path(appId).path("appattempts")
|
|
|
+ .accept(MediaType.APPLICATION_JSON)
|
|
|
.get(ClientResponse.class);
|
|
|
JSONObject json = response.getEntity(JSONObject.class);
|
|
|
JSONArray requests = json.getJSONArray("appAttempt");
|
|
@@ -467,24 +328,27 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
logFiles.add(elements.item(i).getTextContent());
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
- System.out.println("Unable to parse xml from webservice. Error:");
|
|
|
- System.out.println(e.getMessage());
|
|
|
+ System.err.println("Unable to parse xml from webservice. Error:");
|
|
|
+ System.err.println(e.getMessage());
|
|
|
throw new IOException(e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
} catch (ClientHandlerException | UniformInterfaceException ex) {
|
|
|
- System.out.println("Unable to fetch log files list");
|
|
|
+ System.err.println("Unable to fetch log files list");
|
|
|
throw new IOException(ex);
|
|
|
}
|
|
|
return logFiles.toArray(new String[0]);
|
|
|
}
|
|
|
|
|
|
private void printContainerLogsFromRunningApplication(Configuration conf,
|
|
|
- String appId, String containerIdStr, String nodeHttpAddress,
|
|
|
+ ContainerId containerId, String nodeHttpAddress,
|
|
|
String nodeId, String[] logFiles, LogCLIHelpers logCliHelper,
|
|
|
String appOwner) throws IOException {
|
|
|
- String [] requestedLogFiles = logFiles;
|
|
|
+ String appId = containerId.getApplicationAttemptId()
|
|
|
+ .getApplicationId().toString();
|
|
|
+ String containerIdStr = containerId.toString();
|
|
|
+ String[] requestedLogFiles = logFiles;
|
|
|
// fetch all the log files for the container
|
|
|
if (fetchAllLogFiles(logFiles)) {
|
|
|
requestedLogFiles =
|
|
@@ -511,7 +375,7 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
System.out.println(response.getEntity(String.class));
|
|
|
System.out.println("End of LogType:" + logFile);
|
|
|
} catch (ClientHandlerException | UniformInterfaceException ex) {
|
|
|
- System.out.println("Can not find the log file:" + logFile
|
|
|
+ System.err.println("Can not find the log file:" + logFile
|
|
|
+ " for the container:" + containerIdStr + " in NodeManager:"
|
|
|
+ nodeId);
|
|
|
}
|
|
@@ -528,7 +392,8 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
System.out.println(containerString);
|
|
|
System.out.println(StringUtils.repeat("=", containerString.length()));
|
|
|
logCliHelper.dumpAContainersLogsForALogType(appId, containerId,
|
|
|
- nodeAddress, appOwner, logFiles != null ? Arrays.asList(logFiles) : null);
|
|
|
+ nodeAddress, appOwner, logFiles != null ? Arrays.asList(logFiles)
|
|
|
+ : null);
|
|
|
}
|
|
|
|
|
|
private int printContainerLogsForFinishedApplicationWithoutNodeId(
|
|
@@ -607,7 +472,7 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
if (amContainers.contains("ALL")) {
|
|
|
for (AMLogsRequest request : requests) {
|
|
|
outputAMContainerLogs(request, conf, appId, logFiles, logCliHelper,
|
|
|
- appOwner);
|
|
|
+ appOwner);
|
|
|
}
|
|
|
System.out.println();
|
|
|
System.out.println("Specified ALL for -am option. "
|
|
@@ -617,11 +482,11 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
int amContainerId = Integer.parseInt(amContainer.trim());
|
|
|
if (amContainerId == -1) {
|
|
|
outputAMContainerLogs(requests.get(requests.size() - 1), conf, appId,
|
|
|
- logFiles, logCliHelper, appOwner);
|
|
|
+ logFiles, logCliHelper, appOwner);
|
|
|
} else {
|
|
|
if (amContainerId <= requests.size()) {
|
|
|
outputAMContainerLogs(requests.get(amContainerId - 1), conf, appId,
|
|
|
- logFiles, logCliHelper, appOwner);
|
|
|
+ logFiles, logCliHelper, appOwner);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -648,27 +513,271 @@ public class LogsCLI extends Configured implements Tool {
|
|
|
}
|
|
|
}
|
|
|
if (nodeId != null && !nodeId.isEmpty()) {
|
|
|
- String [] requestedLogFilesList = null;
|
|
|
+ String[] requestedLogFilesList = null;
|
|
|
if(!fetchAllLogFiles(logFiles)) {
|
|
|
requestedLogFilesList = logFiles;
|
|
|
}
|
|
|
printContainerLogsForFinishedApplication(appId, containerId, nodeId,
|
|
|
- requestedLogFilesList, logCliHelper, appOwner);
|
|
|
+ requestedLogFilesList, logCliHelper, appOwner);
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
if (nodeHttpAddress != null && containerId != null
|
|
|
&& !nodeHttpAddress.isEmpty() && !containerId.isEmpty()) {
|
|
|
- String [] requestedLogFiles = logFiles;
|
|
|
+ String[] requestedLogFiles = logFiles;
|
|
|
// fetch all the log files for the AM
|
|
|
if (fetchAllLogFiles(logFiles)) {
|
|
|
requestedLogFiles =
|
|
|
getContainerLogFiles(getConf(), containerId, nodeHttpAddress);
|
|
|
}
|
|
|
- printContainerLogsFromRunningApplication(conf, appId, containerId,
|
|
|
- nodeHttpAddress, nodeId, requestedLogFiles, logCliHelper, appOwner);
|
|
|
+ printContainerLogsFromRunningApplication(conf,
|
|
|
+ ContainerId.fromString(containerId), nodeHttpAddress, nodeId,
|
|
|
+ requestedLogFiles, logCliHelper, appOwner);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int showMetaInfo(YarnApplicationState appState,
|
|
|
+ boolean appStateObtainedSuccessfully, LogCLIHelpers logCliHelper,
|
|
|
+ ApplicationId appId, String containerIdStr, String nodeAddress,
|
|
|
+ String appOwner) throws IOException {
|
|
|
+ if (!isApplicationFinished(appState) && appStateObtainedSuccessfully) {
|
|
|
+ System.err.println("The -show_meta_info command can be only used "
|
|
|
+ + "with finished applications");
|
|
|
+ return -1;
|
|
|
+ } else {
|
|
|
+ logCliHelper.printLogMetadata(appId, containerIdStr, nodeAddress,
|
|
|
+ appOwner, System.out, System.err);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int showNodeLists(YarnApplicationState appState,
|
|
|
+ boolean appStateObtainedSuccessfully, LogCLIHelpers logCliHelper,
|
|
|
+ ApplicationId appId, String appOwner) throws IOException {
|
|
|
+ if (!isApplicationFinished(appState) && appStateObtainedSuccessfully) {
|
|
|
+ System.err.println("The -list_nodes command can be only used with "
|
|
|
+ + "finished applications");
|
|
|
+ return -1;
|
|
|
+ } else {
|
|
|
+ logCliHelper.printNodesList(appId, appOwner, System.out, System.err);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Options createCommandOpts() {
|
|
|
+ Options opts = new Options();
|
|
|
+ opts.addOption(HELP_CMD, false, "Displays help for all commands.");
|
|
|
+ Option appIdOpt =
|
|
|
+ new Option(APPLICATION_ID_OPTION, true, "ApplicationId (required)");
|
|
|
+ appIdOpt.setRequired(true);
|
|
|
+ opts.addOption(appIdOpt);
|
|
|
+ opts.addOption(CONTAINER_ID_OPTION, true, "ContainerId. "
|
|
|
+ + "By default, it will only print syslog if the application is runing."
|
|
|
+ + " Work with -logFiles to get other logs.");
|
|
|
+ opts.addOption(NODE_ADDRESS_OPTION, true, "NodeAddress in the format "
|
|
|
+ + "nodename:port");
|
|
|
+ opts.addOption(APP_OWNER_OPTION, true,
|
|
|
+ "AppOwner (assumed to be current user if not specified)");
|
|
|
+ Option amOption = new Option(AM_CONTAINER_OPTION, true,
|
|
|
+ "Prints the AM Container logs for this application. "
|
|
|
+ + "Specify comma-separated value to get logs for related AM "
|
|
|
+ + "Container. For example, If we specify -am 1,2, we will get "
|
|
|
+ + "the logs for the first AM Container as well as the second "
|
|
|
+ + "AM Container. To get logs for all AM Containers, use -am ALL. "
|
|
|
+ + "To get logs for the latest AM Container, use -am -1. "
|
|
|
+ + "By default, it will only print out syslog. Work with -logFiles "
|
|
|
+ + "to get other logs");
|
|
|
+ amOption.setValueSeparator(',');
|
|
|
+ amOption.setArgs(Option.UNLIMITED_VALUES);
|
|
|
+ amOption.setArgName("AM Containers");
|
|
|
+ opts.addOption(amOption);
|
|
|
+ Option logFileOpt = new Option(CONTAINER_LOG_FILES, true,
|
|
|
+ "Work with -am/-containerId and specify comma-separated value "
|
|
|
+ + "to get specified container log files. Use \"ALL\" to fetch all the "
|
|
|
+ + "log files for the container.");
|
|
|
+ logFileOpt.setValueSeparator(',');
|
|
|
+ logFileOpt.setArgs(Option.UNLIMITED_VALUES);
|
|
|
+ logFileOpt.setArgName("Log File Name");
|
|
|
+ opts.addOption(logFileOpt);
|
|
|
+ opts.addOption(SHOW_META_INFO, false, "Show the log metadata, "
|
|
|
+ + "including log-file names, the size of the log files. "
|
|
|
+ + "You can combine this with --containerId to get log metadata for "
|
|
|
+ + "the specific container, or with --nodeAddress to get log metadata "
|
|
|
+ + "for all the containers on the specific NodeManager. "
|
|
|
+ + "Currently, this option can only be used for finished "
|
|
|
+ + "applications.");
|
|
|
+ opts.addOption(LIST_NODES_OPTION, false,
|
|
|
+ "Show the list of nodes that successfully aggregated logs. "
|
|
|
+ + "This option can only be used with finished applications.");
|
|
|
+ opts.getOption(APPLICATION_ID_OPTION).setArgName("Application ID");
|
|
|
+ opts.getOption(CONTAINER_ID_OPTION).setArgName("Container ID");
|
|
|
+ opts.getOption(NODE_ADDRESS_OPTION).setArgName("Node Address");
|
|
|
+ opts.getOption(APP_OWNER_OPTION).setArgName("Application Owner");
|
|
|
+ opts.getOption(AM_CONTAINER_OPTION).setArgName("AM Containers");
|
|
|
+ return opts;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Options createPrintOpts(Options commandOpts) {
|
|
|
+ Options printOpts = new Options();
|
|
|
+ printOpts.addOption(commandOpts.getOption(HELP_CMD));
|
|
|
+ printOpts.addOption(commandOpts.getOption(CONTAINER_ID_OPTION));
|
|
|
+ printOpts.addOption(commandOpts.getOption(NODE_ADDRESS_OPTION));
|
|
|
+ printOpts.addOption(commandOpts.getOption(APP_OWNER_OPTION));
|
|
|
+ printOpts.addOption(commandOpts.getOption(AM_CONTAINER_OPTION));
|
|
|
+ printOpts.addOption(commandOpts.getOption(CONTAINER_LOG_FILES));
|
|
|
+ printOpts.addOption(commandOpts.getOption(SHOW_META_INFO));
|
|
|
+ printOpts.addOption(commandOpts.getOption(LIST_NODES_OPTION));
|
|
|
+ return printOpts;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<String> parseAMContainer(CommandLine commandLine,
|
|
|
+ Options printOpts) throws NumberFormatException {
|
|
|
+ List<String> amContainersList = new ArrayList<String>();
|
|
|
+ String[] amContainers = commandLine.getOptionValues(AM_CONTAINER_OPTION);
|
|
|
+ for (String am : amContainers) {
|
|
|
+ boolean errorInput = false;
|
|
|
+ if (!am.trim().equalsIgnoreCase("ALL")) {
|
|
|
+ try {
|
|
|
+ int id = Integer.parseInt(am.trim());
|
|
|
+ if (id != -1 && id <= 0) {
|
|
|
+ errorInput = true;
|
|
|
+ }
|
|
|
+ } catch (NumberFormatException ex) {
|
|
|
+ errorInput = true;
|
|
|
+ }
|
|
|
+ if (errorInput) {
|
|
|
+ String errMessage =
|
|
|
+ "Invalid input for option -am. Valid inputs are 'ALL', -1 "
|
|
|
+ + "and any other integer which is larger than 0.";
|
|
|
+ printHelpMessage(printOpts);
|
|
|
+ throw new NumberFormatException(errMessage);
|
|
|
+ }
|
|
|
+ amContainersList.add(am.trim());
|
|
|
+ } else {
|
|
|
+ amContainersList.add("ALL");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return amContainersList;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int fetchAMContainerLogs(String[] logFiles,
|
|
|
+ YarnApplicationState appState, ApplicationId appId,
|
|
|
+ String appOwner, List<String> amContainersList,
|
|
|
+ LogCLIHelpers logCliHelper) throws Exception {
|
|
|
+ // if we do not specify the value for CONTAINER_LOG_FILES option,
|
|
|
+ // we will only output syslog
|
|
|
+ if (logFiles == null || logFiles.length == 0) {
|
|
|
+ logFiles = new String[] {"syslog"};
|
|
|
+ }
|
|
|
+ // If the application is running, we will call the RM WebService
|
|
|
+ // to get the AppAttempts which includes the nodeHttpAddress
|
|
|
+ // and containerId for all the AM Containers.
|
|
|
+ // After that, we will call NodeManager webService to get the
|
|
|
+ // related logs
|
|
|
+ if (appState == YarnApplicationState.ACCEPTED
|
|
|
+ || appState == YarnApplicationState.RUNNING) {
|
|
|
+ return printAMContainerLogs(getConf(), appId.toString(), amContainersList,
|
|
|
+ logFiles, logCliHelper, appOwner, false);
|
|
|
+ } else {
|
|
|
+ // If the application is in the final state, we will call RM webservice
|
|
|
+ // to get all AppAttempts information first. If we get nothing,
|
|
|
+ // we will try to call AHS webservice to get related AppAttempts
|
|
|
+ // which includes nodeAddress for the AM Containers.
|
|
|
+ // After that, we will use nodeAddress and containerId
|
|
|
+ // to get logs from HDFS directly.
|
|
|
+ if (getConf().getBoolean(YarnConfiguration.APPLICATION_HISTORY_ENABLED,
|
|
|
+ YarnConfiguration.DEFAULT_APPLICATION_HISTORY_ENABLED)) {
|
|
|
+ return printAMContainerLogs(getConf(), appId.toString(),
|
|
|
+ amContainersList, logFiles, logCliHelper, appOwner, true);
|
|
|
+ } else {
|
|
|
+ System.err.println("Can not get AMContainers logs for "
|
|
|
+ + "the application:" + appId);
|
|
|
+ System.err.println("This application:" + appId + " is finished."
|
|
|
+ + " Please enable the application history service. Or Using "
|
|
|
+ + "yarn logs -applicationId <appId> -containerId <containerId> "
|
|
|
+ + "--nodeAddress <nodeHttpAddress> to get the container logs");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int fetchContainerLogs(YarnApplicationState appState,
|
|
|
+ boolean appStateObtainedSuccessfully, String[] logFiles,
|
|
|
+ String appOwner, String nodeAddress,
|
|
|
+ ContainerId containerId, LogCLIHelpers logCliHelper) throws IOException {
|
|
|
+ int resultCode = 0;
|
|
|
+ String appIdStr = containerId.getApplicationAttemptId()
|
|
|
+ .getApplicationId().toString();
|
|
|
+ String containerIdStr = containerId.toString();
|
|
|
+ // if we provide the node address and the application is in the final
|
|
|
+ // state, we could directly get logs from HDFS.
|
|
|
+ if (nodeAddress != null && (!appStateObtainedSuccessfully ||
|
|
|
+ isApplicationFinished(appState))) {
|
|
|
+ // if user specified "ALL" as the logFiles param, pass null
|
|
|
+ // to logCliHelper so that it fetches all the logs
|
|
|
+ List<String> logs;
|
|
|
+ if (logFiles == null) {
|
|
|
+ logs = null;
|
|
|
+ } else if (fetchAllLogFiles(logFiles)) {
|
|
|
+ logs = null;
|
|
|
+ } else {
|
|
|
+ logs = Arrays.asList(logFiles);
|
|
|
+ }
|
|
|
+ return logCliHelper.dumpAContainersLogsForALogType(appIdStr,
|
|
|
+ containerIdStr, nodeAddress, appOwner, logs);
|
|
|
+ }
|
|
|
+ String nodeHttpAddress = null;
|
|
|
+ String nodeId = null;
|
|
|
+ try {
|
|
|
+ // If the nodeAddress is not provided, we will try to get
|
|
|
+ // the ContainerReport. In the containerReport, we could get
|
|
|
+ // nodeAddress and nodeHttpAddress
|
|
|
+ ContainerReport report = getContainerReport(containerIdStr);
|
|
|
+ nodeHttpAddress =
|
|
|
+ report.getNodeHttpAddress().replaceFirst(
|
|
|
+ WebAppUtils.getHttpSchemePrefix(getConf()), "");
|
|
|
+ nodeId = report.getAssignedNode().toString();
|
|
|
+ } catch (IOException | YarnException ex) {
|
|
|
+ if (!appStateObtainedSuccessfully || isApplicationFinished(appState)) {
|
|
|
+ String[] requestedLogFiles = logFiles;
|
|
|
+ if(fetchAllLogFiles(logFiles)) {
|
|
|
+ requestedLogFiles = null;
|
|
|
+ }
|
|
|
+ return printContainerLogsForFinishedApplicationWithoutNodeId(
|
|
|
+ appIdStr, containerIdStr, requestedLogFiles, logCliHelper,
|
|
|
+ appOwner);
|
|
|
+ } else if (!isApplicationFinished(appState)) {
|
|
|
+ System.err.println("Unable to get logs for this container:"
|
|
|
+ + containerIdStr + "for the application:" + appIdStr);
|
|
|
+ System.err.println("The application: " + appIdStr
|
|
|
+ + " is still running, and we can not get Container report "
|
|
|
+ + "for the container: " + containerIdStr +". Please try later "
|
|
|
+ + "or after the application finishes.");
|
|
|
+ return -1;
|
|
|
}
|
|
|
}
|
|
|
+ // If the application is not in the final state,
|
|
|
+ // we will provide the NodeHttpAddress and get the container logs
|
|
|
+ // by calling NodeManager webservice.
|
|
|
+ if (!isApplicationFinished(appState)) {
|
|
|
+ if (logFiles == null || logFiles.length == 0) {
|
|
|
+ logFiles = new String[] {"syslog"};
|
|
|
+ }
|
|
|
+ printContainerLogsFromRunningApplication(getConf(), containerId,
|
|
|
+ nodeHttpAddress, nodeId, logFiles, logCliHelper, appOwner);
|
|
|
+ } else {
|
|
|
+ String[] requestedLogFiles = logFiles;
|
|
|
+ if(fetchAllLogFiles(logFiles)) {
|
|
|
+ requestedLogFiles = null;
|
|
|
+ }
|
|
|
+ // If the application is in the final state, we will directly
|
|
|
+ // get the container logs from HDFS.
|
|
|
+ printContainerLogsForFinishedApplication(appIdStr, containerIdStr,
|
|
|
+ nodeId, requestedLogFiles, logCliHelper, appOwner);
|
|
|
+ }
|
|
|
+ return resultCode;
|
|
|
}
|
|
|
|
|
|
private static class AMLogsRequest {
|