首页 > 编程语言 >Java-Log框架

Java-Log框架

时间:2023-07-20 10:37:05浏览次数:34  
标签:Java Log 框架 log4j2 slf4j apache org logback log4j

java日志

SLF4j是日志门面api,log4j、log4j2、logback才是真正的日志实现库。

各个库单独使用

1 log4j

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

classpath下配置文件log4j.properties

log4j.rootLogger=INFO,console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %c: %m%n

使用:

import org.apache.log4j.Logger;
...
static final Logger LOGGER = Logger.getLogger(Main.class);

2 log4j2

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.12.1</version>
</dependency>

classpath下log4j2.properties

rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT

appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} [%p] %c: %m%n
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
...
static final Logger LOGGER = LogManager.getLogger(Main.class);

3 logback

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

classpath下logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%p] %c: %m%n</pattern>
        </encoder>
    </appender>
    <root level="debug">
        <appender-ref ref="console" />
    </root>
</configuration>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
static final Logger LOGGER = LoggerFactory.getLogger(Main.class);

各个库实现slf4j标准使用

注意:logback本身就是实现slf4j的,如上代码中的logger本就是slf4j的。

log4j实现方式,引入slf4j-log4j12

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.29</version>
</dependency>

log4j2的实现方式,引入log4j-slf4j-impl

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.12.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.9.0</version>
</dependency>

这样组装后就可以用slf4j的写法了

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
static final Logger LOGGER = LoggerFactory.getLogger(Main.class);

多依赖项目的日志统一

事实上,我们的项目可能有很多依赖,各个依赖有可能有着各不相同的日志实现方式。比如我们有五个依赖,他们分别是:

  • 独立log4j
  • 独立log4j2
  • slf化log4j
  • slf化log4j2
  • slf化logback 因为logback只能slf化,没有独立使用的方式,所以是5种。

而当前我们项目期望使用logback,并期望统一为slf化的logback形式,只配置一个logback.xml就能对所有依赖进行配置。以下配置几乎是万能的,当遇到问题的时候,直接全部拷贝进去,稳定解决,绝不复发。

<!-- 处理单独log4j的依赖: -->
<!-- 用log4j-over-slf4j替换log4j,使依赖中的log4j也能"实现"slf4j-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.29</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>99.99.99</version>
</dependency>

<!-- 处理单独log4j2的依赖: -->
<!-- 用log4j-to-slf4j替换log4j2,使依赖中的log4j2也能"实现"slf4j -->
 <dependency>
    <groupId>org.apache.logging.log4j</groupId>
     <artifactId>log4j-to-slf4j</artifactId>
    <version>2.12.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>99.99.99</version>
</dependency>

<!-- 处理slf化的log4j的依赖: -->
<!-- 因为slf选binding的时候有多个候选,为防止slf4j-log4j12选中,直接去掉他 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>99.99.99</version>
</dependency>

<!-- 处理slf化的log4j2的依赖: -->
<!-- 因为slf选binding的时候有多个候选,为防止log4j-slf4j-impl选中,直接去掉他 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>99.99.99</version>
</dependency>

<!-- 最后引个新版本的logback -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

小结

  • slf4j-log4j12:与log4j联合使用,用于使当前项目的log4j实现slf标准
  • log4j-slf4j-impl:与log4j2联合使用,用于使当前项目的log4j实现slf标准
  • log4j-over-slf4j:与剔除log4j联合使用,替换log4j,使log4j实现slf。用于让单独用log4j的依赖能遵循slf,进而统一日志配置。
  • log4j-to-slf4j:与剔除log4j2联合使用,替换log4j2,使log4j2实现slf。用于让单独用log4j2的依赖能遵循slf,进而统一日志配置。

原理

slf4j是门面,大的设计模式是门面系统,而logback是直接实现了slf4j-api中的接口,是通过接口实现的方式完成了门面的实现。

而log4j和log4j2没有直接实现接口,所以需要个适配器。slf4j-log4j12和log4j-slf4j-impl就是适配器,将原本不能实现slf4j的变得也能实现这个标准了。添加了适配器后,就能使用slf4j的接口来使用log4j了。 

项目的依赖中独立使用了log4j/log4j2,注意是依赖中,这时候想要统一到slf4j上来,就需要log4j-over-slf4j/log4j-to-slf4j。 以log4j-over-slf4j为例,他实际上是重写了log4j所有的类,将原来的info、debug等等方法委托给slf4j执行了,上面我们将log4j用不存在版本的方式彻底剔除了log4j中的类,使依赖加载的类被偷梁换柱为log4j-over-slf4j中的logger,这个logger中方法又委托给slf4j,slf4j向下找binding找到仅存的logback。

下面是log4j和log4j-over-slf4j重写的logger类,他们形式上一样包括包名,这里就放一张图了

