【日志框架-笔记】深入浅出 Log4j,理论-源码-配置

news2024/11/18 4:51:14

log4j

  • 一、log4j 的概述及其入门程序
    • 入门程序
  • 二、日志输出的需要及PatternLayout类源码分析
    • 日志输出的需要
    • PatternLayout类的源码分析
  • 三、Log4j 占位符的具体含义
  • 四、Log4j 配置文件实操
    • 如何对配置文件进行解析的?(LogManager的静态代码块)
    • 实操
  • 五、自定义 Log4j 配置
    • 取消父类继承的Appender
  • 六、Log4j.xml配置

有关为什么学习Java日志框架和 JUL 的使用在上篇说过:

JUL的介绍及其使用

一、log4j 的概述及其入门程序

Log4j 全称 Logging for Java;它是一个用于Java编程语言的日志记录库(框架),支持多种日志记录格式。包括文本、xml、数据库。和其他日志框架一样,可以把日志信息发送到控制台、文件等不同目的地。有强大的配置功能,当然也可以进行过滤,根据实际情况而论,还是比较灵活的。

Log4j 有三个主要的组件:

  1. Loggers(记录器)
  2. Appenders(输出源)
  3. Layouts(布局,格式转换)

这三组件在上篇 JUL 中也阐述过,Log4j 中的 Logger 也是存在父子关系的,其关系和JUL是一样的。

看看log4j官方对该父子关系的举例(log4j介绍官网):

在这里插入图片描述

Logger 的基本用法:

 public class Logger {

    // Creation & retrieval methods:
    public static Logger getRootLogger();
    public static Logger getLogger(String name);

    // printing methods:
    public void trace(Object message);
    public void debug(Object message);
    public void info(Object message);
    public void warn(Object message);
    public void error(Object message);
    public void fatal(Object message);

    // generic printing method:
    public void log(Level l, Object message);
}

从方法体中也可以发现 log4j 的日志级别名称不同于 JUL。

log4j 的级别(TRACE、DEBUG、INFO、WARN、ERROR、FATAL)。

入门程序

org.apache.log4j.Logger 不同于 java.util.logging.Logger 的是其静态方法的 getLogger 方法除了可以传字符串以外,还可以传Class对象(当然其本质还是XX.class.getName,重载的好处,让你少写点代码🤣)。

在这里插入图片描述

测试:

在这里插入图片描述
下面出现警告信息表示:无法找到该logger的输出源,就是不知道往哪里去输出。

我们可以上官网了解一下如何进行基础配置(就像JUL是默认使用的是conf下面的logging.properties配置文件):

在这里插入图片描述

配置后进行检测:

在这里插入图片描述

可以观察到该基础配置的日志级别的debug

  • 看看BasicCofiguratorconfigure 这个静态方法的实现:

在这里插入图片描述

看完之后咱就可以学着自行去配置输出源和字符串的匹配模式了。上面匹配的是配置父类的,让其按那个格式在控制台进行输出,然后子类会自动继承,也拥有该‘能力’。

二、日志输出的需要及PatternLayout类源码分析

日志输出的需要

首先需要一个输出源(Appender),输出源需要设置输出日志信息的所在位置(setWriter),再确定输出格式,确定日志信息的布局(Layout)。最后将日志联系起输出源进行输出日志信息。

PatternLayout类的源码分析

在这里插入图片描述

  1. 调式进入构造方法(pattern 传入构造 PatternParser解析去去解析它)

在这里插入图片描述
2. 进入到 parse 方法中查看解析过程。首先是去遍历 pattern 字符串,然后遇到占位符(%?)会先存入到 currentLiteral(StringBuffer对象) 当中,然后再通过 finalizeConverter 方法进行转换。

在这里插入图片描述
3. 进入到 finalizeConverter 方法中查看具体实现。

在这里插入图片描述
在这里插入图片描述
4. 看看最后 head 链表咋用的(看看如何进行布局的)。

在这里插入图片描述

然后下面对上面占位符的具体含义进行介绍(及 finalizeConverter 对占位符的操作)。

三、Log4j 占位符的具体含义

