From db7ad7636605f9051bb7ef07bad6964cecddb163 Mon Sep 17 00:00:00 2001 From: luccioman Date: Thu, 13 Sep 2018 12:17:02 +0200 Subject: [PATCH] Improved support for Java logs file pattern options - support of "%h" and "%t" pattern components - more proper initialization of file handler when the data folder is not the default one, notably to prevent a non blocking but ugly error stack trace reported by the log manager at startup with that kind of setup --- source/net/yacy/cora/util/ConcurrentLog.java | 77 +++++++++++--------- source/net/yacy/yacy.java | 15 ++-- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/source/net/yacy/cora/util/ConcurrentLog.java b/source/net/yacy/cora/util/ConcurrentLog.java index 7a759c5b0..56ca25a1f 100644 --- a/source/net/yacy/cora/util/ConcurrentLog.java +++ b/source/net/yacy/cora/util/ConcurrentLog.java @@ -20,6 +20,7 @@ package net.yacy.cora.util; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -29,9 +30,9 @@ import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; +import java.util.Properties; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; -import java.util.logging.FileHandler; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; @@ -378,46 +379,58 @@ public final class ConcurrentLog { } } - public final static void configureLogging(final File dataPath, final File appPath, final File loggingConfigFile) throws SecurityException, FileNotFoundException, IOException { - FileInputStream fileIn = null; - try { - System.out.println("STARTUP: Trying to load logging configuration from file " + loggingConfigFile.toString()); - fileIn = new FileInputStream(loggingConfigFile); - - // loading the logger configuration from file - final LogManager logManager = LogManager.getLogManager(); - logManager.readConfiguration(fileIn); - - // creating the logging directory - String logPattern = logManager.getProperty("java.util.logging.FileHandler.pattern"); - File logFile = new File(logPattern); - if (!logFile.isAbsolute()) { - logFile = new File(dataPath, logPattern); - logPattern = logFile.getAbsolutePath(); + public static final void configureLogging(final File dataPath, final File loggingConfigFile) throws SecurityException, FileNotFoundException, IOException { + System.out.println("STARTUP: Trying to load logging configuration from file " + loggingConfigFile.toString()); + try (final FileInputStream fileIn = new FileInputStream(loggingConfigFile);){ + + final String logFilePatternKey = "java.util.logging.FileHandler.pattern"; + final Properties logProperties = new Properties(); + logProperties.load(fileIn); + String logFilePattern = logProperties.getProperty(logFilePatternKey, "%h/java%u.log" /* default FileHandler pattern*/); + + File logFile; + if(logFilePattern.startsWith("%h")) { + logFile = new File(System.getProperty("user.home") + logFilePattern.substring(2)); + } else if(logFilePattern.startsWith("%t")) { + String tmpDir = System.getProperty("java.io.tmpdir"); + if (tmpDir == null) { + tmpDir = System.getProperty("user.home"); + } + logFile = new File(tmpDir, logFilePattern.substring(2)); + } else { + logFile = new File(logFilePattern); + if (!logFile.isAbsolute()) { + logFile = new File(dataPath, logFilePattern); + logFilePattern = logFile.getAbsolutePath(); + + /* + * Update the file pattern with the absolute path flavor as LogManager and + * FileHandler classes do not offer a way to configure the base parent path when + * using relative path + */ + logProperties.setProperty(logFilePatternKey, logFilePattern); + } } + + + // creating the logging directory if necessary File logDirectory = logFile.getParentFile(); if(logDirectory != null) { - if (!logDirectory.isAbsolute()) { - logDirectory = new File(dataPath, logDirectory.getPath()); - } if (!logDirectory.exists()) { - if(!logDirectory.mkdir()) { + if(!logDirectory.mkdirs()) { System.err.println("STARTUP: Could not create the logs directory at " + logDirectory.getAbsolutePath()); } } else if(!logDirectory.isDirectory()) { System.err.println("STARTUP: Log file parent path at " + logDirectory.getAbsolutePath() + "is not a directory"); } } - - // generating the root logger - final Logger logger = Logger.getLogger(""); - logger.setUseParentHandlers(false); - - //for (Handler h: logger.getHandlers()) logger.removeHandler(h); - if (!dataPath.getAbsolutePath().equals(appPath.getAbsolutePath())) { - final FileHandler handler = new FileHandler(logPattern, 1024*1024, 20, true); - logger.addHandler(handler); - } + + final ByteArrayOutputStream propsStream = new ByteArrayOutputStream(); + logProperties.store(propsStream, null); + + // loading the logger configuration from properties + final LogManager logManager = LogManager.getLogManager(); + logManager.readConfiguration(new ByteArrayInputStream(propsStream.toByteArray())); // redirect uncaught exceptions to logging final ConcurrentLog exceptionLog = new ConcurrentLog("UNCAUGHT-EXCEPTION"); @@ -438,8 +451,6 @@ public final class ConcurrentLog { } } }); - } finally { - if (fileIn != null) try {fileIn.close();}catch(final Exception e){} } } diff --git a/source/net/yacy/yacy.java b/source/net/yacy/yacy.java index f30349335..e02816ab9 100644 --- a/source/net/yacy/yacy.java +++ b/source/net/yacy/yacy.java @@ -166,6 +166,13 @@ public final class yacy { System.err.println("Error creating DATA-directory in " + dataHome.toString() + " . Please check your write-permission for this folder. YaCy will now terminate."); System.exit(-1); } + + // set jvm tmpdir to a subdir for easy cleanup (as extensive use file.deleteonexit waists memory during long runs, as todelete files names are collected and never cleaned up during runtime) + // keep this as earlier as possible, as any other class can use the "java.io.tmpdir" property, even the log manager, when the log file pattern uses "%t" as an alias for the tmp directory + try { + tmpdir = java.nio.file.Files.createTempDirectory("yacy-tmp-").toString(); // creates sub dir in jvm's temp (see System.property "java.io.tempdir") + System.setProperty("java.io.tmpdir", tmpdir); + } catch (IOException ex) { } // setting up logging f = new File(dataHome, "DATA/LOG/"); @@ -178,7 +185,7 @@ public final class yacy { System.out.println("could not copy yacy.logging"); } try{ - ConcurrentLog.configureLogging(dataHome, appHome, new File(dataHome, "DATA/LOG/yacy.logging")); + ConcurrentLog.configureLogging(dataHome, new File(dataHome, "DATA/LOG/yacy.logging")); } catch (final IOException e) { System.out.println("could not find logging properties in homePath=" + dataHome); ConcurrentLog.logException(e); @@ -203,12 +210,6 @@ public final class yacy { lock = channel.tryLock(); // lock yacy.running } catch (final Exception e) { } - // set jvm tmpdir to a subdir for easy cleanup (as extensive use file.deleteonexit waists memory during long runs, as todelete files names are collected and never cleaned up during runtime) - try { - tmpdir = java.nio.file.Files.createTempDirectory("yacy-tmp-").toString(); // creates sub dir in jvm's temp (see System.property "java.io.tempdir") - System.setProperty("java.io.tmpdir", tmpdir); - } catch (IOException ex) { } - try { sb = new Switchboard(dataHome, appHome, "defaults/yacy.init".replace("/", File.separator), conf); } catch (final RuntimeException e) {