Java 9 - 平台日志 API
关于 Java 9 的新特性从某本书的最后一个说起:平台日志 API。个人没感觉这个有什么实质的用途,所谓的平台日志是指 JDK 自身代码,或者是 JVM 组件中的日志输出,而在自己应用程序代码中却不会去用这个平台日志 API。这个所谓的 Platform Logging API 名称的意义也就是在这里,平台用的,在诊断时用来观察 JDK 类或 JVM 中的日志输出,比如应该可以截获到 JVM 本地代码实现中的日志输出。对我们在项目中如何处理日志并不会有什么影响,该怎么还是怎么,不过了解多一点东西应该不会浪费脑容量的。
新加的平台日志体现在
我们可以尝试着在代码使用一下它
输出如下
System.LoggerFinder 和 System.Logger 默认就是这两个实现类。
如果 JUL 模块不存在,
由此我们看到
Java 9 新加这么一个日志框架门面显得有些累赘了,
日志框架越发复杂了,应该说来,目前更广为人知的用法还是 SLF4J + Log4J 或 SLF4J + Logback, 我更推崇后者。至于 JCL + Log4J 的用法越发稀少,而 Logback 比之 JCL 是个新鲜事物,它基本就是为 SLF4J 设计的。当前业界为了各个组件中使用的不同日志框架而统一日志输出目标,产生了诸如以下适配器
因为 JDK/JVM 用
附:前面说了 JUL 默认只显示 INFO 或更高级别的日志,也就是 CONFIG, FINE, FINER, FINEST 的日志不会显示,那么要降低日志输出级别该怎么做呢?下面代码将开启所有日志输出
JUL 的日志级别还与
JUL 的日志级别:OFF, SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL
System.Logger 的日志级别分别是:OFF, ERROR, WARNING, INFO, DEBUG, TRACE, ALL ---- 这个更符合主流意识形态
当
Java 9 的
当该类在初始化时如果不能解析文件
所以假如我们创建文件
这会去触发
链接:
永久链接 https://yanbin.blog/java-9-platform-logging-api/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
新加的平台日志体现在
java.lang.System 中新加的几个方法和类
我们可以尝试着在代码使用一下它1System.Logger logger = System.getLogger(TestLogging.class.getName());
2logger.log(System.Logger.Level.INFO, "Hello Java 9 Platform Logging API");输出如下
May 26, 2018 10:56:51 AM cc.unmi.TestLogging main新 API 有
INFO: Hello Java 9 Platform Logging API
java.lang.System.Logger 接口默认的,System.getLogger(...) 会使用 JDK 的
java.lang.System.LoggerFinder 用来查找上面 Logger 的实现类
java.lang.System.getLogger(...) 方法,它们会通过 LoggerFinder 找到相应的 Logger 实现
java.util.logging (如果该模块存在时,即 JUL,它默认只输入 INFO 及更高级别的日志) 作为它的日志实现,所以前面的日志输出其实就是 JUL 的输出。见包 sun.util.logging.internal 中的1public final class LoggingProviderImpl extends DefaultLoggerFinder {
2 ........
3 static final class JULWrapper extends LoggerConfiguration
4 implements System.Logger, PlatformLogger.Bridge,
5 PlatformLogger.ConfigurableBridge {
6 ........
7 }
8}System.LoggerFinder 和 System.Logger 默认就是这两个实现类。
如果 JUL 模块不存在,
System.Logger 将把 INFO 及更高级别的日志输出到 System.err 标准错误输出。由此我们看到
System.Logger 也就是作为 JUL 的一个门面,老实说它提供的日志输出方法还不如 JUL 的 java.util.logging.Logger 友好。System.Logger 的每个日志方法都要带上日志级别
JUL 的 Logger 除了提供带日志级别为参数的通用 log(Level, ...) 方法外,还为每一个日志级别提供了像下面那些便利方法(以 warning 为例)warning(String msg)既然
warning(Supplier<String> msgSuppiler)
System.Logger 是一个门面,那么它通过自定的 System.Logger 和 System.LoggerFinder 也能让它的日志桥接到其他日志框架上去,如 Apache Commong Logging(JCL - Jakarta Commons Logging), SLF4J, 或具体的日志实现 Log4j 或 Logback 去。Java 9 新加这么一个日志框架门面显得有些累赘了,
JUL 我们就不会去用它,有了更好的 SLF4J 更不会去用 System.Logger。不过它也说了 JDK 自己的代码会用 System.Logger, 那么我们有可能要做的就是如何把 JDK 中的 System.Logger 日志输出导向到我们熟悉的日志框架中来。日志框架越发复杂了,应该说来,目前更广为人知的用法还是 SLF4J + Log4J 或 SLF4J + Logback, 我更推崇后者。至于 JCL + Log4J 的用法越发稀少,而 Logback 比之 JCL 是个新鲜事物,它基本就是为 SLF4J 设计的。当前业界为了各个组件中使用的不同日志框架而统一日志输出目标,产生了诸如以下适配器
jcl-over-slf4j, slf4j-jcl, log4j-over-slf4j, slf4j-log4j12, jul-to-slf4j倒是没有找到 slf4j-over-jcl 这样的东西,因此 SLF4J 作为日志框架的门面还是当前趋势。简单项目中直接用 Log4J 或 Logback 也是可以的,Logback 自身就依赖了 SLF4J。
因为 JDK/JVM 用
System.Logger 来输出日志,它默认使用 JUL(当该模块存在时) 实现,所以我们只要用 jul-to-slf4j bridge 就能按需把 JDK/JVM 的日志输出到我们想要的地方去。附:前面说了 JUL 默认只显示 INFO 或更高级别的日志,也就是 CONFIG, FINE, FINER, FINEST 的日志不会显示,那么要降低日志输出级别该怎么做呢?下面代码将开启所有日志输出
1Logger rootLogger = LogManager.getLogManager().getLogger("");
2rootLogger.setLevel(Level.ALL);
3for (Handler hander : rootLogger.getHandlers()) {
4 hander.setLevel(Level.ALL);
5}JUL 的日志级别还与
System.Logger 的日志级别还有差异(它们原本就不是一家人)JUL 的日志级别:OFF, SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL
System.Logger 的日志级别分别是:OFF, ERROR, WARNING, INFO, DEBUG, TRACE, ALL ---- 这个更符合主流意识形态
当
System.Logger 默认采用 JUL 来输出日志时,它们的日志级别映射关系可查看 sun.util.logging.PlatformLogger1 ALL(System.Logger.Level.ALL),
2 FINEST(System.Logger.Level.TRACE),
3 FINER(System.Logger.Level.TRACE),
4 FINE(System.Logger.Level.DEBUG),
5 CONFIG(System.Logger.Level.DEBUG),
6 INFO(System.Logger.Level.INFO),
7 WARNING(System.Logger.Level.WARNING),
8 SEVERE(System.Logger.Level.ERROR),
9 OFF(System.Logger.Level.OFF);Java 9 的
Platform Logging API 基本上就说这么多了,只是让大家了解一下 Java 9 中有这么一个东西,它能做什么 事。并没有像某书中那样纠缠于如何自定义 System.Logger 和 System.LoggerFinder ,以及应用 SPI 来把平台日志输出到 Log4J 去,因为那么做的现实意义不大,我们项目中只需要专注于 SLF4J + Logback 的应用。一个 Java 平台类使用 System.Logger 的例子
java.util.Currency 类中就使用到了 System.Logger, 1 private static void info(String message, Throwable t) {
2 PlatformLogger logger = PlatformLogger.getLogger("java.util.Currency");
3 if (logger.isLoggable(PlatformLogger.Level.INFO)) {
4 if (t != null) {
5 logger.info(message, t);
6 } else {
7 logger.info(message);
8 }
9 }
10 }当该类在初始化时如果不能解析文件
JAVA_HOME/lib/currency.properties 文件时就报错 1static {
2 ......
3 // look for the properties file for overrides
4 String propsFile = System.getProperty("java.util.currency.data");
5 if (propsFile == null) {
6 propsFile = System.getProperty("java.home") + File.separator + "lib" +
7 File.separator + "currency.properties";
8 }
9 try {
10 File propFile = new File(propsFile);
11 if (propFile.exists()) {
12 ......//parse currency.properties file
13 }
14 } catch (IOException e) {
15 info("currency.properties is ignored because of an IOException", e);
16 }
17 ......
18}所以假如我们创建文件
JAVA_HOME/lib/currency.properties, 并在其中放入不合法的内容,如ABadCurrencyFile然后执行代码
1Currency.getInstance("USD");这会去触发
Currency 的 static 块,文件无法解析,控制台可以看到输出May 26, 2018 1:19:15 PM java.util.Currency info这就是平台日志的用法,还有新增的虚拟机参数
INFO: currency.properties entry for ABADCURENCYFILE is ignored because of the invalid country code.
-Xlog 也是在控制平台的日志输出。链接:
永久链接 https://yanbin.blog/java-9-platform-logging-api/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。