日志收集(log4j2->slf4j->阿里云日志服务SLS)

1、log4j2的使用

  Java 中常用的日志框架:

  • logback:Spring Boot 默认使用的日志框架,具有自动压缩日志、支持多样化配置、不需要重启就可以恢复 I/O 异常等特点。

  • log4j2:在性能方面比 logback 更加优秀,使用上与之前版本 log4j 没什么区别(log4j基本被淘汰了,springboot高版本已经不支持log4j了),有一点区别是 log4j2 不再支持 properties 配置文件,支持 xml、json 格式的文件。

  Log4j2的优势包括:

    ——高性能:Log4j2采用异步日志记录机制,能够提供更高的性能和吞吐量,减少对应用程序性能的影响。

    ——灵活配置:Log4j2支持通过配置文件或编程方式进行灵活的日志配置,可以根据需求定义不同的日志级别、输出格式、输出目标等。

    ——多种输出目标:Log4j2支持将日志输出到控制台、文件、数据库等多种目标,方便日志的收集和分析。

    ——强大的过滤和路由功能:Log4j2提供了丰富的过滤器和路由器,可以根据日志内容、级别等条件对日志进行过滤和路由,实现灵活的日志处理。

    ——插件化架构:Log4j2采用插件化架构,支持自定义Appender、Layout、Filter等组件,可以根据需求扩展和定制日志功能。

    ——在使用Log4j2时,可以结合Spring框架的特性,如AOP(面向切面编程)和依赖注入,实现更加灵活和便捷的日志记录和管理。

  下面来看一下 log4j2 的具体使用:

(1)log4j2 的依赖

  以 springboot 中的使用为例,需要加入以下依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!-- 去掉logback配置 -->
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!-- 引入log4j2依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>
</dependencies>

(2)log4j2 的使用

  通过 LogManager.getLogger() 方法,可以获取一个用于记录日志的Logger对象,LogManager.getLogger() 接受一个参数,类的 class 对象或类名称。

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

//使用方式
private static Logger logger = LogManager.getLogger(this.getClass());
private static Logger logger = LogManager.getLogger("xxxxx");

logger.info("this is info");
logger.debug("this is debug");

(3)log4j2 日志级别

  Log4j2 支持多种日志级别,包括:

  • TRACE:这是最低的日志级别,通常用于跟踪详细的调试信息。

  • DEBUG:用于调试目的,输出一些有用的信息,帮助开发人员了解程序的运行情况。

  • INFO:用于记录程序运行的重要信息,通常用于了解程序的整体运行情况。

  • WARN:用于记录可能导致问题的警告信息。虽然这些信息不会导致程序立即崩溃,但可能需要关注和解决。

  • ERROR:用于记录程序运行时发生的错误信息。这些信息通常需要立即关注并解决,以防止程序崩溃或数据丢失。

  • FATAL:这是能输出的最高日志级别,通常用于记录严重的错误或异常情况,这些情况可能导致程序无法继续运行。

  • OFF:关闭所有日志输出。

  Log4j2 还支持自定义日志级别,可以根据实际需求进行配置。通过配置 Log4j2,可以控制不同级别日志的输出格式、输出位置(如控制台、文件、数据库等)以及过滤条件等。

(4)log4j2 的配置

  下面是一个 log4j2.xml 配置文件的示例,一般在项目资源目录(如 src/main/resources/log4j2.xml)中,当项目打包成 JAR 或 WAR 文件时,这个配置文件会被自动包含进去。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug" strict="true" name="antiAdminLog4jConfig"
               packages="com.coohua.mall">

    <Properties>
        <Property name="rootPath">${logRootPath}</Property>
        <Property name="sysLogFilePath">${rootPath}/sys.log</Property>
        <Property name="logLevel">${logLevel}</Property>
        <Property name="isBufferedIO">true</Property>
        <Property name="isImmediateFlush">true</Property>
        <Property name="isIgnoreExceptions">false</Property>
        <Property name="bufferSize">8192</Property>
        <Property name="encodingType">UTF-8</Property>
    </Properties>

    <Appenders>
