用Log4j 2记录日志

说明

maven工程中增加对Log4j 2的依赖

下面代码示例的maven工程中的pom.xml文件中需要增加对Log4j 2的依赖:

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

log4j 2的配置

配置说明参考文档

https://logging.apache.org/log4j/2.x/manual/configuration.html

配置文件中pattern的详细说明

例如,下面配置文件片段中用到了pattern:

  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
       <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="File1" fileName="${filename}">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </File>
  </Appenders>

pattern的详细说明请参考:
https://logging.apache.org/log4j/2.x/manual/layouts.html#PatternLayout
在这里插入图片描述

通常给每个类创建自己的Logger

为了便于对日志的过滤、搜索、排序等,通常每个类都获取它自己的带名字的Logger,而不是所有类共用一个Logger。
例如通常的做法:
private static final Logger logger = LogManager.getLogger();
创建一个Logger ,名字就是调用类的全限定名。

建议将Logger 声明为static的

Logger 可以声明为static的、或者非static的,但建议声明为static的。这样做的目的是为了节约实例化的成本。

Logger的名字

大多数log实现用层级结构匹配Logger的名字和日志的配置,层级结构用点号“.”表示,跟包名类似。例如,com.thb.register和com.thb.common的父都是com.thb。例如,下面几种写法得到的Logger的名字相同:

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	
	private static final Logger logger = LogManager.getLogger();
}
package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {	
	
	private static final Logger logger = LogManager.getLogger(Test.class);
}
package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {	

	private static final Logger logger = LogManager.getLogger(Test.class.getName());
}

替换参数

在记录日志时,经常需要将一些动态信息放进去,log4j 2和log4j 1.x的做法不同。

在log4j 1.x中的做法为如下:

// log4j 1.x中的做法,代码中要显式判断对应级别的日志是否打开
if (logger.isInfoEnabled()) {
	logger.info("面积为:" + Math.PI * Math.pow(r, 2));
}

上面代码,对日志级别的判断实际进行了两次,第一次是调用isInfoEnabled()方法的时候,第二次是调用info方法记录日志的时候。如果记录日志的地方多,代码就显得庞杂

在log4j 2中的做法为:

// log4j 2中的做法,用替换参数,代码中不需要显式判断对应级别的日志是否打开
logger.info("面积为:{}", Math.PI * Math.pow(r, 2));

上面代码,对日志级别的判断只进行了一次,而且日志字符串只有在对应级别的日志允许输出的情况下才进行构造。代码更加简洁

通过Java-8的Lambda表达式支持日志消息懒构造

log4j 2通过Java-8的Lambda表达式支持日志消息懒构造,即日志消息在对应的日志级别打开的情况下才构造:

logger.info("the information is {}", () -> expensiveOperation())

log4j 2的日志级别

下面日志级别按照由高到低列出:
OFF:不记录日志(其实这个本质上不是日志级别,是个关闭所有日志开关)
FATAL
ERROR
WARN
INFO
DEBUG
TRACE
ALL:所有日志都记录(其实这个本质上不是日志级别,是个打开所有日志开关)

在过滤器或者Logger中配置了某个级别的日志,那么实际会记录该级别及该级别以上的日志。例如,如果配置了日志级别为INFO,那么实际会记录FATAL、ERROR、WARN、和INFO几个级别的日志。

代码示例

代码示例公共说明

如果没有特别说明,下面代码示例中maven工程中src/main/resources/log4j2.xml的配置内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
       <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="File1" fileName="${filename}">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </File>
  </Appenders>
  <Loggers>
    <Root level="info">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

用LogManager.ROOT_LOGGER_NAME获取root Logger的名字

LogManager.ROOT_LOGGER_NAME是root Logger的名字,这个名字是空字符串""。

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	
	public static Logger logger = LogManager.getLogger();

	public static void main(String[] args) {
		System.out.println("root logger name: " + LogManager.ROOT_LOGGER_NAME);
		//System.out.println("logger name: " + logger.getName());		
	}

}

运行结果:

在这里插入图片描述
从上面输出结果可以发现,root Logger的名字是空字符串""。

用LogManager的getLogger()获取一个带名字的Logger

LogManager.getLogger()返回一个带名字的Logger,这个Logger的名字就是调用的类的全限定名称。这个方法经常使用。
下面代码中获取Logger的方法是典型的获取方法。

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	
	private static final Logger logger = LogManager.getLogger();

	public static void main(String[] args) {		
		System.out.println("logger name: " + logger.getName());		
	}

}

运行输出:
在这里插入图片描述
从上面输出可以看出,Logger的名字是调用类的全限定名称,此处是com.thb.Test。

