Skip to content

Commit c9a79f7

Browse files
committed
feat: introduce logging + binding
1 parent 56fb895 commit c9a79f7

File tree

15 files changed

+225
-49
lines changed

15 files changed

+225
-49
lines changed

app/src/main/java/com/diffplug/spotless/cli/SpotlessAction.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
*/
1616
package com.diffplug.spotless.cli;
1717

18+
import com.diffplug.spotless.cli.core.SpotlessCommandLineStream;
1819
import com.diffplug.spotless.cli.execution.FormatterStepsSupplier;
1920

2021
public interface SpotlessAction extends SpotlessCommand {
2122
Integer executeSpotlessAction(FormatterStepsSupplier formatterSteps);
23+
24+
default void setupLogging() {}
2225
}

app/src/main/java/com/diffplug/spotless/cli/SpotlessCLI.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import java.util.concurrent.Executors;
2323
import java.util.concurrent.Future;
2424

25+
import com.diffplug.spotless.cli.logging.output.LoggingConfigurer;
26+
import com.diffplug.spotless.cli.logging.output.Output;
2527
import org.jetbrains.annotations.NotNull;
2628

2729
import com.diffplug.spotless.Formatter;
@@ -41,6 +43,8 @@
4143
import com.diffplug.spotless.cli.steps.Prettier;
4244
import com.diffplug.spotless.cli.version.SpotlessCLIVersionProvider;
4345

46+
import org.slf4j.Logger;
47+
import org.slf4j.LoggerFactory;
4448
import picocli.CommandLine;
4549
import picocli.CommandLine.Command;
4650

