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 0000000000..46d13c1316
Binary files /dev/null and b/logback-core/src/test/witness/compress1.txt.xz differ
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 0000000000..41a3b678a2
Binary files /dev/null and b/logback-core/src/test/witness/compress2.txt.xz differ
diff --git a/pom.xml b/pom.xml
index 1f16f1ce1e..5e79119f43 100755
--- a/pom.xml
+++ b/pom.xml
@@ -83,6 +83,8 @@
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