blob: aef90717f822d166aea3462cc271c1f5b6521763 [file] [log] [blame]
package com.pivotal.gemfire.sendlogs.driver;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import com.pivotal.gemfire.sendlogs.remote.RemoteCommands;
import com.pivotal.gemfire.sendlogs.remote.RemoteHost;
import com.pivotal.gemfire.sendlogs.utilities.CompressArtifacts;
import com.pivotal.gemfire.sendlogs.utilities.FileSystem;
import com.pivotal.gemfire.sendlogs.utilities.SendlogsExceptionHandler;
/**
* This class handles the actual collection of logs from GemFire hosts. There
* should be one instance of this class per GemFire host.
*
* @author ablakema
*/
public class GemFireHost {
private final RemoteHost rh;
private final String workingDir;
private final RemoteCommands rc;
private final String hostname;
private final CompressArtifacts zipFile;
private ArrayList<String> missedDirs = new ArrayList<String>();
private boolean haveFilesBeenCollected = false;
private static final Logger logger = Logger.getLogger(GemFireHost.class.getName());
/**
* Sets up the required environment to perform operations on a remote host
* and collect files.
*
* @param rh {@link com.pivotal.gemfire.sendlogs.remote.RemoteHost} object for remote host actions.
* @param topLevelDir Top level working directory
* @param zipFile {@link com.pivotal.gemfire.sendlogs.utilities.CompressArtifacts} to add copied files to.
*/
public GemFireHost(RemoteHost rh, String topLevelDir, CompressArtifacts zipFile) {
this.rh = rh;
this.zipFile = zipFile;
this.hostname = rh.getHostname();
workingDir = String.format("%s/%s", topLevelDir, hostname);
rc = new RemoteCommands(rh);
createWorkingDirectory(workingDir);
}
/**
* Does all of the actual work for this class. SCP's log files,
* and adds each file to the zip file.
*
* This *could* probably be written to redirect the SCPInputStream directly to the ZipFile.
*
*/
public void findAndRetrieveLogs() {
ArrayList<String> pidsFromHost = rc.getGemFirePids();
/* Verify that we have some PIDs to work with */
if (pidsFromHost == null || pidsFromHost.isEmpty()) return;
for (String pid : pidsFromHost) {
dumpStacksToFile(pid);
collectLogFilesFromPidAndWriteToZip(pid);
}
}
/**
* @return An ArrayList containing directories that either didn't exist or
* directories in which we didn't find any files we are interested in.
*/
public ArrayList<String> getMissedDirectories() {
return missedDirs;
}
/**
* Retrieve files from the specified directory
*/
public void retrieveLogs(HashSet<String> directories) {
for (String dirName: directories) {
collectLogFilesFromDirAndWriteToZip(dirName);
}
}
/**
* @return True if log files have been found and collected.
*/
public boolean haveFilesBeenCollected() {
return haveFilesBeenCollected;
}
/**
* Close the SSH connection to the remote host.
*/
public void close() {
rh.closeConnection();
}
/**
* Copy the log files from the remote host and then add them to the zip file.
* @param pid PID of the GemFire process.
*/
private void collectLogFilesFromPidAndWriteToZip(String pid) {
String workingDirForPid = workingDir + "/" + pid;
createWorkingDirectory(workingDirForPid);
HashSet<String> logFileNames = rc.getLogFileNamesFromPid(pid);
if (logFileNames != null && !logFileNames.isEmpty()) {
for (String logFile : logFileNames){
File remoteFile = new File(logFile);
String localFilename = workingDirForPid + "/" + remoteFile.getName();
rh.getRemoteFile(remoteFile.getAbsolutePath(), workingDirForPid);
zipFile.addFileToZip(localFilename, hostname + "/" + pid );
/* TODO: This hasn't actually verified that the above methods were successful */
haveFilesBeenCollected = true;
}
}
}
/**
* Copy the log files from the remote host and then add them to the zip file.
* @param baseDirectory Base working directory for log copies and such.
*/
private void collectLogFilesFromDirAndWriteToZip(String baseDirectory) {
boolean foundLogsInThisDir = false;
String workingDirForBaseDir = workingDir + "/" + baseDirectory;
createWorkingDirectory(workingDirForBaseDir);
logger.debug("Working directory for " + hostname + " " + workingDirForBaseDir);
HashSet<String> logFileNames = rc.getLogFileNamesFromDirectory(baseDirectory);
if (logFileNames != null && !logFileNames.isEmpty()) {
for (String logFile : logFileNames){
File lf = new File(logFile);
logger.debug("Trying to get " + logFile + " from " + hostname);
rh.getRemoteFile(logFile, workingDirForBaseDir);
logger.debug("Trying to zip: " + workingDirForBaseDir + "/" + lf.getName());
zipFile.addFileToZip(workingDirForBaseDir + "/" + lf.getName(), hostname + "/" + lf.getParent());
/* TODO: This hasn't actually verified that the above methods were successful */
haveFilesBeenCollected = true;
foundLogsInThisDir = true;
}
}
if (Boolean.FALSE.equals(foundLogsInThisDir)) {
missedDirs.add(baseDirectory);
}
}
/**
* Writes the stack of a given PID to a file. Filename is in the format pid.stack
* @param pid PID of the GemFire process.
*/
private void dumpStacksToFile(String pid) {
String stackFileName = workingDir + "/" + pid + ".stack";
File stackFile = new File(stackFileName);
try {
FileUtils.writeStringToFile(stackFile, rc.getStackTrace(pid));
zipFile.addFileToZip(stackFile.getAbsolutePath(), hostname);
/* TODO: This hasn't actually verified that the above methods were successful */
haveFilesBeenCollected = true;
} catch (IOException e) {
SendlogsExceptionHandler.handleException(e);
}
}
/**
* Creates a working directory for this host. The base level working directory is
* related to the hostname of the server. Additional directories for each PID are then
* created. This is is all relative to the working directory defined in {@link Driver}
*/
private void createWorkingDirectory(String dirName) {
FileSystem.createDirectory(dirName);
}
}