0
点赞
收藏
分享

微信扫一扫

Java日志--slf4j--使用/教程/实例

Brose 2022-02-15 阅读 58


简介

说明

        本文用示例介绍Java的slf4j这个日志框架的用法。同时也会介绍相关的知识。

官网

官网:​​SLF4J​​

官网文档:​​SLF4J Documentation​​

slf4j简介

概述

说明




说明



名词解释



slf4j : simple log facade for java :简单日志门面。



作用



类似适配器,直接使用slf4j的方法打印即可,最终会调用到具体的日志,比如java.util.logging、logback和log4j。



优点



系统换了一个日志源后,不需要更改代码;省内存(可以使用占位符{})。



配置方法



日志的格式、记录级别、输出方式等通过具体日志系统的配置来实现。



支持的日志系统



NOP, Simple,log4j, log4j2, java.util.logging, JCL and logback。



绑定日志实现库的时机



编译时静态绑定真正的Log库



切换日志系统方法



切换jar包即可。例如:从java.util.logging切换到 log4j,仅把 slf4j-jdk14-xxx.jar替换成 slf4j-log4j12-xxx.jar即可。


slf4j与commons-logging区别




slf4j



commons-logging



绑定日志实现库的时机



编译时静态绑定真正的Log库。

可在OSGI中使用



动态查找的机制,在程序运行时自动找出真正使用的日志库。

它使用ClassLoader寻找和载入日志库, 导致了像OSGI这样的框架无法正常工作,因为OSGI的不同的插件使用自己的ClassLoader(OSGI的这种机制保证了插件互相独立)。



占位符



可以使用占位符“{}”



不可使用占位符


slf4j的占位符​

一般log用法(以log4j为例)

java文件

import org.apache.log4j.Logger;

public class TestLog4j {
private static final Logger LOGGER = Logger.getLogger(TestLog4j.class);

public static void main(String[] args) {
String message = "Hello World.";
LOGGER.info("This is a test message: " + message);
}
}

此法缺点

1.字符串相加是一个比较消耗性能的操作

2.若log4j配置的输出级别是ERROR,则根本不会输出,占用内存。

第2个缺点的解决方法:加判断,但会使代码繁琐。例如:

if (LOGGER.isInfoEnabled()) {
LOGGER.info("This is a test message: " + message);
}

slf4j的{}占位符方法

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestLog4j {
private static final Logger LOGGER = LoggerFactory.getLogger(TestLog4j.class);

public static void main(String[] args) {
String message = "Hello World.";
LOGGER.info("This is a test message: {}", message);
}
}

        使用了{}占位符,不会有字符串拼接操作。

        在生产最终日志信息的字符串之前,这个方法会检查一个特定的日志级别是不是打开了,这不仅降低了内存消耗而且预先降低了CPU去处理字符串连接命令的时间。

相关源码:slf4j-log4j12-1.6.1.jar=> Log4jLoggerAdapter

public void debug(String format, Object arg1, Object arg2) {
if (logger.isDebugEnabled()) {
FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
}
}

slf4j的包

下表中,只需指定加粗的依赖即可,它会自动拉取其他依赖。也可以强制其他依赖一个确定的版本,只需将其他依赖放到加粗依赖的后边即可。




含义



所需依赖



slf4j-api-xxx.jar



slf4j核心接口包






slf4j-simple-xxx.jar



slf4jSimpleLogger日志实现包



slf4j-api-xxx.jar=>  slf4j-simple-xxx.jar



slf4j-log4j12-xxx.jar



slf4j调用log4j的1.2版本的实现包



slf4j-api-xxx.jar=>  slf4j-log4j12-xxx.jar=> log4j-xxx.jar(1.2版本)



slf4j-log4j13-xxx.jar



slf4j调用log4j的1.3版本的实现包






slf4j-jdk14-xxx.jar



slf4j调用jdk的java.util.logging的实现包(jdk1.4及之后才有)



slf4j-api-xxx.jar=>  slf4j-jdk14-xxx.jar =>  java.util.logging



slf4j-nop-xxx.jar



slf4j调用nop(没有任何打印)



slf4j-api-xxx.jar=>  slf4j-nop-xxx.jar =>  /dev/null



slf4j-migrator-xxx.jar



帮助迁移你的代码来使用SLF4J。






slf4j-ext-xxx.jar









jul-to-slf4j-xxx.jar



原来jul的打印代码委托给slf4j



slf4j-api-xxx.jar=>  jul-to-slf4j-xxx.jar=> slf4j-yyy(例:slf4j-simple-xxx.jar)



log4j-over-slf4j-xxx.jar



原来log4j的代码保持不变,使用slf4j接口输出



slf4j-api-xxx.jar=>  log4j-over-slf4j-xxx.jar=> slf4j-yyy(例:slf4j-simple-xxx.jar)



jcl-over-slf4j-xxx.jar



原来jcl的代码保持不变,使用slf4j接口输出



slf4j-api-xxx.jar=>  log4j-over-slf4j-xxx.jar=> slf4j-yyy(例:slf4j-simple-xxx.jar)



slf4j-jcl-xxx.jar



原来slf4j的代码保持不变,使用jcl输出






logback-classic-xxx.jar



log4j的升级。不是由slf4j提供。



slf4j-api-xxx.jar=>  logback-classic-xxx.jar, logback-core-xxx.jar

logback天生支持slf4j,所以不需要连接层


调用结构

