Warning mode, diagnostic collector, BuilderProblem enrichments - #12698
Warning mode, diagnostic collector, BuilderProblem enrichments#12698gnodet wants to merge 1 commit into
Conversation
b0617f7 to
1a419b7
Compare
0cc76eb to
6124231
Compare
Add the mvnlog tool for viewing and analyzing build-report JSON files. Includes BuildReportRenderer for human-readable output, SimpleJsonReader for dependency-free JSON parsing, shell scripts (mvnlog/mvnlog.cmd), and --log routing in mvn/mvn.cmd. Also adds integration tests for build report generation, console modes, and the mvnlog viewer, plus --console=verbose flags for ITs that depend on verbose output. Part 5 of the #12572 split (depends on warning mode PR #12698). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add the mvnlog tool for viewing and analyzing build-report JSON files. Includes BuildReportRenderer for human-readable output, SimpleJsonReader for dependency-free JSON parsing, shell scripts (mvnlog/mvnlog.cmd), and --log routing in mvn/mvn.cmd. Also adds integration tests for build report generation, console modes, and the mvnlog viewer, plus --console=verbose flags for ITs that depend on verbose output. Part 5 of the #12572 split (depends on warning mode PR #12698). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6124231 to
dc3bccd
Compare
1e4c616 to
eb4b145
Compare
dc3bccd to
a7c83db
Compare
Add the mvnlog tool for viewing and analyzing build-report JSON files. Includes BuildReportRenderer for human-readable output, SimpleJsonReader for dependency-free JSON parsing, shell scripts (mvnlog/mvnlog.cmd), and --log routing in mvn/mvn.cmd. Also adds integration tests for build report generation, console modes, and the mvnlog viewer, plus --console=verbose flags for ITs that depend on verbose output. Part 5 of the #12572 split (depends on warning mode PR #12698). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
eb4b145 to
35cf036
Compare
a7c83db to
7243fd7
Compare
Add the mvnlog tool for viewing and analyzing build-report JSON files. Includes BuildReportRenderer for human-readable output, SimpleJsonReader for dependency-free JSON parsing, shell scripts (mvnlog/mvnlog.cmd), and --log routing in mvn/mvn.cmd. Also adds integration tests for build report generation, console modes, and the mvnlog viewer, plus --console=verbose flags for ITs that depend on verbose output. Part 5 of the #12572 split (depends on warning mode PR #12698). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
35cf036 to
e06f638
Compare
7243fd7 to
af945c2
Compare
Add the mvnlog tool for viewing and analyzing build-report JSON files. Includes BuildReportRenderer for human-readable output, SimpleJsonReader for dependency-free JSON parsing, shell scripts (mvnlog/mvnlog.cmd), and --log routing in mvn/mvn.cmd. Also adds integration tests for build report generation, console modes, and the mvnlog viewer, plus --console=verbose flags for ITs that depend on verbose output. Part 5 of the #12572 split (depends on warning mode PR #12698). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
e06f638 to
77ddf3a
Compare
af945c2 to
850a04c
Compare
Add the mvnlog tool for viewing and analyzing build-report JSON files. Includes BuildReportRenderer for human-readable output, SimpleJsonReader for dependency-free JSON parsing, shell scripts (mvnlog/mvnlog.cmd), and --log routing in mvn/mvn.cmd. Also adds integration tests for build report generation, console modes, and the mvnlog viewer, plus --console=verbose flags for ITs that depend on verbose output. Part 5 of the #12572 split (depends on warning mode PR #12698). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add the mvnlog tool for viewing and analyzing build-report JSON files. Includes BuildReportRenderer for human-readable output, SimpleJsonReader for dependency-free JSON parsing, shell scripts (mvnlog/mvnlog.cmd), and --log routing in mvn/mvn.cmd. Also adds integration tests for build report generation, console modes, and the mvnlog viewer, plus --console=verbose flags for ITs that depend on verbose output. Part 5 of the #12572 split (depends on warning mode PR #12698). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- --warning-mode=summary|all|none|fail CLI flag - BuilderProblem enrichments: getKey(), getSuggestion(), getDocumentationUrl() - INFO severity level added to BuilderProblem.Severity enum - DiagnosticReporter injectable service for plugins to report structured problems - DefaultDiagnosticCollector: thread-safe, deduplicating problem store - BuildReportCollector upgraded with full diagnostic integration
77ddf3a to
6b6fc7f
Compare
850a04c to
5913a2b
Compare
gnodet
left a comment
There was a problem hiding this comment.
Well-structured diagnostic infrastructure with good test coverage. Two issues found after verification (a third finding about removed try-catch was a false positive — EventSpyDispatcher.onEvent() already provides the safety net).
Also noted:
- Two independent
BuilderProblemimplementations exist (privateDefaultProblemrecord inBuilderand publicDefaultBuilderProblemin impl). Future field additions need to update both. - The
warningModepropagation via user properties (maven.build.warningMode) is pragmatic for an EventSpy but worth noting as a side-channel.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of gnodet
| String key = problem.getKey(); | ||
|
|
||
| // Problems without a key get a synthetic key for storage | ||
| if (key == null) { |
There was a problem hiding this comment.
Race condition: noKeyCounter.increment() and noKeyCounter.longValue() are not atomic together. Two concurrent threads reporting null-key problems can both get the same counter value, producing the same synthetic key "__no_key__N", and the second problem is silently dropped by putIfAbsent.
Fix: use AtomicLong instead of LongAdder with incrementAndGet() for an atomic unique counter:
| if (key == null) { | |
| key = "__no_key__" + noKeyCounter.incrementAndGet(); |
(also change noKeyCounter field type from LongAdder to AtomicLong)
| .get()); | ||
| options.addOption(Option.builder() | ||
| .longOpt(WARNING_MODE) | ||
| .hasArg() |
There was a problem hiding this comment.
No validation of --warning-mode values. An invalid value like --warning-mode=quiet is silently accepted and defaults to summary behavior. BaseParser.validate() already validates --color and --fail-on-severity against allowed values — --warning-mode should follow the same pattern for consistency.
gnodet
left a comment
There was a problem hiding this comment.
Well-designed diagnostic infrastructure with good test coverage for the new functionality. A few issues worth addressing, including a concurrency bug and a logic mismatch:
Confirmed findings (verified independently):
-
[Medium — Concurrency bug]
DefaultDiagnosticCollector.java:113— Race condition in synthetic key generation for null-key problems.noKeyCounter.increment()andnoKeyCounter.longValue()are two separate operations on aLongAdder. Between them, another thread can callincrement(), causing two distinct null-key problems to receive the same synthetic key and one will be silently dropped byputIfAbsent. Fix: replaceLongAdderwithAtomicLongand useincrementAndGet()in a single call. -
[Medium — Logic mismatch]
BuildReportCollector.java:251—hasWarnings()returns true for severity WARNING or higher (FATAL, ERROR) via ordinal comparison, but the count loop only counts strictBuilderProblem.Severity.WARNINGentries. If only ERROR-severity diagnostics exist,hasWarnings()returns true butwarningCountstays 0, producing the misleading message "Build has 0 warning(s) and --warning-mode=fail is set". -
[Medium — Test coverage regression] Three existing tests deleted without replacement:
testStackTraceIsTruncated(),testShortStackTraceIsNotTruncated(), andtestTimestampedReportFile(). The production code they covered (truncateStackTrace()method and timestamped report file write/symlink logic) is still present and used. -
[Low]
MavenInvoker.java:268— No input validation for--warning-modevalue. Invalid values like--warning-mode=typoare silently accepted and treated as "summary" behavior. Consider validating against the known set (summary, all, none, fail).
This review was generated by an AI agent (Claude Code) and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
|
|
||
| // Problems without a key get a synthetic key for storage | ||
| if (key == null) { | ||
| noKeyCounter.increment(); |
There was a problem hiding this comment.
[Medium — Concurrency bug] noKeyCounter.increment() + noKeyCounter.longValue() is not atomic. In parallel builds, two threads can call increment() between each other's longValue(), getting the same synthetic key. One problem gets silently dropped by putIfAbsent.
Fix: replace LongAdder with AtomicLong and use incrementAndGet():
| noKeyCounter.increment(); | |
| key = "__no_key__" + noKeyCounter.incrementAndGet(); |
(with field declaration changed to private final AtomicLong noKeyCounter = new AtomicLong();)
| } | ||
|
|
||
| // --warning-mode=fail: fail the build if any warnings were collected | ||
| if ("fail".equalsIgnoreCase(warningMode) && diagnosticCollector.hasWarnings()) { |
There was a problem hiding this comment.
[Medium — Logic mismatch] hasWarnings() returns true for severity WARNING or higher (FATAL, ERROR) via ordinal comparison, but this count loop uses strict == BuilderProblem.Severity.WARNING. If only ERROR-severity diagnostics exist, hasWarnings() triggers but warningCount stays 0, producing "Build has 0 warning(s)".
Consider either: (a) changing hasWarnings() to check for exactly WARNING severity, or (b) counting all severities that hasWarnings() considers (i.e., ordinal <= WARNING).
Summary
Part 4 of the logging feature chain. Depends on #12697 (console modes).
Adds
--warning-modeCLI flag and structured diagnostic infrastructure:--warning-mode=summary(default) — deduplicated warning summary at end of build--warning-mode=all— inline warnings + summary--warning-mode=none— suppress diagnostic summary--warning-mode=fail— treat warnings as build errorsBuilderProblem API enrichments
getKey()— stable deduplication key for cross-module dedupgetSuggestion()— actionable fix suggestiongetDocumentationUrl()— link to relevant docsINFOseverity level added toSeverityenumBuilderProblem.builder()— fluent builder API withDefaultProblemrecordNew service API
DiagnosticReporter—@Inject-able service for plugins to report structured problemsInternal infrastructure
DefaultDiagnosticCollector— thread-safe, deduplicating problem store with suppression supportDefaultDiagnosticReporter/DefaultDiagnosticSummary— wiringBuildReportCollectorupgraded to useDefaultDiagnosticCollector, auto-collect WARN log events, print summaryFiles changed (16 files, ~1600 insertions)
BuilderProblemenrichments,DiagnosticReporter,Options(+warningMode())CommonsCliOptions,LayeredOptions,MavenInvokerBuildReportCollector(full diagnostic integration),BuildReportJsonWriter(problem enrichments)DefaultDiagnosticCollector,DefaultDiagnosticReporter,DefaultDiagnosticSummaryDefaultBuilderProblem(key/suggestion/url fields)DefaultDiagnosticCollectorTest)PR chain
mvnlogviewerTest plan
mvn test -pl impl/maven-core— all tests passmvn test -pl impl/maven-cli— all 692+ tests pass🤖 Generated with Claude Code