去年12月份,随着log4j暴露出高危漏洞,对于 Java 开发人员来说不是一个好消息,对于 Ops 来说更是如此。前者必须使用固定的 Log4J 版本重新打包他们的应用程序,而后者必须重新部署。但对于程序log来说,并不只是。今天让我们来了解一下java系统自带的log机制

简而言之,System.Logger它是日志引擎的一个API。与其使用 SFL4J 的 API 和想要的实现,不如使用System.Logger。Java 9 开始java就已经开放了System.Logger,但我最近才知道它,这真是令人遗憾。

System.Logger API

该 API 与其他日志记录 API 有点不同:它避免了不同的日志记录方法,例如debug(),支持传递日志记录参数info()的单一方法。log()``Level



如果您没有在类路径上提供任何相应的实现,则System.Logger默认为JUL。

public class LoggerExample {

  private static final System.Logger LOGGER = System.getLogger("c.f.b.DefaultLogger"); // 1

  public static void main(String[] args) {
LOGGER.log(DEBUG, "A debug message");
LOGGER.log(INFO, "Hello world!");
}
}
  1. 获取记录器。

运行上面的代码段会输出以下内容:

Dec 24, 2021 10:38:15 AM c.f.b.DefaultLogger main
INFO: Hello world!

广泛兼容其他日志系统

大多数应用程序当前使用Log4J2或SLF4J。两者都提供了兼容的System.Logger实现。

对于 Log4J,我们需要添加两个依赖项:

<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId> <!-- 1 -->
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId> <!-- 2 -->
<artifactId>log4j-jpl</artifactId>
<version>2.17.0</version>
</dependency>
</dependencies>
  1. Log4J 实现System.Logger
  2. System.Logger从到 Log4J 的支持。

与上面相同的日志记录片段现在输出以下内容:

11:00:07.373 [main] INFO  c.f.b.DefaultLogger - Hello world!

要改用 SLF4J,需要添加以下依赖项:

<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId> <!-- 1 -->
<version>2.0.0-alpha5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk-platform-logging</artifactId> <!-- 2 -->
<version>2.0.0-alpha5</version>
</dependency>
</dependencies>
  1. 基本的 SLF4J 实现。任何其他实现都可以,例如Logback。
  2. System.Logger从到 SLF4J 的支持。
[main] INFO c.f.b.DefaultLogger - Hello world!

你自己的System.Logger实现

System.Logger依赖于 Java 的ServiceLoader机制。两者log4j-jpl包含slf4j-jdk-platform-logging一个META-INF/services/java.lang.System$LoggerFinder指向LoggerFinder实现的文件。



我们可以基于System.out目的创建我们自己的日志系统。

第一步是实现日志本身。

public class ConsoleLogger implements System.Logger {

    private final String name;

    public ConsoleLogger(String name) {
this.name = name;
} @Override
public String getName() {
return name;
} @Override
public boolean isLoggable(Level level) {
return level.getSeverity() >= Level.INFO.getSeverity();
} @Override
public void log(Level level, ResourceBundle bundle, String msg, Throwable thrown) {
if (isLoggable(level)) {
System.out.println(msg);
thrown.printStackTrace();
}
} @Override
public void log(Level level, ResourceBundle bundle, String format, Object... params) {
if (isLoggable(level)) {
System.out.println(MessageFormat.format(format, params));
}
}
}

然后,我们需要编写代码System.LoggerFinder:

public class ConsoleLoggerFinder extends System.LoggerFinder {

    private static final Map<String, ConsoleLogger> LOGGERS = new HashMap<>(); // 1

    @Override
public System.Logger getLogger(String name, Module module) {
return LOGGERS.computeIfAbsent(name, ConsoleLogger::new); // 2
}
}

保留所有现有日志的路径:

  1. 如果它不存在,则创建一个记录器并存储它。

最后,我们创建一个服务文件:

ch.frankel.blog.ConsoleLoggerFinder

现在,运行相同的代码片段输出:

Hello world!

结论

虽然 API 比起其他更成熟的日志系统 API 更受限制,但这System.Logger是一个好选择。它提供了作为 JDK 一部分的api。因此,它避免了其他第三方api的漏洞风险,例如SLF4J 到 Log4J2。

出于这个原因,后期可基于System.Logger实现系统日志功能。