几种方法获取相同名字的Logger

方法一:

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	
	private static final Logger logger = LogManager.getLogger();
	
	public static void main(String[] args) {
		System.out.println(logger.getName());
	}

}

运行输出:

com.thb.Test

方法二:

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {	
	
	private static final Logger logger = LogManager.getLogger(Test.class);

	public static void main(String[] args) {
		System.out.println(logger.getName());
	}

}

运行输出:

com.thb.Test

方法三:

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {	

	private static final Logger logger = LogManager.getLogger(Test.class.getName());

	public static void main(String[] args) {
		System.out.println(logger.getName());
	}

}

运行输出:

com.thb.Test

用LogManager的getLogger(String name)创建Logger时指定名字

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	// 创建Logger时明确指定了名字为Thb
	private static final Logger logger = LogManager.getLogger("Thb");

	public static void main(String[] args) {
		double r = 2;
		
		// log4j 2中的做法,代码中不需要显式判断对应级别的日志是否打开
		logger.info("面积为:{}", Math.PI * Math.pow(r, 2));
	}

}

运行输出:

08:55:31.715 [main] INFO  Thb - 面积为:12.566370614359172

在控制台打印一条INFO级别的日志

打印日志的代码:

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	
	private static final Logger logger = LogManager.getLogger();

	public static void main(String[] args) {		
		System.out.println("logger name: " + logger.getName());	
		logger.info("hello");
	}

}

输出:
在这里插入图片描述

在控制台打印日志,使用替换参数构造日志字符串

为了进行对比,首先给出log4j 1.x中的做法:

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	
	private static final Logger logger = LogManager.getLogger();

	public static void main(String[] args) {
		double r = 2;
				
		// log4j 1.x中的做法,代码中要显式判断对应级别的日志是否打开
		if (logger.isInfoEnabled()) {
			logger.info("面积为:" + Math.PI * Math.pow(r, 2));
		}
	}

}

运行输出:

08:41:01.549 [main] INFO  com.thb.Test - 面积为:12.566370614359172

再给出log4j 2中的做法:

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	
	private static final Logger logger = LogManager.getLogger();

	public static void main(String[] args) {
		double r = 2;
		
		// log4j 2中的做法,使用替换参数,代码中不需要显式判断对应级别的日志是否打开
		logger.info("面积为:{}", Math.PI * Math.pow(r, 2));
	}

}

运行输出:

08:43:14.741 [main] INFO  com.thb.Test - 面积为:12.566370614359172

通过Java-8的Lambda表达式支持日志消息懒构造

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	
	private static final Logger logger = LogManager.getLogger();

	public static void main(String[] args) {
		double r = 2;
		
		// 通过Java-8的Lambda表达式支持日志消息懒构造
		logger.info("面积为:{}", () -> Math.PI * Math.pow(r, 2));		
	}

}

运行输出:

09:29:48.911 [main] INFO  com.thb.Test - 面积为:12.566370614359172

两个类都定义了静态的Logger,并且在一个类中调用另外一个类的方法

定义一个类,类中定义了自己的静态Logger:

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class AnotherClass {
	private static final Logger logger = LogManager.getLogger();

	public void method() {
		logger.info("hello from AnotherClass");
	}
}

定义一个主类,在主类中也定义了一个静态Logger:

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	
	private static final Logger logger = LogManager.getLogger();

	public static void main(String[] args) {		
		logger.info("hello from Test");
		
		AnotherClass another = new AnotherClass();
		another.method();
	}

}

运行结果:

15:10:28.161 [main] INFO  com.thb.Test - hello from Test
15:10:28.199 [main] INFO  com.thb.AnotherClass - hello from AnotherClass

用traceEntry(String format, Object… params)在函数的入口记录trace日志

maven工程中src/main/resources/log4j2.xml的配置内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
       <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="File1" fileName="${filename}">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </File>
  </Appenders>
  <Loggers>
    <Root level="trace">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

记录日志的代码示例:

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	
	private static final Logger logger = LogManager.getLogger();

	public static void main(String[] args) {
		Test test = new Test();
		test.method("hello", 10);		
	}
	
	public void method(String name, int age) {
		logger.traceEntry("name: {} and age: {}", name, age);		
	}

}

运行输出:

10:26:48.335 [main] TRACE com.thb.Test - Enter name: hello and age: 10

用traceExit(R result)在函数的结尾记录trace日志

maven工程中src/main/resources/log4j2.xml的配置内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
       <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="File1" fileName="${filename}">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </File>
  </Appenders>
  <Loggers>
    <Root level="trace">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

