refactor(log): 优化基于 AOP 实现日志代码,调整日志整体包结构

This commit is contained in:
2024-12-22 22:56:58 +08:00
parent c089df66cf
commit 265c669eda
28 changed files with 240 additions and 343 deletions

View File

@@ -483,14 +483,14 @@
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 日志模块 - 拦截器Spring Boot Actuator HttpTrace 增强版) --> <!-- 日志模块 - 基于拦截器实现Spring Boot Actuator HttpTrace 增强版) -->
<dependency> <dependency>
<groupId>top.continew</groupId> <groupId>top.continew</groupId>
<artifactId>continew-starter-log-interceptor</artifactId> <artifactId>continew-starter-log-interceptor</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 日志模块 - 基于 AOP 实现日志记录 --> <!-- 日志模块 - 基于 AOP 实现 -->
<dependency> <dependency>
<groupId>top.continew</groupId> <groupId>top.continew</groupId>
<artifactId>continew-starter-log-aop</artifactId> <artifactId>continew-starter-log-aop</artifactId>

View File

@@ -7,8 +7,9 @@
<artifactId>continew-starter-log</artifactId> <artifactId>continew-starter-log</artifactId>
<version>${revision}</version> <version>${revision}</version>
</parent> </parent>
<artifactId>continew-starter-log-aop</artifactId> <artifactId>continew-starter-log-aop</artifactId>
<description>ContiNew Starter 日志模块 - 基于 AOP 实现日志记录</description> <description>ContiNew Starter 日志模块 - 基于 AOP 实现</description>
<dependencies> <dependencies>

View File

@@ -1,54 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.starter.log.aop.annotation;
import top.continew.starter.log.core.enums.Include;
import java.lang.annotation.*;
/**
* 日志注解
* <p>用于接口方法或类上</p>
*
* @author Charles7c
* @since 1.1.0
*/
@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
/**
* 所属模块(用于接口方法或类上)
*/
String module() default "";
/**
* 日志描述 - 接口操作内容(仅用于接口方法上)
*/
String value() default "";
/**
* 包含信息(在全局配置基础上扩展包含信息)
*/
Include[] includes() default {};
/**
* 排除信息(在全局配置基础上减少包含信息)
*/
Include[] excludes() default {};
}

View File

