1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.log4j.config;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.URI;
22 import java.util.Arrays;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.Map.Entry;
26 import java.util.Properties;
27
28 import org.apache.logging.log4j.Level;
29 import org.apache.logging.log4j.core.appender.ConsoleAppender;
30 import org.apache.logging.log4j.core.appender.ConsoleAppender.Target;
31 import org.apache.logging.log4j.core.config.Configuration;
32 import org.apache.logging.log4j.core.config.ConfigurationFactory;
33 import org.apache.logging.log4j.core.config.ConfigurationSource;
34 import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
35 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
36 import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
37 import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
38 import org.apache.logging.log4j.status.StatusLogger;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public class Log4j1ConfigurationFactory extends ConfigurationFactory {
70
71 private Map<String, String> buildClassToPropertyPrefixMap(final Properties properties,
72 final String[] sortedAppenderNames) {
73 final String prefix = "log4j.appender.";
74 final int preLength = prefix.length();
75 final Map<String, String> map = new HashMap<>(sortedAppenderNames.length);
76 for (final Entry<Object, Object> entry : properties.entrySet()) {
77 final Object keyObj = entry.getKey();
78 if (keyObj != null) {
79 final String key = keyObj.toString();
80 if (key.startsWith(prefix)) {
81 if (key.indexOf('.', preLength) < 0) {
82 final String name = key.substring(preLength);
83 if (Arrays.binarySearch(sortedAppenderNames, name) >= 0) {
84 final Object value = entry.getValue();
85 if (value != null) {
86 map.put(name, value.toString());
87 }
88 }
89 }
90 }
91 }
92 }
93 return map;
94 }
95
96 private void buildConsoleAppender(final Properties properties, final String name,
97 final ConfigurationBuilder<BuiltConfiguration> builder) {
98 final AppenderComponentBuilder appenderBuilder = builder.newAppender(name, "CONSOLE");
99 buildConsoleAppenderTarget(properties, name, builder, appenderBuilder);
100 buildAppenderLayout(properties, name, builder, appenderBuilder);
101 buildConsoleAppenderFollow(properties, name, builder, appenderBuilder);
102 builder.add(appenderBuilder);
103 }
104
105 private void buildAppenderLayout(final Properties properties, final String name,
106 final ConfigurationBuilder<BuiltConfiguration> builder, final AppenderComponentBuilder appenderBuilder) {
107 final String layoutValue = getLog4jAppenderValue(properties, name, "layout", null);
108 if (layoutValue != null) {
109 final String cpValue = getLog4jAppenderValue(properties, name, "layout.ConversionPattern", null);
110 switch (layoutValue) {
111 case "org.apache.log4j.PatternLayout": {
112 appenderBuilder.add(newPatternLayout(builder, cpValue));
113 break;
114 }
115 case "org.apache.log4j.EnhancedPatternLayout": {
116 appenderBuilder.add(newPatternLayout(builder, cpValue));
117 break;
118 }
119 case "org.apache.log4j.SimpleLayout": {
120 appenderBuilder.add(newPatternLayout(builder, "%level - %m%n"));
121 break;
122 }
123 case "org.apache.log4j.TTCCLayout": {
124
125 appenderBuilder.add(newPatternLayout(builder, "%relative [%threadName] %level %logger - %m%n"));
126 break;
127 }
128 case "org.apache.log4j.HTMLLayout": {
129 appenderBuilder.add(builder.newLayout("HtmlLayout"));
130 break;
131 }
132 case "org.apache.log4j.XMLLayout": {
133 appenderBuilder.add(builder.newLayout("XmlLayout"));
134 break;
135 }
136 default:
137 reportWarning("Unsupported value for console appender layout: " + layoutValue);
138 }
139 }
140 }
141
142 private LayoutComponentBuilder newPatternLayout(final ConfigurationBuilder<BuiltConfiguration> builder,
143 final String pattern) {
144 final LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout");
145 if (pattern != null) {
146 layoutBuilder.addAttribute("pattern", pattern);
147 }
148 return layoutBuilder;
149 }
150
151 private void buildConsoleAppenderTarget(final Properties properties, final String name,
152 final ConfigurationBuilder<BuiltConfiguration> builder, final AppenderComponentBuilder appenderBuilder) {
153 final String value = getLog4jAppenderValue(properties, name, "Target", "System.out");
154 if (value != null) {
155 final Target target;
156 switch (value) {
157 case "System.out":
158 target = ConsoleAppender.Target.SYSTEM_OUT;
159 break;
160 case "System.err":
161 target = ConsoleAppender.Target.SYSTEM_ERR;
162 break;
163 default:
164 reportWarning("Unknow value for console Target: " + value);
165 target = null;
166 }
167 if (target != null) {
168 appenderBuilder.addAttribute("target", target);
169 }
170 }
171 }
172
173 private void buildConsoleAppenderFollow(final Properties properties, final String name,
174 final ConfigurationBuilder<BuiltConfiguration> builder, final AppenderComponentBuilder appenderBuilder) {
175 final String value = getLog4jAppenderValue(properties, name, "Follow", "false");
176 if (value != null) {
177 appenderBuilder.addAttribute("follow", Boolean.valueOf(value).booleanValue());
178 }
179 }
180
181 Configuration createConfiguration(final String configName, final URI configLocation,
182 final ConfigurationBuilder<BuiltConfiguration> builder) throws IOException {
183 builder.setConfigurationName(configName);
184 final Properties properties = load(configLocation);
185 if (properties == null) {
186 return null;
187 }
188
189 final String debugValue = getLog4jValue(properties, "debug");
190 if (Boolean.valueOf(debugValue)) {
191 builder.setStatusLevel(Level.DEBUG);
192 }
193
194 final String[] sortedAppenderNamesC = buildRootLogger(builder, getRootCategoryValue(properties));
195 final String[] sortedAppenderNamesL = buildRootLogger(builder, getRootLoggerValue(properties));
196 final String[] sortedAppenderNames = sortedAppenderNamesL.length > 0 ? sortedAppenderNamesL
197 : sortedAppenderNamesC;
198
199 final Map<String, String> classNameToProperty = buildClassToPropertyPrefixMap(properties, sortedAppenderNames);
200 for (final Entry<String, String> entry : classNameToProperty.entrySet()) {
201 final String appenderName = entry.getKey();
202 switch (entry.getValue()) {
203 case "org.apache.log4j.ConsoleAppender":
204 buildConsoleAppender(properties, appenderName, builder);
205 break;
206 default:
207 reportWarning("Ignoring appender " + appenderName
208 + "; consider porting your configuration file to the current Log4j format.");
209 }
210 }
211
212 buildLoggers(properties, "log4j.category.", builder);
213 buildLoggers(properties, "log4j.logger.", builder);
214 return builder.build();
215 }
216
217 private String[] buildRootLogger(final ConfigurationBuilder<BuiltConfiguration> builder,
218 final String rootLoggerValue) {
219 if (rootLoggerValue == null) {
220 return new String[0];
221 }
222 final String[] rootLoggerParts = rootLoggerValue.split("\\s*,\\s*");
223 final Level rootLoggerLevel = rootLoggerParts.length > 0 ? Level.valueOf(rootLoggerParts[0]) : Level.ERROR;
224 builder.add(builder.newRootLogger(rootLoggerLevel));
225 final String[] sortedAppenderNames = Arrays.copyOfRange(rootLoggerParts, 1, rootLoggerParts.length);
226 Arrays.sort(sortedAppenderNames);
227 return sortedAppenderNames;
228 }
229
230 private void buildLoggers(final Properties properties, final String prefix,
231 final ConfigurationBuilder<BuiltConfiguration> builder) {
232 final int preLength = prefix.length();
233 for (final Entry<Object, Object> entry : properties.entrySet()) {
234 final Object keyObj = entry.getKey();
235 if (keyObj != null) {
236 final String key = keyObj.toString();
237 if (key.startsWith(prefix)) {
238 final String name = key.substring(preLength);
239 final Object value = entry.getValue();
240 if (value != null) {
241 builder.add(builder.newLogger(name, Level.valueOf(value.toString())));
242 }
243 }
244 }
245 }
246
247 }
248
249 @Override
250 public Configuration getConfiguration(final ConfigurationSource source) {
251 return getConfiguration(source.toString(), null);
252 }
253
254 @Override
255 public Configuration getConfiguration(final String name, final URI configLocation) {
256 try {
257 return createConfiguration(name, configLocation, newConfigurationBuilder());
258 } catch (final IOException e) {
259 StatusLogger.getLogger().error(e);
260 return null;
261 }
262 }
263
264 private String getLog4jAppenderValue(final Properties properties, final String appenderName,
265 final String attributeName, final String defaultValue) {
266 return properties.getProperty("log4j.appender." + appenderName + "." + attributeName, defaultValue);
267 }
268
269 private String getLog4jValue(final Properties properties, final String key) {
270 return properties.getProperty("log4j." + key);
271 }
272
273 private String getRootCategoryValue(final Properties properties) {
274 return getLog4jValue(properties, "rootCategory");
275 }
276
277 private String getRootLoggerValue(final Properties properties) {
278 return getLog4jValue(properties, "rootLogger");
279 }
280
281 @Override
282 protected String[] getSupportedTypes() {
283 return new String[] { "*.properties", ".xml" };
284 }
285
286 private Properties load(final URI uri) throws IOException {
287 final Properties properties = toProperties(uri);
288 final String rootCategoryValue = getRootCategoryValue(properties);
289 final String rootLoggerValue = getRootLoggerValue(properties);
290 if (rootCategoryValue == null && rootLoggerValue == null) {
291
292 return null;
293 }
294 return properties;
295 }
296
297 private void reportWarning(final String msg) {
298 StatusLogger.getLogger().warn("Log4j version 1 to 2 configuration bridge: " + msg);
299
300 }
301
302 private Properties toProperties(final URI uri) throws IOException {
303 final Properties properties;
304 try (InputStream in = uri.toURL().openStream()) {
305 properties = new Properties();
306 if (uri.toString().endsWith(".xml")) {
307 properties.loadFromXML(in);
308 } else {
309 properties.load(in);
310 }
311 }
312 return properties;
313 }
314 }