Skip to content

Commit

Permalink
Roll log files daily
Browse files Browse the repository at this point in the history
  • Loading branch information
dain committed Jan 5, 2022
1 parent b4562b4 commit df12987
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 21 deletions.
6 changes: 6 additions & 0 deletions log-manager/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@
</dependency>

<!-- for testing -->
<dependency>
<groupId>io.airlift</groupId>
<artifactId>testing</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
Expand Down
10 changes: 5 additions & 5 deletions log-manager/src/main/java/io/airlift/log/LogFileName.java
Original file line number Diff line number Diff line change
Expand Up @@ -151,21 +151,21 @@ private static Optional<LogFileName> parseLegacyLogName(String historyFileName,
return Optional.of(new LogFileName(historyFileName, dateTime, OptionalInt.empty(), OptionalInt.of(legacyIndex), slug, compressed));
}

public static LogFileName generateNextLogFileName(Path masterLogFile, Optional<String> compressionExtension)
public static LogFileName generateNextLogFileName(Path masterLogFile, LocalDateTime currentDateTime, Optional<String> compressionExtension)
{
LocalDateTime dateTime = LocalDateTime.now().withNano(0);
String suffix = DATE_TIME_FORMATTER.format(dateTime);
currentDateTime = currentDateTime.withNano(0);
String suffix = DATE_TIME_FORMATTER.format(currentDateTime);
for (int index = 0; index < MAX_GENERATED_INDEX; index++) {
String newFileName = masterLogFile.getFileName() + suffix + (index > 0 ? "-" + index : "");
Path newFile = masterLogFile.resolveSibling(newFileName);
if (!fileAlreadyExists(newFile, compressionExtension)) {
return new LogFileName(newFileName, dateTime, OptionalInt.of(index), OptionalInt.empty(), Optional.empty(), false);
return new LogFileName(newFileName, currentDateTime, OptionalInt.of(index), OptionalInt.empty(), Optional.empty(), false);
}
}
// something strange is happening, just use a random UUID, so we continue logging
String slug = randomUUID().toString();
String randomFileName = masterLogFile.getFileName() + suffix + "--" + slug;
return new LogFileName(randomFileName, dateTime, OptionalInt.of(0), OptionalInt.empty(), Optional.of(slug), false);
return new LogFileName(randomFileName, currentDateTime, OptionalInt.of(0), OptionalInt.empty(), Optional.of(slug), false);
}

private static boolean fileAlreadyExists(Path newFile, Optional<String> compressionExtension)
Expand Down
3 changes: 2 additions & 1 deletion log-manager/src/main/java/io/airlift/log/Logging.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import static com.google.common.collect.Maps.fromProperties;
import static io.airlift.configuration.ConfigurationLoader.loadPropertiesFrom;
import static io.airlift.configuration.ConfigurationUtils.replaceEnvironmentVariables;
import static io.airlift.log.RollingFileMessageOutput.FileTimeRoller.SYSTEM_FILE_TIME_ROLLER;
import static io.airlift.log.RollingFileMessageOutput.createRollingFileHandler;
import static io.airlift.log.SocketMessageOutput.createSocketHandler;

Expand Down Expand Up @@ -125,7 +126,7 @@ public void logToFile(boolean legacyLoggerImplementation, String logPath, int ma
handler = new LegacyRollingFileHandler(logPath, maxHistory, maxFileSize.toBytes(), formatter);
}
else {
handler = createRollingFileHandler(logPath, maxFileSize, maxTotalSize, compressionType, formatter, new BufferedHandlerErrorManager(stdErr));
handler = createRollingFileHandler(logPath, maxFileSize, maxTotalSize, compressionType, formatter, new BufferedHandlerErrorManager(stdErr), SYSTEM_FILE_TIME_ROLLER);
}
ROOT.addHandler(handler);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
*/
package io.airlift.log;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Ticker;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.ByteStreams;
import com.google.common.io.MoreFiles;
Expand All @@ -31,13 +33,15 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.LongSupplier;
import java.util.logging.ErrorManager;
import java.util.logging.Formatter;
import java.util.zip.GZIPOutputStream;
Expand Down Expand Up @@ -84,6 +88,7 @@ public Optional<String> getExtension()
private final long maxFileSize;
private final CompressionType compressionType;
private final Formatter formatter;
private final FileTimeRoller fileTimeRoller;

@GuardedBy("this")
private Path currentOutputFile;
Expand All @@ -104,25 +109,34 @@ public static BufferedHandler createRollingFileHandler(
DataSize maxTotalSize,
CompressionType compressionType,
Formatter formatter,
ErrorManager errorManager)
ErrorManager errorManager,
FileTimeRoller fileTimeRoller)
{
RollingFileMessageOutput output = new RollingFileMessageOutput(filename, maxFileSize, maxTotalSize, compressionType, formatter);
RollingFileMessageOutput output = new RollingFileMessageOutput(filename, maxFileSize, maxTotalSize, compressionType, formatter, fileTimeRoller);
BufferedHandler handler = new BufferedHandler(output, formatter, errorManager);
handler.start();
return handler;
}