%m 输出代码中指定的日志信息;
%p 输出日志级别,及 DEBUG、INFO 等;
%n 换行符;
%r 输出自应用启动到输出该 log 信息耗费的毫秒数
%c 输出打印语句所属的类的全名
%t 输出产生该日志的线程全名
%d 输出服务器当前时间。这种格式:2023-02-27 09:58:12,977
%l 输出日志时间发生的位置,包括类名、线程、及其代码中的行数。如:com.ncpowernode.test.TestLog4j.testLog4j(TestLog4j.java:44)
%F 输出日志消息产生时所在的文件名称
%L 输出代码中的行号。
%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。

其中 %l 所可以输出的内容,就包括了类的全名,及其输出代码中的行号。

下面测试一下:“%d [%p]- %l %m%n"的效果:

在这里插入图片描述

四、Log4j 配置文件实操

如何对配置文件进行解析的?(LogManager的静态代码块)

我们知道获取 Logger 对象是通过 Logger的静态方法 getLogger 去得到的。

static public Logger getLogger(Class clazz) {
    return LogManager.getLogger(clazz.getName());
  }

解析配置文件肯定是要在获取 Logger 对象之前的,如何在此之前呢?

通过静态代码块进行实现。 我们知道 getLogger 方法被调用了,那 LogManager 也会被初始化,所以其静态成员会运行。

在这里插入图片描述

下面是部分静态代码块的静态代码,主要就是先会去拿 log4j.xml 的URL,拿不到就去找 log4j.properties 的URL,然后去解析。

static{
      URL url = null;

      // 如果用户没有指定log4j.configuration
      // 我们首先搜索文件"log4j.xml"然后是"log4j.properties"
      if(configurationOptionStr == null) {	
	url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
	if(url == null) {
	  url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
	}
      } else {
	try {
	  url = new URL(configurationOptionStr);
	} catch (MalformedURLException ex) {
	  // so, resource is not a URL:
	  // attempt to get the resource from the class path
	  url = Loader.getResource(configurationOptionStr); 
	}	
      }
      	}
	
	    if(url != null) {
	    LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
        try {
            OptionConverter.selectAndConfigure(url, configuratorClassName,
					   LogManager.getLoggerRepository());
        } catch (NoClassDefFoundError e) {
            LogLog.warn("Error during default initialization", e);
        }
      } else {
	    LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
      }

就是说配置文件名字不能乱取,要么log4j.xml 要么log4j.properties.

实操

配置 log4j.properties 文件(文件名不能乱写)。

log4j.rootLogger=TRACE, A1, FILE


log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout

# Print the date in ISO 8601 format
log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %l - %m%n

# Print only messages of level WARN or above in the package com.foo.
log4j.logger.com.foo=WARN

# FILE users FileAppender
# fileName、append属性通过set方法进行赋值的,这里是set后面的名称
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.file=D://logs/log4j.log
log4j.appender.FILE.append=false
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d [%t] %-5p %l - %m%n

测试:

	private static final Logger logger = Logger.getLogger(TestLog4j.class);
    @Test
    public void testLog4jFirst(){
        // 日志记录输出
        logger.info("hello log4j");
        // 日志级别
        logger.fatal("fatal");// 严重错误;一般会造成系统崩溃和终止运行
        logger.error("error");// 错误信息, 但不会影响系统运行
        logger.warn("warn");// 警告信息, 可能会发生问题
        logger.info("info");// 程序运行信息,数据库的连接、网络、IO操作等
        logger.debug("debug");// 调试信息,一般在开发阶段使用,记录程序的变量、参数等
        logger.trace("trace");// 追踪信息,记录程序的所有流程信息
    }

在这里插入图片描述

五、自定义 Log4j 配置

当我们需要自定义去配置 Log4j 时,我们可以在配置文件中进行对应的配置。

properties 配置文件中的配置格式:log4j.logger.logger名=级别,Appender....

像下面配置 logger 名为 com.ncpowernode.logstudy 的 logger。

在这里插入图片描述

对该代码进行测试:

    @Test
    public void testLog4jSelfConfig(){
        logger.trace("trace");
        logger.debug("debug");
        logger.error("error");
    }

在这里插入图片描述

输出了两条一样的,是因为 Appender 是可以继承的,可以通过配置或者Java代码进行取消继承,跟 JUL 是一样的,使用配置可以针对某个输出源进行取消,而使用Java代码的话会默认取消所有的父类下来的Appender。从输出结果可以看见,trace没有没输出,可以说明级别取的是父类(最接近的)。

