NIFI-488: Redirect nifi output streams and redirect bootstrap log messages to file
Project: http://git-wip-us.apache.org/repos/asf/incubator-nifi/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-nifi/commit/abd279c1 Tree: http://git-wip-us.apache.org/repos/asf/incubator-nifi/tree/abd279c1 Diff: http://git-wip-us.apache.org/repos/asf/incubator-nifi/diff/abd279c1 Branch: refs/heads/NIFI-271 Commit: abd279c1e01e3aea3332e6b378701554722317e6 Parents: 7819afb Author: Mark Payne <marka...@hotmail.com> Authored: Wed Apr 8 13:41:34 2015 -0400 Committer: Mark Payne <marka...@hotmail.com> Committed: Wed Apr 8 13:41:34 2015 -0400 ---------------------------------------------------------------------- .../java/org/apache/nifi/bootstrap/RunNiFi.java | 131 ++++++++++++++++--- .../src/main/resources/conf/bootstrap.conf | 5 + 2 files changed, 119 insertions(+), 17 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/abd279c1/nifi/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/RunNiFi.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/RunNiFi.java b/nifi/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/RunNiFi.java index 28a9b71..d25df97 100644 --- a/nifi/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/RunNiFi.java +++ b/nifi/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/RunNiFi.java @@ -45,9 +45,10 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import java.util.logging.ConsoleHandler; +import java.util.logging.FileHandler; import java.util.logging.Handler; import java.util.logging.Level; +import java.util.logging.SimpleFormatter; /** @@ -92,16 +93,82 @@ public class RunNiFi { private final java.util.logging.Logger logger; - public RunNiFi(final File bootstrapConfigFile, final boolean verbose) { + public RunNiFi(final File bootstrapConfigFile, final boolean verbose) throws IOException { this.bootstrapConfigFile = bootstrapConfigFile; logger = java.util.logging.Logger.getLogger("Bootstrap"); + + final Properties bootstrapProps = new Properties(); + try (final InputStream configIn = new FileInputStream(bootstrapConfigFile)) { + bootstrapProps.load(configIn); + } + + String logFilename = bootstrapProps.getProperty("bootstrap.log.file"); + if ( logFilename == null ) { + logFilename = "./logs/bootstrap.log"; + } + + File logFile = new File(logFilename); + if ( !logFile.isAbsolute() ) { + final File workDir = getDefaultWorkingDirectory(); + logFile = new File(workDir, logFilename); + } + + final File logFileDir = logFile.getParentFile(); + final Handler fileHandler; + if ( logFileDir.exists() || logFileDir.mkdirs() ) { + final int maxSize = getIntProp(bootstrapProps, "bootstrap.log.max.bytes", 1024 * 1024 * 10); // 10 MB + final int numFiles = getIntProp(bootstrapProps, "bootstrap.log.count", 10); + + fileHandler = new FileHandler(logFile.getAbsolutePath(), maxSize, numFiles, true); + fileHandler.setFormatter(new SimpleFormatter()); + logger.addHandler(fileHandler); + } else { + fileHandler = null; + logger.severe("Could not create log file directory " + logFileDir + ". Will not log bootstrap info to file or redirect NiFi standard out to file"); + } + if ( verbose ) { logger.info("Enabling Verbose Output"); logger.setLevel(Level.FINE); - final Handler handler = new ConsoleHandler(); - handler.setLevel(Level.FINE); - logger.addHandler(handler); + + for ( final Handler handler : logger.getHandlers() ) { + handler.setLevel(Level.FINE); + } + } + } + + + private File getLogFile() throws IOException { + final Properties bootstrapProps = new Properties(); + try (final InputStream configIn = new FileInputStream(bootstrapConfigFile)) { + bootstrapProps.load(configIn); + } + + String logFilename = bootstrapProps.getProperty("bootstrap.log.file"); + if ( logFilename == null ) { + logFilename = "./logs/bootstrap.log"; + } + + File logFile = new File(logFilename); + if ( !logFile.isAbsolute() ) { + final File workDir = getDefaultWorkingDirectory(); + logFile = new File(workDir, logFilename); + } + + return logFile; + } + + private static int getIntProp(final Properties properties, final String name, final int defaultValue) { + String propVal = properties.getProperty(name); + if ( propVal == null || propVal.trim().isEmpty() ) { + return defaultValue; + } + + try { + return Integer.parseInt(propVal.trim()); + } catch (final NumberFormatException nfe) { + throw new NumberFormatException("Expected bootstrap property '" + name + "' to be an integer but found value: " + propVal); } } @@ -581,6 +648,35 @@ public class RunNiFi { } } + private void redirectOutput(final Process process) { + redirectStreamToLogs(process.getInputStream()); + redirectStreamToLogs(process.getErrorStream()); + } + + private void redirectStreamToLogs(final InputStream in) { + final Thread t = new Thread(new Runnable() { + @Override + public void run() { + try (final BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { + String line; + while ((line = reader.readLine()) != null) { + logger.info(line); + } + } catch (IOException e) { + logger.warning("Failed to read output of NiFi console: " + e); + } + } + }); + t.setDaemon(true); + t.start(); + } + + private File getDefaultWorkingDirectory() { + final File bootstrapConfigAbsoluteFile = bootstrapConfigFile.getAbsoluteFile(); + final File binDir = bootstrapConfigAbsoluteFile.getParentFile(); + return binDir.getParentFile(); + } + @SuppressWarnings({ "rawtypes", "unchecked" }) public void start(final boolean monitor) throws IOException, InterruptedException { final Integer port = getCurrentPort(); @@ -590,7 +686,6 @@ public class RunNiFi { } final ProcessBuilder builder = new ProcessBuilder(); - if ( !bootstrapConfigFile.exists() ) { throw new FileNotFoundException(bootstrapConfigFile.getAbsolutePath()); } @@ -604,18 +699,17 @@ public class RunNiFi { props.putAll( (Map) properties ); final String specifiedWorkingDir = props.get("working.dir"); - if ( specifiedWorkingDir != null ) { - builder.directory(new File(specifiedWorkingDir)); - } - - final File bootstrapConfigAbsoluteFile = bootstrapConfigFile.getAbsoluteFile(); - final File binDir = bootstrapConfigAbsoluteFile.getParentFile(); - final File workingDir = binDir.getParentFile(); - + final File workingDir = getDefaultWorkingDirectory(); if ( specifiedWorkingDir == null ) { builder.directory(workingDir); + } else { + builder.directory(new File(specifiedWorkingDir)); } + final File logDir = getLogFile().getParentFile(); + builder.redirectError(new File(logDir, "nifi.err")); + builder.redirectOutput(new File(logDir, "nifi.out")); + final String libFilename = replaceNull(props.get("lib.dir"), "./lib").trim(); File libDir = getFile(libFilename, workingDir); @@ -738,14 +832,15 @@ public class RunNiFi { try { gracefulShutdownSeconds = Integer.parseInt(gracefulShutdown); } catch (final NumberFormatException nfe) { - throw new NumberFormatException("The '" + GRACEFUL_SHUTDOWN_PROP + "' property in Bootstrap Config File " + bootstrapConfigAbsoluteFile.getAbsolutePath() + " has an invalid value. Must be a non-negative integer"); + throw new NumberFormatException("The '" + GRACEFUL_SHUTDOWN_PROP + "' property in Bootstrap Config File " + bootstrapConfigFile.getAbsolutePath() + " has an invalid value. Must be a non-negative integer"); } if ( gracefulShutdownSeconds < 0 ) { - throw new NumberFormatException("The '" + GRACEFUL_SHUTDOWN_PROP + "' property in Bootstrap Config File " + bootstrapConfigAbsoluteFile.getAbsolutePath() + " has an invalid value. Must be a non-negative integer"); + throw new NumberFormatException("The '" + GRACEFUL_SHUTDOWN_PROP + "' property in Bootstrap Config File " + bootstrapConfigFile.getAbsolutePath() + " has an invalid value. Must be a non-negative integer"); } Process process = builder.start(); + redirectOutput(process); Long pid = getPid(process); if ( pid != null ) { nifiPid = pid; @@ -776,7 +871,8 @@ public class RunNiFi { if (autoRestartNiFi) { logger.warning("Apache NiFi appears to have died. Restarting..."); process = builder.start(); - + redirectOutput(process); + pid = getPid(process); if ( pid != null ) { nifiPid = pid; @@ -802,6 +898,7 @@ public class RunNiFi { } } else { final Process process = builder.start(); + redirectOutput(process); final Long pid = getPid(process); if ( pid != null ) { http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/abd279c1/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap.conf ---------------------------------------------------------------------- diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap.conf b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap.conf index c1536d8..e87bde2 100644 --- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap.conf +++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap.conf @@ -21,6 +21,11 @@ java=java # Username to use when running NiFi. This value will be ignored on Windows. run.as= +# Bootstrap logger info +bootstrap.log.file=logs/nifi-bootstrap.log +bootstrap.log.max.bytes=10485760 +bootstrap.log.count=10 + # Configure where NiFi's lib and conf directories live lib.dir=./lib conf.dir=./conf