@@ -1,96 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.starter.log.aop.aspect;
import com.alibaba.ttl.TransmittableThreadLocal;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import top.continew.starter.log.aop.autoconfigure.LogProperties;
import java.time.Duration;
import java.time.Instant;
/**
* 控制台 输出日志切面
*
* @author echo
* @date 2024/12/06 10:33
**/
@Aspect
public class ConsoleLogAspect {
private static final Logger log = LoggerFactory.getLogger(ConsoleLogAspect.class);
private final LogProperties logProperties;
private final TransmittableThreadLocal<Instant> timeTtl = new TransmittableThreadLocal<>();
public ConsoleLogAspect(LogProperties logProperties) {
this.logProperties = logProperties;
}
/**
* 切点 - 匹配所有控制器层的方法
*/
@Pointcut("execution(* *..controller.*.*(..)) || execution(* *..*Controller.*(..))")
public void controllerLayer() {
}
/**
* 处理请求前执行
*/
@Before(value = "controllerLayer()")
public void doBefore() {
// 打印请求日志
if (Boolean.TRUE.equals(logProperties.getIsPrint())) {
Instant startTime = Instant.now();
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
log.info("[{}] {}", request.getMethod(), request.getRequestURI());
}
timeTtl.set(startTime);
}
}
/**
* 处理请求后执行
*/
@After(value = "controllerLayer()")
public void afterAdvice() {
// 打印请求耗时
if (Boolean.TRUE.equals(logProperties.getIsPrint())) {
Instant endTime = Instant.now();
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return;
}
HttpServletRequest request = attributes.getRequest();
HttpServletResponse response = attributes.getResponse();
Duration timeTaken = Duration.between(timeTtl.get(), endTime);
log.info("[{}] {} {} {}ms", request.getMethod(), request.getRequestURI(), response != null
? response.getStatus()
: "N/A", timeTaken.toMillis());
}
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.starter.log.aspect;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import top.continew.starter.log.autoconfigure.LogProperties;
import java.time.Duration;
import java.time.Instant;
/**
* 访问日志切面
*
* @author echo
* @author Charles7c
* @since 2.8.0
*/
@Aspect
public class AccessLogAspect {
private static final Logger log = LoggerFactory.getLogger(AccessLogAspect.class);
private final LogProperties logProperties;
public AccessLogAspect(LogProperties logProperties) {
this.logProperties = logProperties;
}
/**
* 切点 - 匹配所有控制器层的方法
*/
@Pointcut("execution(* *..controller.*.*(..)) || execution(* *..*Controller.*(..))")
public void pointcut() {
}
/**
* 打印访问日志
*
* @param joinPoint 切点
* @return 返回结果
* @throws Throwable 异常
*/
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Instant startTime = Instant.now();
// 非 Web 环境不记录
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return joinPoint.proceed();
}
HttpServletRequest request = attributes.getRequest();
HttpServletResponse response = attributes.getResponse();
try {
// 打印请求日志
if (Boolean.TRUE.equals(logProperties.getIsPrint())) {
log.info("[{}] {}", request.getMethod(), request.getRequestURI());
}
return joinPoint.proceed();
} finally {
Instant endTime = Instant.now();
if (Boolean.TRUE.equals(logProperties.getIsPrint())) {
Duration timeTaken = Duration.between(startTime, endTime);
log.info("[{}] {} {} {}ms", request.getMethod(), request.getRequestURI(), response != null
? response.getStatus()
: "N/A", timeTaken.toMillis());
}
}
}
}

View File