取消父类继承的Appender

log4j 中 Logger 类中有个 setAdditivity 方法,可以取消该 logger 上继承下来的 Appender

当然也可以通过配置文件进行取消:下面取消 com.ncpowernode 的父类继承的Appender。

在这里插入图片描述

然后再将上面的测试代码进行测试结果为:

在这里插入图片描述

rootLogger 配置的输出源被完美取消。

六、Log4j.xml配置

log4j.xml 配置感觉会比 properties 配置要好点,复用性强点。

具体可以看 Log.xml配置文件详解.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/380795.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ClickHouse的架构与基本概念

一、ClickHouse的定义 ClickHouse是一个完全的列式分布式数据库管理系统(DBMS),允许在运行时创建表和数据库,加载数据和运行查询,而无需重新配置和重新启动服务器,支持线性扩展,简单方便,高可靠性&#xf…

spring spring-boot @valid @NotNull @NotEmpty 基本校验使用以及 全局异常优化集成

valid NotNull NotEmpty 一套标准的基础校验&#xff0c;可以将校验注解和附带错误信息添加到请求入参上即可完成校验&#xff0c;可以去除简单的校验代码&#xff0c;节省一定的时间和代码量 Maven 依赖 spring-boot <dependency><groupId>org.springframewor…

【已解决】VM中安装的Ubuntu窗口太小、无法和Windows复制粘贴

按理说窗口都是铺满VM的&#xff0c;可是有时候安装Ubuntu之后发现小太了&#xff0c;就800*600&#xff08;4:3&#xff09; 1 窗口太小方法一 在桌面右键&#xff0c;打开display settings 调整resolution&#xff0c;选择你需要的即可&#xff0c;但是这样的调整不是很完…

结构体占用内存大小如何确定?-->结构体字节对齐 | C语言

目录 一、什么是结构体 二、为什么需要结构体 三、结构体的字节对齐 3.1、示例1 3.2、示例2 3.3、示例3 3.4、示例4 3.5、示例5 四、结构体字节对齐总结 一、什么是结构体 结构体是将不同类型的数据按照一定的功能需 求进行整体封装&#xff0c;封装的数据类型与大小均…

日期:Date,SimpleDateFormat常见API以及包装类