<!-- 控制台输出 --> <Console name="STDOUT" target="SYSTEM_OUT"> <PatternLayout pattern="%d[%p]%C{1}.%M(%L)|%m%n"/> </Console> <!-- 文件输出,输出到指定的文件 --> <RollingRandomAccessFile name="sysLogAppender" fileName="${sysLogFilePath}" filePattern="${sysLogFilePath}.%d{yyyyMMdd}.%i.log" immediateFlush="${isImmediateFlush}" ignoreExceptions="${isIgnoreExceptions}" bufferSize="${bufferSize}"> <PatternLayout> <Pattern>%d[%p]%C{1}.%M(%L)|%m%n</Pattern> <charset>${encodingType}</charset> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy /> <SizeBasedTriggeringPolicy size="250 MB" /> </Policies> <DefaultRolloverStrategy> <Delete basePath="${rootPath}" maxDepth="1"> <IfFileName glob="*.log" /> <IfLastModified age="30d" /> </Delete> </DefaultRolloverStrategy> </RollingRandomAccessFile> <Async name="asyncSysLogAppender"> <AppenderRef ref="sysLogAppender"></AppenderRef> </Async> </Appenders> <Loggers> <Root level="${logLevel}"> <AppenderRef ref="STDOUT"/> </Root> <Logger name="sysLogger" level="warn" additivity="false"> <AppenderRef ref="sysLogAppender"></AppenderRef> </Logger> <Logger name="errorLogger" level="${logLevel}" additivity="false"> <AppenderRef ref="errorLogAppender"></AppenderRef> </Logger> </Loggers> </Configuration>

  配置文件说明:

  • Configuration:配置文件的根元素,其中 status 属性可以设置为 "DEBUG", "INFO", "WARN", "ERROR", 或 "FATAL",用于控制 Log4j2 的内部日志级别。

  • Appenders:定义了日志的输出位置和格式。在这个例子中,我们定义了一个控制台输出和一个文件输出。

  • Console:定义了控制台输出的格式和目标(这里是 SYSTEM_OUT,即标准输出)。

  • RollingRandomAccessFile:定义了文件输出的格式和策略。这里使用了时间与大小两种触发策略,当文件达到指定大小或时间时,会自动滚动生成新的日志文件。filePattern 定义了滚动后的文件名格式。DefaultRolloverStrategy 定义了保留的历史文件30天。

  • Loggers:定义了日志记录器,可以设置全局的日志级别和输出目标,也可以为特定的包或类设置自定义的日志级别和输出目标。在这个例子中,我们定义了一个根记录器(Root logger)和一个针对特定包的记录器。

   配置详解

  <Appenders> 可以理解成管道,日志文件通过不同管道输出到不同的文件中。它支持多种日志输出策略,包括滚动文件(RollingFile)和随机访问滚动文件(RollingRandomAccessFile)。

RollingRandomAccessFile

  通常用于需要随机访问日志文件的场景,比如需要快速查找日志中的特定事件。 可以配置多种策略:

  • fileName 属性定义了日志文件的初始名称。

  • filePattern 定义了滚动后的日志文件名称模式,包括日期和时间戳,以及文件扩展名。

  • <PatternLayout> 定义了日志输出的格式。

  • <Policies> 以控制日志何时(When)进行滚动。所谓「日志滚动」就是当达到设定的条件后,日志文件进行切分(即重命名原日志文件用于备份,并重新生成一个新的日志文件)

    Policy常用的实现类:

      ——SizeBasedTriggeringPolicy,根据日志文件的大小进行滚动。单位有:KBMBGB

      ——CronTriggeringPolicy,使用 Cron 表达式进行日志滚动,很灵活

      ——TimeBasedTriggeringPolicy,这个配置需要和 filePattern 结合使用,注意 filePattern 中配置的文件重命名规则。滚动策略依赖于 filePattern 中配置的最具体的时间单位,根据最具体的时间单位进行滚动。这种方式比较简洁。CronTriggeringPolicy 策略更强大。

  • <Strategy> 以控制日志如何(How)进行滚动。

    Strategy常用的实现类:

      ——DefaultRolloverStrategy

      ——DirectWriteRolloverStrategy

 

  • ImmediateFlush=true,一旦有新日志写入,立马将日志写入到磁盘的文件中。当日志很多,这种频繁操作文件显然性能很低下
  • immediateFlush:log4j2 接收到日志事件时,是否立即将日志刷到磁盘。默认为 true。
  • BufferedIO: 文件流写出是否使用缓冲,true 表示使用,默认值为 false 即不使用缓冲。测试显示,即使在启用immediateFlush 的情况下,设置 bufferedIO=true 也能提高性能。

注意点:多个 RollingRandomAccessFile 不能指向同一个日志文件,否则会报错:Configuration has multiple incompatible Appenders pointing to the same resource 'logs/mybatis-demo-warn.log'

2、slf4j 框架

  slf4j 不是真正的日志框架,它是对所有日志框架制定的一种规范、标准、接口,并不是一个框架的具体的实现,因为接口并不能独立使用,需要和具体的日志框架实现配合使用。可以在软件部署的时候决定要使用的 Logging 框架,目前主要支援的有 Java logging API、log4j 及 logback 等框架。

  《阿里巴巴Java开发手册》,其中有一条规范做了「强制」要求: 

