java日志

日志是软件开发的重要组成部分。一个精心编写的日志代码提供快速的调试,维护方便,以及应用程序的运行时信息结构化存储。日志记录确实也有它的缺点。它可以减缓的应用程序

日志实现框架(具体实现):JUL(java util logging)、logback、log4j、log4j2

日志门面框架(规则接口):JCL(Jakarta Commons Logging)、slf4j

JUL日志框架

组件介绍

JUL是Java原生的日志框架,使用时不需要引入第三方类库。

1、Loggers记录器,只负责打日志。面向用户,调用其api

2、Appenders,一个Logger关联一个或多个Appenders处理器

3、Layouts:日志需要按照特定的格式打印或者输出

4、Level,每一条日志都有级别

5、Filters:过滤日志信息,哪些需要记录


日志级别

 日志的级别,总共七级
            Level.SEVERE:(最高级)错误
            Level.WARNING:警告
            Level.INFO:(默认级别)消息
            Level.CONFIG:配置级别
            Level.FINE:详细信息(少)
            Level.FINER:详细信息(中)
            Level.FINEST:(最低级)详细信息(多)

       两个特殊的级别:
            Level.OFF;可用来关闭日志记录
            Level.ALL:启用所有日志记录


jdk默认JUL配置

cmd进入命令行窗口,使用set命令查看环境变量

再进入jre/lib,找到logging.properties

删除注释后,就剩这些了

handlers= java.util.logging.ConsoleHandler
.level= INFO
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
com.xyz.foo.level = SEVERE

自定义JUL配置


Log4j

日志级别

Log4j是Apache的一个开放源代码项目,通过使用Log4j,

我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务 器、NT的事件记录器、UNIX Syslog守护进程等;

我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。

DEBUG < INFO < WARN < ERROR < FATAL,分别用来指定这条日志信息的重要程度

如下定义日志级别为info级别,那么error和warn的日志可以显示而比他优先级低的debug信息就不显示

log4j.rootLogger=info,A1,B2,C3 

log4j.properties

lg4j使用:第⼀步,在 pom.xml ⽂件中引⼊ Log4j 包:

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

第⼆步,在 resources ⽬录下创建 log4j.properties ⽂件

这个配置文件告 诉Log4J以什么样的格式、把什么样的信息、输出到什么地方。

log4j.rootLogger = info,stdout

### 输出信息到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
Log4j有三个主要的 组件:Loggers(记录器),Appenders(输出源)和Layouts(布局),这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出

Appenders 输出源

Log4j日志系统允许把日志输出到不同的地方,如控制台(Console)、文件(Files)、根据天数或者文件大小产生新的文件、以流的形式发送到其它地方等等。

  •  org.apache.log4j.ConsoleAppender(控制台)

  •  org.apache.log4j.FileAppender(文件)

  •  org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)

  • org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)

  •  org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

配置时语法如下:

log4j.appender.appenderName = fully.qualified.name.of.appender.class 
log4j.appender.appenderName.option1 = value1 
… 
log4j.appender.appenderName.option = valueN

第一次看,我就很懵。这option1、value1啥玩意???


Layouts 布局

有时用户希望根据自己的喜好格式化自己的日志输出。Log4j可以在Appenders的后面附加Layouts来完成这个功能。

Log4j 提供的格式有下⾯ 4 种:

  • org.apache.log4j.HTMLLayout:HTML 表格

  • org.apache.log4j.PatternLayout:⾃定义

  • org.apache.log4j.SimpleLayout:包含⽇志信息的级别和信息字符串

  • org.apache.log4j.TTCCLayout:包含⽇志产⽣的时间、线程、类别等等信息

配置时语法如下:

log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class 
log4j.appender.appenderName.layout.option1 = value1 
… 
log4j.appender.appenderName.layout.option = valueN

⾃定义格式的参数

%m:输出代码中指定的消息

%p:输出优先级

%r:输出应⽤启动到输出该⽇志信息时花费的毫秒数

%c:输出所在类的全名

%t:输出该⽇志所在的线程名

%n:输出⼀个回⻋换⾏符

%d:输出⽇志的时间点

%l:输出⽇志的发⽣位置,包括类名、线程名、⽅法名、代码⾏数

