blob: 95517085dcca86881bd040af0f4d2143002e85d2 [file] [log] [blame]
package com.pivotal.gemfire.sendlogs.remote;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import org.apache.log4j.Logger;
/**
*
* This relies on the {@link RemoteHost} class to do the actual work.
*
* @author ablakeman
*
*/
public class RemoteCommands {
private final RemoteHost rh;
private static final Logger logger = Logger.getLogger(RemoteCommands.class.getName());
public RemoteCommands(RemoteHost rh) {
this.rh = rh;
}
/**
* @return List of all pids matching a subset of package names.
*/
public ArrayList<String> getGemFirePids() {
ArrayList<String> pids = new ArrayList<String>();
String[] output = rh.executeCommand("jps -l").split("\n");
for (String line : output) {
if (line.contains("com.vmware") || line.contains("com.gemstone") || line.contains("com.pivotal")
|| line.contains("io.pivotal") || line.contains("gemfire") || line.contains("com.gopivotal")) {
if (!(line.contains("com.pivotal.gemfire.sendlogs")
|| line.contains("io.pivotal.gemfire.sendlogs")) ) {
String foundGfePid = line.split("\\s+")[0];
logger.info("Found gemfire pid: " + foundGfePid);
pids.add(foundGfePid);
}
}
}
getGemFirePidsFromProcessTable(pids);
return pids.isEmpty() ? null : pids;
}
/**
* Try to find possible GemFire processes using the ps command
* looks for gemfire.jar and classpath in output of ps.
*
* @param pids
*/
protected void getGemFirePidsFromProcessTable(ArrayList<String> pids){
//Looking for possible PID's via the process classpath that contain gemfire.jar
//We should consider making this optional since many add everything including
//the kitchen sink to the classpath even when not required
String[] output;
output=rh.executeCommand("ps -fa | grep java").split("\n");
for (String line : output){
if ( line.contains("classpath") && line.contains("gemfire.jar") ){
if(!(line.contains("com.pivotal.gemfire.sendlogs")||
line.contains("io.pivotal.gemfire.sendlogs"))){
String foundGfePid = line.split("\\s+")[1];
if(!pids.contains(foundGfePid)){
pids.add(foundGfePid);
logger.info("Found gemfire pid: " + foundGfePid);
}
}
}
}
}
/**
* @param pid PID of GemFire process.
* @return String containing the entire stack trace. This is newline delimited.
*/
public String getStackTrace(String pid) {
return rh.executeCommand("jstack -l " + pid);
}
/**
* Get all of the log files associated with the remote PID. This first reads /proc/$PID/fd.
* From there it will look for base directories of files open from /proc/$PID/fd and then
* look for valid logs in each of the directories found in this manner.
* @param pid PID of GemFire process.
* @return A HashSet containing the full filenames of all found logs or null if nothing was found.
*/
public HashSet<String> getLogFileNamesFromPid(String pid) {
HashSet<String> allFiles = new HashSet<String>();
HashSet<String> filesFromLs = new HashSet<String>();
/* First get files with open file descriptors */
String[] linesFromRemoteFdFolder = rh.executeCommand(String.format("ls -l /proc/%s/fd", pid)).split("\n");
if (linesFromRemoteFdFolder.length > 0) {
for (String s : linesFromRemoteFdFolder) {
/* TODO: Figure out a better way to do this */
if (checkFileType(s)) {
String[] lsOutputSplit = s.split("\\s+");
String filename = lsOutputSplit[lsOutputSplit.length -1];
filesFromLs.add(filename);
allFiles.add(filename);
}
}
/* Then check the directories that those files were in for other logs */
for (String extraLogFile : getlogFilesFromFdOutput(filesFromLs)) {
allFiles.add(extraLogFile);
}
}
return allFiles.isEmpty() ? null : allFiles;
}
/**
* This method should be re-written to provide the functionality of
* {@link com.pivotal.gemfire.sendlogs.remote.RemoteCommands#getLogFileNamesFromPid(String)}. Given the a base
* directory name return a HashSet<String> of files that we're interested in collecting.
* @param dirName Directory name in which to look for interesting log files.
* @return HashSet<String> that includes all of the files that were matched in {@link com.pivotal.gemfire.sendlogs.remote.RemoteCommands#checkFileType}
*/
public HashSet<String> getLogFileNamesFromDirectory(String dirName) {
HashSet<String> allFiles = new HashSet<String>();
String[] dirContents = rh.executeCommand(String.format("ls -1 " + dirName)).split("\n");
if (dirContents.length > 0) {
for (String filename : dirContents) {
if (checkFileType(filename)) {
allFiles.add(dirName + "/" + filename);
}
}
}
return allFiles.isEmpty() ? null : allFiles;
}
/**
* Based on the extension of the file, determine whether or not it should be collected to send to support.
* @param fullPath Full path of file to determine whether or not this is an interesting file that should be
* collected.
* @return True if the file is of an interesting type to support.
*/
public boolean checkFileType(String fullPath) {
return fullPath.toLowerCase().endsWith(".log")
|| fullPath.toLowerCase().endsWith(".err")
|| fullPath.toLowerCase().endsWith(".cfg")
|| fullPath.toLowerCase().endsWith(".gfs")
|| fullPath.toLowerCase().endsWith(".stack")
|| fullPath.toLowerCase().endsWith(".xml")
|| fullPath.toLowerCase().endsWith(".properties")
|| fullPath.toLowerCase().endsWith(".txt");
}
/**
* @param fullFileName Complete filename of a file including it's path. EG. /export/foo/bar/test.txt
* @return String containing the base path of the file passed in. EG. passing in /export/foo/bar/baz/test.txt
* will return /export/foo/bar/baz
*/
public String getBaseDir(String fullFileName) {
File f = new File(fullFileName);
return f.getParent();
}
/**
* Used by {@link com.pivotal.gemfire.sendlogs.remote.RemoteCommands#getLogFileNamesFromPid} to get log files (and
* anything else defined by {@link com.pivotal.gemfire.sendlogs.remote.RemoteCommands#checkFileType})
*
* @param filesFromLs Files from the LS output of the 'fd' folder for a given PID. This takes that 'ls' outpoint which
* will have a symlink to the original log folder and gets the base directory name from that
* symlink.
* @return HashSet containing a list of all of the files found that aren't currently open but are in a "log" directory.
*/
private HashSet<String> getlogFilesFromFdOutput(HashSet<String> filesFromLs) {
HashSet<String> nonOpenLogs = new HashSet<String>();
if (!filesFromLs.isEmpty()) {
for (String fullFileName : filesFromLs) {
String baseDirOfFile = getBaseDir(fullFileName);
String[] linesFromRemoteFdFolder = rh.executeCommand("ls " + baseDirOfFile).split("\n");
for (String line: linesFromRemoteFdFolder) {
if (checkFileType(line)) {
/* the LS returns just the filename so re-append the full PATH to the file */
nonOpenLogs.add(baseDirOfFile + "/"+ line);
}
}
}
}
return nonOpenLogs;
}
}