log4j的替换方案的更多相关文章

  1. Google Earth API 替换方案

    众所周知,GE API将会在15年12月25日结束服务,对于众多采用该API的软件,需要一些替换方案. 例如google map或者cesiumjs http://cesiumjs.org/ 或者尝试 ...

  2. Microsoft.AspNet.Web.Optimization.Bundle的完美替换方案

    Web应用程序中包含大量的样式(css)和脚本(js)文件,这些文件的引用.管理和发布有很多解决方案.在Asp.Net MVC应用程序中,大家最熟悉的解决方案应属Microsoft.AspNet.We ...

  3. arguments.callee的作用及替换方案

    arguments.callee的作用 arguments 的主要用途是保存函数参数, 但这个对象还有一个名叫 callee 的属性,返回正被执行的 Function 对象,也就是所指定的 Funct ...

  4. UIActionSheet上加入UIPickerView iOS8替换方案

    此套替换方案採用"UIView+动画"方式实现(将UIActionSheet替换为UIView) 界面层级例如以下: 第一层:view(这一层充满整个屏幕,初始化时颜色为透明.us ...

  5. switch...case...之替换方案一

    很多时候,当switch中有N个分支,且分支数已达10+,每个分支都是一个不小的方法体,那我们是不是应该考虑换一种方式来实现这个分支. 而我目前所能想到的是会用到如下几种方法. 1.Action 2. ...

  6. spring boot拦截器WebMvcConfigurerAdapter,以及高版本的替换方案(转)

    文章转自 http://blog.51cto.com/12066352/2093750 最近项目采用spring icloud,用的spring boot版本是1.5.x的,spring boot 2 ...

  7. JAVA字符配置替换方案

    在JAVA中,很多时候,我们后台要对数据进行变量配置,希望可以在运行时再进行变量替换.我们今天给大空提供的是org.apache.commons.text方案. 1.首先,引用org.apache.c ...

  8. EF架构~为导航属性赋值时ToList()的替换方案

    回到目录 今天在进行EF开发时,遇到一个问题,在进行join查询时,类中的一个集合类型的导航属性,在给它赋值时,将查询出来的结果ToList()后,出错了,linq to entity不支持这种操作, ...

  9. regexp_substr在oracle9i的替换方案

    regexp_substr()方法在oracle9i尚不存在,是从oracle10g开始新增,如下为替换解决方法. SELECT regexp_substr('|83~GT67XVFU0RCVIV|6 ...

随机推荐

  1. Spring系列2:Spring容器基本概念和使用

    本文内容 简单回顾IoC和DI概念 Spring容器的概念 的xml配置和初始化 容器的基本使用 bean的定义和初始化配置 简单理解IoC和DI概念 什么是IoC控制反转? 通俗地但不严谨地讲,以前 ...

  2. 01-JS中字面量与变量

    01-JS中字面量与变量 一.直接量(字面量) 字面量:英语叫做literals,也做直接量,看见什么,它就是什么. (一)数字的字面量 数字的字面量,就是这个数字自己,并不需要任何的符号来界定这个数 ...

  3. sql语句 异常 Err] 1064 - You have an error in your SQL syntax;

    在我们开发的工程中,有时候会报[Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds ...

  4. nodejs express异常捕获

    参考链接: http://blog.coinidea.com/web开发/nodejs-1131.html 由于nodejs是非阻塞单进程单线程的,一旦nodejs抛出异常,整个服务就会停掉.服务将会 ...

  5. NTT 快速数论变换

    NTT 先学习FFT 由于FFT是使用复数运算,精度并不好,而且也无法取模,所以有了NTT(快速数论变换). 建议先完全理解FFT后再学习NTT. 原根 NTT使用与单位根性质相似的原根来代替单位根. ...

  6. golang中闭包讲解

    1. 非闭包时的结果 package main import "fmt" func main() { var funcSlice []func() for i := 0; i &l ...

  7. iPhone12和iPhone12pro的区别有什么?

    阅读全部 说法一 iPhone12和iPhone12pro的区别有:颜色.价格.运行内存.拍照.屏幕最高亮度.电池容量.材质.重量等,具体对比如下: 颜色:iPhone12五色可选,青春绚丽:iPho ...

  8. new实例化和反射实例化有什么区别?

    在工厂设计模式中,使用反射实例化,子类可以随便增加,工厂类不需要做任何的修改 使用反射之后最大的好处就是解耦合

  9. 直接copy大于某一个时间小于某一个时间的文件--find进阶用法

    find ./ -type f -newermt '2000-01-04 10:30:00' ! -newermt '2019-10-28 10:57:00' -exec cp -a {} /var/ ...

  10. 从容器中获取宿主机IP地址

    背景: docker 中的程序需要连接外部的程序,连接的过程中会告知外部程序自己的ip地址,然后外部的程序会回连docker中的程序.由于docker使用的是rancher中的托管模式,外部程序是没办 ...