Skip to content

Commit a11c416

Browse files
authored
Improve logging for JctCompilationFactoryImpl.java (#565)
Improve log messages and include processing latency from JCT itself in logs. --------- Signed-off-by: ascopes <73482956+ascopes@users.noreply.github.com>
1 parent 47a5d25 commit a11c416

File tree

1 file changed

+48
-25
lines changed

1 file changed

+48
-25
lines changed

java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctCompilationFactoryImpl.java

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@
5555
public final class JctCompilationFactoryImpl implements JctCompilationFactory {
5656

5757
private static final Logger LOGGER = LoggerFactory.getLogger(JctCompilationFactoryImpl.class);
58-
private static final String THE_ROOT_PACKAGE = "";
58+
private static final String ROOT_PACKAGE = "";
5959

6060
private final JctCompiler compiler;
6161

6262
public JctCompilationFactoryImpl(JctCompiler compiler) {
63-
this.compiler = compiler;
63+
this.compiler = requireNonNull(compiler);
6464
}
6565

6666
@Override
@@ -71,6 +71,7 @@ public JctCompilation createCompilation(
7171
@Nullable Collection<String> classNames
7272
) {
7373
try {
74+
final var startPreparation = System.nanoTime();
7475
var compilationUnits = findFilteredCompilationUnits(fileManager, classNames);
7576

7677
if (compilationUnits.isEmpty()) {
@@ -81,16 +82,18 @@ public JctCompilation createCompilation(
8182
var writer = TeeWriter.wrapOutputStream(System.out, compiler.getLogCharset());
8283

8384
var diagnosticListener = new TracingDiagnosticListener<>(
84-
compiler.getDiagnosticLoggingMode() != LoggingMode.DISABLED,
85-
compiler.getDiagnosticLoggingMode() == LoggingMode.STACKTRACES
85+
/* enabled */ compiler.getDiagnosticLoggingMode() != LoggingMode.DISABLED,
86+
/* stackTraces */ compiler.getDiagnosticLoggingMode() == LoggingMode.STACKTRACES
8687
);
8788

89+
// We work out the classes to annotation process rather than relying on the
90+
// compiler to do this, as we retain more control by doing so.
8891
var task = jsr199Compiler.getTask(
8992
writer,
9093
fileManager,
9194
diagnosticListener,
9295
flags,
93-
null,
96+
/* classes */ null,
9497
compilationUnits
9598
);
9699

@@ -101,20 +104,23 @@ public JctCompilation createCompilation(
101104

102105
task.setLocale(compiler.getLocale());
103106

107+
var preparationExecutionTimeMs = timeDeltaMs(startPreparation);
108+
104109
LOGGER
105110
.atInfo()
106-
.setMessage("Starting compilation with {} (found {} compilation units)")
111+
.setMessage("Starting compilation with {} (found {} compilation units in approx {}ms)")
107112
.addArgument(compiler::getName)
108113
.addArgument(compilationUnits::size)
114+
.addArgument(preparationExecutionTimeMs)
109115
.log();
110116

111-
var start = System.nanoTime();
117+
var startCompilation = System.nanoTime();
112118
var success = requireNonNull(
113119
task.call(),
114120
() -> "Compiler " + compiler.getName()
115121
+ " task .call() method returned null unexpectedly!"
116122
);
117-
var delta = (System.nanoTime() - start) / 1_000_000L;
123+
var compilationExecutionTimeMs = timeDeltaMs(startCompilation);
118124

119125
// Ensure we commit the writer contents to the wrapped output stream in full.
120126
writer.flush();
@@ -124,8 +130,11 @@ public JctCompilation createCompilation(
124130
.setMessage("Compilation with {} {} after approximately {}ms (roughly {} classes/sec)")
125131
.addArgument(compiler::getName)
126132
.addArgument(() -> success ? "completed successfully" : "failed")
127-
.addArgument(delta)
128-
.addArgument(() -> String.format("%.2f", 1000.0 * compilationUnits.size() / delta))
133+
.addArgument(compilationExecutionTimeMs)
134+
.addArgument(() -> String.format(
135+
"%.2f",
136+
(1000.0 * compilationUnits.size()) / compilationExecutionTimeMs
137+
))
129138
.log();
130139

131140
return JctCompilationImpl
@@ -177,8 +186,9 @@ private Collection<JavaFileObject> findFilteredCompilationUnits(
177186
private Collection<JavaFileObject> findCompilationUnits(
178187
JctFileManager fileManager
179188
) throws IOException {
180-
var locations = IterableUtils
181-
.flatten(fileManager.listLocationsForModules(StandardLocation.MODULE_SOURCE_PATH));
189+
// If we use modules, we may have more than one module location to search for.
190+
var deepLocations = fileManager.listLocationsForModules(StandardLocation.MODULE_SOURCE_PATH);
191+
var locations = IterableUtils.flatten(deepLocations);
182192

183193
if (locations.isEmpty()) {
184194
LOGGER.info(
@@ -192,30 +202,24 @@ private Collection<JavaFileObject> findCompilationUnits(
192202
}
193203

194204
// Use a linked hash set to retain order for consistency.
195-
var objects = new LinkedHashSet<JavaFileObject>();
205+
var fileObjects = new LinkedHashSet<JavaFileObject>();
206+
var kinds = Set.of(Kind.SOURCE);
196207

197208
for (var location : locations) {
198-
objects.addAll(fileManager.list(location, THE_ROOT_PACKAGE, Set.of(Kind.SOURCE), true));
209+
var nextFileObjects = fileManager.list(location, ROOT_PACKAGE, kinds, true);
210+
fileObjects.addAll(nextFileObjects);
199211
}
200212

201-
return objects;
213+
return fileObjects;
202214
}
203215

204216
private Collection<JavaFileObject> filterCompilationUnitsByBinaryNames(
205217
Collection<JavaFileObject> compilationUnits,
206218
Collection<String> classNames
207219
) {
208-
// We need to access the binary name of each file object. This forces us
209-
// to cast to PathFileObject in an unsafe way as the standard JavaFileObject
210-
// interface does not expose this information consistently.
211-
// All JCT implementations should be using PathFileObject types internally
212-
// anyway, so this should be fine as a hack for now. In the future I may decide
213-
// to add an additional set of methods to PathFileObject to expose searching
214-
// for PathFileObjects directly to prevent the cast back to JavaFileObject that
215-
// makes us need this hsck.
216220
var binaryNamesToCompilationUnits = compilationUnits
217221
.stream()
218-
.map(PathFileObject.class::cast)
222+
.map(this::forceUpcastJavaFileObject)
219223
.filter(fo -> classNames.contains(fo.getBinaryName()))
220224
.collect(Collectors.toMap(PathFileObject::getBinaryName, JavaFileObject.class::cast));
221225

@@ -228,11 +232,30 @@ private Collection<JavaFileObject> filterCompilationUnitsByBinaryNames(
228232
}
229233

230234
LOGGER.atDebug()
231-
.setMessage("Filtered {} candidate compilation units down to {} final compilation units")
235+
.setMessage("Filtered {} candidate compilation units down to {} via class whitelist {}")
232236
.addArgument(compilationUnits::size)
233237
.addArgument(binaryNamesToCompilationUnits::size)
238+
.addArgument(classNames)
234239
.log();
235240

236241
return binaryNamesToCompilationUnits.values();
237242
}
243+
244+
// We need to access the binary name of each file object. This forces us
245+
// to cast to PathFileObject in an unsafe way as the standard JavaFileObject
246+
// interface does not expose this information consistently.
247+
// All JCT implementations should be using PathFileObject types internally
248+
// anyway, so this should be fine as a hack for now. In the future I may decide
249+
// to add an additional set of methods to PathFileObject to expose searching
250+
// for PathFileObjects directly to prevent the cast back to JavaFileObject that
251+
// makes us need this hack.
252+
private PathFileObject forceUpcastJavaFileObject(JavaFileObject jfo) {
253+
assert jfo instanceof PathFileObject
254+
: "Unexpected state: JavaFileObject " + jfo + " was not a PathFileObject!";
255+
return (PathFileObject) jfo;
256+
}
257+
258+
private static long timeDeltaMs(long startNanos) {
259+
return (System.nanoTime() - startNanos) / 1_000_000;
260+
}
238261
}

0 commit comments

Comments
 (0)