Java自定义日志处理器无法输出至Stdout且日志配置不生效问题求助
Java自定义日志处理器无法输出至Stdout且日志配置不生效问题求助
Java Logging完全不像预期那样工作。它要么输出到stderr,要么什么都不打印,要么完全不读取配置。到底是怎么回事?
我在很多项目里用过它,但这是第一次遇到这种毫无缘由的异常情况。以下是相关代码:
自定义Handler(设置日志级别、格式化器并输出到stdout):
public class CustomHandler extends StreamHandler { public CustomHandler(Level level) { super(System.out, new CustomFormatter()); setLevel(level); } @Override public void publish(LogRecord record) { if (LogService.getInstance().publishExternalLogs() || record.getSourceClassName().startsWith( "com.my.package")) { super.publish(record); super.flush(); } } }
自定义控制台日志格式化器:
public class CustomFormatter extends Formatter { private static final String FORMAT_WITH_MESSAGE = "%1$tF %1$tT - %2$-7s - %3$s%n"; private static final String FORMAT_WITHOUT_MESSAGE = "%1$tF %1$tT - %2$-7s%n"; private String replaceDefaultLevel(Level level) { switch (level.intValue()) { case 300: // Level.FINEST return "\u001B[34mTRACE\u001B[0m"; case 400: // Level.FINER return "\u001B[34mDEBUG\u001B[0m"; case 500: // Level.FINE return "\u001B[34mINFO\u001B[0m"; case 800: // Level.INFO return "\u001B[34mINFO\u001B[0m"; case 900: // Level.WARNING return "\u001B[33mWARNING\u001B[0m"; case 1000: // Level.SEVERE return "\u001B[31mSEVERE\u001B[0m"; default: return level.getLocalizedName(); } } @Override public synchronized String format(LogRecord logRecord) { if (logRecord.getMessage() == null || logRecord .getMessage() .isEmpty()) { return String.format( FORMAT_WITHOUT_MESSAGE, new Date(logRecord.getMillis()), replaceDefaultLevel(logRecord.getLevel()) ); } else { return String.format( FORMAT_WITH_MESSAGE, new Date(logRecord.getMillis()), replaceDefaultLevel(logRecord.getLevel()), logRecord.getMessage() ); } } }
日志文件专用自定义格式化器:
public class CustomFileFormatter extends SimpleFormatter { private static final String FORMAT_WITH_MESSAGE = "%1$tF %1$tT - %2$-7s - %3$s%n"; private static final String FORMAT_WITHOUT_MESSAGE = "%1$tF %1$tT - %2$-7s%n"; @Override public synchronized String format(LogRecord logRecord) { if (logRecord.getMessage() == null || logRecord .getMessage() .isEmpty()) { return String.format( FORMAT_WITHOUT_MESSAGE, new Date(logRecord.getMillis()), logRecord.getLevel().toString() ); } else { return String.format( FORMAT_WITH_MESSAGE, new Date(logRecord.getMillis()), logRecord.getLevel().toString(), logRecord.getMessage() ); } } }
日志管理服务类:
public class LogService { private static final Logger LOGGER_INFO = LogService.getInstance().getLogger( LogService.class.getCanonicalName(), Level.INFO ); private static class LogServiceInstance { static final LogService INSTANCE = new LogService(); } public static LogService getInstance() { return LogServiceInstance.INSTANCE; } /* * Show external libraries logs? */ private boolean publishExternalLogs; private LogService() { this.publishExternalLogs = true; } public void init(String config) { try { LogManager .getLogManager() .readConfiguration(new java.io.ByteArrayInputStream(config.getBytes())); } catch (IOException ioe) { throw new RuntimeException( "Error while trying to configure logging.", ioe ); } } public Logger getLogger(String className, Level level) { Logger logger = Logger.getLogger(String.format( "%s_%s", className, level.toString() )); logger.setUseParentHandlers(false); logger.setLevel(level); logger.addHandler(new CustomHandler(level)); return logger; } public boolean publishExternalLogs() { return this.publishExternalLogs; } public Logger getLoggerWithLogFile(String className, Level level) { Logger logger = getLogger(className, level); String logPath = System.getenv("LOG_PATH"); if (logPath == null) { logPath = new File(".").getAbsolutePath().replaceAll("\\.", ""); } try { String[] split = className.split("\\."); String logFile = String.format( "%s%s_%s" + ".log", logPath, split[split.length - 1], level ); LOGGER_INFO.info(String.format( "Creating logger file : %s", logFile )); FileHandler fileHandler = new FileHandler(logFile); fileHandler.setFormatter(new CustomFileFormatter()); logger.addHandler(fileHandler); } catch (IOException e) { throw new RuntimeException(e); } return logger; } public void setLevel(Level level, boolean publishExternalLogs) { Logger root = Logger.getLogger(""); root.setLevel(level); this.publishExternalLogs = publishExternalLogs; } }
测试用的Main方法:
private static final Logger LOGGER_INFO = LogService .getInstance() .getLoggerWithLogFile(App.class.getCanonicalName(), Level.INFO); public static void main(String[] args) { LogService.getInstance().setLevel(Level.FINEST, false); LOGGER_INFO.info("Abcd"); LOGGER_INFO.info("Abcd"); LOGGER_INFO.info("Abcd"); LOGGER_INFO.info("Abcd"); LOGGER_INFO.info("Abcd"); }
实际输出结果:
实际运行后,控制台只输出了来自LogService#getLoggerWithLogFile方法的这一行日志:
2025-02-12 14:27:02 - INFO - Creating logger file : C:\Users\user\Workspace\myapp\App_INFO.log
日志配置不生效的问题:
另外,像这样配置日志似乎也不起作用——外部库的stderr日志仍然会显示在控制台:
String logConfig = "java.util.logging.FileHandler" + ".limit=" + 50000 + "\n"; logConfig += "java.util.logging.FileHandler" + ".count=" + 5 + "\n"; //set your custom levels logConfig += "jdk.event.security" + ".level=" + Level.SEVERE + "\n"; logConfig += "org.glassfish.grizzly" + ".level=" + Level.SEVERE + "\n"; logConfig += "org.glassfish.tyrus" + ".level=" + Level.SEVERE + "\n"; LogService.getInstance().init(logConfig);
核心疑问:
为什么配置不生效?为什么stdout里没有预期的"Abcd"日志输出?
备注:内容来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

