You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合Lombok以编程方式设置Log4j属性

Programmatically Configuring Log4j to Write to %appdata%// in JavaFX

Great question! Configuring Log4j to use a platform-specific app data directory is a common requirement for desktop apps, and JavaFX's initialization phase is the perfect place to set this up. Here's a step-by-step solution that builds on your existing ConfigurationFactory approach:

Step 1: Resolve the Platform-Specific App Data Directory

First, we need a reliable way to get the correct app data path across Windows, macOS, and Linux. Here's a helper method to handle cross-platform paths:

private static File getAppLogDirectory(String appName, String appVersion) {
    String os = System.getProperty("os.name").toLowerCase();
    File appDataDir;

    if (os.contains("win")) {
        // Windows: %APPDATA%/<app>/<version>
        appDataDir = new File(System.getenv("APPDATA"), appName + File.separator + appVersion);
    } else if (os.contains("mac")) {
        // macOS: ~/Library/Application Support/<app>/<version>
        appDataDir = new File(System.getProperty("user.home"), 
            "Library" + File.separator + "Application Support" + File.separator + appName + File.separator + appVersion);
    } else {
        // Linux/Unix: ~/.config/<app>/<version>
        appDataDir = new File(System.getProperty("user.home"), 
            ".config" + File.separator + appName + File.separator + appVersion);
    }

    // Create directory structure if it doesn't exist
    if (!appDataDir.exists()) {
        appDataDir.mkdirs();
    }

    return appDataDir;
}

Step 2: Implement the Custom Log4j ConfigurationFactory

Now integrate this directory path into your ConfigurationFactory to set up a file appender. This example includes both a console appender and a rolling file appender (adjust log levels and patterns to your needs):

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.appender.RollingFileAppender;
import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Order;
import org.apache.logging.log4j.core.config.builder.api.*;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import java.io.File;

@Order(1) // Prioritize this factory over default Log4j configurations
public class Log4jConfigurationFactory extends ConfigurationFactory {

    private static final String APP_NAME = "YourAppName";
    private static final String APP_VERSION = "1.0.0";
    private static final String LOG_FILE_NAME = "app.log";

    @Override
    protected String[] getSupportedTypes() {
        return new String[]{"*"}; // Support all configuration types
    }

    @Override
    public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
        return getConfiguration(loggerContext, source.toString(), null);
    }

    @Override
    public Configuration getConfiguration(LoggerContext loggerContext, String name, URI configLocation) {
        // Build configuration programmatically
        ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();

        // Set root log level
        builder.setStatusLevel(Level.INFO);
        builder.setConfigurationName("CustomAppConfig");

        // Create pattern layout for log messages
        LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout")
                .addAttribute("pattern", "%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n");

        // Add console appender
        AppenderComponentBuilder consoleAppender = builder.newAppender("Console", "Console")
                .add(layoutBuilder);
        builder.add(consoleAppender);

        // Get the app log directory and log file path
        File logDir = getAppLogDirectory(APP_NAME, APP_VERSION);
        File logFile = new File(logDir, LOG_FILE_NAME);

        // Add rolling file appender (rolls daily or at 10MB)
        AppenderComponentBuilder fileAppender = builder.newAppender("File", "RollingFile")
                .addAttribute("fileName", logFile.getAbsolutePath())
                .addAttribute("filePattern", logDir.getAbsolutePath() + File.separator + "app-%d{yyyy-MM-dd}-%i.log.gz")
                .add(layoutBuilder);

        // Configure rolling policies
        ComponentBuilder triggeringPolicies = builder.newComponent("Policies")
                .addComponent(builder.newComponent("TimeBasedTriggeringPolicy")
                        .addAttribute("interval", 1)
                        .addAttribute("modulate", true))
                .addComponent(builder.newComponent("SizeBasedTriggeringPolicy")
                        .addAttribute("size", "10MB"));

        fileAppender.add(triggeringPolicies);
        builder.add(fileAppender);

        // Attach appenders to root logger
        builder.add(builder.newRootLogger(Level.INFO)
                .add(builder.newAppenderRef("Console"))
                .add(builder.newAppenderRef("File")));

        return builder.build();
    }

    private static File getAppLogDirectory(String appName, String appVersion) {
        // Reuse the cross-platform directory helper method here
        String os = System.getProperty("os.name").toLowerCase();
        File appDataDir;

        if (os.contains("win")) {
            appDataDir = new File(System.getenv("APPDATA"), appName + File.separator + appVersion);
        } else if (os.contains("mac")) {
            appDataDir = new File(System.getProperty("user.home"),
                    "Library" + File.separator + "Application Support" + File.separator + appName + File.separator + appVersion);
        } else {
            appDataDir = new File(System.getProperty("user.home"),
                    ".config" + File.separator + appName + File.separator + appVersion);
        }

        if (!appDataDir.exists()) {
            appDataDir.mkdirs();
        }

        return appDataDir;
    }
}

Step 3: Register the Factory in JavaFX Initialization

To ensure Log4j uses your custom configuration, register the factory before any logger is initialized. The init() method of your JavaFX app is ideal for this:

import javafx.application.Application;
import javafx.stage.Stage;
import org.apache.logging.log4j.core.config.ConfigurationFactory;

public class YourJavaFXApp extends Application {

    @Override
    public void init() throws Exception {
        super.init();
        // Register our custom Log4j configuration factory
        ConfigurationFactory.setConfigurationFactory(new Log4jConfigurationFactory());
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        // Your app UI initialization logic here
        primaryStage.setTitle("Your App");
        // ... rest of your application code
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Key Notes:

  • Cross-Platform Support: The directory helper method uses standard OS-specific app data locations, so your app behaves consistently across Windows, macOS, and Linux.
  • Rolling Appender: The example uses a rolling file appender that creates compressed archives of old logs, preventing log files from growing indefinitely. Adjust the size and interval attributes to match your needs.
  • Priority: The @Order(1) annotation ensures your factory takes precedence over default Log4j configurations.
  • Directory Creation: The mkdirs() call ensures the entire directory path is created if it doesn't exist, so you don't have to handle missing folders manually.

Just replace YourAppName and 1.0.0 with your actual app details, and tweak the log pattern/levels to fit your application's requirements. This setup will automatically create the log file in the correct app data directory when your JavaFX app starts.

内容的提问来源于stack exchange,提问作者Eray Erdin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:27:42