[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

Log4j程序中使用

在对Logger实例进行命名时,没有限制,可以取任意自己感兴趣的名字。一般情况下建议以类的所在位置来命名Logger实例,这是目前来讲比较有效的Logger命名方式。这样可以使得每个类建立自己的日志信息,便于管理。比如:

Logger.getLogger(Log4jExample.class.getName ())


import org.apache.log4j.Logger;

/**
 * @Description:
 * @Author: 小羽毛
 * @Date: 2023/3/7 20:41
 */
public class Log4jExample {
    static Logger logger = Logger.getLogger(Log4jExample.class.getName ()) ;

    public static void main(String[] args) {
        // 记录debug级别的信息
        logger.debug("debug.");
        // 记录info级别的信息
        logger.info("info.");
        // 记录error级别的信息
        logger.error("error.");
    }
}

因为配置了日志级别是info级别,所以debug级别的信息不会打印到控制台


Log4j使用注意点

  1. 在打印 DEBUG 级别的⽇志时,切记要使⽤ isDebugEnabled()

如果⽇志系统的级别不是 DEBUG,就会多执⾏了字符串拼接的操作,⽩⽩浪费了性能。

if(logger.isDebugEnabled()) {
 logger.debug("⽤户名是:" + getName());
}

2、在打印⽇志的时候带上类的全名和线程名,在多线程环境下,这点尤为重要,否则定位问题的时候就太难了


SLF4J

为什么用slf4j

  1. 在使⽤⽇志系统的时候,⼀定要使⽤ SLF4J 作为⻔⾯担当

  1. SLF4J 可以统⼀⽇志系统,作为上层的抽象接⼝,不需要关注底层的⽇志实现,可以是 Log4j,也可

以是 Logback,或者 JUL、JCL。

3.使用slf4j后不再需要 isDebugEnabled() 先进⾏判断

slf4j是如何将自己的通用日志格式转成不同的日志系统的格式的呢?
不同日志系统包都会有一个Adapter,用来在slf4j和不同日志系统之间做转换

第⼀步,把 log4j 的依赖替换为 slf4j-log4j12

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

第⼆步,在 resources ⽬录下创建 log4j.properties ⽂件,内容和上面⼀篇完全相同


参数化日志消息

SLF4J 在打印⽇志的时候使⽤了占位符 {} 。

解决锚点:字符串拼接会创建很多不必要的字符串对象,极⼤的消耗了内存空间.如下

String name = "小羽毛";
int age = 8;
logger.debug(name + ",年纪:" + age + ",阿姨有糖吃吗");

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

public class SLF4jExample {
    static Logger logger = LoggerFactory.getLogger(SLF4jExample.class.getName ()) ;

    public static void main(String[] args) {
        logger.info("{},想问问阿姨有糖吃吗","小羽毛");
    }
}

还可以在消息中使用两个参数 -


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

public class SLF4jExample {
    static Logger logger = LoggerFactory.getLogger(SLF4jExample.class.getName ()) ;

    public static void main(String[] args) {
        logger.info("颜值:{} 分, 天赋 {}分", 100, 99);
    }
}

Logback

logback依赖

Spring Boot 的默认⽇志框架使⽤的是 Logback。

logback-classic 模块需要在 classpath 添加 slf4j-api.jar、logback-core.jar 以及 logback-classic.jar。

在 pom.xml ⽂件中添加 Logback 的依赖:


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

Maven 会⾃动导⼊另外两个依赖:

logback-core 是 Logback 的核⼼,logback-classic 是 SLF4J 的实现


默认配置策略

如果你想在每个类中打印日志,那么你需要将当前类的全称或者当前类当作参数,调用 org.slf4j.LoggerFactory.getLogger() 方法。

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

public class LogbackTest {
    static Logger logger = LoggerFactory.getLogger(LogbackTest.class);

    public static void main(String[] args) {
        logger.debug("巅峰对决");
    }
}

appender:直译为“输出目的地,输出终端”

Logback 没有找到 logback-test.xml 和 logback.xml 配置文件,所以通过默认的配置策略-添加一个基本的 ConsoleAppender 来进行配置。

Appenders 包括 console,files,Syslog,TCP Sockets,JMS 等等其它的日志输出目的地。用户可以根据自己的情况轻松的创建自己的 Appender。


logback配置

⼀般来说,我们会在本地环境中配置 logback-test.xml,在⽣产环境下配置 logback.xml

配置文件命名

1、配置文件要放在classpath路径下,文件名logback-test.xml

2、在spring-boot项目中可以命名为logback-spring.xml,这样在读取完application.yml文件后springboot会自动读取logback-spring.xml文件

在 resource ⽬录下增加 logback-test.xml ⽂件

<configuration debug="true">
    <!--    配置⽇志的输出⽬的地-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--            pattern ⽤来指定⽇志的输出格式-->
            <pattern>%d{HH:mm:ss.SSS} %relative [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="debug">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

配置 <root>,它只⽀持⼀个属性——level,值可以为:TRACE、DEBUG、INFO、WARN、ERROR、 ALL、OFF。 appender-ref ⽤来指定具体的 appender。


配置appender

配置 appender,也就是配置⽇志的输出⽬的地,通过 name 属性指定名字,通过 class 属性指定 ⽬的地:

ch.qos.logback.core.ConsoleAppender:输出到控制台。

ch.qos.logback.core.FileAppender:输出到⽂件。 ch.qos.logback.core.rolling.RollingFileAppender:⽂件⼤⼩超过阈值时产⽣⼀个新⽂件。

除了输出到本地,还可以通过 SocketAppender 和 SSLSocketAppender 输出到远程设备,通过 SMTPAppender 输出到邮件。甚⾄可以通过 DBAppender 输出到数据库中。

<!--    配置⽇志的输出⽬的地-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <!--            pattern ⽤来指定⽇志的输出格式-->
        <pattern>%d{HH:mm:ss.SSS} %relative [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender>

pattern ⽤来指定⽇志的输出格式:

%d :输出的时间格式。

%relative :输出从程序启动到创建⽇志记录的时间,单位为毫秒。

%thread :⽇志的线程

%-5level :⽇志的输出级别,填充到 5 个字符。方便⽇志信息就对⻬。

%logger{length} :logger 的名称,length ⽤来缩短名称。没有指定表示完整输出;0 表示只输 出 logger 最右边点号之后的字符串;其他数字表示输出⼩数点最后边点号之前的字符数量。

%msg :⽇志的具体信息。

%n :换⾏符。

运⾏LogbackTest类,可以在控制台看到以下信息

22:47:48.364 618 [main] DEBUG com.atguigu.log.LogbackTest - 巅峰对决

日志文件拆分

文件日志以日期和大小进行拆分生成。

		<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
			<FileNamePattern>logs/demo-logback/info.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>
			<!--只保留最近90天的日志-->
			<maxHistory>90</maxHistory>
			<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
			<!--<totalSizeCap>1GB</totalSizeCap>-->
			<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
				<!-- maxFileSize:这是活动文件的大小,默认值是10MB,本篇设置为1KB,只是为了演示 -->
				<maxFileSize>2MB</maxFileSize>
			</timeBasedFileNamingAndTriggeringPolicy>
		</rollingPolicy>

自动删除三天前日志

要实现达到一定大小后将日志文件压缩,并删除三天前的日志数据,可以结合使用 SizeAndTimeBasedRollingPolicy 滚动策略和 DeleteOlderThan 选项来配置。


监听器

创建监听器:

public class CustomLogContextListener extends ContextAwareBase implements LoggerContextListener, LifeCycle {

    /**
     * 存储日志路径标识
     */
    public static final String LOG_PAHT_KEY = "LOG_PATH";

    @Override
    public boolean isResetResistant() {
        return false;
    }

    @Override
    public void onStart(LoggerContext loggerContext) {

    }

    @Override
    public void onReset(LoggerContext loggerContext) {

    }

    @Override
    public void onStop(LoggerContext loggerContext) {

    }

    @Override
    public void onLevelChange(Logger logger, Level level) {

    }

    @Override
    public void start() {
        // "user.dir"是指用户当前工作目录
        String s = ScriptFileUtil.rootPath + "/rpa-client-logs/";
        System.setProperty(LOG_PAHT_KEY, s);
        Context context = getContext();
        context.putProperty(LOG_PAHT_KEY, s);
    }

    @Override
    public void stop() {

    }

    @Override
    public boolean isStarted() {
        return false;
    }
}

在初始化 logback 初始化过程中,将我们需要的日志路径设置到上下文中

<?xml version="1.0" encoding="UTF-8" ?>
<configuration debug="true" scan="true" scanPeriod="60 seconds">
 
<contextListener class="com.midea.jr.credit.accounting.utils.LoggerStartupListener" />
</configuration>

就可以直接通过声明的变量名称使用路径(${LOG_PATH}),LOG_PATH就是在CustomLogContextListener类中指定的变量名称

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值