记录日志的代码示例:

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	
	private static final Logger logger = LogManager.getLogger();

	public static void main(String[] args) {
		Test test = new Test();
		test.method("hello", 10);		
	}
	
	public boolean method(String name, int age) {
		boolean result = true;
		logger.traceExit(result);
		return result;
	}

}

运行输出:

10:36:38.201 [main] TRACE com.thb.Test - Exit with(true)

用traceEntry()和traceExit()记录函数的进入和离开trace日志

如果函数没有参数、或者我们对参数不感兴趣,可以直接用traceEntry()记录函数的进入日志。
如果函数不返回任何结果、或者我们对返回结果不感兴趣,可以直接用traceExit()记录函数的离开日志。
maven工程中src/main/resources/log4j2.xml的配置内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
       <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="File1" fileName="${filename}">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </File>
  </Appenders>
  <Loggers>
    <Root level="trace">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

输出日志代码:

package com.thb;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
	
	private static final Logger logger = LogManager.getLogger();

	public static void main(String[] args) {
		Test test = new Test();
		test.method();
	}
	
	public void method() {
		logger.traceEntry();
		logger.traceExit();		
	}
}

运行结果:

11:09:29.794 [main] TRACE com.thb.Test - Enter
11:09:29.799 [main] TRACE com.thb.Test - Exit

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SQL92 SQL99 语法 Oracle 、SQL Server 、MySQL 多表连接、Natural 、USING

SQL92 VS SQL 99 语法 92语法 内连接 from table1&#xff0c; table2 where table1.col table2.col 外连接 放在 从表 左连接&#xff1a; from table1&#xff0c; table2 where table1.col table2.col() 右连接&#xff1a; from table1&#xff0c; table2 where table…

分布式协议与算法——拜占庭将军问题

拜占庭将军问题 背景&#xff1a;以战国时期为背景 战国时期&#xff0c;齐、楚、燕、韩、赵、魏、秦七雄并立&#xff0c;后来秦国的势力不断强大起来&#xff0c;成了东方六国的共同威胁。于是&#xff0c;这六个国家决定联合&#xff0c;全力抗秦&#xff0c;免得被秦国各个…

18. SpringBoot 如何在 POM 中引入本地 JAR 包

❤️ 个人主页&#xff1a;水滴技术 &#x1f338; 订阅专栏&#xff1a;成功解决 BUG 合集 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; Spring Boot 是一种基于 Spring 框架的轻量级应用程序开发框架&#xff0c;它提供了快速开发应用程…

el-table那些事

el-table那些事 获取el-table所有勾选的行数据 用于记录工作和日常学习遇到的坑&#xff0c;需求。 vue3element-plusts 获取el-table所有勾选的行数据 1、需要先声明一个ref变量&#xff0c;并赋值给el-table 2、通过el-table提供的getSelectionRows()函数获取选中的"行…

uni-app:分页实现多选功能

效果 代码解析 一、标签-列表 <view class"item_all" v-for"(item, index) in info" :key"index"><view class"position parameter-info text-over" :class"{checked_parameter: item.checked}" :data-id"i…

gradio创建机器学习的好工具 基本使用和示例

1.gradio介绍 Gradio: 用Python构建机器学习网页APP Gradio是一个开源的Python库,用于构建演示机器学习或数据科学,以及web应用程序。 使用Gradio,您可以基于您的机器学习模型或数据科学工作流快速创建一个漂亮的用户界面,让用户可以”尝试“拖放他们自己的图像、粘贴文本…

HTML5(H5)的前生今世

目录 概述HTML5与其他HTML的区别CSS3与其他CSS版本的区别总结 概述 HTML5是一种用于构建和呈现网页的最新标准。它是HTML&#xff08;超文本标记语言&#xff09;的第五个版本&#xff0c;于2014年由万维网联盟&#xff08;W3C&#xff09;正式推出。HTML5的前身可以追溯到互联…

java实现钉钉群机器人@机器人获取信息后,机器人回复(机器人接收消息)

1.需求 鉴于需要使用钉钉群机器人回复&#xff0c;人们提出的问题&#xff0c;需要识别提出的问题中的关键词&#xff0c;后端进行处理实现对应的业务逻辑 2.实现方式 用户群机器人&#xff0c;附带提出的问题&#xff0c;后端接收消息后识别消息内容&#xff0c;读取到关键…

无人机机巢有哪些,无人机机场/机场的主要分类

随着无人机技术的飞速发展&#xff0c;无人机已经渗透到了物流、农业、救援、公共安全等多个领域。而为了使这些无人机能更加高效、灵活地运行&#xff0c;一个新的概念应运而生&#xff0c;那就是无人机机巢&#xff08;UAV Nest&#xff09;。复亚智能无人机机巢是一种供无人…

