Skip to content

Logging foundation: structured LogEvent, JUL handler, Log API enhancements - #12694

Draft
gnodet wants to merge 1 commit into
masterfrom
feature/logging-foundation
Draft

Logging foundation: structured LogEvent, JUL handler, Log API enhancements#12694
gnodet wants to merge 1 commit into
masterfrom
feature/logging-foundation

Conversation

@gnodet

@gnodet gnodet commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Focused, reviewable PR that lays the logging infrastructure foundation for the build report work (#12572). Split out from #12572 to enable focused review and discussion of the logging architecture.

What's included

Log API enhancements (maven-api-core)

  • Log.trace() — 5 overloads + isTraceEnabled() to separate Maven core internals (trace) from user-facing debug output (debug). Maps to SLF4J TRACE / JUL FINEST.
  • Log.child(name) — hierarchical sub-loggers for plugins that want to separate concerns while keeping level control. Default implementation returns this for backward compatibility.

Structured LogEvent (maven-api-core, maven-core)

  • LogEvent / LogLevel API for structured log event representation
  • Optional JUL metadata fields: sourceClassName(), sourceMethodName(), threadId() — populated only for events originating from java.util.logging, null for SLF4J/Log API events

Custom JUL Handler (maven-logging)

  • MavenJulHandler replaces SLF4JBridgeHandler — reimplements JUL→SLF4J bridging while preserving the full LogRecord metadata that the standard bridge silently drops
  • Uses a ThreadLocal to pass JUL metadata synchronously to ProjectBuildLogAppender during the same publish() call
  • Three code paths, one pipeline: Log API → SLF4J, SLF4J direct, JUL → MavenJulHandler → SLF4J — all converge on the same structured LogEvent

Structured LogSink (maven-logging, maven-core)

  • MavenSimpleLogger.LogSink — structured callback with (level, loggerName, cleanMessage, formattedMessage, throwable) replacing the old Consumer<String> sink
  • ProjectBuildLogAppender produces LogEvent objects (with JUL metadata when available) instead of raw strings
  • BuildEventListener.projectLogMessage() now takes LogEvent instead of String

Mojo MDC & logger name (maven-core)

  • maven.mojo.id MDC key set during mojo execution (format: prefix:goal@executionId)
  • Logger name changed from getFullGoalName() ("compiler:compile") to getImplementation() (FQCN like org.apache.maven.plugins.compiler.CompilerMojo) for proper hierarchical SLF4J level configuration

Bug fix

  • DefaultLog.warn(Supplier<String>, Throwable) was calling logger.info() instead of logger.warn()

Context

This is Part 1 of the #12572 split. The build report, console modes, and warning mode features will follow as separate PRs on top of this foundation. See discussion in the dev@ thread and Martin's feedback on JUL field preservation.

Depends on / blocks

Test plan

  • mvn test -pl impl/maven-core,impl/maven-logging — 580 tests pass
  • Full CI validation
  • IT suite with JUL-using plugins (verify metadata preservation)

🤖 Generated with Claude Code

Add the foundational logging infrastructure for the new build reporting
pipeline:

- LogEvent API: structured log event with level, message, loggerName,
  sourceClassName, sourceMethodName, threadId, and instant
- MavenSimpleLogger: intercept SLF4J log calls and route them through
  LogSink for structured capture by ProjectBuildLogAppender
- MavenJulHandler: custom JUL handler that bypasses SLF4J when LogSink
  is available, preserving JUL metadata (sourceClassName, threadId)
  that SLF4JBridgeHandler discards
- Log.trace() and Log.child(): API additions for trace-level logging
  and hierarchical logger names (parentLogger.childName)
- Remove dead logging dependencies: jul-to-slf4j, logback-classic,
  LogbackConfiguration, Log4j2Configuration — the LogSink pipeline
  bypasses SLF4J for log capture, making pluggable SLF4J backend
  shims unnecessary

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet
gnodet force-pushed the feature/logging-foundation branch from bae1db9 to 5a5af1e Compare August 8, 2026 01:19
gnodet added a commit that referenced this pull request Aug 8, 2026
Add a structured build report that captures per-module and per-mojo
execution results, timing, log events, and failures as a JSON file
(target/build-reports/) at the end of every build.

Part 2 of the #12572 split. Builds on the logging foundation from
PR #12694 (LogEvent, LogLevel, LogEventSink).

New API interfaces:
- BuildReport: root report with metadata, modules, failures, problems
- BuildStatus: SUCCESS/FAILURE/SKIPPED enum
- ModuleReport: per-module results with mojo list
- MojoReport: per-mojo execution with captured log events
- FailureReport: exception details and stack traces

Implementation:
- BuildReportCollector: EventSpy that tracks lifecycle events and
  captures log output via LogEventSink, routing events to
  mojo/module/build-level buffers using thread-based tracking
- BuildReportJsonWriter: zero-dependency JSON serializer
- Atomic file writes with timestamped files and latest symlink
- Thread-safe for parallel builds (-T)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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