Skip to content

Commit 22ad6b2

Browse files
committed
Move compression into new log4j-compress module
We move the code that depends on Commons Compress into a new `log4j-compress` module. At the same time, we perform the following behavioral changes: - Compression is performed by the `CompressActionFactoryProvider`, with the maximum order. In the current setting, if `log4j-compress` is on the classpath, it is used for everything, even GZ and ZIP. - The `compressionLevel` parameter, specific to the GZ and ZIP compression factories in the JRE, is replaced by a more generic `compressionOptions` map. This will allow adding more compression options in the future if users request it. - The available list of compression algorithms is no longer hardcoded, but depends entirely on the list of compressors supported by Apache Commons Compress. > [!NOTE] > Currently Commons Compress does not offer an algorithm-independent > interface to supply additional compression options. > However, each algorithm does provide such a way.
1 parent 326ae14 commit 22ad6b2

File tree

210 files changed

+1697
-1157
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

210 files changed

+1697
-1157
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This file is here to activate the `plugin-processing` Maven profile.

log4j-compress/pom.xml

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Licensed to the Apache Software Foundation (ASF) under one or more
4+
~ contributor license agreements. See the NOTICE file distributed with
5+
~ this work for additional information regarding copyright ownership.
6+
~ The ASF licenses this file to you under the Apache License, Version 2.0
7+
~ (the "License"); you may not use this file except in compliance with
8+
~ the License. You may obtain a copy of the License at
9+
~
10+
~ http://www.apache.org/licenses/LICENSE-2.0
11+
~
12+
~ Unless required by applicable law or agreed to in writing, software
13+
~ distributed under the License is distributed on an "AS IS" BASIS,
14+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
~ See the License for the specific language governing permissions and
16+
~ limitations under the License.
17+
-->
18+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
19+
<modelVersion>4.0.0</modelVersion>
20+
<parent>
21+
<groupId>org.apache.logging.log4j</groupId>
22+
<artifactId>log4j</artifactId>
23+
<version>${revision}</version>
24+
<relativePath>../log4j-parent</relativePath>
25+
</parent>
26+
27+
<artifactId>log4j-compress</artifactId>
28+
<name>Apache Log4j Core: Extended Compression Support</name>
29+
<description>Add additional compression formats to Log4j Core.</description>
30+
31+
<properties>
32+
<commons-compress.version>1.27.1</commons-compress.version>
33+
<jimfs.version>1.3.0</jimfs.version>
34+
<xz.version>1.10</xz.version>
35+
<zstd.version>1.5.6-5</zstd.version>
36+
</properties>
37+
38+
<dependencyManagement>
39+
<dependencies>
40+
41+
<dependency>
42+
<groupId>org.apache.commons</groupId>
43+
<artifactId>commons-compress</artifactId>
44+
<version>${commons-compress.version}</version>
45+
</dependency>
46+
47+
<dependency>
48+
<groupId>com.google.jimfs</groupId>
49+
<artifactId>jimfs</artifactId>
50+
<version>${jimfs.version}</version>
51+
</dependency>
52+
53+
<dependency>
54+
<groupId>org.tukaani</groupId>
55+
<artifactId>xz</artifactId>
56+
<version>${xz.version}</version>
57+
</dependency>
58+
59+
<dependency>
60+
<groupId>com.github.luben</groupId>
61+
<artifactId>zstd-jni</artifactId>
62+
<version>${zstd.version}</version>
63+
</dependency>
64+
65+
</dependencies>
66+
</dependencyManagement>
67+
68+
<dependencies>
69+
70+
<dependency>
71+
<groupId>org.apache.commons</groupId>
72+
<artifactId>commons-compress</artifactId>
73+
</dependency>
74+
75+
<dependency>
76+
<groupId>org.apache.logging.log4j</groupId>
77+
<artifactId>log4j-api</artifactId>
78+
</dependency>
79+
80+
<dependency>
81+
<groupId>org.apache.logging.log4j</groupId>
82+
<artifactId>log4j-core</artifactId>
83+
</dependency>
84+
85+
<dependency>
86+
<groupId>org.apache.logging.log4j</groupId>
87+
<artifactId>log4j-plugins</artifactId>
88+
</dependency>
89+
90+
<dependency>
91+
<groupId>org.assertj</groupId>
92+
<artifactId>assertj-core</artifactId>
93+
<scope>test</scope>
94+
</dependency>
95+
96+
<dependency>
97+
<groupId>org.junit.jupiter</groupId>
98+
<artifactId>junit-jupiter-api</artifactId>
99+
<scope>test</scope>
100+
</dependency>
101+
102+
<dependency>
103+
<groupId>org.junit.jupiter</groupId>
104+
<artifactId>junit-jupiter-params</artifactId>
105+
<scope>test</scope>
106+
</dependency>
107+
108+
<dependency>
109+
<groupId>com.google.jimfs</groupId>
110+
<artifactId>jimfs</artifactId>
111+
<scope>test</scope>
112+
</dependency>
113+
114+
<dependency>
115+
<groupId>org.apache.logging.log4j</groupId>
116+
<artifactId>log4j-api-test</artifactId>
117+
<scope>test</scope>
118+
</dependency>
119+
120+
</dependencies>
121+
122+
<build>
123+
<plugins>
124+
125+
<plugin>
126+
<groupId>org.apache.maven.plugins</groupId>
127+
<artifactId>maven-surefire-plugin</artifactId>
128+
<executions>
129+
<execution>
130+
<id>default-test</id>
131+
<configuration>
132+
<excludes>
133+
<exclude>org/apache/logging/log4j/compress/commons/lzma/*</exclude>
134+
<exclude>org/apache/logging/log4j/compress/commons/xz/*</exclude>
135+
<exclude>org/apache/logging/log4j/compress/commons/zstd/*</exclude>
136+
</excludes>
137+
</configuration>
138+
</execution>
139+
<!--
140+
~ The XZ algorithm requires additional Commons Compress dependencies
141+
-->
142+
<execution>
143+
<id>test-xz</id>
144+
<goals>
145+
<goal>test</goal>
146+
</goals>
147+
<configuration>
148+
<additionalClasspathDependencies>
149+
<dependency>
150+
<groupId>org.tukaani</groupId>
151+
<artifactId>xz</artifactId>
152+
<version>${xz.version}</version>
153+
</dependency>
154+
</additionalClasspathDependencies>
155+
<includes>
156+
<include>org/apache/logging/log4j/compress/commons/xz/*Test.class</include>
157+
</includes>
158+
</configuration>
159+
</execution>
160+
<!--
161+
~ The XZ algorithm requires additional Commons Compress dependencies
162+
-->
163+
<execution>
164+
<id>test-zstd</id>
165+
<goals>
166+
<goal>test</goal>
167+
</goals>
168+
<configuration>
169+
<additionalClasspathDependencies>
170+
<dependency>
171+
<groupId>com.github.luben</groupId>
172+
<artifactId>zstd-jni</artifactId>
173+
<version>${zstd.version}</version>
174+
</dependency>
175+
</additionalClasspathDependencies>
176+
<includes>
177+
<include>org/apache/logging/log4j/compress/commons/zstd/*Test.class</include>
178+
</includes>
179+
</configuration>
180+
</execution>
181+
</executions>
182+
</plugin>
183+
184+
</plugins>
185+
</build>
186+
</project>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.compress.commons;
18+
19+
import java.io.BufferedOutputStream;
20+
import java.io.IOException;
21+
import java.io.OutputStream;
22+
import java.nio.file.Path;
23+
import java.util.Objects;
24+
import org.apache.commons.compress.compressors.CompressorException;
25+
import org.apache.commons.compress.compressors.CompressorStreamProvider;
26+
import org.apache.logging.log4j.core.appender.rolling.action.AbstractCompressAction;
27+
28+
/**
29+
* Compresses a file using bzip2 compression.
30+
*/
31+
final class CommonsCompressAction extends AbstractCompressAction {
32+
33+
private final CompressorStreamProvider provider;
34+
35+
/**
36+
* Compressor name. One of "gz", "bzip2", "xz", "pack200" or "deflate".
37+
*/
38+
private final String name;
39+
40+
/**
41+
* Creates new instance of Bzip2CompressAction.
42+
*
43+
* @param name The compressor name. One of "gz", "bzip2", "xz", "pack200", or "deflate".
44+
* @param source The file to compress, may not be null.
45+
* @param destination The compressed file, may not be null.
46+
*/
47+
CommonsCompressAction(
48+
final CompressorStreamProvider provider, final String name, final Path source, final Path destination) {
49+
super(source, destination);
50+
this.provider = Objects.requireNonNull(provider);
51+
this.name = Objects.requireNonNull(name, "name");
52+
}
53+
54+
@Override
55+
protected OutputStream wrapOutputStream(OutputStream stream) throws IOException {
56+
try {
57+
return new BufferedOutputStream(provider.createCompressorOutputStream(name, stream), BUF_SIZE);
58+
} catch (final CompressorException e) {
59+
throw new IOException(e);
60+
}
61+
}
62+
63+
@Override
64+
protected String getAlgorithmName() {
65+
return name;
66+
}
67+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.compress.commons;
18+
19+
import java.nio.file.Path;
20+
import java.util.Map;
21+
import org.apache.commons.compress.compressors.CompressorStreamProvider;
22+
import org.apache.logging.log4j.core.appender.rolling.action.Action;
23+
import org.apache.logging.log4j.core.appender.rolling.action.CompressActionFactory;
24+
import org.jspecify.annotations.NullMarked;
25+
26+
@NullMarked
27+
final class CommonsCompressActionFactory implements CompressActionFactory {
28+
29+
private final CompressorStreamProvider provider;
30+
31+
private final String name;
32+
33+
CommonsCompressActionFactory(final String name, final CompressorStreamProvider provider) {
34+
this.name = name;
35+
this.provider = provider;
36+
}
37+
38+
@Override
39+
public Action createCompressAction(final Path source, final Path destination, final Map<String, ?> ignored) {
40+
return new CommonsCompressAction(provider, name, source, destination);
41+
}
42+
43+
@Override
44+
public String getAlgorithmName() {
45+
return name;
46+
}
47+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.compress.commons;
18+
19+
import static org.apache.logging.log4j.util.Strings.toRootLowerCase;
20+
import static org.apache.logging.log4j.util.Strings.toRootUpperCase;
21+
22+
import org.apache.commons.compress.compressors.CompressorStreamFactory;
23+
import org.apache.commons.compress.compressors.CompressorStreamProvider;
24+
import org.apache.commons.compress.compressors.lzma.LZMAUtils;
25+
import org.apache.commons.compress.compressors.xz.XZUtils;
26+
import org.apache.commons.compress.compressors.zstandard.ZstdUtils;
27+
import org.apache.logging.log4j.Logger;
28+
import org.apache.logging.log4j.core.appender.rolling.action.CompressActionFactory;
29+
import org.apache.logging.log4j.core.appender.rolling.action.CompressActionFactoryProvider;
30+
import org.apache.logging.log4j.plugins.Namespace;
31+
import org.apache.logging.log4j.plugins.Ordered;
32+
import org.apache.logging.log4j.plugins.Plugin;
33+
import org.apache.logging.log4j.status.StatusLogger;
34+
import org.jspecify.annotations.Nullable;
35+
36+
@Plugin
37+
@Namespace(CompressActionFactoryProvider.NAMESPACE)
38+
@Ordered(0)
39+
public final class CommonsCompressActionFactoryProvider implements CompressActionFactoryProvider {
40+
41+
private static final Logger LOGGER = StatusLogger.getLogger();
42+
private static final String COMMONS_COMPRESS_DOCUMENTATION =
43+
"See https://commons.apache.org/proper/commons-compress/index.html for more information.";
44+
45+
private final CompressorStreamFactory factory = new CompressorStreamFactory();
46+
47+
private static void missingDependencyWarning(final String algorithm) {
48+
LOGGER.warn(
49+
"{} compression is not available due to a missing dependency. {}",
50+
algorithm,
51+
COMMONS_COMPRESS_DOCUMENTATION);
52+
}
53+
54+
private @Nullable CompressorStreamProvider getCompressorStreamProvider(String algorithm) {
55+
switch (toRootLowerCase(algorithm)) {
56+
case CompressorStreamFactory.LZMA:
57+
if (!LZMAUtils.isLZMACompressionAvailable()) {
58+
missingDependencyWarning("LZMA");
59+
return null;
60+
}
61+
break;
62+
case CompressorStreamFactory.PACK200:
63+
LOGGER.warn("Pack200 compression is not suitable for log files and will not be used.");
64+
return null;
65+
case CompressorStreamFactory.XZ:
66+
if (!XZUtils.isXZCompressionAvailable()) {
67+
missingDependencyWarning("XZ");
68+
return null;
69+
}
70+
break;
71+
case CompressorStreamFactory.ZSTANDARD:
72+
if (!ZstdUtils.isZstdCompressionAvailable()) {
73+
missingDependencyWarning("Zstd");
74+
return null;
75+
}
76+
break;
77+
}
78+
// Commons Compress uses upper case keys.
79+
return CompressorStreamFactory.findAvailableCompressorOutputStreamProviders()
80+
.get(toRootUpperCase(algorithm));
81+
}
82+
83+
@Override
84+
public @Nullable CompressActionFactory createFactoryForAlgorithm(String algorithm) {
85+
CompressorStreamProvider provider = getCompressorStreamProvider(algorithm);
86+
if (provider != null) {
87+
return new CommonsCompressActionFactory(algorithm, provider);
88+
}
89+
return null;
90+
}
91+
}

0 commit comments

Comments
 (0)