1
+
/*
2
+
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
+
*/
4
+
5
+
package net.sourceforge.pmd.ant.internal;
6
+
7
+
import java.io.PrintStream;
8
+
import java.lang.reflect.Field;
9
+
import java.lang.reflect.Method;
10
+
import java.util.HashMap;
11
+
import java.util.Map;
12
+
13
+
import org.apache.tools.ant.BuildListener;
14
+
import org.apache.tools.ant.DefaultLogger;
15
+
import org.apache.tools.ant.Project;
16
+
import org.apache.tools.ant.XmlLogger;
17
+
import org.apache.tools.ant.taskdefs.RecorderEntry;
18
+
import org.slf4j.ILoggerFactory;
19
+
import org.slf4j.LoggerFactory;
20
+
import org.slf4j.LoggerFactoryFriend;
21
+
import org.slf4j.event.Level;
22
+
23
+
public final class Slf4jSimpleConfigurationForAnt {
24
+
private Slf4jSimpleConfigurationForAnt() { }
25
+
26
+
private static final Level DEFAULT_LEVEL = Level.INFO;
27
+
28
+
// Maps from ant's Project.MSG_* to org.slf4j.event.Level
29
+
private static final Level[] LOG_LEVELS = {
30
+
Level.ERROR, // Project.MSG_ERR=0
31
+
Level.WARN, // Project.MSG_WARN=1
32
+
Level.INFO, // Project.MSG_INFO=2
33
+
Level.DEBUG, // Project.MSG_VERBOSE=3
34
+
Level.TRACE, // Project.MSG_DEBUG=4
35
+
};
36
+
37
+
private static final Map<String, Integer> ANT_LOG_LEVELS;
38
+
39
+
static {
40
+
ANT_LOG_LEVELS = new HashMap<>();
41
+
ANT_LOG_LEVELS.put(Level.ERROR.name(), Project.MSG_ERR);
42
+
ANT_LOG_LEVELS.put(Level.WARN.name(), Project.MSG_WARN);
43
+
ANT_LOG_LEVELS.put(Level.INFO.name(), Project.MSG_INFO);
44
+
ANT_LOG_LEVELS.put(Level.DEBUG.name(), Project.MSG_VERBOSE);
45
+
ANT_LOG_LEVELS.put(Level.TRACE.name(), Project.MSG_DEBUG);
46
+
}
47
+
48
+
@SuppressWarnings("PMD.CloseResource")
49
+
public static Level reconfigureLoggingForAnt(Project antProject) {
50
+
PrintStream original = System.err;
51
+
try {
52
+
PrintStream interceptedStream = new PrintStream(original) {
53
+
private StringBuilder buffer = new StringBuilder(100);
54
+
55
+
@Override
56
+
public void println(String x) {
57
+
buffer.append(x).append(System.lineSeparator());
58
+
}
59
+
60
+
@Override
61
+
public void flush() {
62
+
String logLevel = determineLogLevel();
63
+
int antLogLevel = ANT_LOG_LEVELS.getOrDefault(logLevel, Project.MSG_INFO);
64
+
antProject.log(buffer.toString(), antLogLevel);
65
+
buffer.setLength(0);
66
+
}
67
+
68
+
private String determineLogLevel() {
69
+
int firstSpace = buffer.indexOf(" ");
70
+
if (firstSpace != -1) {
71
+
String level = buffer.substring(0, firstSpace);
72
+
buffer.delete(0, firstSpace + 1);
73
+
return level;
74
+
}
75
+
return DEFAULT_LEVEL.name();
76
+
}
77
+
};
78
+
System.setErr(interceptedStream);
79
+
80
+
Level level = getAntLogLevel(antProject);
81
+
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", level.toString());
82
+
System.setProperty("org.slf4j.simpleLogger.showDateTime", "false");
83
+
System.setProperty("org.slf4j.simpleLogger.showThreadName", "false");
84
+
System.setProperty("org.slf4j.simpleLogger.showThreadId", "false");
85
+
System.setProperty("org.slf4j.simpleLogger.levelInBrackets", "false");
86
+
System.setProperty("org.slf4j.simpleLogger.cacheOutputStream", "true");
87
+
System.setProperty("org.slf4j.simpleLogger.logFile", "System.err");
88
+
89
+
// Call SimpleLogger.init() by reflection.
90
+
// Alternatively: move the CLI related classes into an own module, add
91
+
// slf4j-simple as a compile dependency and create a PmdSlf4jSimpleFriend class in
92
+
// the package org.slf4j.simple to gain access to this package-private init method.
93
+
ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
94
+
Class<? extends ILoggerFactory> loggerFactoryClass = loggerFactory.getClass();
95
+
try {
96
+
Class<?> simpleLoggerClass = loggerFactoryClass.getClassLoader().loadClass("org.slf4j.simple.SimpleLogger");
97
+
Method initMethod = simpleLoggerClass.getDeclaredMethod("init");
98
+
initMethod.setAccessible(true);
99
+
initMethod.invoke(null);
100
+
} catch (ReflectiveOperationException ex) {
101
+
original.println("Error while initializing logging: " + ex);
102
+
}
103
+
104
+
LoggerFactoryFriend.reset();
105
+
106
+
return level;
107
+
} finally {
108
+
System.setErr(original);
109
+
}
110
+
}
111
+
112
+
@SuppressWarnings("PMD.AvoidAccessibilityAlteration")
113
+
private static Level getAntLogLevel(Project project) {
114
+
for (final BuildListener l : project.getBuildListeners()) {
115
+
Field declaredField = null;
116
+
try {
117
+
if (l instanceof DefaultLogger) {
118
+
declaredField = DefaultLogger.class.getDeclaredField("msgOutputLevel");
119
+
} else if (l instanceof XmlLogger) {
120
+
declaredField = XmlLogger.class.getDeclaredField("msgOutputLevel");
121
+
} else if (l instanceof RecorderEntry) {
122
+
declaredField = RecorderEntry.class.getDeclaredField("loglevel");
123
+
} else if ("org.gradle.api.internal.project.ant.AntLoggingAdapter".equals(l.getClass().getName())) {
124
+
return determineGradleLogLevel(project, l);
125
+
} else {
126
+
try {
127
+
declaredField = l.getClass().getDeclaredField("logLevel");
128
+
if (declaredField.getType() != Integer.class && declaredField.getType() != int.class) {
129
+
declaredField = null;
130
+
project.log("Unsupported build listener: " + l.getClass(), Project.MSG_DEBUG);
131
+
}
132
+
} catch (final NoSuchFieldException e) {
133
+
project.log("Unsupported build listener: " + l.getClass(), Project.MSG_DEBUG);
134
+
}
135
+
}
136
+
137
+
if (declaredField != null) {
138
+
declaredField.setAccessible(true);
139
+
return LOG_LEVELS[declaredField.getInt(l)];
140
+
}
141
+
142
+
} catch (final ReflectiveOperationException ignored) {
143
+
// Just ignore it
144
+
}
145
+
}
146
+
147
+
project.log("Could not determine ant log level, no supported build listeners found. "
148
+
+ "Log level is set to " + DEFAULT_LEVEL, Project.MSG_WARN);
149
+
150
+
return DEFAULT_LEVEL;
151
+
}
152
+
153
+
@SuppressWarnings("PMD.AvoidAccessibilityAlteration")
154
+
private static Level determineGradleLogLevel(Project project, BuildListener l) {
155
+
try {
156
+
project.log("Detected gradle AntLoggingAdapter", Project.MSG_DEBUG);
157
+
Field loggerField = l.getClass().getDeclaredField("logger");
158
+
loggerField.setAccessible(true);
159
+
// org.gradle.internal.logging.slf4j.OutputEventListenerBackedLogger
160
+
Object logger = loggerField.get(l);
161
+
162
+
Class<?> gradleLogLevel = l.getClass().getClassLoader().loadClass("org.gradle.api.logging.LogLevel");
163
+
164
+
Method isLevelAtMostMethod = logger.getClass().getDeclaredMethod("isLevelAtMost", gradleLogLevel);
165
+
isLevelAtMostMethod.setAccessible(true);
166
+
167
+
Object[] logLevels = gradleLogLevel.getEnumConstants();
168
+
// the log levels in gradle are declared in the order DEBUG, INFO, LIFECYCLE, WARN, QUIET, ERROR
169
+
Level[] mapping = new Level[] {
170
+
Level.TRACE, // DEBUG
171
+
Level.DEBUG, // INFO
172
+
Level.INFO, // LIFECYCLE
173
+
Level.WARN, // WARN
174
+
Level.ERROR, // QUIET
175
+
Level.ERROR, // ERROR
176
+
};
177
+
178
+
for (int i = 0; i < Math.min(logLevels.length, mapping.length); i++) {
179
+
boolean enabled = (boolean) isLevelAtMostMethod.invoke(logger, logLevels[i]);
180
+
if (enabled) {
181
+
project.log("Current log level: " + logLevels[i] + " -> " + mapping[i], Project.MSG_DEBUG);
182
+
return mapping[i];
183
+
}
184
+
}
185
+
} catch (ReflectiveOperationException ignored) {
186
+
// ignored
187
+
}
188
+
project.log("Could not determine log level, falling back to default: " + DEFAULT_LEVEL, Project.MSG_WARN);
189
+
return DEFAULT_LEVEL;
190
+
}
191
+
192
+
}
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4