首页 > 解决方案 > 为什么我的 java 日志记录到控制台和文件

问题描述

我将我的应用程序配置为使用日志记录类,而不是 jre conf 文件夹中的 logging.properties 文件,使用 -Djava.util.logging.config.class=com.jthink.songkong.logging.StandardLogging

它有效,除了我注意到只是意味着要进入我的日志文件的信息也会进入控制台窗口,在 Windows 上使用 --win-console 和 jpackage 时会注意到这一点,但我认为它已经发生了在我使用 JPackage 之前

这是我的日志记录类:

public final class StandardLogging
{

public static int LOG_SIZE_IN_BYTES = 10000000;

//Default parent logger
public static  Logger  defaultLogger                = Logger.getLogger("");

//jaudiotagger logger
public static  Logger  ioLogger                     = Logger.getLogger("org.jaudiotagger");

//SongKong logger
public static  Logger  debugLogger                  = Logger.getLogger("com.jthink");

//SongKong usaer Message Logger
public static  Logger  userInfoLogger               = Logger.getLogger("com.jthink.songkong.ui.MainWindow");

//General c3p0
public static  Logger  c3p0Logger                   = Logger.getLogger("com.mchange.v2.c3p0");

//For capturing Preapred stament Cache hits
//public static  Logger  c3p0ConnectionLogger         = Logger.getLogger("com.mchange.v2.c3p0.stmt");

//For capturing stack traces when connection lasted too long
public static  Logger  c3p0PooledConnectionLogger   = Logger.getLogger("com.mchange.v2.resourcepool.BasicResourcePool");

//HIbernate SQL
public static  Logger  hibernateLogger              = Logger.getLogger("org.hibernate.SQL");



//TODO not sure this even used, I think CmdLogger just does System.out
private static Logger cmdlineLogger = Logger.getLogger("cmdline");

protected void configureLoggerLevels()
{
    //Default Log Level, used by any 3rd party libs we are using if not configured further
    defaultLogger.setLevel(Level.WARNING);

    //For Debug (songKong and jaudiotagger)
    ioLogger.setLevel(Level.WARNING);
    ioLogger.setUseParentHandlers(false);

    try
    {
        //If GeneralPreferences exist and we can access set from user value
        ioLogger.setLevel(Level.parse(String.valueOf(GeneralPreferences.getInstance().getIoDebugLevel())));
    }
    catch(Exception ex)
    {

    }

    debugLogger.setLevel(Level.WARNING);
    debugLogger.setUseParentHandlers(false);
    try
    {
        //If GeneralPreferences exist and we cBuildBuiklan access set from user value
        debugLogger.setLevel(Level.parse(String.valueOf(GeneralPreferences.getInstance().getDebugLevel())));
    }
    catch(Exception ex)
    {

    }

    //C3p0 Logger
    c3p0Logger.setLevel(Level.INFO);
    c3p0Logger.setUseParentHandlers(false);

    //Set to FINEST to see SQL
    hibernateLogger.setLevel(Level.WARNING);
    hibernateLogger.setUseParentHandlers(false);

    //For Capturing CheckIn/Outs nad Prepared Statement Cache Hits
    //c3p0ConnectionLogger.setLevel(Level.FINEST);
    //c3p0ConnectionLogger.setUseParentHandlers(false);

    //For capturing stacktrace from timed out connections
    c3p0PooledConnectionLogger.setLevel(Level.INFO);
    c3p0PooledConnectionLogger.setUseParentHandlers(false);

    //For user message log
    userInfoLogger.setUseParentHandlers(false);
    userInfoLogger.setLevel(Level.FINEST);

    userInfoLogger.setUseParentHandlers(false);
    userInfoLogger.setLevel(Level.FINEST);

}

protected void configureHandlers() throws Exception
{
    //Set Filehandler used for writing to debug log
    String logFileName = Platform.getPlatformLogFolderInLogfileFormat() + "songkong_debug%u-%g.log";
    FileHandler fe = new FileHandler(logFileName, LOG_SIZE_IN_BYTES, 10, true);
    fe.setEncoding(StandardCharsets.UTF_8.name());
    fe.setFormatter(new LogFormatter());
    fe.setLevel(Level.FINEST);

    //Set Filehandler used for writing to user log
    String userLogFileName = Platform.getPlatformLogFolderInLogfileFormat() + "songkong_user%u-%g.log";
    FileHandler userFe = new FileHandler(userLogFileName, LOG_SIZE_IN_BYTES, 10, true);
    userFe.setFormatter(new com.jthink.songkong.logging.UserLogFormatter());
    userFe.setLevel(Level.FINEST);

    //Write this output to debug log file
    //defaultLogger.addHandler(fe);
    c3p0Logger.addHandler(fe);
    c3p0PooledConnectionLogger.addHandler(fe);
    //c3p0ConnectionLogger.addHandler(fe);
    ioLogger.addHandler(fe);
    debugLogger.addHandler(fe);
    hibernateLogger.addHandler(fe);

    //Write this output to user log file
    userInfoLogger.addHandler(userFe);

    //For cmd line output, is this still used
    cmdlineLogger.setUseParentHandlers(false);
    ConsoleHandler cmdLineHandler = new java.util.logging.ConsoleHandler();
    cmdLineHandler.setLevel(Level.FINEST);
    cmdLineHandler.setFormatter(new CmdLineFormatter());
    cmdlineLogger.addHandler(cmdLineHandler);

    System.out.println("debuglogfile is:" + logFileName);
    System.out.println("userlogfile is:"  + userLogFileName);

}

public StandardLogging()
{
    try
    {
        configureLoggerLevels();
        configureHandlers();
    }
    catch (Exception ex)
    {
        ex.printStackTrace();
    }
}
}

这是我希望转到我的 songkong-debug0-0.log 文件的代码示例,但它也被输出到控制台窗口:

MainWindow.logger.warning("User Dir:"+ System.getProperty("user.dir"));
MainWindow.logger.warning("Java Dir:"+ System.getProperty("java.home"));

为什么会这样?

标签: javajava.util.loggingjpackage

解决方案


添加代码以在配置结束时com.jthink.songkong.logging.StandardLogging 打印记录器树。这将帮助您解决正在发生的事情。由于您使用的是配置类,因此如果将来需要,您甚至可以创建自己的系统属性来切换打印记录器树。

如果您的控制台输出看起来像CmdLineFormatter您创建的格式,那么代码要么使用该记录器,要么使用正在打印到父处理程序的子记录器。假设您控制了格式,CmdLineFormatter您可以在输出中包含记录器名称以定位有问题的记录器。

如果输出看起来像,SimpleFormatter那么更有可能是附加到根记录器的控制台处理程序。只需从配置类的根记录器中删除该处理程序即可。

StandardLogging更完整的解决方案是在类构造函数的开头调用 LogManager.reset 。这将清除 JRE 在调用更改之前设置的配置。除了设置您的java.util.logging.config.class.


推荐阅读