mirror of https://github.com/apache/nifi.git
NIFI-488: Redirect nifi output streams and redirect bootstrap log messages to file
This commit is contained in:
parent
7819afbefd
commit
abd279c1e0
|
@ -45,9 +45,10 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.locks.Condition;
|
import java.util.concurrent.locks.Condition;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
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.Handler;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.SimpleFormatter;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,16 +93,82 @@ public class RunNiFi {
|
||||||
|
|
||||||
private final java.util.logging.Logger logger;
|
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;
|
this.bootstrapConfigFile = bootstrapConfigFile;
|
||||||
logger = java.util.logging.Logger.getLogger("Bootstrap");
|
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 ) {
|
if ( verbose ) {
|
||||||
logger.info("Enabling Verbose Output");
|
logger.info("Enabling Verbose Output");
|
||||||
|
|
||||||
logger.setLevel(Level.FINE);
|
logger.setLevel(Level.FINE);
|
||||||
final Handler handler = new ConsoleHandler();
|
|
||||||
handler.setLevel(Level.FINE);
|
for ( final Handler handler : logger.getHandlers() ) {
|
||||||
logger.addHandler(handler);
|
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" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
public void start(final boolean monitor) throws IOException, InterruptedException {
|
public void start(final boolean monitor) throws IOException, InterruptedException {
|
||||||
final Integer port = getCurrentPort();
|
final Integer port = getCurrentPort();
|
||||||
|
@ -590,7 +686,6 @@ public class RunNiFi {
|
||||||
}
|
}
|
||||||
|
|
||||||
final ProcessBuilder builder = new ProcessBuilder();
|
final ProcessBuilder builder = new ProcessBuilder();
|
||||||
|
|
||||||
if ( !bootstrapConfigFile.exists() ) {
|
if ( !bootstrapConfigFile.exists() ) {
|
||||||
throw new FileNotFoundException(bootstrapConfigFile.getAbsolutePath());
|
throw new FileNotFoundException(bootstrapConfigFile.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
@ -604,17 +699,16 @@ public class RunNiFi {
|
||||||
props.putAll( (Map) properties );
|
props.putAll( (Map) properties );
|
||||||
|
|
||||||
final String specifiedWorkingDir = props.get("working.dir");
|
final String specifiedWorkingDir = props.get("working.dir");
|
||||||
if ( specifiedWorkingDir != null ) {
|
final File workingDir = getDefaultWorkingDirectory();
|
||||||
|
if ( specifiedWorkingDir == null ) {
|
||||||
|
builder.directory(workingDir);
|
||||||
|
} else {
|
||||||
builder.directory(new File(specifiedWorkingDir));
|
builder.directory(new File(specifiedWorkingDir));
|
||||||
}
|
}
|
||||||
|
|
||||||
final File bootstrapConfigAbsoluteFile = bootstrapConfigFile.getAbsoluteFile();
|
final File logDir = getLogFile().getParentFile();
|
||||||
final File binDir = bootstrapConfigAbsoluteFile.getParentFile();
|
builder.redirectError(new File(logDir, "nifi.err"));
|
||||||
final File workingDir = binDir.getParentFile();
|
builder.redirectOutput(new File(logDir, "nifi.out"));
|
||||||
|
|
||||||
if ( specifiedWorkingDir == null ) {
|
|
||||||
builder.directory(workingDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String libFilename = replaceNull(props.get("lib.dir"), "./lib").trim();
|
final String libFilename = replaceNull(props.get("lib.dir"), "./lib").trim();
|
||||||
File libDir = getFile(libFilename, workingDir);
|
File libDir = getFile(libFilename, workingDir);
|
||||||
|
@ -738,14 +832,15 @@ public class RunNiFi {
|
||||||
try {
|
try {
|
||||||
gracefulShutdownSeconds = Integer.parseInt(gracefulShutdown);
|
gracefulShutdownSeconds = Integer.parseInt(gracefulShutdown);
|
||||||
} catch (final NumberFormatException nfe) {
|
} 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 ) {
|
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();
|
Process process = builder.start();
|
||||||
|
redirectOutput(process);
|
||||||
Long pid = getPid(process);
|
Long pid = getPid(process);
|
||||||
if ( pid != null ) {
|
if ( pid != null ) {
|
||||||
nifiPid = pid;
|
nifiPid = pid;
|
||||||
|
@ -776,6 +871,7 @@ public class RunNiFi {
|
||||||
if (autoRestartNiFi) {
|
if (autoRestartNiFi) {
|
||||||
logger.warning("Apache NiFi appears to have died. Restarting...");
|
logger.warning("Apache NiFi appears to have died. Restarting...");
|
||||||
process = builder.start();
|
process = builder.start();
|
||||||
|
redirectOutput(process);
|
||||||
|
|
||||||
pid = getPid(process);
|
pid = getPid(process);
|
||||||
if ( pid != null ) {
|
if ( pid != null ) {
|
||||||
|
@ -802,6 +898,7 @@ public class RunNiFi {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final Process process = builder.start();
|
final Process process = builder.start();
|
||||||
|
redirectOutput(process);
|
||||||
final Long pid = getPid(process);
|
final Long pid = getPid(process);
|
||||||
|
|
||||||
if ( pid != null ) {
|
if ( pid != null ) {
|
||||||
|
|
|
@ -21,6 +21,11 @@ java=java
|
||||||
# Username to use when running NiFi. This value will be ignored on Windows.
|
# Username to use when running NiFi. This value will be ignored on Windows.
|
||||||
run.as=
|
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
|
# Configure where NiFi's lib and conf directories live
|
||||||
lib.dir=./lib
|
lib.dir=./lib
|
||||||
conf.dir=./conf
|
conf.dir=./conf
|
||||||
|
|
Loading…
Reference in New Issue