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

Lay the groundwork for structured build reporting and richer
log capture by introducing:

- Log.trace() level (5 overloads + isTraceEnabled) to separate
  Maven core internals from user-facing debug output
- Log.child(name) for hierarchical sub-loggers
- LogEvent/LogLevel API for structured log event representation,
  including optional JUL metadata (sourceClassName, sourceMethodName,
  threadId) that the standard SLF4J bridge silently drops
- MavenJulHandler: a custom java.util.logging Handler that replaces
  SLF4JBridgeHandler, preserving full LogRecord metadata through a
  ThreadLocal read by ProjectBuildLogAppender
- Structured LogSink in MavenSimpleLogger (level, logger name, clean
  message, formatted output, throwable) replacing the old string sink
- mojoId MDC (maven.mojo.id) set during mojo execution so all log
  messages carry mojo context
- Logger name changed from getFullGoalName() to getImplementation()
  (FQCN) for proper hierarchical SLF4J level control
- Fix: DefaultLog.warn(Supplier, Throwable) was calling logger.info()

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