private RollingFileMessageOutput(String filename, DataSize maxFileSize, DataSize maxTotalSize, CompressionType compressionType, Formatter formatter)
private RollingFileMessageOutput(
String filename,
DataSize maxFileSize,
DataSize maxTotalSize,
CompressionType compressionType,
Formatter formatter,
FileTimeRoller fileTimeRoller)
{
requireNonNull(filename, "filename is null");
requireNonNull(maxFileSize, "maxFileSize is null");
requireNonNull(maxTotalSize, "maxTotalSize is null");
requireNonNull(compressionType, "compressionType is null");
requireNonNull(formatter, "formatter is null");
requireNonNull(fileTimeRoller, "fileTimeRoller is null");

this.maxFileSize = maxFileSize.toBytes();
this.compressionType = compressionType;
this.formatter = formatter;
this.fileTimeRoller = fileTimeRoller;

symlink = Paths.get(filename);

Expand Down Expand Up @@ -238,7 +252,7 @@ public synchronized void close()
public synchronized void writeMessage(byte[] message)
throws IOException
{
if (currentFileSize + message.length > maxFileSize) {
if (currentFileSize + message.length > maxFileSize || fileTimeRoller.shouldRoll()) {
try {
rollFile();
}
Expand All @@ -264,7 +278,8 @@ private synchronized void rollFile()
OutputStream newOutputStream = null;
for (int i = 0; i < MAX_OPEN_NEW_LOG_ATTEMPTS; i++) {
try {
newFileName = LogFileName.generateNextLogFileName(symlink, compressionType.getExtension());
// Note: use the current date time from the file time roller for the file name, to ensure tests work as expected
newFileName = LogFileName.generateNextLogFileName(symlink, fileTimeRoller.currentDateTime(), compressionType.getExtension());
newFile = symlink.resolveSibling(newFileName.getFileName());
newOutputStream = new BufferedOutputStream(Files.newOutputStream(newFile, CREATE_NEW), MAX_BATCH_BYTES);
break;
Expand Down Expand Up @@ -310,6 +325,7 @@ private synchronized void rollFile()
currentOutputFileName = newFileName;
currentOutputStream = newOutputStream;
currentFileSize = 0;
fileTimeRoller.updateNextRollTime(newFileName.getDateTime());

// update symlink
try {
Expand Down Expand Up @@ -444,4 +460,48 @@ public synchronized Set<LogFileName> getFiles()
}
return files.build();
}

@VisibleForTesting
static class FileTimeRoller
{
public static final FileTimeRoller SYSTEM_FILE_TIME_ROLLER = new FileTimeRoller(System::currentTimeMillis, Ticker.systemTicker());

private final LongSupplier systemTimeMillis;
private final Ticker ticker;

@GuardedBy("this")
private long lastRollNanos;

@GuardedBy("this")
private long nanosToNextRoll;

public FileTimeRoller(LongSupplier systemTimeMillis, Ticker ticker)
{
this.systemTimeMillis = requireNonNull(systemTimeMillis, "systemTimeMillis is null");
this.ticker = requireNonNull(ticker, "ticker is null");
}

public LocalDateTime currentDateTime()
{
return LocalDateTime.ofInstant(Instant.ofEpochMilli(systemTimeMillis.getAsLong()), ZoneId.systemDefault());
}

public synchronized boolean shouldRoll()
{
return ticker.read() - lastRollNanos >= nanosToNextRoll;
}

@VisibleForTesting
synchronized long getNextRollNanos()
{
return lastRollNanos + nanosToNextRoll;
}

public synchronized void updateNextRollTime(LocalDateTime logFileCreateTime)
{
lastRollNanos = ticker.read();
long epochMilli = logFileCreateTime.toLocalDate().plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
nanosToNextRoll = TimeUnit.MILLISECONDS.toNanos(epochMilli - systemTimeMillis.getAsLong());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public void testComparisonNewAndLegacy()
public void testGenerateNextLogFileName()
{
// note: no actual files are created here
LogFileName logFileName = LogFileName.generateNextLogFileName(Paths.get(BASE_NAME), Optional.empty());
LogFileName logFileName = LogFileName.generateNextLogFileName(Paths.get(BASE_NAME), LocalDateTime.now(), Optional.empty());
assertEquals(logFileName.getIndex(), OptionalInt.of(0));
assertEquals(logFileName.getLegacyIndex(), OptionalInt.empty());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -141,7 +142,7 @@ public void testRuntimePrune()
private static LogFileName createTestFile(Path masterLogName)
throws IOException
{
LogFileName logFileName = LogFileName.generateNextLogFileName(masterLogName, Optional.empty());
LogFileName logFileName = LogFileName.generateNextLogFileName(masterLogName, LocalDateTime.now(), Optional.empty());
Files.write(masterLogName.resolveSibling(logFileName.getFileName()), new byte[FILE_SIZE], CREATE_NEW);
return logFileName;
}
Expand Down

0 comments on commit df12987

Please sign in to comment.