Skip to content

Commit f4392b1

Browse files
authored
Adds a Configuration Converter API (#142)
Adds an API to perform automatic conversions between different logging configuration file formats and a basic implementation. The implementation supports the following configuration file formats: - Log4j Core 2 XML, - Log4j Core 2 JSON, - Log4j Core 2 YAML, - Log4j Core 2 Properties (read-only), - Log4j Core 3 Properties. The API is extensible through `ServiceLoader` and allows integrators to provide support for additional configuration file formats. Read-only support for the Log4j 1 Properties and Log4j 1 XML configuration formats will be provided in a separate PR. **Note**: Currently the API is only accessible from Java code. Its main purpose is to provide a "Migrate Log4j 1.x to Log4j Core 2.x", a "Migrate Logback to Log4j Core 2.x" and a "Migrate JUL to Log4j Core 2.x" [OpenRewrite recipe](https://docs.openrewrite.org/recipes/java/logging/log4j). A `picocli`-based `log4j-transform-cli` tool to access all the goodies in this repository, will be provided later. Closes apache/logging-log4j2#2080
1 parent 27ef8a8 commit f4392b1

Some content is hidden

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

45 files changed

+3234
-30
lines changed

log4j-codegen/pom.xml

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,24 +43,6 @@
4343

4444
<dependencies>
4545

46-
<dependency>
47-
<groupId>org.osgi</groupId>
48-
<artifactId>org.osgi.annotation.bundle</artifactId>
49-
<scope>provided</scope>
50-
</dependency>
51-
52-
<dependency>
53-
<groupId>org.osgi</groupId>
54-
<artifactId>org.osgi.annotation.versioning</artifactId>
55-
<scope>provided</scope>
56-
</dependency>
57-
58-
<dependency>
59-
<groupId>com.github.spotbugs</groupId>
60-
<artifactId>spotbugs-annotations</artifactId>
61-
<scope>provided</scope>
62-
</dependency>
63-
6446
<!-- Compile dependencies: the artifact is shaded, so limit these. -->
6547
<dependency>
6648
<groupId>info.picocli</groupId>

log4j-converter-config/pom.xml

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
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-transform-parent</artifactId>
23+
<version>${revision}</version>
24+
<relativePath>../log4j-transform-parent</relativePath>
25+
</parent>
26+
27+
<artifactId>log4j-converter-config</artifactId>
28+
<name>Apache Log4j Configuration Converter</name>
29+
<description>Converts various logging configuration formats to the Log4j Core 2.x format.</description>
30+
31+
<properties>
32+
<!-- This artifact is an API: we need to generate its Javadoc -->
33+
<maven.javadoc.skip>false</maven.javadoc.skip>
34+
35+
<!-- Remove after first release -->
36+
<bnd.baseline.fail.on.missing>false</bnd.baseline.fail.on.missing>
37+
38+
<!-- Dependencies -->
39+
<jackson.version>2.18.1</jackson.version>
40+
<txw2.version>4.0.5</txw2.version>
41+
</properties>
42+
43+
<dependencyManagement>
44+
<dependencies>
45+
46+
<dependency>
47+
<groupId>com.fasterxml.jackson</groupId>
48+
<artifactId>jackson-bom</artifactId>
49+
<version>${jackson.version}</version>
50+
<type>pom</type>
51+
<scope>import</scope>
52+
</dependency>
53+
54+
</dependencies>
55+
</dependencyManagement>
56+
57+
<dependencies>
58+
59+
<dependency>
60+
<groupId>org.apache.logging.log4j</groupId>
61+
<artifactId>log4j-api</artifactId>
62+
</dependency>
63+
64+
<dependency>
65+
<groupId>org.jspecify</groupId>
66+
<artifactId>jspecify</artifactId>
67+
</dependency>
68+
69+
<!-- Used in the JSON configuration format -->
70+
<dependency>
71+
<groupId>com.fasterxml.jackson.core</groupId>
72+
<artifactId>jackson-databind</artifactId>
73+
</dependency>
74+
75+
<!-- Used in the v3 Properties configuration format -->
76+
<dependency>
77+
<groupId>com.fasterxml.jackson.dataformat</groupId>
78+
<artifactId>jackson-dataformat-properties</artifactId>
79+
</dependency>
80+
81+
<!-- Used in the YAML configuration format -->
82+
<dependency>
83+
<groupId>com.fasterxml.jackson.dataformat</groupId>
84+
<artifactId>jackson-dataformat-yaml</artifactId>
85+
</dependency>
86+
87+
<!-- Used in the XML configuration format -->
88+
<dependency>
89+
<groupId>org.glassfish.jaxb</groupId>
90+
<artifactId>txw2</artifactId>
91+
<version>${txw2.version}</version>
92+
</dependency>
93+
94+
<dependency>
95+
<groupId>org.junit.jupiter</groupId>
96+
<artifactId>junit-jupiter-api</artifactId>
97+
<scope>test</scope>
98+
</dependency>
99+
100+
<dependency>
101+
<groupId>org.junit.jupiter</groupId>
102+
<artifactId>junit-jupiter-params</artifactId>
103+
<scope>test</scope>
104+
</dependency>
105+
106+
<dependency>
107+
<groupId>org.assertj</groupId>
108+
<artifactId>assertj-core</artifactId>
109+
<scope>test</scope>
110+
</dependency>
111+
112+
</dependencies>
113+
</project>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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.converter.config;
18+
19+
import java.io.InputStream;
20+
import java.io.OutputStream;
21+
import java.util.Set;
22+
import org.apache.logging.converter.config.internal.DefaultConfigurationConverter;
23+
24+
/**
25+
* Service class to convert between different logging configuration formats.
26+
*/
27+
public interface ConfigurationConverter {
28+
29+
/**
30+
* A default implementation of {@link ConfigurationConverter} that uses {@link java.util.ServiceLoader} to load additional formats.
31+
* @see org.apache.logging.converter.config.spi.ConfigurationMapper
32+
*/
33+
static ConfigurationConverter getInstance() {
34+
return DefaultConfigurationConverter.INSTANCE;
35+
}
36+
37+
/**
38+
* Converts a logging configuration file from one format to another.
39+
*
40+
* @param inputStream The input configuration file, never {@code null}.
41+
* @param inputFormat The input format. Must be one of the formats returned by {@link #getSupportedInputFormats()}.
42+
* @param outputStream The output configuration file, never {@code null}.
43+
* @param outputFormat The output format. Must be one of the formats returned by {@link #getSupportedOutputFormats()}.
44+
* @throws ConfigurationConverterException If any kind of error occurs during the conversion process.
45+
*/
46+
void convert(InputStream inputStream, String inputFormat, OutputStream outputStream, String outputFormat)
47+
throws ConfigurationConverterException;
48+
49+
/**
50+
* Returns the list of supported input formats.
51+
*/
52+
Set<String> getSupportedInputFormats();
53+
54+
/**
55+
* Returns the list of supported output formats.
56+
*/
57+
Set<String> getSupportedOutputFormats();
58+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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.converter.config;
18+
19+
/**
20+
* Exception thrown by {@link ConfigurationConverter}, when a problem occurs during the conversion.
21+
*/
22+
public class ConfigurationConverterException extends RuntimeException {
23+
24+
private static final long serialVersionUID = 1L;
25+
26+
public ConfigurationConverterException(final String message) {
27+
super(message);
28+
}
29+
30+
public ConfigurationConverterException(final String message, final Throwable cause) {
31+
super(message, cause);
32+
}
33+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
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.converter.config.internal;
18+
19+
import java.util.ArrayList;
20+
import java.util.Collection;
21+
import java.util.Collections;
22+
import java.util.List;
23+
import java.util.Map;
24+
import java.util.TreeMap;
25+
import java.util.function.Supplier;
26+
import org.apache.logging.converter.config.ConfigurationConverterException;
27+
import org.apache.logging.converter.config.spi.ConfigurationNode;
28+
import org.jspecify.annotations.Nullable;
29+
30+
public final class ComponentUtils {
31+
32+
public static ConfigurationNodeBuilder newNodeBuilder() {
33+
return new ConfigurationNodeBuilder();
34+
}
35+
36+
public static ConfigurationNode createThresholdFilter(String level) {
37+
return newNodeBuilder()
38+
.setPluginName("ThresholdFilter")
39+
.addAttribute("level", level)
40+
.build();
41+
}
42+
43+
public static ConfigurationNode createCompositeFilter(Iterable<? extends ConfigurationNode> filters) {
44+
ConfigurationNodeBuilder builder = newNodeBuilder().setPluginName("Filters");
45+
filters.forEach(builder::addChild);
46+
return builder.build();
47+
}
48+
49+
private ComponentUtils() {}
50+
51+
public static class ConfigurationNodeBuilder implements Supplier<ConfigurationNode> {
52+
53+
private @Nullable String pluginName;
54+
private final Map<String, String> attributes = new TreeMap<>();
55+
private final List<ConfigurationNode> children = new ArrayList<>();
56+
57+
protected ConfigurationNodeBuilder() {}
58+
59+
public ConfigurationNodeBuilder setPluginName(String pluginName) {
60+
this.pluginName = pluginName;
61+
return this;
62+
}
63+
64+
public ConfigurationNodeBuilder addAttribute(String key, @Nullable String value) {
65+
if (value != null) {
66+
attributes.put(key, value);
67+
}
68+
return this;
69+
}
70+
71+
public ConfigurationNodeBuilder addAttribute(String key, boolean value) {
72+
attributes.put(key, String.valueOf(value));
73+
return this;
74+
}
75+
76+
public ConfigurationNodeBuilder addChild(ConfigurationNode child) {
77+
children.add(child);
78+
return this;
79+
}
80+
81+
public ConfigurationNode build() {
82+
if (pluginName == null) {
83+
throw new ConfigurationConverterException("No plugin name specified");
84+
}
85+
return new ConfigurationNodeImpl(pluginName, attributes, children);
86+
}
87+
88+
@Override
89+
public ConfigurationNode get() {
90+
return build();
91+
}
92+
}
93+
94+
private static final class ConfigurationNodeImpl implements ConfigurationNode {
95+
96+
private final String pluginName;
97+
private final Map<String, String> attributes;
98+
private final List<ConfigurationNode> children;
99+
100+
private ConfigurationNodeImpl(
101+
final String pluginName,
102+
final Map<String, String> attributes,
103+
final Collection<ConfigurationNode> children) {
104+
this.pluginName = pluginName;
105+
this.attributes = Collections.unmodifiableMap(new TreeMap<>(attributes));
106+
this.children = Collections.unmodifiableList(new ArrayList<>(children));
107+
}
108+
109+
@Override
110+
public String getPluginName() {
111+
return pluginName;
112+
}
113+
114+
@Override
115+
public Map<String, String> getAttributes() {
116+
return attributes;
117+
}
118+
119+
@Override
120+
public List<? extends ConfigurationNode> getChildren() {
121+
return children;
122+
}
123+
124+
private static void formatTo(ConfigurationNode node, StringBuilder builder, int indent) {
125+
String indentation = getIndentation(indent);
126+
builder.append(indentation).append("<").append(node.getPluginName());
127+
for (final Map.Entry<String, String> entry : node.getAttributes().entrySet()) {
128+
builder.append(" ")
129+
.append(entry.getKey())
130+
.append("=\"")
131+
.append(entry.getValue())
132+
.append("\"");
133+
}
134+
builder.append(">\n");
135+
for (ConfigurationNode child : node.getChildren()) {
136+
formatTo(child, builder, indent + 1);
137+
builder.append('\n');
138+
}
139+
builder.append(indentation)
140+
.append("</")
141+
.append(node.getPluginName())
142+
.append(">");
143+
}
144+
145+
private static String getIndentation(int indent) {
146+
return String.join("", Collections.nCopies(indent, " "));
147+
}
148+
149+
@Override
150+
public String toString() {
151+
StringBuilder builder = new StringBuilder();
152+
formatTo(this, builder, 0);
153+
return builder.toString();
154+
}
155+
}
156+
}

0 commit comments

Comments
 (0)