log4j的替换方案
去年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!");
}
}
- 获取记录器。
运行上面的代码段会输出以下内容:
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>
- Log4J 实现System.Logger
- 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>
- 基本的 SLF4J 实现。任何其他实现都可以,例如Logback。
- 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
}
}
保留所有现有日志的路径:
- 如果它不存在,则创建一个记录器并存储它。
最后,我们创建一个服务文件:
ch.frankel.blog.ConsoleLoggerFinder
现在,运行相同的代码片段输出:
Hello world!
结论
虽然 API 比起其他更成熟的日志系统 API 更受限制,但这System.Logger是一个好选择。它提供了作为 JDK 一部分的api。因此,它避免了其他第三方api的漏洞风险,例如SLF4J 到 Log4J2。
出于这个原因,后期可基于System.Logger实现系统日志功能。
log4j的替换方案的更多相关文章
- Google Earth API 替换方案
众所周知,GE API将会在15年12月25日结束服务,对于众多采用该API的软件,需要一些替换方案. 例如google map或者cesiumjs http://cesiumjs.org/ 或者尝试 ...
- Microsoft.AspNet.Web.Optimization.Bundle的完美替换方案
Web应用程序中包含大量的样式(css)和脚本(js)文件,这些文件的引用.管理和发布有很多解决方案.在Asp.Net MVC应用程序中,大家最熟悉的解决方案应属Microsoft.AspNet.We ...
- arguments.callee的作用及替换方案
arguments.callee的作用 arguments 的主要用途是保存函数参数, 但这个对象还有一个名叫 callee 的属性,返回正被执行的 Function 对象,也就是所指定的 Funct ...
- UIActionSheet上加入UIPickerView iOS8替换方案
此套替换方案採用"UIView+动画"方式实现(将UIActionSheet替换为UIView) 界面层级例如以下: 第一层:view(这一层充满整个屏幕,初始化时颜色为透明.us ...
- switch...case...之替换方案一
很多时候,当switch中有N个分支,且分支数已达10+,每个分支都是一个不小的方法体,那我们是不是应该考虑换一种方式来实现这个分支. 而我目前所能想到的是会用到如下几种方法. 1.Action 2. ...
- spring boot拦截器WebMvcConfigurerAdapter,以及高版本的替换方案(转)
文章转自 http://blog.51cto.com/12066352/2093750 最近项目采用spring icloud,用的spring boot版本是1.5.x的,spring boot 2 ...
- JAVA字符配置替换方案
在JAVA中,很多时候,我们后台要对数据进行变量配置,希望可以在运行时再进行变量替换.我们今天给大空提供的是org.apache.commons.text方案. 1.首先,引用org.apache.c ...
- EF架构~为导航属性赋值时ToList()的替换方案
回到目录 今天在进行EF开发时,遇到一个问题,在进行join查询时,类中的一个集合类型的导航属性,在给它赋值时,将查询出来的结果ToList()后,出错了,linq to entity不支持这种操作, ...
- regexp_substr在oracle9i的替换方案
regexp_substr()方法在oracle9i尚不存在,是从oracle10g开始新增,如下为替换解决方法. SELECT regexp_substr('|83~GT67XVFU0RCVIV|6 ...
随机推荐
- 面渣逆袭:Java并发六十问,快来看看你会多少道!
大家好,我是老三,面渣逆袭 继续,这节我们来盘一盘另一个面试必问知识点--Java并发. 这篇文章有点长,四万字,图文详解六十道Java并发面试题.人已经肝麻了,大家可以点赞.收藏慢慢看!扶我起来,我 ...
- 如何更改Docker已经挂载的目录
更改docker已经挂载的目录,主要有两种方式:一是重新创建容器,二是更改配置文件.第一种方式较为简单,下面具体演示第二种方式,通过更改配置文件来更换目录 挂载. 安装docker yum -y in ...
- 【Java】抽象类与抽象方法
文章目录 抽象类与抽象方法 abstract关键字的使用 abstract修饰类:抽象类 abstract修饰方法:抽象方法 abstract使用上的注意点: 抽象类的匿名子类 模板方法设计模式 抽象 ...
- leetcode 264. 丑数 II 及 313. 超级丑数
264. 丑数 II 题目描述 编写一个程序,找出第 n 个丑数. 丑数就是只包含质因数 2, 3, 5 的正整数. 示例: 输入: n = 10 输出: 12 解释: 1, 2, 3, 4, 5, ...
- 【源码阅读】VictoriaMetrics中理解vm-backup中设置origin地址的用途
lib/backup/actions/backup.go: // 118 行 partsToCopy := common.PartsDifference(srcParts, dstParts) //要 ...
- 元编程 (meta-programming)
元编程 (meta-programming) 术语 meta:英语前缀词根,来源于希腊文.中国大陆一般翻译成"元". 在逻辑学中,可以理解为:关于X的更高层次,同时,这个更高层次的 ...
- JVM专题3: GC 垃圾回收
合集目录 JVM专题3: GC 垃圾回收 什么是GC? 为什么要有 GC? Garbage Collection, 用于内存回收. 简述一下 Java 垃圾回收机制? 那些内存需要回收 虚拟机中程序计 ...
- 浅谈FFT(快速傅里叶变换)
前言 啊摸鱼真爽哈哈哈哈哈哈 这个假期努力多更几篇( 理解本算法需对一些< 常 用 >数学概念比较清楚,如复数.虚数.三角函数等(不会的自己查去(其实就是懒得写了(¬︿̫̿¬☆) 整理了一 ...
- spring学习五:Spring Bean 定义继承
Bean 定义继承 bean 定义可以包含很多的配置信息,包括构造函数的参数,属性值,容器的具体信息例如初始化方法,静态工厂方法名,等等. 子 bean 的定义继承父定义的配置数据.子定义可以根据需要 ...
- C++中三种正则表达式比较(C regex,C ++regex,boost regex)
工作需要用到C++中的正则表达式,以下三种正则可供参考 1,C regex #include <regex.h> #include <iostream> #include &l ...