然后都是继承Category这个类,实际上主要的方法实现都在这里,下面分别是log4j包和log4j-over-slf4j包中的Category:

从图中可以看出log4j就是自己在写日志,而后者则委托给了slf4j。

这是slf官网的图。

不存在版本的方式剔除log4j是一种暴力方式,其实目的是让原来的log4j不要先加载就行,可以在pom中将log4j-over-slf4j写在log4j前面就行,log4j写存在的版本就行(因为也不会加载)。

疑惑:pom中不写log4j会有问题吗?

回答:可能会有问题。maven决定了依赖的加载顺序,假如用了log4j的依赖叫A。不写log4j在pom中就必须保证log4j-over-slf4j写在A前面。

标签:Java,Log,框架,log4j2,slf4j,apache,org,logback,log4j
From: https://blog.51cto.com/zhangzhixi/6782948

相关文章

  • Java详解ThreadLocal
    threadlocal1基础现象:threadlocal作为一个全局变量,在不同的线程去get的时候能够获取不同的值。应用场景:SimpleDateFormat线程不安全,每个线程都要用,new太多,放到threadlocal中线程池可反复使用。一个请求链路很长,经过数个服务,每次都要放到参数带着。改为直接放到threadlocal作为上下......
  • Java开发工具MyEclipse发布v2023.1.2,今年第二个修复版!
    MyEclipse一次性提供了巨量的Eclipse插件库,无需学习任何新的开发语言和工具,便可在一体化的IDE下进行JavaEE、Web和PhoneGap移动应用的开发;强大的智能代码补齐功能,让企业开发化繁为简。MyEclipsev2023.1.2官方正式版下载更新日志如下:v2023.1.2是MyEclipse2023的一个小错误修......
  • Java各种注解
    @EnableConfigurationProperties({MinIOConfigProperties.class})将@ConfigurationProperties标记的类作为Bean注入到容器中,也可以在原来的@ConfigurationProperties上继续加@Component,相当于吧@ConditionalOnClass(FileStorageService.class)表示有这个类时才会注入spring容器......
  • Blazor前后端框架Known-V1.2.5
    V1.2.5Known是基于C#和Blazor开发的前后端分离快速开发框架,开箱即用,跨平台,一处代码,多处运行。Gitee:https://gitee.com/known/KnownGithub:https://github.com/known/Known概述基于C#和Blazor实现的快速开发框架,前后端分离,开箱即用。跨平台,单页应用,混合桌面应用,Web和桌面......
  • Javascript和jQuery有什么不同?
     Javascript和jQuery都是前端开发必备的语言和框架,但他们之间有很多不同。下面我们来详细的分析一下。Javascript是一种脚本语言,可以在浏览器端直接运行。它的语法简单,可以操作HTML和CSS,实现动态效果,如表单验证、动态创建元素等。Javascript的核心是ECMAScript标准,它定义了语......
  • JavaScript和Java如何进行通信
     JavaScript和Java是两种不同的编程语言,但是它们可以通过一些技术手段进行通信。在Web开发领域,JavaScript和Java的交互性十分重要,因为它们可以实现复杂的交互操作和数据处理,为Web应用程序带来更好的用户体验。一、Java与JavaScript的通信方式1.JavaappletJavaapplet是一......
  • JavaScript汉字转码原理解析
     JavaScript是一种高级编程语言,广泛应用于Web、移动应用开发等领域。其中,涉及到的汉字编码问题一直备受关注。本篇文章将从JavaScript汉字转码的原理解析入手,为读者深入剖析这一现象。什么是汉字编码?汉字编码是指计算机用二进制形式来表示中文字符的方式。由于计算机只能识别......
  • JavaScript函数中嵌套函数的使用方法及技巧
     在JavaScript编程中,函数是用来封装可重用代码的一种重要工具。但是,有时候在函数内部需要创建另一个函数来完成一些特定的功能。这种在函数内部定义的函数被称为嵌套函数。本文将讨论JavaScript函数中嵌套函数的使用方法及技巧。1.嵌套函数的定义在JavaScript中,嵌套函数可以......
  • JavaScript函数重载实现方法
     在编写JavaScript代码时,我们常常遇到需要编写多个名称相同但参数类型不同的函数的情况。这时,我们可以使用JavaScript函数重载来实现这一功能。函数重载是指在同一个作用域内定义多个同名函数,但参数类型和数量各不相同。在调用函数时,根据传入的参数类型和数量,自动匹配对应的函......
  • taro框架使用经验
    就是京东那个taro框架1. taro3.x的Picker(2023-7-20)默认会报错 TypeError:Cannotreadpropertiesofundefined(reading'split')<Pickermode='date'onChange={this.onDateChange}><ViewclassName='picker'>当前选择:{this.......