package water.util;
import water.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* Get zipped log directory data from a node.
* The intent here is to return a binary blob with the data for saving as a file.
* This is used as part of the "/3/Logs/download" REST API.
*/
public class GetLogsFromNode extends Iced {
static final int MB = 1 << 20;
static final int MAX_SIZE = 25 * MB;
// Input
/**
* Node number to get logs from (starting at 0).
*/
public int nodeidx;
// Output
/**
* Byte array containing a zipped file with the entire log directory.
*/
public byte[] bytes;
/**
* Do the work.
*/
public void doIt() {
if (nodeidx == -1) {
GetLogsTask t = new GetLogsTask();
t.doIt();
bytes = t._bytes;
}
else {
H2ONode node = H2O.CLOUD._memary[nodeidx];
GetLogsTask t = new GetLogsTask();
Log.trace("GetLogsTask starting to node " + nodeidx + "...");
// Synchronous RPC call to get ticks from remote (possibly this) node.
new RPC<>(node, t).call().get();
Log.trace("GetLogsTask completed to node " + nodeidx);
bytes = t._bytes;
}
}
private static class GetLogsTask extends DTask<GetLogsTask> {
private byte[] _bytes;
public GetLogsTask() { super(H2O.MIN_HI_PRIORITY); _bytes = null; }
public void doIt() {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
zipDir(Log.LOG_DIR, baos, zos);
zos.close();
baos.close();
_bytes = baos.toByteArray();
}
catch (Exception e) {
_bytes = StringUtils.toBytes(e);
}
}
@Override public void compute2() {
doIt();
tryComplete();
}
//here is the code for the method
private void zipDir(String dir2zip, ByteArrayOutputStream baos, ZipOutputStream zos) throws IOException
{
try
{
//create a new File object based on the directory we have to zip.
File zipDir = new File(dir2zip);
//get a listing of the directory content
String[] dirList = zipDir.list();
byte[] readBuffer = new byte[4096];
int bytesIn = 0;
//loop through dirList, and zip the files
for(int i=0; i<dirList.length; i++)
{
File f = new File(zipDir, dirList[i]);
if(f.isDirectory())
{
//if the File object is a directory, call this
//function again to add its content recursively
String filePath = f.getPath();
zipDir(filePath, baos, zos);
//loop again
continue;
}
// In the Sparkling Water case, when running in the local-cluster configuration,
// there are jar files in the log directory too. Ignore them.
if (f.toString().endsWith(".jar")) {
continue;
}
//if we reached here, the File object f was not a directory
//create a FileInputStream on top of f
FileInputStream fis = new FileInputStream(f);
// create a new zip entry
ZipEntry anEntry = new ZipEntry(f.getPath());
anEntry.setTime(f.lastModified());
//place the zip entry in the ZipOutputStream object
zos.putNextEntry(anEntry);
//now write the content of the file to the ZipOutputStream
boolean stopEarlyBecauseTooMuchData = false;
while((bytesIn = fis.read(readBuffer)) != -1)
{
zos.write(readBuffer, 0, bytesIn);
if (baos.size() > MAX_SIZE) {
stopEarlyBecauseTooMuchData = true;
break;
}
}
//close the Stream
fis.close();
zos.closeEntry();
if (stopEarlyBecauseTooMuchData) {
Log.warn("GetLogsTask stopEarlyBecauseTooMuchData");
break;
}
}
}
catch(Exception e) {
Log.warn(e);
}
}
}
}