From be6ebde965d0c257ccb4ccca41b1b93dbb41d09d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Alcarraz?= Date: Thu, 8 Feb 2024 11:19:37 -0500 Subject: [PATCH] Let the max depth for deletion be configurable. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andrés Alcarraz #580 About the rotation of q2 logs --- .../java/org/jpos/util/DailyLogListener.java | 9 ++- .../org/jpos/util/DailyLogListenerTest.java | 68 +++++++++++++++++++ .../jpos/util/LogRotationTestDirectory.java | 11 +++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/jpos/src/main/java/org/jpos/util/DailyLogListener.java b/jpos/src/main/java/org/jpos/util/DailyLogListener.java index 415f9cb315..3c8fd70fc1 100644 --- a/jpos/src/main/java/org/jpos/util/DailyLogListener.java +++ b/jpos/src/main/java/org/jpos/util/DailyLogListener.java @@ -20,6 +20,7 @@ import org.jpos.core.Configuration; import org.jpos.core.ConfigurationException; +import org.jpos.core.annotation.Config; import java.io.*; import java.nio.file.Files; @@ -56,6 +57,10 @@ public class DailyLogListener extends RotateLogListener{ private static final int DEF_BUFFER_SIZE = 128*1024;//128 KB private static final String[] DEF_COMPRESSED_SUFFIX= {"",".gz",".zip"}; private static final Map COMPRESSION_FORMATS = new HashMap(3); + + @Config("max-depth-deletion") + private int maxDepthDeletion = DEF_MAXDEPTH; + static { COMPRESSION_FORMATS.put("none", NONE); COMPRESSION_FORMATS.put("gzip", GZIP); @@ -93,7 +98,7 @@ public void setConfiguration(Configuration cfg) throws ConfigurationException { setCompressionBufferSize(cfg.getInt("compression-buffer-size", DEF_BUFFER_SIZE)); - deleteRegex = cfg.get("delete-regex", defaultDeleteRegex()); + deleteRegex = cfg.get("delete-regex", defaultDeleteRegex()); setLastDate(fmt.format(new Date())); @@ -178,7 +183,7 @@ public void deleteOldLogs() throws IOException { long currentSystemTime = System.currentTimeMillis(); try { - Files.find(logBasePath, DEF_MAXDEPTH, + Files.find(logBasePath, maxDepthDeletion, (path, attributes) -> path.getFileName().toString().matches(deleteRegex) && attributes.isRegularFile() diff --git a/jpos/src/test/java/org/jpos/util/DailyLogListenerTest.java b/jpos/src/test/java/org/jpos/util/DailyLogListenerTest.java index b4ac150d80..18bf231f37 100644 --- a/jpos/src/test/java/org/jpos/util/DailyLogListenerTest.java +++ b/jpos/src/test/java/org/jpos/util/DailyLogListenerTest.java @@ -20,17 +20,24 @@ import static org.apache.commons.lang3.JavaVersion.JAVA_14; import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; import static org.jpos.util.LogFileTestUtils.getStringFromCompressedFile; import static org.jpos.util.LogFileTestUtils.getStringFromFile; import static org.junit.jupiter.api.Assertions.*; +import static org.hamcrest.io.FileMatchers.anExistingFile; +import static org.hamcrest.MatcherAssert.*; import java.io.*; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.FileTime; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.Properties; import java.util.zip.Deflater; @@ -40,6 +47,8 @@ import org.jpos.core.ConfigurationException; import org.jpos.core.SimpleConfiguration; import org.jpos.core.SubConfiguration; +import org.jpos.q2.QFactory; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -427,6 +436,65 @@ public void testMaxAgeFeatureWhenThereIsNonLogFiles() throws Exception { listener.destroy(); } + @Test + public void testDeleteOldLogsWithCustomMaxDepth() throws ConfigurationException, IOException, IllegalAccessException { + Path parent = logRotationTestDirectory.getDirectory().resolve("parent"); + //create a file at level 0 in condition to be deleted. + Path level0file = Files.createTempFile(logRotationTestDirectory.getDirectory(), "child", ".log"); + assertThat("level 0 file should have been created", level0file.toFile(), is(anExistingFile())); + Files.setLastModifiedTime(level0file, FileTime.from(Instant.now().minus(1, ChronoUnit.DAYS))); //old enough + //create a file at level 1 in condition to be deleted. + Files.createDirectory(parent); + Path level1file = Files.createTempFile(parent, "child", ".log"); + assertThat("level 1 file should have been created", level1file.toFile(), is(anExistingFile())); + Files.setLastModifiedTime(level1file, FileTime.from(Instant.now().minus(1, ChronoUnit.DAYS))); //old enough + + try (DailyLogListener listener = new DailyLogListener()) { + SimpleConfiguration cfg = new SimpleConfiguration(); + cfg.put("prefix", logRotationTestDirectory.getFile("q2").toString()); + cfg.put("max-depth-deletion", "2"); + cfg.put("delete-regex", "^child.*\\.log"); + cfg.put("maxage", "1"); //created files are much older than 1s + QFactory.autoconfigure(listener, cfg); + listener.setConfiguration(cfg); + + listener.deleteOldLogs(); + } + assertThat("level 1 file should have been deleted", level1file.toFile(), is(not(anExistingFile()))); + assertThat("level 0 file should have been deleted", level0file.toFile(), is(not(anExistingFile()))); + Files.delete(parent); + + } + @Test + public void testDeleteOldLogsWithoutCustomMaxDepth() throws ConfigurationException, IOException, IllegalAccessException { + Path parent = logRotationTestDirectory.getDirectory().resolve("parent"); + //create a file at level 0 in condition to be deleted. + Path level0file = Files.createTempFile(logRotationTestDirectory.getDirectory(), "child", ".log"); + assertThat("level 0 file should have been created", level0file.toFile(), is(anExistingFile())); + Files.setLastModifiedTime(level0file, FileTime.from(Instant.now().minus(1, ChronoUnit.DAYS))); //old enough + //create a file at level 1 in condition to be deleted. + Files.createDirectory(parent); + Path level1file = Files.createTempFile(parent, "child", ".log"); + assertThat("level 1 file should have been created", level1file.toFile(), is(anExistingFile())); + Files.setLastModifiedTime(level1file, FileTime.from(Instant.now().minus(1, ChronoUnit.DAYS))); //old enough + + try (DailyLogListener listener = new DailyLogListener()) { + SimpleConfiguration cfg = new SimpleConfiguration(); + cfg.put("prefix", logRotationTestDirectory.getFile("q2").toString()); + cfg.put("delete-regex", "^child.*\\.log"); + cfg.put("maxage", "1000"); + QFactory.autoconfigure(listener, cfg); + listener.setConfiguration(cfg); + + listener.deleteOldLogs(); + } + assertThat("level 1 file should have not been deleted", level1file.toFile(), is(anExistingFile())); + assertThat("level 0 file should have been deleted", level0file.toFile(), is(not(anExistingFile()))); + + Files.delete(level1file); //so it doesn't give problems in windows + Files.delete(parent); + + } @Test @Disabled("This feature doesn't work in Windows so we reverted the patch c94ff02f2") public void testLogRotateAbortsWhenCreatingNewFileFails() throws Exception { diff --git a/jpos/src/test/java/org/jpos/util/LogRotationTestDirectory.java b/jpos/src/test/java/org/jpos/util/LogRotationTestDirectory.java index c241d180ff..c4fb0e053d 100644 --- a/jpos/src/test/java/org/jpos/util/LogRotationTestDirectory.java +++ b/jpos/src/test/java/org/jpos/util/LogRotationTestDirectory.java @@ -18,6 +18,7 @@ package org.jpos.util; +import java.io.File; import java.io.IOException; import java.nio.file.FileStore; import java.nio.file.Files; @@ -87,4 +88,14 @@ public void allowNewFileCreation() throws IOException { throw new IOException("Directory " + directory.toString() + " has unsupported FileStore type: " + filestore.type()); } } + + /** + * Deletes the directory and its content. + * @throws IOException if an exception is thrown while walking the directory + */ + public void delete() throws IOException { + Files.walk(directory) + .map(Path::toFile) + .forEach(File::delete); + } }