当前位置: 首页 > news >正文

系统复习Java日志体系

一,我们采用硬编码体验一下几个使用比较多的日志

分别导入几种日志的 jar 包

<?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.fll</groupId><artifactId>log-system-study</artifactId><version>1.0-SNAPSHOT</version><name>log-system-study</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><!--  ===  log4j1 相关jar包  ====  --><!-- 单独导入 log4j1 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><!--  ===  log4j2 相关jar包  ===  --><!-- 单独导入 log4j2 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.13.3</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.13.3</version></dependency><!--  === logback 相关jar包  ====  --><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.4</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.2.4</version></dependency></dependencies><build></build></project>
package com.fll;import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.util.ContextInitializer;
import ch.qos.logback.core.joran.spi.JoranException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.spi.ExtendedLogger;
import org.junit.Test;import java.net.URL;
import java.util.logging.Logger;public class LoggerTest {/*** java自带的日志工具 * java.util.logging.Logger*/@Testpublic void julLogger() {Logger logger = Logger.getLogger("julLogger");//System.setProperty("-Djava.util.logging.config.file", "classpath:/logging.properties");//logger.setLevel(Level.FINE);logger.info("julLogger Hello World!");
//运行结果  显示红色
//七月 30, 2024 10:51:38 上午 com.fll.LoggerTest julLogger
//信息: julLogger Hello World!}/*** log4j1*/@Testpublic void log4JLogger(){org.apache.log4j.Logger log4JLogger = org.apache.log4j.Logger.getLogger("log4JLogger");log4JLogger.info("log4J_1_Logger Hello World!");
//运行结果
//[log4j_1] 2024-07-30 10:55:29,017 INFO [log4J_1_Logger] - log4J_1_Logger Hello World!}/*** log4j2*/@Testpublic void log4J_2_Logger(){ExtendedLogger logger= LogManager.getContext().getLogger("log4J_2_Logger");logger.info("log4J_2_Logger Hello World!");
//运行结果
//[log4j_2] line=41 10:55:50.050 [main]INFO  - log4J_2_Logger Hello World!}/*** logback*/@Testpublic void logBackLogger(){// Here we create contextLoggerContext loggerContext = new LoggerContext();//创建一个LoggerContext的初始化器,该初始化器可以通过configureByResource()方法,//使用指定的配置(xml,或者 properties)对LoggerContext实例进行初始化// Initializer is used to enrich context with detailsContextInitializer contextInitializer = new ContextInitializer(loggerContext);try {//获取我们的配置文件// Get a configuration file from classpathURL configurationUrl = Thread.currentThread().getContextClassLoader().getResource("logback.xml");if (configurationUrl == null) {throw new IllegalStateException("Unable to find custom logback configuration file");}// 解析配置文件,将解析到的配置设置给 LoggerContext// Ask context initializer to load configuration into contextcontextInitializer.configureByResource(configurationUrl);// Here we get logger from contextch.qos.logback.classic.Logger logger = loggerContext.getLogger("logBackLogger");logger.info("logBackLogger Hello World!");
//运行结果
//[logback] 2024-07-30 10:57:03 [main] INFO  logBackLogger - logBackLogger Hello World!} catch (JoranException e) {throw new RuntimeException("Unable to configure logger", e);}}@Testpublic void logBackLogger1(){// Here we create contextLoggerContext loggerContext = new LoggerContext();// Initializer is used to enrich context with detailsContextInitializer contextInitializer = new ContextInitializer(loggerContext);try {//autoConfig 方法中 会先调用 findURLOfDefaultConfigurationFile()//获取一个默认的配置文件,// 然后调用configureByResource 对 loggerContext进行初始化// findURLOfDefaultConfigurationFile 逻辑是先获取环境变量 //logback.configurationFile// 配置的文件,找不到再找 logback-test.xml ,logback.groovy , logback.xmlcontextInitializer.autoConfig();// Here we get logger from contextch.qos.logback.classic.Logger logger =     loggerContext.getLogger("logBackLogger");logger.info("logBackLogger Hello World!");//运行结果
//[logback] 2024-07-30 10:57:51 [main] INFO  logBackLogger - logBackLogger Hello World!} catch (JoranException e) {throw new RuntimeException("Unable to configure logger", e);}}}

 log4j的配置文件  log4j.properties

log4j.rootLogger=info, stdoutlog4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[log4j_1] %d %p [%c] - %m%n

 log4j2的配置文件  log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration><appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="[log4j_2] line=%L %d{HH:mm:ss.sss} [%t]%highlight{%-5level} - %msg%n"/></Console><!-- <Console name="Console" target="SYSTEM_0UT"> --><!-- <PatternLayout pattern="file=%c line=%L %dHH:mm:ss.sss}[%t]%highlight{%-5level} %logger{36}-%msg%n"/> --><!-- </Console> --></appenders><loggers><root level="debug"><appender-ref ref="Console"/></root></loggers></configuration>

java.util.logging.Logger 配置文件 logging.properties

.level=WARNINGhandlers=java.util.logging.ConsoleHandlerjava.util.logging.ConsoleHandler.level=WARNING
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

logback的配置文件 logback.xml

<configuration><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>[logback] %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><root level="debug"><appender-ref ref="STDOUT" /></root></configuration>

二、采用 commons-logging 动态选用日志

<!--  ===  commons-logging 相关jar包  ==  -->
<dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version>
</dependency>

先只导入commons-logging.jar不导入其他的日志包

package com.fll;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;public class CommonLoggingTest {@Testpublic void commonLogging(){Log logger = LogFactory.getLog("commonLogging");logger.info("commonLogging Hello World!");}}

 可以看到运行结果:日志打印采用的是 
class org.apache.commons.logging.impl.Jdk14Logger
内部封装的是 java.util.logging.Logger

除了commons-logging之外再导入 log4j1的 jar 包

<!--  ===  commons-logging 相关jar包  ==  -->
<dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version>
</dependency><!-- 单独导入 log4j1 -->
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>

  可以看到运行结果:日志打印采用的是 
class org.apache.commons.logging.impl.Log4JLogger

public static Log getLog(String name) throws LogConfigurationException {return getFactory().getInstance(name);
}

 可以看到 LogFactory 只有一个实现类 
org.apache.commons.logging.impl.LogFactoryImpl

org.apache.commons.logging.impl.LogFactoryImpl#getInstance(java.lang.String)

public Log getInstance(String name) throws LogConfigurationException {Log instance = (Log) instances.get(name);if (instance == null) {instance = newInstance(name);instances.put(name, instance);}return instance;
}protected Log newInstance(String name) throws LogConfigurationException {Log instance;try {if (logConstructor == null) {// 关键的方法,根据环境和配置获取要实例化的日志对象instance = discoverLogImplementation(name);}else {Object params[] = { name };instance = (Log) logConstructor.newInstance(params);}if (logMethod != null) {Object params[] = { this };logMethod.invoke(instance, params);}return instance;//省略不重要代码
}/*** The names of classes that will be tried (in order) as logging* adapters. Each class is expected to implement the Log interface,* and to throw NoClassDefFound or ExceptionInInitializerError when* loaded if the underlying logging library is not available. Any* other error indicates that the underlying logging library is available* but broken/unusable for some reason.*/
private static final String[] classesToDiscover = {LOGGING_IMPL_LOG4J_LOGGER,"org.apache.commons.logging.impl.Jdk14Logger","org.apache.commons.logging.impl.Jdk13LumberjackLogger","org.apache.commons.logging.impl.SimpleLog"
};/**
* 根据环境和配置获取要实例化的日志对象
*
*/
private Log discoverLogImplementation(String logCategory)throws LogConfigurationException {if (isDiagnosticsEnabled()) {logDiagnostic("Discovering a Log implementation...");}initConfiguration();Log result = null;//先看用户有没有指定的 Log 的实现
//LOG_PROPERTY = "org.apache.commons.logging.Log";
//LOG_PROPERTY_OLD = "org.apache.commons.logging.log";
//从attributes中获取 
//先从 String specifiedClass = (String) getAttribute(LOG_PROPERTY);
//再从 specifiedClass = (String) getAttribute(LOG_PROPERTY_OLD);//从环境变量中获取
//先找 specifiedClass = getSystemProperty(LOG_PROPERTY, null); 
//再找 specifiedClass = getSystemProperty(LOG_PROPERTY_OLD, null);// See if the user specified the Log implementation to useString specifiedLogClassName = findUserSpecifiedLogClassName();//如果找到用户配置的的 日志实现if (specifiedLogClassName != null) {if (isDiagnosticsEnabled()) {logDiagnostic("Attempting to load user-specified log class '" + specifiedLogClassName + "'...");}//使用用户 配置的日志实现result = createLogFromClass(specifiedLogClassName,logCategory,true);//如果按照用户配置的创建日志对象失败if (result == null) {StringBuffer messageBuffer =  new StringBuffer("User-specified log class '");messageBuffer.append(specifiedLogClassName);messageBuffer.append("' cannot be found or is not useable.");// Mistyping or misspelling names is a common fault.// Construct a good error message, if we caninformUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LOG4J_LOGGER);informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_JDK14_LOGGER);informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LUMBERJACK_LOGGER);informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_SIMPLE_LOGGER);throw new LogConfigurationException(messageBuffer.toString());}//如果按照用户配置的创建日志对象成功,直接返回创建的对象return result;}if (isDiagnosticsEnabled()) {logDiagnostic("No user-specified Log implementation; performing discovery" +" using the standard supported logging implementations...");}// 如果用户没有配置任何日志实现// 依次遍历 classesToDiscover 并尝试在classpath中加载每一个日志实现// 如果哪个加载成功就返回哪一个,后面的不在尝试// 所以按照顺序是// 先加载 = "org.apache.commons.logging.impl.Log4JLogger";// 再加载 org.apache.commons.logging.impl.Jdk14Loggerfor(int i=0; i<classesToDiscover.length && result == null; ++i) {result = createLogFromClass(classesToDiscover[i], logCategory, true);}//如果从classpath没有加载到任何日志实现 就报错if (result == null) {throw new LogConfigurationException("No suitable Log implementation");}return result;
}
private static final String[] classesToDiscover = {"org.apache.commons.logging.impl.Log4JLogger","org.apache.commons.logging.impl.Jdk14Logger","org.apache.commons.logging.impl.Jdk13LumberjackLogger","org.apache.commons.logging.impl.SimpleLog"
};这里是写死的,
优先加载 org.apache.commons.logging.impl.Log4JLogger
然后加载 org.apache.commons.logging.impl.Jdk14Logger 

 

org.apache.commons.logging.impl.Log4JLogger是对org.apache.log4j.Logger简单装饰
org.apache.commons.logging.impl.Jdk14Logger是对java.util.logging.Logger简单装饰可以看到 commons-logging 中默认实现的日志我们常用的只有 org.apache.log4j.Logger
和 java.util.logging.Logger 如果想用其他的一些流行的日志还得自己去实现该日志的装饰
类,并且还得通过 attributes 或者 环境变量进行 配置才能使用,要不就得下载源码,自己在
数组中加入要使用的日志实现。这样就比较麻烦。所以使用commons-logging的人越来越少了,
还有一个原因是 自从 1.2 版本之后,commons-logging 就不再更新了

三、slf4j 通过动态绑定灵活调整要使用的日志

http://www.lryc.cn/news/409963.html

相关文章:

  • 网络管理linux命令
  • PowerDNS架构解析与安装部署指南
  • Ubuntu 20.04.6 安装 Elasticsearch
  • Python for循环迭代原理(迭代器 Iterator)
  • 通信原理-思科实验四:静态路由项配置实验
  • ngzero使用外部的svg图标
  • 逆矩阵、秩
  • pc端小程序抓包修改数据相关记录
  • 用Python打造精彩动画与视频.2.1 Python基础语法概述
  • Golang高效合并(拼接)多个gzip压缩文件
  • MySQL数据库-基本概念
  • 【无标题】web+http协议+nginx搭建+nginx反向代理(环境准备)
  • c-periphery RS485串口库文档serial.md(serial.h)(非阻塞读)(VMIN、VTIME)
  • Matlab arrayfun 与 bsxfun——提高编程效率的利器!
  • 【Unity编辑器拓展】GraphView自定义可视化节点
  • 教程系列4 | 趋动云『社区项目』极速体验 LivePortrait 人脸表情“移花接木”大法
  • WGS84、GCJ-02、BD09三大坐标系详解
  • css上下动画 和淡化
  • 深入解析C#中的URI和URL编码:理解EscapeDataString、EscapeUriString和UrlEncode的区别及字符编码错误处理
  • 【CSS】给图片设置 max-width
  • 区块链——代码格式检查(prettier、solhint)
  • 搭建自动化 Web 页面性能检测系统 —— 部署篇
  • 知识图谱增强的RAG(KG-RAG)详细解析
  • python中list的深拷贝和浅拷贝
  • 【LeetCode】字母异位词分组
  • Golang | Leetcode Golang题解之第295题数据流的中位数
  • 【C语言】C语言期末突击/考研--数据的输入输出
  • How can I fix my Flask server‘s 405 error that includes OpenAi api?
  • LeetCode Hot100 将有序数组转换为二叉搜索树
  • 【Linux】线程的控制