package water.api; import water.*; import water.api.schemas3.LogsV3; import water.util.LinuxProcFileReader; import water.util.Log; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; public class LogsHandler extends Handler { private static class GetLogTask extends DTask<GetLogTask> { public String name; public String log; public boolean success = false; public GetLogTask() { super(H2O.GUI_PRIORITY); log = null; } public void doIt() { String logPathFilename = "/undefined"; // Satisfy IDEA inspection. try { if (name == null || name.equals("default")) { name = "debug"; } if (name.equals("stdout") || name.equals("stderr")) { LinuxProcFileReader lpfr = new LinuxProcFileReader(); lpfr.read(); if (! lpfr.valid()) { log = "This option only works for Linux hosts"; } else { String pid = lpfr.getProcessID(); String fdFileName = "/proc/" + pid + "/fd/" + (name.equals("stdout") ? "1" : "2"); File f = new File(fdFileName); logPathFilename = f.getCanonicalPath(); if (logPathFilename.startsWith("/dev")) { log = "Unsupported when writing to console"; } if (logPathFilename.startsWith("socket")) { log = "Unsupported when writing to a socket"; } if (logPathFilename.startsWith("pipe")) { log = "Unsupported when writing to a pipe"; } if (logPathFilename.equals(fdFileName)) { log = "Unsupported when writing to a pipe"; } Log.trace("LogPathFilename calculation: " + logPathFilename); } } else if ( name.equals("trace") || name.equals("debug") || name.equals("info") || name.equals("warn") || name.equals("error") || name.equals("fatal") || name.equals("httpd") ) { name = water.util.Log.getLogFileName(name); try { String logDir = Log.getLogDir(); logPathFilename = logDir + File.separator + name; } catch (Exception e) { log = "H2O logging not configured."; } } else { throw new IllegalArgumentException("Illegal log file name requested (try 'default')"); } if (log == null) { File f = new File(logPathFilename); if (!f.exists()) { throw new IllegalArgumentException("File " + f + " does not exist"); } if (!f.canRead()) { throw new IllegalArgumentException("File " + f + " is not readable"); } BufferedReader reader = new BufferedReader(new FileReader(f)); String line; StringBuilder sb = new StringBuilder(); line = reader.readLine(); while (line != null) { sb.append(line); sb.append("\n"); line = reader.readLine(); } reader.close(); log = sb.toString(); } success = true; } catch (Exception e) { throw new RuntimeException(e); } } @Override public void compute2() { doIt(); tryComplete(); } } @SuppressWarnings("unused") // called through reflection by RequestServer public LogsV3 fetch(int version, LogsV3 s) { int nodeidx = s.nodeidx; if ((nodeidx < -1) || (nodeidx >= H2O.CLOUD.size())) { throw new IllegalArgumentException("node does not exist"); } String filename = s.name; if (filename != null) { if (filename.contains(File.separator)) { throw new IllegalArgumentException("filename may not contain File.separator character"); } } GetLogTask t = new GetLogTask(); t.name = filename; if (nodeidx == -1) { // Local node. try { t.doIt(); } catch (Exception e) { Log.err(e); } } else { // Remote node. Log.trace("GetLogTask starting to node " + nodeidx + "..."); H2ONode node = H2O.CLOUD._memary[nodeidx]; new RPC<>(node, t).call().get(); Log.trace("GetLogTask completed to node " + nodeidx); } if (! t.success) { throw new RuntimeException("GetLogTask failed"); } s.log = t.log; return s; } }