应用中不可直接使用日志系统(Log4j Logback)中的 API,而应依赖使用日志框架 SLF4J 中的 API,使用日志门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

  基于 slf4j 框架的使用:

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

// 这了两种写法都 OK,推荐第一种,不用每次都要修改类名
private static final Logger logger = LoggerFactory.getLogger(this.getClass());
private static final Logger logger = LogManager.getLogger(UserController.class);
//...
logger.debug("this is debug");
logger.info("this is info");

  可以看出之前 log4j2 的使用是在代码中通过 LogManager.getLogger(this.getClass()) 获取 Logger,但是使用了slf4j 框架后,再将 log4j2 改为 logback 就无需改动代码了,只需改动相应的配置即可切换项目的日志框架,这也是适配器模式的一个使用场景。

使用lombok输出日志

  每次都使⽤ LoggerFactory.getLogger(xxx.class) 很繁琐,且每个类都添加⼀遍,也很麻烦,可以使⽤ lombok 来更简单的输出。

                 

 (1)添加 lombok 依赖

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

(2)使用 lombok 输出日志

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class UserService {

     private void shareUrl(){
          //使用 log
          log.info("lombok log");      
    }
}

  注意:使⽤ @Slf4j 注解,在程序中使⽤ log 对象即可输⼊⽇志, 并且只能使⽤ log 对象才能输出,这是 lombok 提供的对象名。

(3)lombok 打印日志原理

  lombok 能够打印⽇志的“秘密”就在 target ⽬录⾥⾯,target 为项⽬最终执⾏的代码,查看 target ⽬录如下:

                     

   也就是说我们在使用@Slf4j的注解后,lombok自动将注解转换成代码,减轻了开发者简单繁琐的工作。

3、阿里云日志服务SLS

  使用Loghub Log4j Appender,可以控制日志的输出目的地为阿里云日志服务,有一点需要特别注意,Loghub Log4j Appender不支持设置日志的输出格式,写到日志服务中的日志的样式如下:

level:ERROR
location:test.TestLog4jAppender.main(TestLog4jAppender.java:18)
message:test log4j appender
thread:main
time:2016-05-27T03:15+0000

  level是日志级别,location是日志打印语句的代码位置,message是日志内容,thread是线程名称,time是日志打印时间。

(1)使用Loghub Log4j Appender的好处

  • 客户端日志不落盘:既数据生产后直接通过网络发往服务端。

  • 对于已经使用log4j记录日志的应用,只需要简单修改配置文件就可以将日志传输到日志服务。

  • 异步高吞吐,Loghub Log4j Appender会将用户的日志merge之后异步发送,提高网络IO效率。

(2)接入阿里云日志服务

  step1 引入依赖:

<dependency>
    <groupId>com.aliyun.openservices</groupId>
    <artifactId>log-loghub-log4j-appender</artifactId>
    <version>0.1.3</version>
</dependency>

  step2 配置 log4j2.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>

<appenders>
    <Console name="STDOUT" target="SYSTEM_OUT">
        <PatternLayout pattern="${PATTERN}"/>
    </Console>

    <Loghub name="traceLogHubAppender"
            project="service-log4j2"
            logStore="pro"
            endpoint="cn-beijing-intranet.log.aliyuncs.com"
            accessKeyId="*******************"
            accessKeySecret="******************"
            totalSizeInBytes="104857600"
            maxBlockMs="60000"
            ioThreadCount="1"
            batchSizeThresholdInBytes="524288"
            batchCountThreshold="4096"
            lingerMs="2000"
            retries="10"
            baseRetryBackoffMs="100"
            maxRetryBackoffMs="100"
            topic="trace"
            source="bp-user-info"
            timeFormat="yyyy-MM-dd'T'HH:mmZ"
            timeZone="UTC"
            ignoreExceptions="true">
        <PatternLayout pattern="%d %-5level [%thread] %logger{0}: %msg"/>
    </Loghub>

</appenders>

<loggers>
        <ROOT level="${OUTPUT_LOG_LEVEL}" additivity="true">
            <AppenderRef ref="traceLogHubAppender"/>
        </ROOT>
</loggers>

  开通阿里云日志服务后,获取用于接入日志服务的凭证信息,包括Endpoint、ProjectName、AccessKeyId和AccessKeySecret。

(3)使用阿里云日志服务

  阿里云日志可以根据特定语法很方便的查询日志,语法类似 SQL 语句,还可以配置日志告警等,使用起来很方便。

posted @ 2024-04-17 12:42  jingyi_up  阅读(61)  评论(0编辑  收藏  举报