五一国际劳动节来了,各位朋友节日快乐。今天聊一下日志这个话题,虽然测试写的代码大多比较“烂”,但是开发写的代码看多了,也学到了一些比较好的编程习惯,清晰的日志可以帮助开发者更快的定位问题。今天分享下如何有效的打日志。

我就以Java栈为例,目前市面上常见的日志工具有如下几个:

  1. Log4j:它是Java平台上最流行的日志库之,提供了可配置的输出格式和过滤器,并且易于集成到大多数Java应用程序中。它支持多种输出目标,如文件、控制台、TCP/UDP套接字等,并能够自定义日志级别以及动态修改日志级别。
  2. Logback:它是Log4j的改进版,比Log4j更快、更稳定、更灵活并且支持SLF4J等其他框架。除了与Log4j相似的功能之外,它还支持异步日志记录和归档。它也易于配置和使用,并提供了适当的默认设置,使得开发人员可以快速启动使用。由于其性能和生产力的优势,Logback已成为当今Java应用程序中最受欢迎的日志库之一。
  3. java.util.logging:这是Java平台默认提供的日志库,它具有内置于JDK中的优点,因此不需要额外的依赖。它支持多种输出目标,并能够自定义日志级别以及动态修改日志级别。但是,相对于Log4j和Logback来说,它的配置和使用起来会更加复杂。
  4. Apache Commons Logging:它是一个通用的日志接口,可以让开发人员通过简单地更改配置文件来切换不同的日志实现。它易于使用,并且不需要大量的配置。但是,它的扩展性和灵活性相对较低,不能像Log4j或Logback那样提供在运行时动态调整日志级别的功能。

本文以Logback为例实践,先介绍基本用法,再封装一个通用的日志工具。

基本用法

1. 添加Logback依赖

在pom.xml文件中添加以下代码:

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

2. 配置Logback

在项目的src/main/resources目录下创建logback.xml文件,添加如下代码:

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
      <file>app.log</file>
      <append>true</append>
      <encoder>
          <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
      </encoder>
  </appender>

  <root level="INFO">
      <appender-ref ref="FILE" />
  </root>
</configuration>

上述配置将日志输出到控制台,并指定了输出格式和输出级别。

3. 使用Logback

在Java类中导入org.slf4j.Logger和org.slf4j.LoggerFactory,然后使用Logger接口来记录日志信息。例如:

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

public class SomeClass {
    private static final Logger logger = LoggerFactory.getLogger(SomeClass.class);

    public void someMethod() {
        logger.debug("This is a debug message");
        logger.info("This is an info message");
        logger.warn("This is a warning message");
        logger.error("This is an error message", new Exception());
    }
}

上述代码使用Slf4j的Logger接口来记录日志信息,并提供了debug、info、warn、error等方法来记录不同级别的日志信息。

实现一个切面

下面是详细的代码实现:

  1. 创建日志工具类

创建一个名为LogUtils的类,在其中添加如下代码:

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

public class LogUtils {
    private static final Logger logger = LoggerFactory.getLogger(LogUtils.class);

    public static void info(String message) {
        logger.info(message);
    }

    public static void error(String message, Throwable throwable) {
        logger.error(message, throwable);
    }
}

上述代码使用Slf4j的Logger接口来记录日志信息,并提供了info和error方法来记录不同级别的日志。

2. 添加aop切面

首先,需要在pom.xml文件中添加AspectJ依赖:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.7</version>
</dependency>

接下来,创建一个名为LogAspect的切面类,在其中添加如下代码:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {
    @Before("execution(* com.example.demo.service.*.*(..))")
    public void before(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        LogUtils.info("Executing method: " + methodName);
    }

    @After("execution(* com.example.demo.service.*.*(..))")
    public void after(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        LogUtils.info("Finished executing method: " + methodName);
    }
}

上述代码使用@Aspect和@Component注解将LogAspect声明为aop切面。

@Before注解表示在方法调用前执行该切面逻辑。它的参数是一个切点表达式,用于匹配需要织入切面逻辑的目标方法。这里的切点表达式表示匹配com.example.demo.service包中所有类的所有方法。

@After注解表示在方法调用后执行该切面逻辑。同样,它的参数是一个切点表达式。

3. 配置Spring

在Spring的配置文件(比如applicationContext.xml)中添加以下代码,来启用AspectJ自动代理:

<aop:aspectj-autoproxy/>

引用通用工具

将LogUtils作为通用工具使用,可以按照以下步骤来实现:

1. 创建一个公共的"utils"模块

首先,创建一个名为"utils"的新模块,用于存放通用工具类。

2. 将LogUtils移动到"utils"模块中

将LogUtils类从原始的模块中复制到新建的"utils"模块中,并在pom.xml文件中添加logback依赖。

3. 添加Maven依赖

在需要使用LogUtils的模块中的pom.xml文件中,添加如下代码来引入"utils"模块的依赖:

<dependency>
    <groupId>com.example</groupId>
    <artifactId>utils</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

上述代码中,groupId应该是你自己项目中的groupId,version应该是你自己项目中"utils"模块的版本号。

4. 使用LogUtils

在需要使用LogUtils的地方,直接导入LogUtils类,并调用它提供的方法即可。例如:

import com.example.utils.LogUtils;

public class SomeClass {
    public void someMethod() {
        LogUtils.info("This is an info message");
        LogUtils.error("This is an error message", new Exception());
    }
}

完结,撒花🎉