MIT 6.824 -- MapReduce -- 01

MIT 6.824 -- MapReduce -- 01 引言抽象和实现可扩展性可用性(容错性)一致性MapReduceMap函数和Reduce函数疑问 课程b站视频地址: MIT 6.824 Distributed Systems Spring 2020 分布式系统 推荐伴读读物: 极客时间 – 大数据经典论文解读DDIA – 数据密集型应用大数据相关论文…

RabbitMQ(一) - 基本结构、SpringBoot整合RabbitMQ、工作队列、发布订阅、直接、主题交换机模式

RabbitMQ结构 Publisher &#xff1a; 生产者 Queue: 存储消息的容器队列&#xff1b; Consumer:消费者 Connection&#xff1a;消费者与消息服务的TCP连接 Channel:信道&#xff0c;是TCP里面的虚拟连接。例如&#xff1a;电缆相当于TCP&#xff0c;信道是一条独立光纤束&…

【JavaEE】Spring Boot - 项目的创建和使用

【JavaEE】Spring Boot 开发要点总结&#xff08;1&#xff09; 文章目录 【JavaEE】Spring Boot 开发要点总结&#xff08;1&#xff09;1. Spring Boot 的优点2. Spring Boot 项目创建2.1 下载安装插件2.2 创建项目过程2.3 加载项目2.4 启动项目2.5 删除一些没用的文件 3. Sp…

python 连接oracle pandas以简化excel的编写和数据操作

python代码 Author: liukai 2810248865qq.com Date: 2022-08-18 04:28:52 LastEditors: liukai 2810248865qq.com LastEditTime: 2023-07-06 22:12:56 FilePath: \PythonProject02\pandas以简化excel的编写和数据操作.py Description: 这是默认设置,请设置customMade, 打开koro…

大厂架构笔记 暂记 :Airbnb,可汗学院,来福车

Airbnb的架构 https://quastor.substack.com/p/airbnbs-architecturehttps://www.youtube.com/watch?vyGOtTd-l_3E我们将介绍每个体系结构&#xff0c;并讨论其优缺点以及迁移Airbnb原因。我们将介绍每个体系结构&#xff0c;并讨论其优缺点以及迁移Airbnb原因。我们将介绍每…

无涯教程-Perl - Subroutines(子例程)

定义子程序 Perl编程语言中 Subroutine子程序定义的一般形式如下: sub subroutine_name {body of the subroutine } 调用该Perl Subroutine的典型方式如下- subroutine_name( list of arguments ); 在Perl 5.0之前的版本中&#xff0c;调用 Subroutine的语法略有不同&…

过去几十年来,主要湖泊遭受了严重的水流失

一项新的研究表明&#xff0c;干旱和潮湿地区的损失是全球性的&#xff0c;可能对地球四分之一的人口产生重大影响。 美国宇航局的地表水和海洋地形任务&#xff08;如图所示&#xff09;在轨道上运行&#xff0c;将扫描湖泊和水库&#xff0c;为全球湖泊水储存估计提供新数据…

【Python机器学习】实验08 决策树

文章目录 决策树1 创建数据2 定义香农信息熵3 条件熵4 信息增益5 计算所有特征的信息增益&#xff0c;选择最优最大信息增益的特征返回6 利用ID3算法生成决策树7 利用数据构造一颗决策树Scikit-learn实例决策树分类决策树回归Scikit-learn 的决策树参数决策树调参 实验1 通过sk…

weblogic XML反序列化分析——CVE-2017-10271

环境 https://vulhub.org/#/environments/weblogic/CVE-2017-10271/ 启动环境 docker-compose up -d代码审计 传入参数 中间跟进函数 最后的出口 没有限制&#xff0c;直接包参数传入xmlDecoder public String readLine() throws IOException {return (String)this.xml…

css实现卡片的左上角有一个三角形的遮盖效果

需求: 卡片的左上角有一个绿色的三角形标签,用来区分状态 实现: .vCard{position: relative;overflow: hidden; } .vCard::before {content: "";position: absolute;top: 0;left: 0;width: 0;height: 0;border-bottom: 20px solid transparent;border-left: 20px …

OPENCV C++(四)形态学操作+连通域统计

形态学操作 先得到一个卷积核 Mat kernel getStructuringElement(MORPH_RECT,Size(5,5)); 第一个是形状 第二个是卷积核大小 依次为腐蚀 膨胀 开运算 闭运算 Mat erodemat,dilatemat,openmat,closemat;morphologyEx(result1, erodemat, MORPH_ERODE, kernel);morphologyEx…