slf4j-api(接口层

         | 

各日志实现包的连接层( slf4j-jdk14, slf4j-log4j等) 

         | 

各日志实现包(实现层

兼容问题

1. 连接层绑定一个具体的实现层

        比如: slf4j-jdk14.jar或 slf4j-log4j12.jar

2. 接口层与连接层版本要相同

        不同版本的slf4j-api(接口层)和连接层绑定混合在一起可能会引起问题。比如:slf4j-api-1.7.19.jar 对应 slf4j-simple-1.7.19.jar,使用 slf4j-simple-1.5.5.jar将不会正常工作。

3. 客户端与任意接口层兼容

        从客户端的观点来看,所有版本的 slf4j-api都是兼容的。可以使用任何版本的 slf4j-api.jar,只要满足第二条就不会有问题。

桥接

其他网址

官网:​​Bridging legacy APIs​​

简介 

        假如你正在开发应用程序所调用的组件当中已经使用了 JCL 的,还有一些组建可能直接调用了 java.util.logging,这时你需要一个桥接器(名字为 xxx-over/to-slf4j.jar)把他们的日志输出重定向到 SLF4J。

        桥接器就是一个假的日志实现工具。比如:把 jcl-over-slf4j.jar 放到 CLASS_PATH 时,即使某个组件原本是通过 JCL 输出日志的,现在却会被 jcl-over-slf4j “骗到”SLF4J 里,然后 SLF4J 又会根据绑定器把日志交给具体的日志实现工具。下边有相关例程:下边的示例2,示例3。

       CLASS_PATH 里同时放置 log4j-over-slf4j.jar 和 slf4j-log4j12-version.jar 会发生的情况:日志会被踢来踢去,最终进入死循环,会造成内存溢出,其他包相互转发也是这种情况。(log4j-over-slf4j 与 slf4j-log4j12例外,log4j-over-slf4内部做了一个判断,可以防止造成内存溢出:判断slf4j-log4j12 jar包中的org.slf4j.impl.Log4jLoggerFactory是否存在,如果存在则表示冲突了,抛出异常提示用户要去掉对应的jar包,代码在slf4j-log4j12-xxx.jar=> org.apache.log4j.Log4jLoggerFactory=> static域)。

slf4j官方图

Java日志--slf4j--使用/教程/实例_java

示例

@Slf4j

        每次写新的类,就需要写:private static final Logger logger = = LoggerFactory.getLogger(Demo.class);简洁方法:使用lombok的@Slf4j。

步骤

1.引入lombok依赖

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

2.类上写上@Slf4j

3.直接使用log变量

Java日志--slf4j--使用/教程/实例_apache_02

slf4j-simple

java文件

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo {
private static final Logger logger = = LoggerFactory.getLogger(Demo.class);
public static void main(String[] args) {
logger.info("Hello World");
}
}

pom.xml

pom.xml(slf4j-simple)

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>

测试

编译并运行HelloWorld程序,现在在控制台会有下列输出:

[main] INFO org.example.a.Demo - Hello World

注意:若没配置slf4j-xxx(比如没有加入依赖),则会有如下报错。

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".

SLF4J: Defaulting to no-operation (NOP) logger implementation

SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

失败原因:class path下没有找到绑定的slf4j

slf4j-log4j12

要提供log4j.properties配置文件。

依赖

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
<scope>test</scope>
</dependency>

 用法跟slf4j-simple相同

jul转为slf4j-simple​

转换之前:jdk自带的java.util.logging(jul)

java文件

使用jdk自带的java.util.logging(jul)。

package com.example;

import java.util.logging.Logger;

public class HelloWorld {
private static final Logger logger = Logger.getLogger(HelloWorld.class.getName());

public static void main(String[] args) {
logger.severe("jul severe 测试");
logger.warning("jul warning 测试");
logger.info("jul info 测试");
}
}

测试

三月 06, 2020 9:10:07 上午 com.example.HelloWorld main

严重: jul severe 测试

三月 06, 2020 9:10:07 上午 com.example.HelloWorld main

警告: jul warning 测试

三月 06, 2020 9:10:07 上午 com.example.HelloWorld main

信息: jul info 测试

转换之后:jul转到slf4j-simple

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>mytest</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
</project>

java文件

main函数里面添加下列语句:

SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();

添加之后的java文件

package com.example;

import org.slf4j.bridge.SLF4JBridgeHandler;
import java.util.logging.Logger;

public class Demo {
private static final Logger logger = Logger.getLogger(Demo.class.getName());

public static void main(String[] args) {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();

logger.severe("jul severe 测试");
logger.warning("jul warning 测试");
logger.info("jul info 测试");
}
}

测试

[main] ERROR com.example.Demo - jul severe 测试
[main] WARN com.example.Demo - jul warning 测试
[main] INFO com.example.Demo - jul info 测试

jcl转为slf4j

转换之前:jcl

java程序

package com.example;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Demo {
private final static Log logger = LogFactory.getLog(Demo .class);

public static void main(String[] args) {
logger.debug("DEBUG ...");
logger.info("INFO ...");
logger.error("ERROR ...");
}
}

maven依赖

<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>

配置文件

commons-logging.properties

org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

测试

[INFO] Demo - INFO ...
[ERROR] Demo - ERROR ...

转换之后:jcl转为slf4j

只修改maven依赖

<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>

测试

[main] INFO com.example.Demo - INFO ...
[main] ERROR com.example.Demo - ERROR ...

其他网址

​​slf4j的包使用说明 - - ITeye博客​​

​​log4j与commons-logging,slf4j的关系 - sxfans - ITeye博客​​


举报

相关推荐

0 条评论