CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-maven--maven-plugin-api

The API for plugins - Mojos - development

Pending
Overview
Eval results
Files

logging-system.mddocs/

Logging System

Standardized logging interface for Maven plugins with support for debug, info, warn, and error levels. Integrates with Maven's output system and supports both message-only and message-with-throwable logging.

Capabilities

Log Interface

Main logging interface providing the standard Maven logging mechanism. Accepts CharSequence (not just String) for convenience and provides hierarchical log levels with enable/disable checking.

/**
 * Logging interface for Maven plugins using standard Maven channels
 */
public interface Log {
    
    /**
     * Check if debug level is enabled
     * @return true if debug messages will be output
     */
    boolean isDebugEnabled();
    
    /**
     * Send debug message to user
     * @param content message content (accepts CharSequence for convenience)
     */
    void debug(CharSequence content);
    
    /**
     * Send debug message with exception to user
     * @param content message content
     * @param error exception whose stacktrace will be output
     */
    void debug(CharSequence content, Throwable error);
    
    /**
     * Send exception to user at debug level
     * @param error exception whose stacktrace will be output
     */
    void debug(Throwable error);
    
    /**
     * Check if info level is enabled
     * @return true if info messages will be output
     */
    boolean isInfoEnabled();
    
    /**
     * Send info message to user
     * @param content message content
     */
    void info(CharSequence content);
    
    /**
     * Send info message with exception to user
     * @param content message content
     * @param error exception whose stacktrace will be output
     */
    void info(CharSequence content, Throwable error);
    
    /**
     * Send exception to user at info level
     * @param error exception whose stacktrace will be output
     */
    void info(Throwable error);
    
    /**
     * Check if warn level is enabled
     * @return true if warn messages will be output
     */
    boolean isWarnEnabled();
    
    /**
     * Send warning message to user
     * @param content message content
     */
    void warn(CharSequence content);
    
    /**
     * Send warning message with exception to user
     * @param content message content
     * @param error exception whose stacktrace will be output
     */
    void warn(CharSequence content, Throwable error);
    
    /**
     * Send exception to user at warn level
     * @param error exception whose stacktrace will be output
     */
    void warn(Throwable error);
    
    /**
     * Check if error level is enabled
     * @return true if error messages will be output
     */
    boolean isErrorEnabled();
    
    /**
     * Send error message to user
     * @param content message content
     */
    void error(CharSequence content);
    
    /**
     * Send error message with exception to user
     * @param content message content
     * @param error exception whose stacktrace will be output
     */
    void error(CharSequence content, Throwable error);
    
    /**
     * Send exception to user at error level
     * @param error exception whose stacktrace will be output
     */
    void error(Throwable error);
}

Usage Examples:

public class ExampleMojo extends AbstractMojo {
    
    @Override
    public void execute() throws MojoExecutionException {
        Log log = getLog();
        
        // Basic logging
        log.info("Starting plugin execution");
        log.debug("Debug mode enabled");
        
        // Conditional logging to avoid expensive operations
        if (log.isDebugEnabled()) {
            log.debug("Processing files: " + files.stream()
                .map(File::getName)
                .collect(Collectors.joining(", ")));
        }
        
        // Logging with exceptions
        try {
            processFiles();
        } catch (IOException e) {
            log.error("Failed to process files", e);
            throw new MojoExecutionException("Processing failed", e);
        }
        
        // Warning about deprecated usage
        if (useDeprecatedOption) {
            log.warn("The 'oldOption' parameter is deprecated. Use 'newOption' instead.");
        }
        
        // CharSequence support - can pass StringBuilder directly
        StringBuilder report = new StringBuilder();
        report.append("Processed ").append(fileCount).append(" files");
        log.info(report);
    }
}

SystemStreamLog Class

Default Log implementation that outputs to System.out and System.err. Used as fallback when no logger has been injected into the Mojo.

/**
 * Default Log implementation using System.out and System.err streams
 */
