YARN-4966. Improve yarn logs to fetch container logs without specifying nodeId. Contributed by Xuan Gong.
(cherry picked from commit 66b07d8374
)
This commit is contained in:
parent
9d3ddb0b4d
commit
cf3e93ee73
|
@ -212,6 +212,7 @@ public class LogsCLI extends Configured implements Tool {
|
||||||
appOwner = UserGroupInformation.getCurrentUser().getShortUserName();
|
appOwner = UserGroupInformation.getCurrentUser().getShortUserName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean appStateKnown = true;
|
||||||
YarnApplicationState appState = YarnApplicationState.NEW;
|
YarnApplicationState appState = YarnApplicationState.NEW;
|
||||||
try {
|
try {
|
||||||
appState = getApplicationState(appId);
|
appState = getApplicationState(appId);
|
||||||
|
@ -222,6 +223,7 @@ public class LogsCLI extends Configured implements Tool {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} catch (IOException | YarnException e) {
|
} catch (IOException | YarnException e) {
|
||||||
|
appStateKnown = false;
|
||||||
System.err.println("Unable to get ApplicationState."
|
System.err.println("Unable to get ApplicationState."
|
||||||
+ " Attempting to fetch logs directly from the filesystem.");
|
+ " Attempting to fetch logs directly from the filesystem.");
|
||||||
}
|
}
|
||||||
|
@ -270,7 +272,8 @@ public class LogsCLI extends Configured implements Tool {
|
||||||
if (containerIdStr != null) {
|
if (containerIdStr != null) {
|
||||||
// if we provide the node address and the application is in the final
|
// if we provide the node address and the application is in the final
|
||||||
// state, we could directly get logs from HDFS.
|
// state, we could directly get logs from HDFS.
|
||||||
if (nodeAddress != null && isApplicationFinished(appState)) {
|
if (nodeAddress != null && (!appStateKnown ||
|
||||||
|
isApplicationFinished(appState))) {
|
||||||
// if user specified "ALL" as the logFiles param, pass null
|
// if user specified "ALL" as the logFiles param, pass null
|
||||||
// to logCliHelper so that it fetches all the logs
|
// to logCliHelper so that it fetches all the logs
|
||||||
List<String> logs;
|
List<String> logs;
|
||||||
|
@ -284,48 +287,57 @@ public class LogsCLI extends Configured implements Tool {
|
||||||
return logCliHelper.dumpAContainersLogsForALogType(appIdStr,
|
return logCliHelper.dumpAContainersLogsForALogType(appIdStr,
|
||||||
containerIdStr, nodeAddress, appOwner, logs);
|
containerIdStr, nodeAddress, appOwner, logs);
|
||||||
}
|
}
|
||||||
|
String nodeHttpAddress = null;
|
||||||
|
String nodeId = null;
|
||||||
try {
|
try {
|
||||||
// If the nodeAddress is not provided, we will try to get
|
// If the nodeAddress is not provided, we will try to get
|
||||||
// the ContainerReport. In the containerReport, we could get
|
// the ContainerReport. In the containerReport, we could get
|
||||||
// nodeAddress and nodeHttpAddress
|
// nodeAddress and nodeHttpAddress
|
||||||
ContainerReport report = getContainerReport(containerIdStr);
|
ContainerReport report = getContainerReport(containerIdStr);
|
||||||
String nodeHttpAddress =
|
nodeHttpAddress =
|
||||||
report.getNodeHttpAddress().replaceFirst(
|
report.getNodeHttpAddress().replaceFirst(
|
||||||
WebAppUtils.getHttpSchemePrefix(getConf()), "");
|
WebAppUtils.getHttpSchemePrefix(getConf()), "");
|
||||||
String nodeId = report.getAssignedNode().toString();
|
nodeId = report.getAssignedNode().toString();
|
||||||
// If the application is not in the final state,
|
} catch (IOException | YarnException ex) {
|
||||||
// we will provide the NodeHttpAddress and get the container logs
|
if (!appStateKnown || isApplicationFinished(appState)) {
|
||||||
// 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;
|
String [] requestedLogFiles = logFiles;
|
||||||
if(fetchAllLogFiles(logFiles)) {
|
if(fetchAllLogFiles(logFiles)) {
|
||||||
requestedLogFiles = null;
|
requestedLogFiles = null;
|
||||||
}
|
}
|
||||||
// If the application is in the final state, we will directly
|
return printContainerLogsForFinishedApplicationWithoutNodeId(
|
||||||
// get the container logs from HDFS.
|
appIdStr, containerIdStr, requestedLogFiles, logCliHelper,
|
||||||
printContainerLogsForFinishedApplication(appIdStr, containerIdStr,
|
appOwner);
|
||||||
nodeId, 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;
|
||||||
}
|
}
|
||||||
return resultCode;
|
|
||||||
} catch (IOException | YarnException ex) {
|
|
||||||
System.err.println("Unable to get logs for this container:"
|
|
||||||
+ containerIdStr + "for the application:" + appId);
|
|
||||||
if (!getConf().getBoolean(YarnConfiguration.APPLICATION_HISTORY_ENABLED,
|
|
||||||
YarnConfiguration.DEFAULT_APPLICATION_HISTORY_ENABLED)) {
|
|
||||||
System.out.println("Please enable the application history service. Or ");
|
|
||||||
}
|
|
||||||
System.out.println("Using "
|
|
||||||
+ "yarn logs -applicationId <appId> -containerId <containerId> "
|
|
||||||
+ "--nodeAddress <nodeHttpAddress> to get the container logs");
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
return resultCode;
|
||||||
} else {
|
} else {
|
||||||
if (nodeAddress == null) {
|
if (nodeAddress == null) {
|
||||||
resultCode =
|
resultCode =
|
||||||
|
@ -506,7 +518,7 @@ public class LogsCLI extends Configured implements Tool {
|
||||||
}
|
}
|
||||||
// for the case, we have already uploaded partial logs in HDFS
|
// for the case, we have already uploaded partial logs in HDFS
|
||||||
logCliHelper.dumpAContainersLogsForALogType(appId, containerIdStr, nodeId,
|
logCliHelper.dumpAContainersLogsForALogType(appId, containerIdStr, nodeId,
|
||||||
appOwner, Arrays.asList(requestedLogFiles));
|
appOwner, Arrays.asList(requestedLogFiles), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printContainerLogsForFinishedApplication(String appId,
|
private void printContainerLogsForFinishedApplication(String appId,
|
||||||
|
@ -519,6 +531,17 @@ public class LogsCLI extends Configured implements Tool {
|
||||||
nodeAddress, appOwner, logFiles != null ? Arrays.asList(logFiles) : null);
|
nodeAddress, appOwner, logFiles != null ? Arrays.asList(logFiles) : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int printContainerLogsForFinishedApplicationWithoutNodeId(
|
||||||
|
String appId, String containerId, String[] logFiles,
|
||||||
|
LogCLIHelpers logCliHelper, String appOwner) throws IOException {
|
||||||
|
String containerString = "\n\nContainer: " + containerId;
|
||||||
|
System.out.println(containerString);
|
||||||
|
System.out.println(StringUtils.repeat("=", containerString.length()));
|
||||||
|
return logCliHelper.dumpAContainersLogsForALogTypeWithoutNodeId(appId,
|
||||||
|
containerId, appOwner, logFiles != null ?
|
||||||
|
Arrays.asList(logFiles) : null);
|
||||||
|
}
|
||||||
|
|
||||||
private ContainerReport getContainerReport(String containerIdStr)
|
private ContainerReport getContainerReport(String containerIdStr)
|
||||||
throws YarnException, IOException {
|
throws YarnException, IOException {
|
||||||
YarnClient yarnClient = createYarnClient();
|
YarnClient yarnClient = createYarnClient();
|
||||||
|
|
|
@ -317,6 +317,21 @@ public class TestLogsCLI {
|
||||||
"Hello container_0_0001_01_000003 in syslog!"));
|
"Hello container_0_0001_01_000003 in syslog!"));
|
||||||
sysOutStream.reset();
|
sysOutStream.reset();
|
||||||
|
|
||||||
|
YarnClient mockYarnClientWithException =
|
||||||
|
createMockYarnClientWithException();
|
||||||
|
cli = new LogsCLIForTest(mockYarnClientWithException);
|
||||||
|
cli.setConf(configuration);
|
||||||
|
|
||||||
|
exitCode =
|
||||||
|
cli.run(new String[] { "-applicationId", appId.toString(),
|
||||||
|
"-containerId", containerId3.toString() });
|
||||||
|
assertTrue(exitCode == 0);
|
||||||
|
assertTrue(sysOutStream.toString().contains(
|
||||||
|
"Hello container_0_0001_01_000003 in syslog!"));
|
||||||
|
assertTrue(sysOutStream.toString().contains(
|
||||||
|
"Hello container_0_0001_01_000003 in stdout!"));
|
||||||
|
sysOutStream.reset();
|
||||||
|
|
||||||
fs.delete(new Path(remoteLogRootDir), true);
|
fs.delete(new Path(remoteLogRootDir), true);
|
||||||
fs.delete(new Path(rootLogDir), true);
|
fs.delete(new Path(rootLogDir), true);
|
||||||
}
|
}
|
||||||
|
@ -439,6 +454,16 @@ public class TestLogsCLI {
|
||||||
return mockClient;
|
return mockClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private YarnClient createMockYarnClientWithException()
|
||||||
|
throws YarnException, IOException {
|
||||||
|
YarnClient mockClient = mock(YarnClient.class);
|
||||||
|
doThrow(new YarnException()).when(mockClient).getApplicationReport(
|
||||||
|
any(ApplicationId.class));
|
||||||
|
doThrow(new YarnException()).when(mockClient).getContainerReport(
|
||||||
|
any(ContainerId.class));
|
||||||
|
return mockClient;
|
||||||
|
}
|
||||||
|
|
||||||
private YarnClient createMockYarnClientUnknownApp() throws YarnException,
|
private YarnClient createMockYarnClientUnknownApp() throws YarnException,
|
||||||
IOException {
|
IOException {
|
||||||
YarnClient mockClient = mock(YarnClient.class);
|
YarnClient mockClient = mock(YarnClient.class);
|
||||||
|
|
|
@ -57,7 +57,17 @@ public class LogCLIHelpers implements Configurable {
|
||||||
@Private
|
@Private
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public int dumpAContainersLogsForALogType(String appId, String containerId,
|
public int dumpAContainersLogsForALogType(String appId, String containerId,
|
||||||
String nodeId, String jobOwner, List<String> logType) throws IOException {
|
String nodeId, String jobOwner, List<String> logType)
|
||||||
|
throws IOException {
|
||||||
|
return dumpAContainersLogsForALogType(appId, containerId, nodeId, jobOwner,
|
||||||
|
logType, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Private
|
||||||
|
@VisibleForTesting
|
||||||
|
public int dumpAContainersLogsForALogType(String appId, String containerId,
|
||||||
|
String nodeId, String jobOwner, List<String> logType,
|
||||||
|
boolean outputFailure) throws IOException {
|
||||||
Path remoteRootLogDir = new Path(getConf().get(
|
Path remoteRootLogDir = new Path(getConf().get(
|
||||||
YarnConfiguration.NM_REMOTE_APP_LOG_DIR,
|
YarnConfiguration.NM_REMOTE_APP_LOG_DIR,
|
||||||
YarnConfiguration.DEFAULT_NM_REMOTE_APP_LOG_DIR));
|
YarnConfiguration.DEFAULT_NM_REMOTE_APP_LOG_DIR));
|
||||||
|
@ -113,13 +123,70 @@ public class LogCLIHelpers implements Configurable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!foundContainerLogs) {
|
if (!foundContainerLogs && outputFailure) {
|
||||||
containerLogNotFound(containerId);
|
containerLogNotFound(containerId);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Private
|
||||||
|
public int dumpAContainersLogsForALogTypeWithoutNodeId(String appId,
|
||||||
|
String containerId, String jobOwner, List<String> logType)
|
||||||
|
throws IOException {
|
||||||
|
Path remoteRootLogDir = new Path(getConf().get(
|
||||||
|
YarnConfiguration.NM_REMOTE_APP_LOG_DIR,
|
||||||
|
YarnConfiguration.DEFAULT_NM_REMOTE_APP_LOG_DIR));
|
||||||
|
ApplicationId applicationId = ConverterUtils.toApplicationId(appId);
|
||||||
|
String user = jobOwner;
|
||||||
|
String logDirSuffix = LogAggregationUtils.getRemoteNodeLogDirSuffix(
|
||||||
|
getConf());
|
||||||
|
Path remoteAppLogDir = LogAggregationUtils.getRemoteAppLogDir(
|
||||||
|
remoteRootLogDir, applicationId, user, logDirSuffix);
|
||||||
|
RemoteIterator<FileStatus> nodeFiles;
|
||||||
|
try {
|
||||||
|
Path qualifiedLogDir =
|
||||||
|
FileContext.getFileContext(getConf()).makeQualified(remoteAppLogDir);
|
||||||
|
nodeFiles = FileContext.getFileContext(qualifiedLogDir.toUri(),
|
||||||
|
getConf()).listStatus(remoteAppLogDir);
|
||||||
|
} catch (FileNotFoundException fnf) {
|
||||||
|
logDirNotExist(remoteAppLogDir.toString());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
boolean foundContainerLogs = false;
|
||||||
|
while(nodeFiles.hasNext()) {
|
||||||
|
FileStatus thisNodeFile = nodeFiles.next();
|
||||||
|
if (!thisNodeFile.getPath().getName().endsWith(
|
||||||
|
LogAggregationUtils.TMP_FILE_SUFFIX)) {
|
||||||
|
AggregatedLogFormat.LogReader reader = null;
|
||||||
|
try {
|
||||||
|
reader =
|
||||||
|
new AggregatedLogFormat.LogReader(getConf(),
|
||||||
|
thisNodeFile.getPath());
|
||||||
|
if (logType == null) {
|
||||||
|
if (dumpAContainerLogs(containerId, reader, System.out,
|
||||||
|
thisNodeFile.getModificationTime()) > -1) {
|
||||||
|
foundContainerLogs = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dumpAContainerLogsForALogType(containerId, reader, System.out,
|
||||||
|
thisNodeFile.getModificationTime(), logType) > -1) {
|
||||||
|
foundContainerLogs = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (reader != null) {
|
||||||
|
reader.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundContainerLogs) {
|
||||||
|
containerLogNotFound(containerId);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@Private
|
@Private
|
||||||
public int dumpAContainerLogs(String containerIdStr,
|
public int dumpAContainerLogs(String containerIdStr,
|
||||||
AggregatedLogFormat.LogReader reader, PrintStream out,
|
AggregatedLogFormat.LogReader reader, PrintStream out,
|
||||||
|
|
Loading…
Reference in New Issue