001/** 002* Licensed to the Apache Software Foundation (ASF) under one 003* or more contributor license agreements. See the NOTICE file 004* distributed with this work for additional information 005* regarding copyright ownership. The ASF licenses this file 006* to you under the Apache License, Version 2.0 (the 007* "License"); you may not use this file except in compliance 008* with the License. You may obtain a copy of the License at 009* 010* http://www.apache.org/licenses/LICENSE-2.0 011* 012* Unless required by applicable law or agreed to in writing, software 013* distributed under the License is distributed on an "AS IS" BASIS, 014* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015* See the License for the specific language governing permissions and 016* limitations under the License. 017*/ 018 019package org.apache.hadoop.yarn.client.cli; 020 021import java.io.IOException; 022 023import org.apache.commons.cli.CommandLine; 024import org.apache.commons.cli.CommandLineParser; 025import org.apache.commons.cli.GnuParser; 026import org.apache.commons.cli.HelpFormatter; 027import org.apache.commons.cli.Option; 028import org.apache.commons.cli.Options; 029import org.apache.commons.cli.ParseException; 030import org.apache.hadoop.classification.InterfaceAudience.Public; 031import org.apache.hadoop.classification.InterfaceStability.Evolving; 032import org.apache.hadoop.conf.Configuration; 033import org.apache.hadoop.conf.Configured; 034import org.apache.hadoop.security.UserGroupInformation; 035import org.apache.hadoop.util.Tool; 036import org.apache.hadoop.yarn.api.records.ApplicationId; 037import org.apache.hadoop.yarn.api.records.ApplicationReport; 038import org.apache.hadoop.yarn.client.api.YarnClient; 039import org.apache.hadoop.yarn.conf.YarnConfiguration; 040import org.apache.hadoop.yarn.exceptions.YarnException; 041import org.apache.hadoop.yarn.logaggregation.LogCLIHelpers; 042import org.apache.hadoop.yarn.util.ConverterUtils; 043 044import com.google.common.annotations.VisibleForTesting; 045 046@Public 047@Evolving 048public class LogsCLI extends Configured implements Tool { 049 050 private static final String CONTAINER_ID_OPTION = "containerId"; 051 private static final String APPLICATION_ID_OPTION = "applicationId"; 052 private static final String NODE_ADDRESS_OPTION = "nodeAddress"; 053 private static final String APP_OWNER_OPTION = "appOwner"; 054 public static final String HELP_CMD = "help"; 055 056 @Override 057 public int run(String[] args) throws Exception { 058 059 Options opts = new Options(); 060 opts.addOption(HELP_CMD, false, "Displays help for all commands."); 061 Option appIdOpt = 062 new Option(APPLICATION_ID_OPTION, true, "ApplicationId (required)"); 063 appIdOpt.setRequired(true); 064 opts.addOption(appIdOpt); 065 opts.addOption(CONTAINER_ID_OPTION, true, 066 "ContainerId (must be specified if node address is specified)"); 067 opts.addOption(NODE_ADDRESS_OPTION, true, "NodeAddress in the format " 068 + "nodename:port (must be specified if container id is specified)"); 069 opts.addOption(APP_OWNER_OPTION, true, 070 "AppOwner (assumed to be current user if not specified)"); 071 opts.getOption(APPLICATION_ID_OPTION).setArgName("Application ID"); 072 opts.getOption(CONTAINER_ID_OPTION).setArgName("Container ID"); 073 opts.getOption(NODE_ADDRESS_OPTION).setArgName("Node Address"); 074 opts.getOption(APP_OWNER_OPTION).setArgName("Application Owner"); 075 076 Options printOpts = new Options(); 077 printOpts.addOption(opts.getOption(HELP_CMD)); 078 printOpts.addOption(opts.getOption(CONTAINER_ID_OPTION)); 079 printOpts.addOption(opts.getOption(NODE_ADDRESS_OPTION)); 080 printOpts.addOption(opts.getOption(APP_OWNER_OPTION)); 081 082 if (args.length < 1) { 083 printHelpMessage(printOpts); 084 return -1; 085 } 086 if (args[0].equals("-help")) { 087 printHelpMessage(printOpts); 088 return 0; 089 } 090 CommandLineParser parser = new GnuParser(); 091 String appIdStr = null; 092 String containerIdStr = null; 093 String nodeAddress = null; 094 String appOwner = null; 095 try { 096 CommandLine commandLine = parser.parse(opts, args, true); 097 appIdStr = commandLine.getOptionValue(APPLICATION_ID_OPTION); 098 containerIdStr = commandLine.getOptionValue(CONTAINER_ID_OPTION); 099 nodeAddress = commandLine.getOptionValue(NODE_ADDRESS_OPTION); 100 appOwner = commandLine.getOptionValue(APP_OWNER_OPTION); 101 } catch (ParseException e) { 102 System.err.println("options parsing failed: " + e.getMessage()); 103 printHelpMessage(printOpts); 104 return -1; 105 } 106 107 if (appIdStr == null) { 108 System.err.println("ApplicationId cannot be null!"); 109 printHelpMessage(printOpts); 110 return -1; 111 } 112 113 ApplicationId appId = null; 114 try { 115 appId = ConverterUtils.toApplicationId(appIdStr); 116 } catch (Exception e) { 117 System.err.println("Invalid ApplicationId specified"); 118 return -1; 119 } 120 121 try { 122 int resultCode = verifyApplicationState(appId); 123 if (resultCode != 0) { 124 System.out.println("Logs are not avaiable right now."); 125 return resultCode; 126 } 127 } catch (Exception e) { 128 System.err.println("Unable to get ApplicationState." 129 + " Attempting to fetch logs directly from the filesystem."); 130 } 131 132 LogCLIHelpers logCliHelper = new LogCLIHelpers(); 133 logCliHelper.setConf(getConf()); 134 135 if (appOwner == null || appOwner.isEmpty()) { 136 appOwner = UserGroupInformation.getCurrentUser().getShortUserName(); 137 } 138 int resultCode = 0; 139 if (containerIdStr == null && nodeAddress == null) { 140 resultCode = logCliHelper.dumpAllContainersLogs(appId, appOwner, System.out); 141 } else if ((containerIdStr == null && nodeAddress != null) 142 || (containerIdStr != null && nodeAddress == null)) { 143 System.out.println("ContainerId or NodeAddress cannot be null!"); 144 printHelpMessage(printOpts); 145 resultCode = -1; 146 } else { 147 resultCode = 148 logCliHelper.dumpAContainersLogs(appIdStr, containerIdStr, 149 nodeAddress, appOwner); 150 } 151 152 return resultCode; 153 } 154 155 private int verifyApplicationState(ApplicationId appId) throws IOException, 156 YarnException { 157 YarnClient yarnClient = createYarnClient(); 158 159 try { 160 ApplicationReport appReport = yarnClient.getApplicationReport(appId); 161 switch (appReport.getYarnApplicationState()) { 162 case NEW: 163 case NEW_SAVING: 164 case SUBMITTED: 165 return -1; 166 case ACCEPTED: 167 case RUNNING: 168 case FAILED: 169 case FINISHED: 170 case KILLED: 171 default: 172 break; 173 174 } 175 } finally { 176 yarnClient.close(); 177 } 178 return 0; 179 } 180 181 @VisibleForTesting 182 protected YarnClient createYarnClient() { 183 YarnClient yarnClient = YarnClient.createYarnClient(); 184 yarnClient.init(getConf()); 185 yarnClient.start(); 186 return yarnClient; 187 } 188 189 public static void main(String[] args) throws Exception { 190 Configuration conf = new YarnConfiguration(); 191 LogsCLI logDumper = new LogsCLI(); 192 logDumper.setConf(conf); 193 int exitCode = logDumper.run(args); 194 System.exit(exitCode); 195 } 196 197 private void printHelpMessage(Options options) { 198 System.out.println("Retrieve logs for completed YARN applications."); 199 HelpFormatter formatter = new HelpFormatter(); 200 formatter.printHelp("yarn logs -applicationId <application ID> [OPTIONS]", new Options()); 201 formatter.setSyntaxPrefix(""); 202 formatter.printHelp("general options are:", options); 203 } 204}