java.util.logging配置报错:FileHandler级别设置失败及日志问题求助
咱们一步步拆解并解决你的问题,你现在遇到三个核心问题:配置文件报错、Debug日志不输出、自定义日志格式不生效,这些都不是语法错误,而是代码逻辑和java.util.logging的工作机制没配合好导致的。
1. 配置文件报错:Bad level value for property: java.util.logging.FileHandler.level
这个错误的核心原因是你在代码里手动创建了FileHandler,但读取配置文件时,LogManager会尝试给全局管理的FileHandler实例设置级别,可此时并没有由LogManager创建的FileHandler存在。
看你当前的代码逻辑:
- 先初始化Logger并设置级别
- 再读取配置文件(此时LogManager会加载配置里的
FileHandler属性,但你没让它创建Handler,而是自己后续手动创建) - 最后手动创建
FileHandler并添加到Logger
这种情况下,LogManager找不到对应的FileHandler实例来应用级别配置,就会抛出这个错误。
2. Debug日志(FINE级别)无法输出
你的debug()方法调用logger.fine("dddd"),但手动创建的FileHandler默认级别是Level.INFO,FINE的级别低于INFO,会被FileHandler直接过滤掉,不会写入日志文件。
另外,哪怕你给Logger设置了Level.ALL,Handler本身的级别优先级更高——只有同时满足Logger级别和Handler级别的日志才会被输出。
3. 自定义日志格式不生效
配置文件里定义的java.util.logging.SimpleFormatter.format是给LogManager创建的SimpleFormatter实例用的,但你在代码里手动new SimpleFormatter(),这个新实例不会自动读取配置里的格式,所以自定义格式完全没起作用。
修复方案
我们需要调整代码逻辑,让配置文件和自定义Logger类正确配合,同时解决上述三个问题:
方案一:让LogManager管理Handler(推荐)
这种方式会完全复用配置文件的设置,不需要手动创建Handler,最符合java.util.logging的设计逻辑:
public class classLogger { Logger logger; public classLogger(String classname){ try { String path = "D:\\myprojects\\logger\\conf\\logging.properties"; FileInputStream configFile = new FileInputStream(path); // 先读取配置,再初始化Logger,确保LogManager的配置全量生效 LogManager.getLogManager().readConfiguration(configFile); } catch (IOException ex) { // 别空吞异常!至少打印出来,不然出问题根本找不到原因 ex.printStackTrace(); } // 初始化Logger,此时LogManager会自动根据配置创建Handler、应用级别和格式 this.logger = Logger.getLogger(classname); // 不需要手动设置Logger级别,配置文件中的.level会生效 // logger.setLevel(Level.ALL); } public void error(String msg){ logger.severe(msg); } public void warning(String msg){ logger.warning(msg); } public void info(String msg){ logger.info(msg); } public void debug(String msg){ logger.fine(msg); } public static void main(String[] args) { classLogger log = new classLogger(classLogger.class.getName()); log.warning("attention please"); log.error("error"); log.debug("dddd"); log.info("info"); } }
同时修改配置文件的日志路径,匹配你需要的输出位置:
.level=ALL handlers = java.util.logging.FileHandler java.util.logging.FileHandler.level = FINE java.util.logging.FileHandler.append = true java.util.logging.FileHandler.limit = 1000000 java.util.logging.FileHandler.count = 100 # 修改为你需要的日志文件路径 java.util.logging.FileHandler.pattern = C:\\Documents and Settings\\E520user\\Desktop\\test\\try.log java.util.logging.SimpleFormatter.format = [%1$tc] - [%2$s] [%4$s] [%5$s] %n java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
方案二:手动创建Handler并应用配置(灵活定制场景)
如果你必须手动创建Handler,需要手动读取配置中的级别和格式:
public class classLogger { Logger logger; FileHandler fh; SimpleFormatter sf; public classLogger(String classname){ this.logger = Logger.getLogger(classname); logger.setLevel(Level.ALL); // 关闭默认的ConsoleHandler,避免重复输出日志 logger.setUseParentHandlers(false); try { String path = "D:\\myprojects\\logger\\conf\\logging.properties"; FileInputStream configFile = new FileInputStream(path); LogManager.getLogManager().readConfiguration(configFile); } catch (IOException ex) { ex.printStackTrace(); } try { String directory = "C:\\Documents and Settings\\E520user\\Desktop\\test"; String filename = "\\try.log"; // 传入append参数,对应配置中的append=true this.fh = new FileHandler(directory+filename, true); // 手动从配置中读取FileHandler的级别 String levelStr = LogManager.getLogManager().getProperty("java.util.logging.FileHandler.level"); if(levelStr != null){ fh.setLevel(Level.parse(levelStr)); } else { fh.setLevel(Level.FINE); // 兜底默认值 } this.sf = new SimpleFormatter(); // 由于JDK未公开设置格式的方法,通过反射读取配置中的格式并设置 try { Field formatField = SimpleFormatter.class.getDeclaredField("format"); formatField.setAccessible(true); String format = LogManager.getLogManager().getProperty("java.util.logging.SimpleFormatter.format"); if(format != null){ formatField.set(sf, format); } } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } fh.setFormatter(sf); logger.addHandler(fh); } catch (IOException ex1) { ex1.printStackTrace(); } } // 其余方法保持不变... public static void main(String[] args) { classLogger log = new classLogger(classLogger.class.getName()); log.warning("attention please"); log.error("error"); log.debug("dddd"); log.info("info"); } }
关键注意事项
- 别空吞异常:你的代码里用了空的
catch (IOException ex) { },这会导致配置加载失败、Handler创建失败等问题完全无法排查,一定要添加异常打印逻辑。 - 级别优先级规则:只有当日志级别同时≥Logger级别和Handler级别时,日志才会被输出。
- 配置加载时机:必须在初始化Logger之前读取配置文件,否则LogManager的配置不会应用到已创建的Logger上。
内容的提问来源于stack exchange,提问作者Phyxil