@@ -66,6 +70,8 @@
6670
subcommands = {LicenseHeader.class, GoogleJavaFormat.class, Prettier.class})
6771
public class SpotlessCLI implements SpotlessAction, SpotlessCommand, SpotlessActionContextProvider {
6872

73+
private static final Logger LOGGER = LoggerFactory.getLogger(SpotlessCLI.class);
74+
6975
@CommandLine.Spec
7076
CommandLine.Model.CommandSpec spec; // injected by picocli
7177

@@ -114,21 +120,32 @@ public void setParallelity(int parallelity) {
114120
}
115121

116122
@Override
117-
public Integer executeSpotlessAction(FormatterStepsSupplier formatterSteps) {
123+
public void setupLogging() {
124+
LoggingConfigurer.configureLogging(LoggingConfigurer.CLIOutputLevel.VVVVV, null); // TODO add options to set that
125+
}
118126

127+
@Override
128+
public Integer executeSpotlessAction(FormatterStepsSupplier formatterSteps) {
129+
// Test output
130+
Output.out("Executing Spotless action!!! {}", this);
131+
LOGGER.info("Executing Spotless action!!! -- logger -- {}", this);
119132
validateTargets();
120133
TargetResolver targetResolver = targetResolver();
121134

122135
try (FormatterFactory formatterFactory =
123136
new ThreadLocalFormatterFactory(lineEnding.createPolicy(), encoding, formatterSteps);
124-
ExecutorService executor = createExecutorServiceForFormatting(formatterFactory)) {
137+
ExecutorService executor = createExecutorServiceForFormatting()) {
125138

126139
List<Future<Result>> stepResults = targetResolver
127140
.resolveTargets()
128141
.map(path -> {
129142
return executor.submit(() -> {
130143
Formatter formatter = formatterFactory.createFormatter();
131-
return new Result(path, LintState.of(formatter, path.toFile()), formatter);
144+
// actual formatting
145+
LOGGER.debug("Formatting file: {}", path);
146+
LintState lintState = LintState.of(formatter, path.toFile());
147+
LOGGER.debug("LintState for file {}: {}", path, lintState);
148+
return new Result(path, lintState, formatter);
132149
});
133150
})
134151
.toList();
@@ -140,7 +157,7 @@ public Integer executeSpotlessAction(FormatterStepsSupplier formatterSteps) {
140157
}
141158
}
142159

143-
private @NotNull ExecutorService createExecutorServiceForFormatting(FormatterFactory formatterFactory) {
160+
private @NotNull ExecutorService createExecutorServiceForFormatting() {
144161
return Executors.newFixedThreadPool(numberOfParallelThreads());
145162
}
146163

@@ -158,12 +175,11 @@ private void validateTargets() {
158175

159176
private ResultType handleResult(Result result) {
160177
if (result.lintState().isClean()) {
161-
// System.out.println("File is clean: " + result.target.toFile().getName());
178+
LOGGER.debug("File is clean: {}", result.target().toFile());
162179
return ResultType.CLEAN;
163180
}
164181
if (result.lintState().getDirtyState().didNotConverge()) {
165-
System.err.println("File did not converge: "
166-
+ result.target().toFile().getName()); // TODO: where to print the output to?
182+
LOGGER.warn("File did not converge: {}", result.target().toFile()); // maybe log to user facing?
167183
return ResultType.DID_NOT_CONVERGE;
168184
}
169185
return this.spotlessMode.handleResult(result);

app/src/main/java/com/diffplug/spotless/cli/SpotlessMode.java

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,41 +16,44 @@
1616
package com.diffplug.spotless.cli;
1717

1818
import com.diffplug.spotless.ThrowingEx;
19+
import com.diffplug.spotless.cli.logging.output.Output;
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
1922

2023
enum SpotlessMode {
2124
CHECK {
25+
private static final Logger LOGGER = LoggerFactory.getLogger(SpotlessMode.class);
2226
@Override
2327
ResultType handleResult(Result result) {
2428
if (result.lintState().isHasLints()) {
25-
result.lintState().asStringOneLine(result.target().toFile(), result.formatter());
29+
Output.out(
30+
() -> new Output.MessageWithArgs("File has lints: {} -- {}", result.target().toFile().getPath(), result.lintState().asStringOneLine(result.target().toFile(), result.formatter())),
31+
() -> new Output.MessageWithArgs("File has lints: {}\n\t{}", result.target().toFile().getPath(), result.lintState().asStringDetailed(result.target().toFile(), result.formatter()))
32+
);
2633
} else {
27-
System.out.println(String.format("%s is violating formatting rules.", result.target()));
34+
LOGGER.debug("File is clean: {}", result.target().toFile().getPath());
2835
}
2936
return ResultType.DIRTY;
3037
}
3138

3239
@Override
3340
Integer translateResultTypeToExitCode(ResultType resultType) {
34-
if (resultType == ResultType.CLEAN) {
35-
return 0;
36-
}
37-
if (resultType == ResultType.DIRTY) {
38-
return 1;
39-
}
40-
if (resultType == ResultType.DID_NOT_CONVERGE) {
41-
return -1;
42-
}
43-
throw new IllegalStateException("Unexpected result type: " + resultType);
41+
return switch(resultType) {
42+
case CLEAN -> 0;
43+
case DIRTY -> 1;
44+
case DID_NOT_CONVERGE -> -1;
45+
};
4446
}
4547
},
4648
APPLY {
4749
@Override
4850
ResultType handleResult(Result result) {
4951
if (result.lintState().isHasLints()) {
5052
// something went wrong, we should not apply the changes
51-
System.err.println("File has lints: " + result.target().toFile().getName());
52-
System.err.println("lint:\n"
53-
+ result.lintState().asStringDetailed(result.target().toFile(), result.formatter()));
53+
Output.out(
54+
() -> new Output.MessageWithArgs("File has lints: {} -- {}", result.target().toFile().getPath(), result.lintState().asStringOneLine(result.target().toFile(), result.formatter())),
55+
() -> new Output.MessageWithArgs("File has lints: {}\n\t{}", result.target().toFile().getPath(), result.lintState().asStringDetailed(result.target().toFile(), result.formatter()))
56+
);
5457
return ResultType.DIRTY;
5558
}
5659
ThrowingEx.run(() -> result.lintState()
@@ -61,16 +64,11 @@ ResultType handleResult(Result result) {
6164

6265
@Override
6366
Integer translateResultTypeToExitCode(ResultType resultType) {
64-
if (resultType == ResultType.CLEAN) {
65-
return 0;
66-
}
67-
if (resultType == ResultType.DIRTY) {
68-
return 0;
69-
}
70-
if (resultType == ResultType.DID_NOT_CONVERGE) {
71-
return -1;
72-
}
73-
throw new IllegalStateException("Unexpected result type: " + resultType);
67+
return switch(resultType) {
68+
case CLEAN -> 0;
69+
case DIRTY -> 1;
70+
case DID_NOT_CONVERGE -> -1;
71+
};
7472
}
7573
};
7674

app/src/main/java/com/diffplug/spotless/cli/ThreadLocalFormatterFactory.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,13 @@
2121
import com.diffplug.spotless.Formatter;
2222
import com.diffplug.spotless.LineEnding;
2323
import com.diffplug.spotless.cli.execution.FormatterStepsSupplier;
24+
import org.slf4j.Logger;
25+
import org.slf4j.LoggerFactory;
2426

2527
public class ThreadLocalFormatterFactory implements FormatterFactory {
28+
29+
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadLocalFormatterFactory.class);
30+
2631
private final LineEnding.Policy policy;
2732
private final Charset encoding;
2833
private final FormatterStepsSupplier formatterSteps;
@@ -42,8 +47,7 @@ public Formatter createFormatter() {
4247
if (threadLocalFormatter.get() == null) {
4348
synchronized (this) {
4449
if (threadLocalFormatter.get() == null) {
45-
System.out.println("ThreadLocalFormatterFactory.createFormatter() thread.name: "
46-
+ Thread.currentThread().getName());
50+
LOGGER.info("Creating Formatter for thread: {}", Thread.currentThread().getName());
4751
Formatter formatter = Formatter.builder()
4852
.lineEndingsPolicy(policy)
4953
.encoding(encoding)

app/src/main/java/com/diffplug/spotless/cli/core/TargetResolver.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,13 @@
2929
import org.jetbrains.annotations.NotNull;
3030

3131
import com.diffplug.spotless.ThrowingEx;
32+
import org.slf4j.Logger;
33+
import org.slf4j.LoggerFactory;
3234

3335
public class TargetResolver {
3436

37+
private static final Logger LOGGER = LoggerFactory.getLogger(TargetResolver.class);
38+
3539
private final List<String> targets;
3640
private final FileResolver fileResolver;
3741

@@ -46,18 +50,20 @@ public Stream<Path> resolveTargets() {
4650

4751
private Stream<Path> resolveTarget(String target) {
4852
boolean isGlob = target.contains("*") || target.contains("?");
49-
System.out.println("isGlob: " + isGlob + " target: " + target);
5053
if (isGlob) {
54+
LOGGER.debug("Resolving target as glob: {}", target);
5155
return resolveGlob(target);
5256
}
5357
Path targetPath = fileResolver.resolvePath(Path.of(target));
5458
if (Files.isRegularFile(targetPath) && Files.isReadable(targetPath)) {
59+
LOGGER.debug("Resolving target as file: {}", target);
5560
return Stream.of(targetPath);
5661
}
5762
if (Files.isDirectory(targetPath)) {
63+
LOGGER.debug("Resolving target as directory: {}", target);
5864
return resolveDir(targetPath);
5965
}
60-
// Optionally log a warning if the target was not found.
66+
LOGGER.info("Target not found: {}", target);
6167
return Stream.empty();
6268
}
6369

app/src/main/java/com/diffplug/spotless/cli/execution/SpotlessExecutionStrategy.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ public int execute(CommandLine.ParseResult parseResult) throws CommandLine.Execu
3333
}
3434

3535
private Integer runSpotlessActions(SpotlessCommandLineStream commandLineStream) {
36+
// 0. setup logging
37+
commandLineStream.actions()
38+
.findFirst()
39+
.ifPresent(action -> action.setupLogging());
3640
// 1. prepare context
3741
SpotlessActionContext context = provideSpotlessActionContext(commandLineStream);
3842

app/src/main/java/com/diffplug/spotless/cli/execution/ThreadLocalFormatterStepsFactory.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ public List<FormatterStep> getFormatterSteps() {
4848
synchronized (this) {
4949
if (threadLocalFormatterSteps.get() == null) {
5050
SpotlessActionContext threadContext = context.deriveContext(threadId.get());
51-
System.out.println("ThreadLocalFormatterStepsSupplier.getFormatterSteps() threadId: "
52-
+ threadId.get() + " thread.name: "
53-
+ Thread.currentThread().getName() + " -- context: " + threadContext);
5451
threadLocalFormatterSteps.set(commandLineStream
5552
.formatterSteps()
5653
.flatMap(step -> step.prepareFormatterSteps(threadContext).stream())
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright 2025 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.cli.logging.output;
17+
18+
import java.io.File;
19+
import java.util.logging.ConsoleHandler;
20+
import java.util.logging.FileHandler;
21+
import java.util.logging.Handler;
22+
import java.util.logging.Level;
23+
import java.util.logging.LogManager;
24+
import java.util.logging.Logger;
25+
import java.util.logging.SimpleFormatter;
26+
27+
import com.diffplug.spotless.ThrowingEx;
28+
import org.jetbrains.annotations.NotNull;
29+
import org.jetbrains.annotations.Nullable;
30+
31+
public final class LoggingConfigurer {
32+
33+
public static void configureLogging(@NotNull CLIOutputLevel cliOutputLevel, @Nullable File logFile) {
34+
configureJdkLogging(cliOutputLevel, logFile);
35+
}
36+
37+
private static void configureJdkLogging(@NotNull CLIOutputLevel cliOutputLevel, @Nullable File logFile) {
38+
39+
// Reset the logging configuration to remove any default handlers
40+
LogManager.getLogManager().reset();
41+
42+
// Create a new console handler
43+
Handler rootHandler = createRootHandler(logFile);
44+
45+
// Set the root logger level to OFF
46+
Logger rootLogger = Logger.getLogger("");
47+
rootLogger.setLevel(Level.OFF); // only enable specifics
48+
rootLogger.addHandler(rootHandler); // Add the configured handler
49+
50+
Logger spotlessLibLogger = Logger.getLogger("com.diffplug.spotless");
51+
Logger spotlessCliLogger = Logger.getLogger("com.diffplug.spotless.cli");
52+
53+
ConsoleHandler outputConsoleHandler = new ConsoleHandler();
54+
outputConsoleHandler.setLevel(Level.ALL); // Set logging level
55+
outputConsoleHandler.setFormatter(new PlainMessageFormatter()); // Set formatter
56+
57+
Logger outputLogger = Logger.getLogger(Output.OUTPUT_LOGGER_NAME);
58+
outputLogger.setLevel(Level.ALL);
59+
outputLogger.setUseParentHandlers(false);
60+
outputLogger.addHandler(outputConsoleHandler);
61+
62+
if (cliOutputLevel == CLIOutputLevel.VVVVV) {
63+
rootLogger.setLevel(Level.ALL);
64+
} else if (cliOutputLevel == CLIOutputLevel.VVVV) {
65+
rootLogger.setLevel(Level.INFO);
66+
spotlessLibLogger.setLevel(Level.ALL);
67+
} else if (cliOutputLevel == CLIOutputLevel.VVV) {
68+
spotlessLibLogger.setLevel(Level.ALL);
69+
} else if (cliOutputLevel == CLIOutputLevel.VV) {
70+
spotlessLibLogger.setLevel(Level.INFO);
71+
} else if (cliOutputLevel == CLIOutputLevel.V) {
72+
// spotlessLibLogger.setLevel(Level.OFF);
73+
spotlessCliLogger.setLevel(Level.INFO);
74+
} else if (cliOutputLevel == CLIOutputLevel.DEFAULT) {
75+
// spotlessLibLogger.setLevel(Level.OFF);
76+
spotlessCliLogger.setLevel(Level.WARNING);
77+
} else if (cliOutputLevel == CLIOutputLevel.QUIET) {
78+
// spotlessLibLogger.setLevel(Level.OFF);
79+
spotlessCliLogger.setLevel(Level.SEVERE);
80+
}
81+
}
82+
83+
private static @NotNull Handler createRootHandler(@Nullable File logFile) {
84+
if (logFile == null) {
85+
ConsoleHandler consoleHandler = new ConsoleHandler();
86+
consoleHandler.setLevel(Level.ALL); // Set logging level
87+
consoleHandler.setFormatter(new SimpleFormatter()); // Set formatter
88+
return consoleHandler;
89+
}
90+
FileHandler fileHandler = ThrowingEx.get(() -> new FileHandler(logFile.getAbsolutePath(), false));
91+
fileHandler.setLevel(Level.ALL); // Set logging level
92+
fileHandler.setFormatter(new SimpleFormatter()); // Set formatter
93+
return fileHandler;
94+
}
95+
96+
public enum CLIOutputLevel {
97+
VVVVV, // everything, even debug levels
98+
VVVV, // spotless on debug, everything else non- debug levels
99+
VVV, // everything spotless, even debug levels
100+
VV, // everything spotless, except debug levels
101+
V, // only info and above
102+
DEFAULT, // only warnings and above
103+
QUIET, // only errors and above
104+
}
105+
}

0 commit comments

Comments
 (0)