public class SystemStreamLog implements Log {
    // Debug level is disabled by default
    // Info, warn, error levels are enabled by default
    // Error messages go to System.err, others to System.out
}

Characteristics:

  • Debug logging is disabled by default
  • Info, warn, and error logging are enabled by default
  • Error-level messages are written to System.err
  • Debug, info, and warn messages are written to System.out
  • Used automatically by AbstractMojo.getLog() when no logger is injected

DefaultLog Class

Log implementation that bridges Maven Plugin API logging to Plexus logging system. Wraps a Plexus Logger and safely converts CharSequence to String. Located in package org.apache.maven.monitor.logging.

/**
 * Log implementation bridging to Plexus logging (org.apache.maven.monitor.logging.DefaultLog)
 */
public class DefaultLog implements Log {
    /**
     * Create DefaultLog wrapping Plexus logger
     * @param logger Plexus logger instance from org.codehaus.plexus.logging.Logger
     */
    public DefaultLog(Logger logger);
}

Features:

  • Wraps a Plexus Logger instance
  • Safely converts CharSequence to String
  • Delegates all logging operations to underlying Plexus logger
  • Used internally by Maven to provide proper logging integration

Logging Best Practices

Log Level Guidelines

Debug Level: Detailed diagnostic information for plugin developers

log.debug("Analyzing file: " + file.getAbsolutePath());
log.debug("Configuration loaded: " + config.toString());
log.debug("Cache hit for key: " + cacheKey);

Info Level: General information about plugin execution progress

log.info("Processing " + fileCount + " source files");
log.info("Generated " + outputFiles.size() + " output files");
log.info("Plugin execution completed successfully");

Warn Level: Important issues that don't prevent execution

log.warn("No source files found in " + sourceDirectory);
log.warn("Parameter 'oldParam' is deprecated, use 'newParam' instead");
log.warn("Output file already exists and will be overwritten: " + outputFile);

Error Level: Serious problems that may cause execution to fail

log.error("Failed to read configuration file: " + configFile);
log.error("Required dependency not found on classpath");
log.error("Unable to create output directory: " + outputDir);

Performance Considerations

Always check if logging level is enabled before expensive operations:

// Good - avoids expensive string operations when debug is disabled
if (log.isDebugEnabled()) {
    log.debug("Processing items: " + items.stream()
        .map(Item::toString)
        .collect(Collectors.joining(", ")));
}

// Bad - performs expensive operations even when debug is disabled  
log.debug("Processing items: " + items.stream()
    .map(Item::toString)
    .collect(Collectors.joining(", ")));

Exception Logging

Include both message context and exception details:

try {
    Files.copy(source, target);
} catch (IOException e) {
    // Log the error with context
    log.error("Failed to copy " + source + " to " + target, e);
    
    // Then throw appropriate Mojo exception
    throw new MojoExecutionException("File copy operation failed", e);
}

Structured Logging

Use consistent formatting for better readability:

// Good - consistent, structured format
log.info("=== Starting Code Generation ===");
log.info("Source directory: " + sourceDir);
log.info("Output directory: " + outputDir);
log.info("Template files: " + templateFiles.size());

// Process files...

log.info("=== Code Generation Complete ===");
log.info("Generated " + generatedCount + " files in " + duration + "ms");

CharSequence Support

Take advantage of CharSequence support to avoid unnecessary string conversions:

// Can pass StringBuilder directly
StringBuilder message = new StringBuilder();
message.append("Processed ").append(count).append(" items");
log.info(message);  // No need to call toString()

// StringBuffer also works
StringBuffer buffer = new StringBuffer();
buffer.append("Configuration: ").append(config.getName());
log.debug(buffer);

Never Use System.out or System.err

Always use the injected Log interface instead of direct console output:

// Good - uses Maven logging system
getLog().info("Processing complete");

// Bad - bypasses Maven logging  
System.out.println("Processing complete");

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-maven--maven-plugin-api

docs

core-plugin-development.md

exception-handling.md

index.md

logging-system.md

plugin-descriptors.md

tile.json