五一国际劳动节来了,各位朋友节日快乐。今天聊一下日志这个话题,虽然测试写的代码大多比较“烂”,但是开发写的代码看多了,也学到了一些比较好的编程习惯,清晰的日志可以帮助开发者更快的定位问题。今天分享下如何有效的打日志。
我就以Java栈为例,目前市面上常见的日志工具有如下几个:
- Log4j:它是Java平台上最流行的日志库之,提供了可配置的输出格式和过滤器,并且易于集成到大多数Java应用程序中。它支持多种输出目标,如文件、控制台、TCP/UDP套接字等,并能够自定义日志级别以及动态修改日志级别。
- Logback:它是Log4j的改进版,比Log4j更快、更稳定、更灵活并且支持SLF4J等其他框架。除了与Log4j相似的功能之外,它还支持异步日志记录和归档。它也易于配置和使用,并提供了适当的默认设置,使得开发人员可以快速启动使用。由于其性能和生产力的优势,Logback已成为当今Java应用程序中最受欢迎的日志库之一。
- java.util.logging:这是Java平台默认提供的日志库,它具有内置于JDK中的优点,因此不需要额外的依赖。它支持多种输出目标,并能够自定义日志级别以及动态修改日志级别。但是,相对于Log4j和Logback来说,它的配置和使用起来会更加复杂。
- 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等方法来记录不同级别的日志信息。
实现一个切面
下面是详细的代码实现:
- 创建日志工具类
创建一个名为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());
}
}
完结,撒花🎉