diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2018-10-10 13:30:44 +0200 |
---|---|---|
committer | Henning Baldersheim <balder@yahoo-inc.com> | 2018-10-10 14:28:06 +0200 |
commit | 68eb7c33480bf7a39c68eacd4ebfe065bbfe9a6b (patch) | |
tree | 483f39fd177a0accccc5792f3ef9d515436381c2 /container-accesslogging/src | |
parent | dd0c2900fefeb284f29d52e565cc29adc9ff12a2 (diff) |
Test compression on logrotate and correct visibility and cleanup unused code.
Diffstat (limited to 'container-accesslogging/src')
-rw-r--r-- | container-accesslogging/src/main/java/com/yahoo/container/logging/LogFileHandler.java | 117 | ||||
-rw-r--r-- | container-accesslogging/src/test/java/com/yahoo/container/logging/LogFileHandlerTestCase.java (renamed from container-accesslogging/src/test/java/com/yahoo/container/logging/test/LogFileHandlerTestCase.java) | 45 |
2 files changed, 94 insertions, 68 deletions
diff --git a/container-accesslogging/src/main/java/com/yahoo/container/logging/LogFileHandler.java b/container-accesslogging/src/main/java/com/yahoo/container/logging/LogFileHandler.java index 8220f715b92..56af8be722a 100644 --- a/container-accesslogging/src/main/java/com/yahoo/container/logging/LogFileHandler.java +++ b/container-accesslogging/src/main/java/com/yahoo/container/logging/LogFileHandler.java @@ -10,11 +10,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; -import java.util.logging.Formatter; import java.util.logging.Level; import java.util.logging.LogRecord; +import java.util.logging.Logger; import java.util.logging.StreamHandler; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -31,6 +32,7 @@ import java.util.regex.Pattern; */ public class LogFileHandler extends StreamHandler { + private final static Logger logger = Logger.getLogger(LogFileHandler.class.getName()); /** True to use the sequence file name scheme, false (default) to use the date scheme */ private final boolean useSequenceNameScheme; private final boolean compressOnRotation; @@ -43,12 +45,12 @@ public class LogFileHandler extends StreamHandler { private String fileName; private String symlinkName = null; private ArrayBlockingQueue<LogRecord> logQueue = new ArrayBlockingQueue<>(100000); - LogRecord rotateCmd = new LogRecord(Level.SEVERE, "rotateNow"); + private LogRecord rotateCmd = new LogRecord(Level.SEVERE, "rotateNow"); static private class LogThread extends Thread { LogFileHandler logFileHandler; long lastFlush = 0; - public LogThread(LogFileHandler logFile) { + LogThread(LogFileHandler logFile) { super("Logger"); setDaemon(true); logFileHandler = logFile; @@ -90,46 +92,21 @@ public class LogFileHandler extends StreamHandler { } } } - LogThread logThread = null; + private final LogThread logThread; - public LogFileHandler() { + LogFileHandler() { this(AccessLogConfig.FileHandler.RotateScheme.Enum.DATE, false); } - public LogFileHandler(boolean compressOnRotation) { + LogFileHandler(boolean compressOnRotation) { this(AccessLogConfig.FileHandler.RotateScheme.Enum.DATE, compressOnRotation); } - public LogFileHandler(AccessLogConfig.FileHandler.RotateScheme.Enum rotateScheme) { - this(rotateScheme, false); - } - - public LogFileHandler(AccessLogConfig.FileHandler.RotateScheme.Enum rotateScheme, - boolean compressOnRotation) + LogFileHandler(AccessLogConfig.FileHandler.RotateScheme.Enum rotateScheme, boolean compressOnRotation) { super(); this.useSequenceNameScheme = (rotateScheme == AccessLogConfig.FileHandler.RotateScheme.Enum.SEQUENCE); this.compressOnRotation = compressOnRotation; - init(); - } - - /** - * Constructs a log handler - * - * @param useSequenceNameScheme True to use the sequence file name scheme, false (default) to use the date scheme - */ - public LogFileHandler(OutputStream out, Formatter formatter, boolean useSequenceNameScheme) { - this(out, formatter, useSequenceNameScheme, false); - } - - public LogFileHandler(OutputStream out, Formatter formatter, boolean useSequenceNameScheme, boolean compressOnRotation) { - super(out, formatter); - this.useSequenceNameScheme = useSequenceNameScheme; - this.compressOnRotation = compressOnRotation; - init(); - } - - private void init() { logThread = new LogThread(this); logThread.start(); } @@ -167,7 +144,7 @@ public class LogFileHandler extends StreamHandler { * * @param pattern See LogFormatter for definition */ - public void setFilePattern ( String pattern ) { + void setFilePattern ( String pattern ) { filePattern = pattern; } @@ -177,7 +154,7 @@ public class LogFileHandler extends StreamHandler { * @param timesOfDay in millis, from midnight * */ - public void setRotationTimes ( long[] timesOfDay ) { + void setRotationTimes ( long[] timesOfDay ) { rotationTimes = timesOfDay; } @@ -185,7 +162,7 @@ public class LogFileHandler extends StreamHandler { * * @param prescription string form of times, in minutes */ - public void setRotationTimes ( String prescription ) { + void setRotationTimes ( String prescription ) { setRotationTimes(calcTimesMinutes(prescription)); } @@ -195,7 +172,7 @@ public class LogFileHandler extends StreamHandler { * @param now the specified time; if zero, current time is used. * @return the next rotation time */ - public long getNextRotationTime (long now) { + long getNextRotationTime (long now) { if (now <= 0) { now = System.currentTimeMillis(); } @@ -214,7 +191,17 @@ public class LogFileHandler extends StreamHandler { return next; } - private void checkAndCreateDir(String pathname) throws IOException { + void waitDrained() { + while(! logQueue.isEmpty()) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + } + } + super.flush(); + } + + private void checkAndCreateDir(String pathname) { int lastSlash = pathname.lastIndexOf("/"); if (lastSlash > -1) { String pathExcludingFilename = pathname.substring(0, lastSlash); @@ -228,7 +215,7 @@ public class LogFileHandler extends StreamHandler { /** * Force file rotation now, independent of schedule. */ - public void rotateNow () { + void rotateNow () { publish(rotateCmd); } @@ -278,12 +265,12 @@ public class LogFileHandler extends StreamHandler { } private void triggerCompression(File oldFile) throws InterruptedException { + String oldFileName = oldFile.getPath(); + String gzippedFileName = oldFileName + ".gz"; + StringBuilder cmd = new StringBuilder("gzip"); + cmd.append(" < "). append(oldFileName).append(" > ").append(gzippedFileName); + Runtime r = Runtime.getRuntime(); try { - String oldFileName = oldFile.getPath(); - String gzippedFileName = oldFileName + ".gz"; - Runtime r = Runtime.getRuntime(); - StringBuilder cmd = new StringBuilder("gzip"); - cmd.append(" < "). append(oldFileName).append(" > ").append(gzippedFileName); Process p = r.exec(cmd.toString()); // Detonator pattern: Think of all the fun we can have if gzip isn't what we // think it is, if it doesn't return, etc, etc @@ -294,10 +281,11 @@ public class LogFileHandler extends StreamHandler { if (retval == 0) { oldFile.delete(); nativeIO.dropFileFromCache(new File(gzippedFileName)); + } else { + logger.warning("Command '" + cmd.toString() + "' + failed with exitcode=" + retval); } - } catch (IOException e) { - // little we can do... + logger.warning("Got '" + e + "' while doing'" + cmd + "'."); } } @@ -306,14 +294,25 @@ public class LogFileHandler extends StreamHandler { if (symlinkName == null) return; File f = new File(fileName); File f2 = new File(f.getParent(), symlinkName); + String canonicalPath; + try { + canonicalPath = f.getCanonicalPath(); + } catch (IOException e) { + logger.warning("Got '" + e + "' while doing f.getCanonicalPath() on file '" + f.getPath() + "'."); + return; + } + String [] cmd = new String[]{"/bin/ln", "-sf", canonicalPath, f2.getPath()}; try { Runtime r = Runtime.getRuntime(); - Process p = r.exec(new String[] { "/bin/ln", "-sf", f.getCanonicalPath(), f2.getPath() }); + Process p = r.exec(cmd); // Detonator pattern: Think of all the fun we can have if ln isn't what we // think it is, if it doesn't return, etc, etc - p.waitFor(); + int retval = p.waitFor(); + if (retval != 0) { + logger.warning("Command '" + Arrays.toString(cmd) + "' + failed with exitcode=" + retval); + } } catch (IOException e) { - // little we can do... + logger.warning("Got '" + e + "' while doing'" + Arrays.toString(cmd) + "'."); } } @@ -340,24 +339,10 @@ public class LogFileHandler extends StreamHandler { } /** - * @return last time file rotation occurred for this output file - */ - public long getLastRotationTime () { - return lastRotationTime; - } - - /** - * @return number of records written to this file since last rotation - */ - public long getNumberRecords () { - return numberOfRecords; - } - - /** * Calculate rotation times array, given times in minutes, as "0 60 ..." * */ - public static long[] calcTimesMinutes(String times) { + private static long[] calcTimesMinutes(String times) { ArrayList<Long> list = new ArrayList<>(50); int i = 0; boolean etc = false; @@ -377,7 +362,7 @@ public class LogFileHandler extends StreamHandler { int size = list.size(); long[] longtimes = new long[size]; for (i = 0; i<size; i++) { - longtimes[i] = list.get(i).longValue() // pick up value in minutes past midnight + longtimes[i] = list.get(i) // pick up value in minutes past midnight * 60000; // and multiply to get millis } @@ -406,11 +391,11 @@ public class LogFileHandler extends StreamHandler { // Support staff :-) private static final long lengthOfDayMillis = 24*60*60*1000; // ? is this close enough ? - private static final long timeOfDayMillis ( long time ) { + private static long timeOfDayMillis ( long time ) { return time % lengthOfDayMillis; } - public void setSymlinkName(String symlinkName) { + void setSymlinkName(String symlinkName) { this.symlinkName = symlinkName; } diff --git a/container-accesslogging/src/test/java/com/yahoo/container/logging/test/LogFileHandlerTestCase.java b/container-accesslogging/src/test/java/com/yahoo/container/logging/LogFileHandlerTestCase.java index 47e98c1f8c5..0330a76951d 100644 --- a/container-accesslogging/src/test/java/com/yahoo/container/logging/test/LogFileHandlerTestCase.java +++ b/container-accesslogging/src/test/java/com/yahoo/container/logging/LogFileHandlerTestCase.java @@ -1,11 +1,13 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.logging.test; +package com.yahoo.container.logging; -import com.yahoo.container.logging.LogFileHandler; import com.yahoo.io.IOUtils; import org.junit.Test; import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; @@ -13,8 +15,11 @@ import java.util.logging.Formatter; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.SimpleFormatter; +import java.util.zip.GZIPInputStream; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; /** * @author <a href="mailto:travisb@yahoo-inc.com">Bob Travis</a> @@ -169,4 +174,40 @@ public class LogFileHandlerTestCase { deleteOnExit(f2); } + @Test + public void testcompression() throws InterruptedException, IOException { + IOUtils.recursiveDeleteDir(new File("./testcompression")); + LogFileHandler h = new LogFileHandler(true); + h.setFilePattern("./testcompression/logfilehandlertest.%Y%m%d%H%M%S%s"); + h.setFormatter(new Formatter() { + public String format(LogRecord r) { + DateFormat df = new SimpleDateFormat("yyyy.MM.dd:HH:mm:ss.SSS"); + String timeStamp = df.format(new Date(r.getMillis())); + return ("["+timeStamp+"]" + " " + formatMessage(r) + "\n"); + } + } ); + for (int i=0; i < 10000; i++) { + LogRecord lr = new LogRecord(Level.INFO, "test"); + h.publish(lr); + } + String f1 = h.getFileName(); + assertTrue(f1.startsWith("./testcompression/logfilehandlertest.")); + File uncompressed = new File(f1); + File compressed = new File(f1 + ".gz"); + h.waitDrained(); + assertTrue(uncompressed.exists()); + assertFalse(compressed.exists()); + String content = IOUtils.readFile(uncompressed); + assertEquals(310000, content.length()); + h.rotateNow(); + while (uncompressed.exists()) { + Thread.sleep(10); + } + assertTrue(compressed.exists()); + String unzipped = IOUtils.readAll(new InputStreamReader(new GZIPInputStream(new FileInputStream(compressed)))); + assertEquals(content, unzipped); + + IOUtils.recursiveDeleteDir(new File("./testcompression")); + } + } |