@@ -14,27 +14,28 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.aop.aspect; package top.continew.starter.log.aspect;
import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.ttl.TransmittableThreadLocal;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import top.continew.starter.log.aop.annotation.Log; import top.continew.starter.log.annotation.Log;
import top.continew.starter.log.aop.autoconfigure.LogProperties; import top.continew.starter.log.autoconfigure.LogProperties;
import top.continew.starter.log.core.dao.LogDao; import top.continew.starter.log.dao.LogDao;
import top.continew.starter.log.core.enums.Include; import top.continew.starter.log.enums.Include;
import top.continew.starter.log.core.http.recordable.impl.RecordableServletHttpRequest; import top.continew.starter.log.http.recordable.impl.RecordableServletHttpRequest;
import top.continew.starter.log.core.http.recordable.impl.RecordableServletHttpResponse; import top.continew.starter.log.http.recordable.impl.RecordableServletHttpResponse;
import top.continew.starter.log.core.model.LogRecord; import top.continew.starter.log.model.LogRecord;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.time.Instant; import java.time.Instant;
@@ -45,16 +46,15 @@ import java.util.Set;
* 日志切面 * 日志切面
* *
* @author echo * @author echo
* @date 2024/12/06 09:58 * @author Charles7c
**/ * @since 2.8.0
*/
@Aspect @Aspect
public class LogAspect { public class LogAspect {
private static final Logger log = LoggerFactory.getLogger(LogAspect.class); private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
private final LogDao logDao; private final LogDao logDao;
private final LogProperties logProperties; private final LogProperties logProperties;
private final TransmittableThreadLocal<Instant> timeTtl = new TransmittableThreadLocal<>();
private final TransmittableThreadLocal<LogRecord.Started> logTtl = new TransmittableThreadLocal<>();
public LogAspect(LogDao logDao, LogProperties logProperties) { public LogAspect(LogDao logDao, LogProperties logProperties) {
this.logDao = logDao; this.logDao = logDao;
@@ -64,104 +64,93 @@ public class LogAspect {
/** /**
* 切点 - 匹配日志注解 {@link Log} * 切点 - 匹配日志注解 {@link Log}
*/ */
@Pointcut(value = "@annotation(top.continew.starter.log.aop.annotation.Log)") @Pointcut("@annotation(top.continew.starter.log.annotation.Log)")
public void pointcutService() { public void pointcut() {
} }
/** /**
* 处理请求前执行 * 记录日志
*
* @param joinPoint 切点
* @return 返回结果
* @throws Throwable 异常
*/ */
@Before(value = "pointcutService()") @Around("pointcut()")
public void doBefore() { public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Instant startTime = Instant.now(); Instant startTime = Instant.now();
// Web 环境不记录
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes != null) { if (attributes == null || attributes.getResponse() == null) {
HttpServletRequest request = attributes.getRequest(); return joinPoint.proceed();
LogRecord.Started startedLogRecord = LogRecord.start(startTime, new RecordableServletHttpRequest(request)); }
logTtl.set(startedLogRecord); HttpServletRequest request = attributes.getRequest();
HttpServletResponse response = attributes.getResponse();
String errorMsg = null;
// 开始记录
LogRecord.Started startedLogRecord = LogRecord.start(startTime, new RecordableServletHttpRequest(request));
try {
// 执行目标方法
return joinPoint.proceed();
} catch (Exception e) {
errorMsg = CharSequenceUtil.sub(e.getMessage(), 0, 2000);
throw e;
} finally {
// 结束记录
this.logFinish(startedLogRecord, errorMsg, response, joinPoint);
} }
} }
/** /**
* 处理请求后执行 - 正常返回 * 结束记录日志
* *
* @param joinPoint 切点 * @param startedLogRecord 日志记录器
* @param errorMsg 异常信息
* @param response 响应对象
* @param joinPoint 切点
*/ */
@After(value = "pointcutService()") private void logFinish(LogRecord.Started startedLogRecord,
public void afterAdvice(JoinPoint joinPoint) { String errorMsg,
handleAfterCompletion(joinPoint, null); HttpServletResponse response,
} ProceedingJoinPoint joinPoint) {
/**
* 处理请求后执行 - 异常情况
*
* @param joinPoint 切点
* @param ex 异常
*/
@AfterThrowing(pointcut = "pointcutService()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
handleAfterCompletion(joinPoint, ex);
}
/**
* 处理请求完成后的逻辑
*
* @param joinPoint 切点
* @param ex 异常
* @param result 返回结果
*/
private void handleAfterCompletion(JoinPoint joinPoint, Exception ex) {
try { try {
Instant endTime = Instant.now(); Instant endTime = Instant.now();
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); Method method = this.getMethod(joinPoint);
if (attributes == null) {
return;
}
HttpServletResponse response = attributes.getResponse();
// 处理日志记录
LogRecord.Started startedLogRecord = logTtl.get();
if (startedLogRecord == null) {
return;
}
// 获取方法和类注解信息
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
Class<?> targetClass = joinPoint.getTarget().getClass(); Class<?> targetClass = joinPoint.getTarget().getClass();
Log methodLog = method.getAnnotation(Log.class); Log methodLog = method.getAnnotation(Log.class);
Log classLog = targetClass.getAnnotation(Log.class); Log classLog = targetClass.getAnnotation(Log.class);
Set<Include> includeSet = this.getIncludes(methodLog, classLog);
// 获取日志包含信息
Set<Include> includeSet = getIncludes(methodLog, classLog);
// 完成日志记录
LogRecord finishedLogRecord = startedLogRecord LogRecord finishedLogRecord = startedLogRecord
.finish(endTime, new RecordableServletHttpResponse(response, response.getStatus()), includeSet); .finish(endTime, new RecordableServletHttpResponse(response, response.getStatus()), includeSet);
// 记录异常 // 记录异常信息
if (ex != null) { if (errorMsg != null) {
finishedLogRecord.getResponse().setStatus(1); finishedLogRecord.setErrorMsg(errorMsg);
finishedLogRecord.setErrorMsg(StrUtil.sub(ex.getMessage(), 0, 2000));
} }
// 记录日志描述 // 记录日志描述
if (includeSet.contains(Include.DESCRIPTION)) { if (includeSet.contains(Include.DESCRIPTION)) {
logDescription(finishedLogRecord, methodLog); this.logDescription(finishedLogRecord, methodLog);
} }
// 记录所属模块 // 记录所属模块
if (includeSet.contains(Include.MODULE)) { if (includeSet.contains(Include.MODULE)) {
logModule(finishedLogRecord, methodLog, classLog); this.logModule(finishedLogRecord, methodLog, classLog);
} }
logDao.add(finishedLogRecord); logDao.add(finishedLogRecord);
} catch (Exception e) { } catch (Exception e) {
log.error("Logging http log occurred an error: {}.", e.getMessage(), e); log.error("Logging http log occurred an error: {}.", e.getMessage(), e);
} finally { throw e;
timeTtl.remove();
logTtl.remove();
} }
} }
/**
* 获取方法
*
* @param joinPoint 切点
* @return 方法
*/
private Method getMethod(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
return signature.getMethod();
}
/** /**
* 获取日志包含信息 * 获取日志包含信息
* *
@@ -204,7 +193,7 @@ public class LogAspect {
* @param methodLog 方法级 Log 注解 * @param methodLog 方法级 Log 注解
*/ */
private void logDescription(LogRecord logRecord, Log methodLog) { private void logDescription(LogRecord logRecord, Log methodLog) {
// 如果方法注解存在日志描述 // 例如@Log("新增部门") -> 新增部门
if (null != methodLog && CharSequenceUtil.isNotBlank(methodLog.value())) { if (null != methodLog && CharSequenceUtil.isNotBlank(methodLog.value())) {
logRecord.setDescription(methodLog.value()); logRecord.setDescription(methodLog.value());
} else { } else {
@@ -220,12 +209,12 @@ public class LogAspect {
* @param classLog 类级 Log 注解 * @param classLog 类级 Log 注解
*/ */
private void logModule(LogRecord logRecord, Log methodLog, Log classLog) { private void logModule(LogRecord logRecord, Log methodLog, Log classLog) {
// 例如@Log(module = "部门管理") -> 部门管理
// 优先使用方法注解的模块 // 优先使用方法注解的模块
if (null != methodLog && CharSequenceUtil.isNotBlank(methodLog.module())) { if (null != methodLog && CharSequenceUtil.isNotBlank(methodLog.module())) {
logRecord.setModule(methodLog.module()); logRecord.setModule(methodLog.module());
return; return;
} }
// 其次使用类注解的模块 // 其次使用类注解的模块
if (null != classLog) { if (null != classLog) {
logRecord.setModule(CharSequenceUtil.blankToDefault(classLog.module(), "请在该接口类上指定所属模块")); logRecord.setModule(CharSequenceUtil.blankToDefault(classLog.module(), "请在该接口类上指定所属模块"));

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.aop.autoconfigure; package top.continew.starter.log.autoconfigure;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -24,16 +24,17 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import top.continew.starter.log.aop.annotation.ConditionalOnEnabledLog; import top.continew.starter.log.annotation.ConditionalOnEnabledLog;
import top.continew.starter.log.aop.aspect.ConsoleLogAspect; import top.continew.starter.log.aspect.AccessLogAspect;
import top.continew.starter.log.aop.aspect.LogAspect; import top.continew.starter.log.aspect.LogAspect;
import top.continew.starter.log.core.dao.LogDao; import top.continew.starter.log.dao.LogDao;
import top.continew.starter.log.core.dao.impl.LogDaoDefaultImpl; import top.continew.starter.log.dao.impl.DefaultLogDaoImpl;
/** /**
* 日志自动配置 * 日志自动配置
* *
* @author Charles7c * @author Charles7c
* @author echo
* @since 1.1.0 * @since 1.1.0
*/ */
@Configuration @Configuration
@@ -50,25 +51,25 @@ public class LogAutoConfiguration {
} }
/** /**
* 记录日志切面 * 日志切面
* *
* @return {@link LogAspect } * @return {@link LogAspect }
*/ */
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public LogAspect logAspect() { public LogAspect logAspect(LogDao logDao) {
return new LogAspect(logDao(), logProperties); return new LogAspect(logDao, logProperties);
} }
/** /**
* 控制台输出日志切面 * 访问日志切面
* *
* @return {@link LogAspect } * @return {@link LogAspect }
*/ */
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ConsoleLogAspect consoleLogAspect() { public AccessLogAspect accessLogAspect() {
return new ConsoleLogAspect(logProperties); return new AccessLogAspect(logProperties);
} }
/** /**
@@ -77,11 +78,11 @@ public class LogAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public LogDao logDao() { public LogDao logDao() {
return new LogDaoDefaultImpl(); return new DefaultLogDaoImpl();
} }
@PostConstruct @PostConstruct
public void postConstruct() { public void postConstruct() {
log.debug("[ContiNew Starter] - Auto Configuration 'Log-aop' completed initialization."); log.debug("[ContiNew Starter] - Auto Configuration 'Log-AOP' completed initialization.");
} }
} }

View File

@@ -14,11 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.aop.autoconfigure; package top.continew.starter.log.autoconfigure;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import top.continew.starter.core.constant.PropertiesConstants; import top.continew.starter.core.constant.PropertiesConstants;
import top.continew.starter.log.core.enums.Include; import top.continew.starter.log.enums.Include;
import java.util.Set; import java.util.Set;
@@ -26,6 +26,7 @@ import java.util.Set;
* 日志配置属性 * 日志配置属性
* *
* @author Charles7c * @author Charles7c
* @author echo
* @since 1.1.0 * @since 1.1.0
*/ */
@ConfigurationProperties(PropertiesConstants.LOG) @ConfigurationProperties(PropertiesConstants.LOG)

View File

@@ -1 +1 @@
top.continew.starter.log.aop.autoconfigure.LogAutoConfiguration top.continew.starter.log.autoconfigure.LogAutoConfiguration

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.aop.annotation; package top.continew.starter.log.annotation;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import top.continew.starter.core.constant.PropertiesConstants; import top.continew.starter.core.constant.PropertiesConstants;

View File

@@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.interceptor.annotation; package top.continew.starter.log.annotation;
import top.continew.starter.log.core.enums.Include; import top.continew.starter.log.enums.Include;
import java.lang.annotation.*; import java.lang.annotation.*;

View File

@@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.core.dao; package top.continew.starter.log.dao;
import top.continew.starter.log.core.model.LogRecord; import top.continew.starter.log.model.LogRecord;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;

View File

@@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.core.dao.impl; package top.continew.starter.log.dao.impl;
import top.continew.starter.log.core.dao.LogDao; import top.continew.starter.log.dao.LogDao;
import top.continew.starter.log.core.model.LogRecord; import top.continew.starter.log.model.LogRecord;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@@ -30,7 +30,7 @@ import java.util.List;
* @author Charles7c * @author Charles7c
* @since 1.1.0 * @since 1.1.0
*/ */
public class LogDaoDefaultImpl implements LogDao { public class DefaultLogDaoImpl implements LogDao {
/** /**
* 容量 * 容量

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.core.enums; package top.continew.starter.log.enums;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.core.http.recordable; package top.continew.starter.log.http.recordable;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.core.http.recordable; package top.continew.starter.log.http.recordable;
import java.util.Map; import java.util.Map;

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.core.http.recordable.impl; package top.continew.starter.log.http.recordable.impl;
import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@@ -25,7 +25,7 @@ import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.UriUtils; import org.springframework.web.util.UriUtils;
import org.springframework.web.util.WebUtils; import org.springframework.web.util.WebUtils;
import top.continew.starter.core.constant.StringConstants; import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.log.core.http.recordable.RecordableHttpRequest; import top.continew.starter.log.http.recordable.RecordableHttpRequest;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.core.http.recordable.impl; package top.continew.starter.log.http.recordable.impl;
import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@@ -22,7 +22,7 @@ import cn.hutool.json.JSONUtil;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.util.ContentCachingResponseWrapper; import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils; import org.springframework.web.util.WebUtils;
import top.continew.starter.log.core.http.recordable.RecordableHttpResponse; import top.continew.starter.log.http.recordable.RecordableHttpResponse;
import top.continew.starter.web.util.ServletUtils; import top.continew.starter.web.util.ServletUtils;
import java.util.Map; import java.util.Map;

View File

@@ -14,11 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.core.model; package top.continew.starter.log.model;
import top.continew.starter.log.core.enums.Include; import top.continew.starter.log.enums.Include;
import top.continew.starter.log.core.http.recordable.RecordableHttpRequest; import top.continew.starter.log.http.recordable.RecordableHttpRequest;
import top.continew.starter.log.core.http.recordable.RecordableHttpResponse; import top.continew.starter.log.http.recordable.RecordableHttpResponse;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
@@ -115,9 +115,9 @@ public class LogRecord {
/** /**
* 结束日志记录 * 结束日志记录
* *
* @param clock 时间 * @param timestamp 结束时间
* @param response 响应信息 * @param response 响应信息
* @param includes 包含信息 * @param includes 包含信息
* @return 日志记录 * @return 日志记录
*/ */
public LogRecord finish(Instant timestamp, RecordableHttpResponse response, Set<Include> includes) { public LogRecord finish(Instant timestamp, RecordableHttpResponse response, Set<Include> includes) {
@@ -172,11 +172,11 @@ public class LogRecord {
return timestamp; return timestamp;
} }
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) { public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg; this.errorMsg = errorMsg;
} }
public String getErrorMsg() {
return errorMsg;
}
} }

View File

@@ -14,14 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.core.model; package top.continew.starter.log.model;
import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.CharSequenceUtil;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import top.continew.starter.core.util.ExceptionUtils; import top.continew.starter.core.util.ExceptionUtils;
import top.continew.starter.core.util.IpUtils; import top.continew.starter.core.util.IpUtils;
import top.continew.starter.log.core.enums.Include; import top.continew.starter.log.enums.Include;
import top.continew.starter.log.core.http.recordable.RecordableHttpRequest; import top.continew.starter.log.http.recordable.RecordableHttpRequest;
import top.continew.starter.web.util.ServletUtils; import top.continew.starter.web.util.ServletUtils;
import java.net.URI; import java.net.URI;

View File

@@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.core.model; package top.continew.starter.log.model;
import top.continew.starter.log.core.enums.Include; import top.continew.starter.log.enums.Include;
import top.continew.starter.log.core.http.recordable.RecordableHttpResponse; import top.continew.starter.log.http.recordable.RecordableHttpResponse;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;

View File

@@ -10,7 +10,7 @@
</parent> </parent>
<artifactId>continew-starter-log-interceptor</artifactId> <artifactId>continew-starter-log-interceptor</artifactId>
<description>ContiNew Starter 日志模块 - 拦截器Spring Boot Actuator HttpTrace 增强版)</description> <description>ContiNew Starter 日志模块 - 基于拦截器实现Spring Boot Actuator HttpTrace 增强版)</description>
<dependencies> <dependencies>
<!-- Swagger 注解 --> <!-- Swagger 注解 -->

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.interceptor.autoconfigure; package top.continew.starter.log.autoconfigure;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -26,11 +26,11 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import top.continew.starter.log.core.dao.LogDao; import top.continew.starter.log.dao.LogDao;
import top.continew.starter.log.core.dao.impl.LogDaoDefaultImpl; import top.continew.starter.log.dao.impl.DefaultLogDaoImpl;
import top.continew.starter.log.interceptor.annotation.ConditionalOnEnabledLog; import top.continew.starter.log.annotation.ConditionalOnEnabledLog;
import top.continew.starter.log.interceptor.handler.LogFilter; import top.continew.starter.log.handler.LogFilter;
import top.continew.starter.log.interceptor.handler.LogInterceptor; import top.continew.starter.log.handler.LogInterceptor;
/** /**
* 日志自动配置 * 日志自动配置
@@ -71,11 +71,11 @@ public class LogAutoConfiguration implements WebMvcConfigurer {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public LogDao logDao() { public LogDao logDao() {
return new LogDaoDefaultImpl(); return new DefaultLogDaoImpl();
} }
@PostConstruct @PostConstruct
public void postConstruct() { public void postConstruct() {
log.debug("[ContiNew Starter] - Auto Configuration 'Log-interceptor' completed initialization."); log.debug("[ContiNew Starter] - Auto Configuration 'Log-Interceptor' completed initialization.");
} }
} }

View File

@@ -14,11 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.interceptor.autoconfigure; package top.continew.starter.log.autoconfigure;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import top.continew.starter.core.constant.PropertiesConstants; import top.continew.starter.core.constant.PropertiesConstants;
import top.continew.starter.log.core.enums.Include; import top.continew.starter.log.enums.Include;
import top.continew.starter.web.util.SpringWebUtils; import top.continew.starter.web.util.SpringWebUtils;
import java.util.ArrayList; import java.util.ArrayList;

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.interceptor.handler; package top.continew.starter.log.handler;
import cn.hutool.extra.spring.SpringUtil; import cn.hutool.extra.spring.SpringUtil;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
@@ -28,7 +28,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper; import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper; import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils; import org.springframework.web.util.WebUtils;
import top.continew.starter.log.interceptor.autoconfigure.LogProperties; import top.continew.starter.log.autoconfigure.LogProperties;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.starter.log.interceptor.handler; package top.continew.starter.log.handler;
import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.CharSequenceUtil;
import com.alibaba.ttl.TransmittableThreadLocal; import com.alibaba.ttl.TransmittableThreadLocal;
@@ -28,13 +28,13 @@ import org.slf4j.LoggerFactory;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import top.continew.starter.log.core.http.recordable.impl.RecordableServletHttpRequest; import top.continew.starter.log.http.recordable.impl.RecordableServletHttpRequest;
import top.continew.starter.log.core.http.recordable.impl.RecordableServletHttpResponse; import top.continew.starter.log.http.recordable.impl.RecordableServletHttpResponse;
import top.continew.starter.log.interceptor.annotation.Log; import top.continew.starter.log.annotation.Log;
import top.continew.starter.log.core.dao.LogDao; import top.continew.starter.log.dao.LogDao;
import top.continew.starter.log.core.enums.Include; import top.continew.starter.log.enums.Include;
import top.continew.starter.log.core.model.LogRecord; import top.continew.starter.log.model.LogRecord;
import top.continew.starter.log.interceptor.autoconfigure.LogProperties; import top.continew.starter.log.autoconfigure.LogProperties;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
@@ -109,6 +109,7 @@ public class LogInterceptor implements HandlerInterceptor {
logDao.add(finishedLogRecord); logDao.add(finishedLogRecord);
} catch (Exception ex) { } catch (Exception ex) {
log.error("Logging http log occurred an error: {}.", ex.getMessage(), ex); log.error("Logging http log occurred an error: {}.", ex.getMessage(), ex);
throw ex;
} finally { } finally {
timeTtl.remove(); timeTtl.remove();
logTtl.remove(); logTtl.remove();

View File

@@ -1,35 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.starter.log.interceptor.annotation;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import top.continew.starter.core.constant.PropertiesConstants;
import java.lang.annotation.*;
/**
* 是否启用日志记录注解
*
* @author Charles7c
* @since 1.1.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@ConditionalOnProperty(prefix = PropertiesConstants.LOG, name = PropertiesConstants.ENABLED, havingValue = "true", matchIfMissing = true)
public @interface ConditionalOnEnabledLog {
}

View File

@@ -1 +1 @@
top.continew.starter.log.interceptor.autoconfigure.LogAutoConfiguration top.continew.starter.log.autoconfigure.LogAutoConfiguration