From 8a37e532127eb4e448c82b9513b455956932d107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Ka=C5=BEim=C3=ADr?= Date: Fri, 14 Jun 2024 18:00:16 +0200 Subject: [PATCH] #755 XZ compression support added --- logback-core/pom.xml | 7 +++ .../rolling/FixedWindowRollingPolicy.java | 1 + .../core/rolling/RollingPolicyBase.java | 3 + .../core/rolling/helper/CompressionMode.java | 2 +- .../core/rolling/helper/Compressor.java | 56 +++++++++++++++++- logback-core/src/main/java/module-info.java | 3 + .../core/rolling/helper/CompressTest.java | 50 +++++++++++++--- .../ch/qos/logback/core/util/Compare.java | 50 +++++++++++++--- .../src/test/witness/compress1.txt.xz | Bin 0 -> 300 bytes .../src/test/witness/compress2.txt.xz | Bin 0 -> 632 bytes pom.xml | 8 +++ 11 files changed, 160 insertions(+), 20 deletions(-) create mode 100644 logback-core/src/test/witness/compress1.txt.xz create mode 100644 logback-core/src/test/witness/compress2.txt.xz diff --git a/logback-core/pom.xml b/logback-core/pom.xml index cbc2f1128e..7ab2fc76d9 100755 --- a/logback-core/pom.xml +++ b/logback-core/pom.xml @@ -40,6 +40,12 @@ true + + org.tukaani + xz + true + + jakarta.mail jakarta.mail-api @@ -180,6 +186,7 @@ org.fusesource.jansi;resolution:=optional, org.codehaus.janino;resolution:=optional, org.codehaus.commons.compiler;resolution:=optional, + org.tukaani.xz;resolution:=optional, * diff --git a/logback-core/src/main/java/ch/qos/logback/core/rolling/FixedWindowRollingPolicy.java b/logback-core/src/main/java/ch/qos/logback/core/rolling/FixedWindowRollingPolicy.java index 21450b1326..fe5ad58b86 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/rolling/FixedWindowRollingPolicy.java +++ b/logback-core/src/main/java/ch/qos/logback/core/rolling/FixedWindowRollingPolicy.java @@ -151,6 +151,7 @@ public void rollover() throws RolloverFailure { util.rename(getActiveFileName(), fileNamePattern.convertInt(minIndex)); break; case GZ: + case XZ: compressor.compress(getActiveFileName(), fileNamePattern.convertInt(minIndex), null); break; case ZIP: diff --git a/logback-core/src/main/java/ch/qos/logback/core/rolling/RollingPolicyBase.java b/logback-core/src/main/java/ch/qos/logback/core/rolling/RollingPolicyBase.java index f1ecf505e1..7c5634ea1b 100755 --- a/logback-core/src/main/java/ch/qos/logback/core/rolling/RollingPolicyBase.java +++ b/logback-core/src/main/java/ch/qos/logback/core/rolling/RollingPolicyBase.java @@ -51,6 +51,9 @@ protected void determineCompressionMode() { } else if (fileNamePatternStr.endsWith(".zip")) { addInfo("Will use zip compression"); compressionMode = CompressionMode.ZIP; + } else if (fileNamePatternStr.endsWith(".xz")) { + addInfo("Will use xz compression"); + compressionMode = CompressionMode.XZ; } else { addInfo("No compression will be used"); compressionMode = CompressionMode.NONE; diff --git a/logback-core/src/main/java/ch/qos/logback/core/rolling/helper/CompressionMode.java b/logback-core/src/main/java/ch/qos/logback/core/rolling/helper/CompressionMode.java index e2fd3cd91a..98ad0f00a1 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/rolling/helper/CompressionMode.java +++ b/logback-core/src/main/java/ch/qos/logback/core/rolling/helper/CompressionMode.java @@ -14,5 +14,5 @@ package ch.qos.logback.core.rolling.helper; public enum CompressionMode { - NONE, GZ, ZIP; + NONE, GZ, ZIP, XZ; } diff --git a/logback-core/src/main/java/ch/qos/logback/core/rolling/helper/Compressor.java b/logback-core/src/main/java/ch/qos/logback/core/rolling/helper/Compressor.java index 22efb58b3c..90ac7035bf 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/rolling/helper/Compressor.java +++ b/logback-core/src/main/java/ch/qos/logback/core/rolling/helper/Compressor.java @@ -22,6 +22,8 @@ import java.util.zip.GZIPOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import org.tukaani.xz.LZMA2Options; +import org.tukaani.xz.XZOutputStream; import ch.qos.logback.core.rolling.RolloverFailure; import ch.qos.logback.core.spi.ContextAwareBase; @@ -30,7 +32,7 @@ import ch.qos.logback.core.util.FileUtil; /** - * The Compression class implements ZIP and GZ file + * The Compression class implements ZIP,GZ and XZ file * compression/decompression methods. * * @author Ceki Gülcü @@ -56,6 +58,9 @@ public void compress(String nameOfFile2Compress, String nameOfCompressedFile, St case GZ: gzCompress(nameOfFile2Compress, nameOfCompressedFile); break; + case XZ: + xzCompress(nameOfFile2Compress, nameOfCompressedFile); + break; case ZIP: zipCompress(nameOfFile2Compress, nameOfCompressedFile, innerEntryName); break; @@ -189,6 +194,50 @@ private void gzCompress(String nameOfFile2gz, String nameOfgzedFile) { } + private void xzCompress(String nameOfFile2xz, String nameOfxzedFile) { + File file2xz = new File(nameOfFile2xz); + + if (!file2xz.exists()) { + addStatus(new WarnStatus("The file to compress named [" + nameOfFile2xz + "] does not exist.", this)); + + return; + } + + if (!nameOfxzedFile.endsWith(".xz")) { + nameOfxzedFile = nameOfxzedFile + ".xz"; + } + + File xzedFile = new File(nameOfxzedFile); + + if (xzedFile.exists()) { + addWarn("The target compressed file named [" + nameOfxzedFile + + "] exist already. Aborting file compression."); + return; + } + + addInfo("XZ compressing [" + file2xz + "] as [" + xzedFile + "]"); + createMissingTargetDirsIfNecessary(xzedFile); + + try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(nameOfFile2xz)); + XZOutputStream xzos = new XZOutputStream(new FileOutputStream(nameOfxzedFile), new LZMA2Options())) { + + byte[] inbuf = new byte[BUFFER_SIZE]; + int n; + + while ((n = bis.read(inbuf)) != -1) { + xzos.write(inbuf, 0, n); + } + } catch (Exception e) { + addStatus(new ErrorStatus( + "Error occurred while compressing [" + nameOfFile2xz + "] into [" + nameOfxzedFile + "].", this, + e)); + } + + if (!file2xz.delete()) { + addStatus(new WarnStatus("Could not delete [" + nameOfFile2xz + "].", this)); + } + } + static public String computeFileNameStrWithoutCompSuffix(String fileNamePatternStr, CompressionMode compressionMode) { int len = fileNamePatternStr.length(); @@ -198,6 +247,11 @@ static public String computeFileNameStrWithoutCompSuffix(String fileNamePatternS return fileNamePatternStr.substring(0, len - 3); else return fileNamePatternStr; + case XZ: + if (fileNamePatternStr.endsWith(".xz")) + return fileNamePatternStr.substring(0, len - 3); + else + return fileNamePatternStr; case ZIP: if (fileNamePatternStr.endsWith(".zip")) return fileNamePatternStr.substring(0, len - 4); diff --git a/logback-core/src/main/java/module-info.java b/logback-core/src/main/java/module-info.java index 3ebdacaa80..1cac384332 100644 --- a/logback-core/src/main/java/module-info.java +++ b/logback-core/src/main/java/module-info.java @@ -18,6 +18,9 @@ // optionally require jansi requires static org.fusesource.jansi; + // optionally require tukaani + requires static org.tukaani.xz; + exports ch.qos.logback.core; exports ch.qos.logback.core.boolex; diff --git a/logback-core/src/test/java/ch/qos/logback/core/rolling/helper/CompressTest.java b/logback-core/src/test/java/ch/qos/logback/core/rolling/helper/CompressTest.java index 830915ecc3..73cea34944 100755 --- a/logback-core/src/test/java/ch/qos/logback/core/rolling/helper/CompressTest.java +++ b/logback-core/src/test/java/ch/qos/logback/core/rolling/helper/CompressTest.java @@ -46,17 +46,23 @@ public void setUp() throws IOException { File dest = new File(CoreTestConstants.TEST_SRC_PREFIX + "input/compress1.txt"); copy(source, dest); - File target = new File(CoreTestConstants.OUTPUT_DIR_PREFIX + "compress1.txt.gz"); - target.mkdirs(); - target.delete(); + File gzTarget = new File(CoreTestConstants.OUTPUT_DIR_PREFIX + "compress1.txt.gz"); + gzTarget.mkdirs(); + gzTarget.delete(); + File xzTarget = new File(CoreTestConstants.OUTPUT_DIR_PREFIX + "compress1.txt.xz"); + xzTarget.mkdirs(); + xzTarget.delete(); } { File source = new File(CoreTestConstants.TEST_SRC_PREFIX + "input/compress2.copy"); File dest = new File(CoreTestConstants.TEST_SRC_PREFIX + "input/compress2.txt"); copy(source, dest); - File target = new File(CoreTestConstants.OUTPUT_DIR_PREFIX + "compress2.txt.gz"); - target.mkdirs(); - target.delete(); + File gzTarget = new File(CoreTestConstants.OUTPUT_DIR_PREFIX + "compress2.txt.gz"); + gzTarget.mkdirs(); + gzTarget.delete(); + File xzTarget = new File(CoreTestConstants.OUTPUT_DIR_PREFIX + "compress2.txt.xz"); + xzTarget.mkdirs(); + xzTarget.delete(); } { File source = new File(CoreTestConstants.TEST_SRC_PREFIX + "input/compress3.copy"); @@ -69,7 +75,7 @@ public void setUp() throws IOException { } @Test - public void test1() throws Exception { + public void test_gz_1() throws Exception { Compressor compressor = new Compressor(CompressionMode.GZ); compressor.setContext(context); compressor.compress(CoreTestConstants.TEST_SRC_PREFIX + "input/compress1.txt", @@ -82,7 +88,7 @@ public void test1() throws Exception { } @Test - public void test2() throws Exception { + public void test_gz_2() throws Exception { Compressor compressor = new Compressor(CompressionMode.GZ); compressor.setContext(context); compressor.compress(CoreTestConstants.TEST_SRC_PREFIX + "input/compress2.txt", @@ -96,7 +102,7 @@ public void test2() throws Exception { } @Test - public void test3() throws Exception { + public void test_zip_1() { Compressor compressor = new Compressor(CompressionMode.ZIP); compressor.setContext(context); compressor.compress(CoreTestConstants.TEST_SRC_PREFIX + "input/compress3.txt", @@ -110,6 +116,32 @@ public void test3() throws Exception { // + "witness/compress3.txt.zip")); } + @Test + public void test_xz_1() throws Exception { + Compressor compressor = new Compressor(CompressionMode.XZ); + compressor.setContext(context); + compressor.compress(CoreTestConstants.TEST_SRC_PREFIX + "input/compress1.txt", + CoreTestConstants.OUTPUT_DIR_PREFIX + "compress1.txt.xz", null); + + StatusChecker checker = new StatusChecker(context); + Assertions.assertTrue(checker.isErrorFree(0)); + Assertions.assertTrue(Compare.xzCompare(CoreTestConstants.OUTPUT_DIR_PREFIX + "compress1.txt.xz", + CoreTestConstants.TEST_SRC_PREFIX + "witness/compress1.txt.xz")); + } + + @Test + public void test_xz_2() throws Exception { + Compressor compressor = new Compressor(CompressionMode.XZ); + compressor.setContext(context); + compressor.compress(CoreTestConstants.TEST_SRC_PREFIX + "input/compress2.txt", + CoreTestConstants.OUTPUT_DIR_PREFIX + "compress2.txt.xz", null); + + StatusChecker checker = new StatusChecker(context); + Assertions.assertTrue(checker.isErrorFree(0)); + Assertions.assertTrue(Compare.xzCompare(CoreTestConstants.OUTPUT_DIR_PREFIX + "compress2.txt.xz", + CoreTestConstants.TEST_SRC_PREFIX + "witness/compress2.txt.xz")); + } + private void copy(File src, File dst) throws IOException { try (InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dst);) { diff --git a/logback-core/src/test/java/ch/qos/logback/core/util/Compare.java b/logback-core/src/test/java/ch/qos/logback/core/util/Compare.java index 7f8553ab1e..1ba0ebc7a4 100644 --- a/logback-core/src/test/java/ch/qos/logback/core/util/Compare.java +++ b/logback-core/src/test/java/ch/qos/logback/core/util/Compare.java @@ -13,6 +13,8 @@ */ package ch.qos.logback.core.util; +import org.tukaani.xz.XZInputStream; + import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -138,12 +140,45 @@ private static void outputFile(String file) throws FileNotFoundException, IOExce } } - public static boolean gzCompare(String file1, String file2) throws FileNotFoundException, IOException { - BufferedReader in1 = null; - BufferedReader in2 = null; - try { - in1 = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(file1)))); - in2 = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(file2)))); + public static boolean gzCompare(String file1, String file2) throws IOException { + try (BufferedReader in1 = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(file1)))); + BufferedReader in2 = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(file2))));) { + + String s1; + int lineCounter = 0; + + while ((s1 = in1.readLine()) != null) { + lineCounter++; + + String s2 = in2.readLine(); + + if (!s1.equals(s2)) { + System.out.println("Files [" + file1 + "] and [" + file2 + "] differ on line " + lineCounter); + System.out.println("One reads: [" + s1 + "]."); + System.out.println("Other reads:[" + s2 + "]."); + outputFile(file1); + outputFile(file2); + + return false; + } + } + + // the second file is longer + if (in2.read() != -1) { + System.out.println("File [" + file2 + "] longer than file [" + file1 + "]."); + outputFile(file1); + outputFile(file2); + + return false; + } + + return true; + } + } + + public static boolean xzCompare(String file1, String file2) throws IOException { + try (BufferedReader in1 = new BufferedReader(new InputStreamReader(new XZInputStream(new FileInputStream(file1)))); + BufferedReader in2 = new BufferedReader(new InputStreamReader(new XZInputStream(new FileInputStream(file2))))) { String s1; int lineCounter = 0; @@ -174,9 +209,6 @@ public static boolean gzCompare(String file1, String file2) throws FileNotFoundE } return true; - } finally { - close(in1); - close(in2); } } diff --git a/logback-core/src/test/witness/compress1.txt.xz b/logback-core/src/test/witness/compress1.txt.xz new file mode 100644 index 0000000000000000000000000000000000000000..46d13c1316c6817898241f255e1eaf47123417b7 GIT binary patch literal 300 zcmV+{0n`5dH+ooF000E$*0e?f03iVu0001VFXf})0VDwHT>u3L^dDx%yfS~_R-&Sx zYvcpT-HEc{;sC7XJ#*WGoUF(inE?yvwTjMpGXX(s1g&2B1w5tMk))}`aO4`uaAAZ% z1@l=Pr_riJHkeeLH{FKdNS^!7cGuaqPHGwTm&|Lh0wKQMGd z*|%eN`32YjOoc?@Ai_3q#OAQMac0b7P&6?^?Z^87q|7yO zaCh4p_x0BRJ9dQ&s;v$Ob$S8Fo;K5?j%JSv@pZ>xRV**t@@+)$>BK4VF6-v`{7rCB y2DqTq6FB~d5&T==0000-oLT-*mhlq+0fz#m0ssJno)N>b#Ao{g000001X)_F=8Vw* literal 0 HcmV?d00001 diff --git a/logback-core/src/test/witness/compress2.txt.xz b/logback-core/src/test/witness/compress2.txt.xz new file mode 100644 index 0000000000000000000000000000000000000000..41a3b678a2d999b49a44b5ff7427da65edac934a GIT binary patch literal 632 zcmV-;0*C$mH+ooF000E$*0e?f03iVu0001VFXf})1GWM+T>u^r%ZCxz&SsGhgC5HL zdo$F3>9^bCsc|&IC4OB75xxG)(#YMrLaq(w)&j|1EU|*62I4%I4F5hc?WT*nW@pE% z6*-|35VUL9-=Xm>%ry7%F)paaK@tUJQa;rPBMLt_faH zLn;s_ZUmlhVN|d#fB3d%*MCsN)-@yfF$2GC`BH`R`jSaPt#Pz=;yecc9Kd;e0fxv$ zgk7Ep!cs*F{$FFqiHS@U2ZJFQ1&lpvXr)`gz-LqR{Pa!hab^aa+c4pJ7$%J%?6{bP z^6tkSiB|*_*~NiiZAS=agaitq2b%Pgk`5+_FEw+xA%h(bmU8{GR(v@7ePrOO^$;91 z{1QZFQdy2aVQ!e@jV*b@h1d{XTA*6)vIXRuJlBHia*^ZC9X>h?{jYtk04fO=@lU*B zmCmBEB}6mc%j2Nu=jIwuQSQk2-%w(_z8Dmcyj`(CPx$s3vbybTFFo@Wh<|NnFOM-V z*RU631.18--> 2.4.0 + 1.9 + 4.8.0 1.12.14 @@ -200,6 +202,12 @@ ${jansi.version} + + org.tukaani + xz + ${tukaani.version} + + jakarta.mail jakarta.mail-api