一.Date类 package com.gch.d1_date;import java.util.Date;/**目标:学会使用Date类处理时间,获取时间的信息*/ public class DateDemo1 {public static void main(String[] args) {// 1.创建一个Date类的对象:代表系统此刻日期时间对象Date d new Date();System.out.println(…

什么是pod类型

很久很久以前&#xff0c;C 语言统一了江湖。几乎所有的系统底层都是用 C 写的&#xff0c;当时定义的基本数据类型有 int、char、float 等整数类型、浮点类型、枚举、void、指针、数组、结构等等。然后只要碰到一串01010110010 之类的数据&#xff0c;编译器都可以正确的把它解…

做软件测试,如何才能实现月入20K?

听我的&#xff0c;测试想要月入20k。 首先你要去大厂&#xff0c;不在大厂起码也得在一线城市&#xff0c;北上广深。 二线城市的话成都、杭州最好。 不然的话想都不要想。 像我之前整理过成都的公司&#xff0c;除了字节跳动、蚂蚁金服、滴滴、美团、京东、平安、字节跳动…

超简单的计数排序!!

假设给定混乱数据为&#xff1a;3&#xff0c;0&#xff0c;1&#xff0c;3&#xff0c;6&#xff0c;5&#xff0c;4&#xff0c;2&#xff0c;1&#xff0c;9。 下面我们将通过使用计数排序的思想来完成对上面数据的排序。(先不谈负数) 计数排序 该排序的思路和它的名字一样…

Java——图像渲染

题目链接 leetcode在线oj题——图像渲染 题目描述 有一幅以 m x n 的二维整数数组表示的图画 image &#xff0c;其中 image[i][j] 表示该图画的像素值大小。 你也被给予三个整数 sr , sc 和 newColor 。你应该从像素 image[sr][sc] 开始对图像进行 上色填充 。 为了完成…

互联网医院系统软件开发|互联网医院管理系统开发的好处

互联网医院一直是现在的热门行业&#xff0c;很多的医院已经开发了互联网医院&#xff0c;并且已经在良好的运行中&#xff0c;而有一些医院和企业正在开发中&#xff0c;或者打算开发互联网医院系统&#xff0c;其实这些企业和医院还是很有远见的&#xff0c;因为他们知道并了…

Swift 第三方 播放器AliyunPlayer(阿里云播放器)(源码)

一直觉得自己写的不是技术&#xff0c;而是情怀&#xff0c;一个个的教程是自己这一路走来的痕迹。靠专业技能的成功是最具可复制性的&#xff0c;希望我的这条路能让你们少走弯路&#xff0c;希望我能帮你们抹去知识的蒙尘&#xff0c;希望我能帮你们理清知识的脉络&#xff0…

卡尔曼滤波——一种基于滤波的时序状态估计方法

文章目录1. Kalman滤波及其应用2. Kalman原理公式推导&#xff1a;Step 1&#xff1a;模型建立Step 2&#xff1a;开始Kalman滤波Step 3&#xff1a;迭代滤波本文是对 How a Kalman filter works, in pictures一文学习笔记&#xff0c;主要是提炼核心知识&#xff0c;方便作者快…

已解决pip install wxPython模块安装失败

已解决&#xff08;pip install wxPython安装失败&#xff09;error: legacy-instal1-failure Encountered error while trying to install package.wxPython note: This is an issue with the package mentioned above&#xff0c;not pip. hint : See above for output from …

如何用AST还原某音的JSVMP

1. 什么是JSVMP vmp简单来说就是将一些高级语言的代码通过自己实现的编译器进行编译得到字节码&#xff0c;这样就可以更有效的保护原有代码&#xff0c;而jsvmp自然就是对JS代码的编译保护&#xff0c;具体的可以看看H5应用加固防破解-JS虚拟机保护方案。 如何区分是不是jsv…

OpenFeign 切换HttpClient遇到的问题

背景 OpenFeign支持三种Http请求方式&#xff0c;默认情况下通过jdk中的HttpURLConnection向下游服务发起http请求&#xff08;详见下图&#xff0c;源码详见feign.Client.Default&#xff09;&#xff0c; 默认的Client 采用 HttpURLConnection&#xff0c; 这种是无法复用的…

为什么一定要做集成测试?

集成测试&#xff0c;我们都不陌生&#xff0c;几乎我们产品每天都在进行。但是我们真的有好好思考&#xff1a;为什么一定要做集成测试吗&#xff1f;只是为了简单的将“积木”搭起来就行&#xff0c;还是有什么其他的深意&#xff1f; 深意可能不一定会有&#xff0c;但是意…

qt5.15 快速安装 国内源

1 qt5.15 安装问题 最大的问题就是需要在线下载与安装。即使挂了科学上网&#xff0c;国外的服务器下载速度也还是超级慢。 在网上找了各种解决办法后&#xff0c;终于找到一个快速下载安装的办法。 2 安装器下载 阿里源、清华源都没有Windows的安装器了&#xff0c;在腾讯…

IPv4地址细讲

文章目录一、IPv4地址简介二、IPv4地址的表示方法点分十进制记法三、IP地址的分类四、特殊IPv4地址&#xff1a;全 “0” 和全 “1”五、常用的三类IP地址使用范围六、五类IP地址的范围一、IPv4地址简介 IPv4地址分5类&#xff0c;每一类地址都由固定长度的字段组成&#xff1…

软件项目管理简答题复习(1)

1.项目&#xff1a;创造唯一的产品&#xff0c;唯一的服务临时性的努力 2.项目特征&#xff1a;不可见性&#xff0c;复杂性&#xff0c;一致性&#xff0c;变更性&#xff0c;特殊性 3.项目和日常活动的区别&#xff1f; 项目具有特殊性&#xff0c;负责人是项目经理&#…

软件项目管理计算题复习(1)

软件项目管理计算题复习&#xff08;1&#xff09; 1.关键路径&#xff1a;决定项目最早完成的一系列的活动。网络图中最长的路&#xff0c;最少的时差&#xff0c;总是差为0&#xff0c;也是关键路径。 2.最短路径也是最短工期 3.总时差&#xff1a;最晚开始-最早开始最晚结…