Skip to content

Build report: structured JSON report with per-mojo log capture - #12695

Open
gnodet wants to merge 1 commit into
feature/logging-foundationfrom
feature/build-report
Open

Build report: structured JSON report with per-mojo log capture#12695
gnodet wants to merge 1 commit into
feature/logging-foundationfrom
feature/build-report

Conversation

@gnodet

@gnodet gnodet commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Part 2 of the logging feature chain (depends on #12694 — logging foundation).

Adds a structured build report that captures per-module and per-mojo execution results, timing, log events, and failures as a JSON file at the end of every build.

15 files changed, ~2700 insertions — focused on report data model, collection, and serialization.

What's in this PR

Layer Files Description
API BuildReport, BuildStatus, ModuleReport, MojoReport, FailureReport Immutable interfaces for the report data model
Impl DefaultBuildReport, DefaultModuleReport, DefaultMojoReport, DefaultFailureReport Record implementations
Collector BuildReportCollector EventSpy that tracks lifecycle events and captures log output via LogEventSink, routing to mojo/module/build-level buffers
Writer BuildReportJsonWriter Zero-dependency JSON serializer with stable field order
Tests 3 test classes, 17 tests Unit tests for collector, JSON writer, and integration

Key design decisions

  • EventSpy pattern: BuildReportCollector is a @Named @Singleton that extends AbstractEventSpy, discovered automatically — no wiring changes needed
  • Thread-based log routing: Uses ConcurrentHashMap<Long, String> (thread ID → mojo/project key) to associate log events with the correct scope in parallel builds
  • Dual sink architecture: Uses LogEventSink (4-arg) independently from the existing LogSink (5-arg) used by ProjectBuildLogAppender — no interference with console output
  • Atomic writes: Reports are written to a temp file, then atomic-moved into place with a timestamped filename and a build-report-latest.json symlink
  • Defensive: onSessionEnded wraps report generation in try-catch so report failures never crash the build

What's NOT in this PR (deferred to later PRs)

PR chain

# PR Feature
1 #12694 Logging foundation
2 This PR Build report
3 #12697 Console modes
4 #12698 Warning mode + diagnostics
5 #12699 mvnlog viewer
6 #12702 Structured problems pipeline
7 #12714 TRACE level migration

Test plan

  • 17 new unit/integration tests pass
  • Full Maven test suite passes (same results as base branch)
  • CI validation

🤖 Generated with Claude Code

@gnodet
gnodet force-pushed the feature/logging-foundation branch from bae1db9 to 5a5af1e Compare August 8, 2026 01:19
@gnodet
gnodet force-pushed the feature/build-report branch from 602fffb to 056dcf0 Compare August 8, 2026 01:23
gnodet added a commit that referenced this pull request Aug 8, 2026
Add the --console CLI flag with four output modes:
- plain: compact one-line-per-module output for CI
- rich: JLine status bar with live reactor progress
- verbose: full mojo-level output (current default)
- machine: JSON lines for piping to external tools

Part 3 of the #12572 split (depends on build report PR #12695).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet
gnodet force-pushed the feature/build-report branch from 056dcf0 to a1ee585 Compare August 8, 2026 05:35
@gnodet
gnodet force-pushed the feature/logging-foundation branch from e64db31 to de8044a Compare August 8, 2026 12:14
@gnodet
gnodet force-pushed the feature/build-report branch from a1ee585 to 0f31ce2 Compare August 8, 2026 12:14
gnodet added a commit that referenced this pull request Aug 8, 2026
Add the --console CLI flag with four output modes:
- plain: compact one-line-per-module output for CI
- rich: JLine status bar with live reactor progress
- verbose: full mojo-level output (current default)
- machine: JSON lines for piping to external tools

Part 3 of the #12572 split (depends on build report PR #12695).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gnodet added a commit that referenced this pull request Aug 8, 2026
Add the --console CLI flag with four output modes:
- plain: compact one-line-per-module output for CI
- rich: JLine status bar with live reactor progress
- verbose: full mojo-level output (current default)
- machine: JSON lines for piping to external tools

Part 3 of the #12572 split (depends on build report PR #12695).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet
gnodet force-pushed the feature/build-report branch from 8083c89 to 170bd72 Compare August 8, 2026 19:35
gnodet added a commit that referenced this pull request Aug 8, 2026
Add the --console CLI flag with four output modes:
- plain: compact one-line-per-module output for CI
- rich: JLine status bar with live reactor progress
- verbose: full mojo-level output (current default)
- machine: JSON lines for piping to external tools

Part 3 of the #12572 split (depends on build report PR #12695).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet
gnodet force-pushed the feature/build-report branch from 170bd72 to af0cc72 Compare August 8, 2026 21:48
gnodet added a commit that referenced this pull request Aug 8, 2026
Add the --console CLI flag with four output modes:
- plain: compact one-line-per-module output for CI
- rich: JLine status bar with live reactor progress
- verbose: full mojo-level output (current default)
- machine: JSON lines for piping to external tools

Part 3 of the #12572 split (depends on build report PR #12695).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- BuildReport/ModuleReport/MojoReport/FailureReport API interfaces
- BuildReportCollector EventSpy tracks lifecycle events and captures log output
- BuildReportJsonWriter zero-dependency JSON serializer with stable field order
- Thread-based log routing for parallel builds via ConcurrentHashMap
- Atomic writes with timestamped filename and build-report-latest.json symlink
@gnodet
gnodet force-pushed the feature/logging-foundation branch from 8baa65a to 02ac855 Compare August 9, 2026 08:11
@gnodet
gnodet force-pushed the feature/build-report branch from af0cc72 to 3658983 Compare August 9, 2026 08:11
@gnodet
gnodet marked this pull request as ready for review August 9, 2026 08:11

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well-designed build report feature with clean API/impl separation and comprehensive tests. A few issues noted below.

Also noted:

  • The architecture is solid: clean API interfaces in maven-api-core, record-based implementations in maven-core, EventSpy pattern for automatic discovery, thread-based log routing for parallel-build safety, atomic file writes with symlink swap.
  • The PR correctly depends on PR #12694 (logging foundation) — should not be merged until #12694 lands.
  • No test for the captureLogEvent routing logic (mojo-level vs module-level vs build-level buffers). This is the core routing mechanism and warrants at least one test exercising the dispatch.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of gnodet

* Maximum number of log events captured per scope (mojo, module, or build).
* Beyond this, events are dropped and a truncation notice is appended.
*/
static final int MAX_LOG_EVENTS_PER_SCOPE = 500;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Javadoc says "Beyond this, events are dropped and a truncation notice is appended" but captureLogEvent silently drops events without appending any truncation notice. Either append a synthetic LogEvent indicating truncation (e.g. with level WARN and message "... N events truncated"), or update the Javadoc to say events are silently dropped.

sb.append('}');
}

private static void writeModule(StringBuilder sb, ModuleReport module, int indent) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hasMore parameter is unused (annotated @SuppressWarnings("unused")) and all call sites pass true. If trailing comma control is no longer needed, the parameter should be removed to reduce confusion.

Suggested change
private static void writeModule(StringBuilder sb, ModuleReport module, int indent) {
private static void writeNullableField(StringBuilder sb, int indent, String key, String value) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant