mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-09 04:59:21 +08:00
feat(log/aop): 新增 log-aop 组件模块(基于 AOP 实现日志记录)
This commit is contained in:
@@ -490,6 +490,13 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 日志模块 - 基于 AOP 实现日志记录 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-log-aop</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 日志模块 - 核心模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
@@ -680,7 +687,8 @@
|
||||
<configuration>
|
||||
<artifacts>
|
||||
<artifact>
|
||||
<file>${project.build.directory}/effective-pom/continew-starter-dependencies.xml</file>
|
||||
<file>${project.build.directory}/effective-pom/continew-starter-dependencies.xml
|
||||
</file>
|
||||
<type>effective-pom</type>
|
||||
</artifact>
|
||||
</artifacts>
|
||||
|
21
continew-starter-log/continew-starter-log-aop/pom.xml
Normal file
21
continew-starter-log/continew-starter-log-aop/pom.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-log</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>continew-starter-log-aop</artifactId>
|
||||
<description>ContiNew Starter 日志模块 - 基于 AOP 实现日志记录</description>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<!-- 日志模块 - 核心模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-log-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.log.interceptor.autoconfigure;
|
||||
package top.continew.starter.log.aop.annotation;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import top.continew.starter.core.constant.PropertiesConstants;
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 {};
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,221 @@
|
||||
package top.continew.starter.log.aop.aspect;
|
||||
|
||||
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.HttpServletResponse;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.*;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
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.annotation.Log;
|
||||
import top.continew.starter.log.aop.autoconfigure.LogProperties;
|
||||
import top.continew.starter.log.core.dao.LogDao;
|
||||
import top.continew.starter.log.core.enums.Include;
|
||||
import top.continew.starter.log.core.http.recordable.impl.RecordableServletHttpRequest;
|
||||
import top.continew.starter.log.core.http.recordable.impl.RecordableServletHttpResponse;
|
||||
import top.continew.starter.log.core.model.LogRecord;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Instant;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 日志切面
|
||||
*
|
||||
* @author echo
|
||||
* @date 2024/12/06 09:58
|
||||
**/
|
||||
@Aspect
|
||||
public class LogAspect {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
|
||||
private final LogDao logDao;
|
||||
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) {
|
||||
this.logDao = logDao;
|
||||
this.logProperties = logProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* 切点 - 匹配日志注解 {@link Log}
|
||||
*/
|
||||
@Pointcut(value = "@annotation(top.continew.starter.log.aop.annotation.Log)")
|
||||
public void pointcutService() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理请求前执行
|
||||
*/
|
||||
@Before(value = "pointcutService()")
|
||||
public void doBefore() {
|
||||
Instant startTime = Instant.now();
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes != null) {
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
LogRecord.Started startedLogRecord = LogRecord.start(startTime, new RecordableServletHttpRequest(request));
|
||||
logTtl.set(startedLogRecord);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理请求后执行 - 正常返回
|
||||
*
|
||||
* @param joinPoint 切点
|
||||
*/
|
||||
@After(value = "pointcutService()")
|
||||
public void afterAdvice(JoinPoint joinPoint) {
|
||||
handleAfterCompletion(joinPoint, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理请求后执行 - 异常情况
|
||||
*
|
||||
* @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 {
|
||||
Instant endTime = Instant.now();
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
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();
|
||||
|
||||
Log methodLog = method.getAnnotation(Log.class);
|
||||
Log classLog = targetClass.getAnnotation(Log.class);
|
||||
|
||||
// 获取日志包含信息
|
||||
Set<Include> includeSet = getIncludes(methodLog, classLog);
|
||||
|
||||
// 完成日志记录
|
||||
LogRecord finishedLogRecord = startedLogRecord
|
||||
.finish(endTime,
|
||||
new RecordableServletHttpResponse(response, response.getStatus()),
|
||||
includeSet);
|
||||
// 记录异常
|
||||
if (ex != null) {
|
||||
finishedLogRecord.getResponse().setStatus(1);
|
||||
finishedLogRecord.setErrorMsg(StrUtil.sub(ex.getMessage(), 0, 2000));
|
||||
}
|
||||
|
||||
// 记录日志描述
|
||||
if (includeSet.contains(Include.DESCRIPTION)) {
|
||||
logDescription(finishedLogRecord, methodLog);
|
||||
}
|
||||
|
||||
// 记录所属模块
|
||||
if (includeSet.contains(Include.MODULE)) {
|
||||
logModule(finishedLogRecord, methodLog, classLog);
|
||||
}
|
||||
logDao.add(finishedLogRecord);
|
||||
} catch (Exception e) {
|
||||
log.error("Logging http log occurred an error: {}.", e.getMessage(), e);
|
||||
} finally {
|
||||
timeTtl.remove();
|
||||
logTtl.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日志包含信息
|
||||
*
|
||||
* @param methodLog 方法级 Log 注解
|
||||
* @param classLog 类级 Log 注解
|
||||
* @return 日志包含信息
|
||||
*/
|
||||
private Set<Include> getIncludes(Log methodLog, Log classLog) {
|
||||
Set<Include> includeSet = new HashSet<>(logProperties.getIncludes());
|
||||
if (null != classLog) {
|
||||
processInclude(includeSet, classLog);
|
||||
}
|
||||
if (null != methodLog) {
|
||||
processInclude(includeSet, methodLog);
|
||||
}
|
||||
return includeSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理日志包含信息
|
||||
*
|
||||
* @param includes 日志包含信息
|
||||
* @param logAnnotation Log 注解
|
||||
*/
|
||||
private void processInclude(Set<Include> includes, Log logAnnotation) {
|
||||
Include[] includeArr = logAnnotation.includes();
|
||||
if (includeArr.length > 0) {
|
||||
includes.addAll(Set.of(includeArr));
|
||||
}
|
||||
Include[] excludeArr = logAnnotation.excludes();
|
||||
if (excludeArr.length > 0) {
|
||||
includes.removeAll(Set.of(excludeArr));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录描述
|
||||
*
|
||||
* @param logRecord 日志信息
|
||||
* @param methodLog 方法级 Log 注解
|
||||
*/
|
||||
private void logDescription(LogRecord logRecord, Log methodLog) {
|
||||
// 如果方法注解存在日志描述
|
||||
if (null != methodLog && CharSequenceUtil.isNotBlank(methodLog.value())) {
|
||||
logRecord.setDescription(methodLog.value());
|
||||
} else {
|
||||
logRecord.setDescription("请在该接口方法上指定日志描述");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录模块
|
||||
*
|
||||
* @param logRecord 日志信息
|
||||
* @param methodLog 方法级 Log 注解
|
||||
* @param classLog 类级 Log 注解
|
||||
*/
|
||||
private void logModule(LogRecord logRecord, Log methodLog, Log classLog) {
|
||||
// 优先使用方法注解的模块
|
||||
if (null != methodLog && CharSequenceUtil.isNotBlank(methodLog.module())) {
|
||||
logRecord.setModule(methodLog.module());
|
||||
return;
|
||||
}
|
||||
|
||||
// 其次使用类注解的模块
|
||||
if (null != classLog) {
|
||||
logRecord.setModule(CharSequenceUtil.blankToDefault(classLog.module(), "请在该接口类上指定所属模块"));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.autoconfigure;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import top.continew.starter.log.aop.annotation.ConditionalOnEnabledLog;
|
||||
import top.continew.starter.log.aop.aspect.ConsoleLogAspect;
|
||||
import top.continew.starter.log.aop.aspect.LogAspect;
|
||||
import top.continew.starter.log.core.dao.LogDao;
|
||||
import top.continew.starter.log.core.dao.impl.LogDaoDefaultImpl;
|
||||
|
||||
/**
|
||||
* 日志自动配置
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnEnabledLog
|
||||
@EnableConfigurationProperties(LogProperties.class)
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
public class LogAutoConfiguration {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LogAutoConfiguration.class);
|
||||
private final LogProperties logProperties;
|
||||
|
||||
public LogAutoConfiguration(LogProperties logProperties) {
|
||||
this.logProperties = logProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录日志切面
|
||||
*
|
||||
* @return {@link LogAspect }
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public LogAspect logAspect() {
|
||||
return new LogAspect(logDao(),logProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* 控制台输出日志切面
|
||||
*
|
||||
* @return {@link LogAspect }
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ConsoleLogAspect consoleLogAspect() {
|
||||
return new ConsoleLogAspect(logProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志持久层接口
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public LogDao logDao() {
|
||||
return new LogDaoDefaultImpl();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Log-aop' completed initialization.");
|
||||
}
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.autoconfigure;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import top.continew.starter.core.constant.PropertiesConstants;
|
||||
import top.continew.starter.log.core.enums.Include;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 日志配置属性
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@ConfigurationProperties(PropertiesConstants.LOG)
|
||||
public class LogProperties {
|
||||
|
||||
/**
|
||||
* 是否启用日志
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* 是否打印日志,开启后可打印访问日志(类似于 Nginx access log)
|
||||
* <p>
|
||||
* 不记录日志也支持开启打印访问日志
|
||||
* </p>
|
||||
*/
|
||||
private Boolean isPrint = false;
|
||||
|
||||
/**
|
||||
* 包含信息
|
||||
*/
|
||||
private Set<Include> includes = Include.defaultIncludes();
|
||||
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public Boolean getIsPrint() {
|
||||
return isPrint;
|
||||
}
|
||||
|
||||
public void setIsPrint(Boolean print) {
|
||||
isPrint = print;
|
||||
}
|
||||
|
||||
public Set<Include> getIncludes() {
|
||||
return includes;
|
||||
}
|
||||
|
||||
public void setIncludes(Set<Include> includes) {
|
||||
this.includes = includes;
|
||||
}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
top.continew.starter.log.aop.autoconfigure.LogAutoConfiguration
|
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.log.core.model;
|
||||
package top.continew.starter.log.core.http.recordable;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.log.core.model;
|
||||
package top.continew.starter.log.core.http.recordable;
|
||||
|
||||
import java.util.Map;
|
||||
|
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.log.interceptor.handler;
|
||||
package top.continew.starter.log.core.http.recordable.impl;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
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.WebUtils;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
import top.continew.starter.log.core.model.RecordableHttpRequest;
|
||||
import top.continew.starter.log.core.http.recordable.RecordableHttpRequest;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.log.interceptor.handler;
|
||||
package top.continew.starter.log.core.http.recordable.impl;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -22,7 +22,7 @@ import cn.hutool.json.JSONUtil;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.util.ContentCachingResponseWrapper;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
import top.continew.starter.log.core.model.RecordableHttpResponse;
|
||||
import top.continew.starter.log.core.http.recordable.RecordableHttpResponse;
|
||||
import top.continew.starter.web.util.ServletUtils;
|
||||
|
||||
import java.util.Map;
|
@@ -17,6 +17,8 @@
|
||||
package top.continew.starter.log.core.model;
|
||||
|
||||
import top.continew.starter.log.core.enums.Include;
|
||||
import top.continew.starter.log.core.http.recordable.RecordableHttpRequest;
|
||||
import top.continew.starter.log.core.http.recordable.RecordableHttpResponse;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
@@ -63,6 +65,11 @@ public class LogRecord {
|
||||
*/
|
||||
private final Instant timestamp;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errorMsg;
|
||||
|
||||
public LogRecord(Instant timestamp, LogRequest request, LogResponse response, Duration timeTaken) {
|
||||
this.timestamp = timestamp;
|
||||
this.request = request;
|
||||
@@ -164,4 +171,11 @@ public class LogRecord {
|
||||
public Instant getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public String getErrorMsg() {
|
||||
return errorMsg;
|
||||
}
|
||||
public void setErrorMsg(String errorMsg) {
|
||||
this.errorMsg = errorMsg;
|
||||
}
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@ import org.springframework.http.HttpHeaders;
|
||||
import top.continew.starter.core.util.ExceptionUtils;
|
||||
import top.continew.starter.core.util.IpUtils;
|
||||
import top.continew.starter.log.core.enums.Include;
|
||||
import top.continew.starter.log.core.http.recordable.RecordableHttpRequest;
|
||||
import top.continew.starter.web.util.ServletUtils;
|
||||
|
||||
import java.net.URI;
|
||||
|
@@ -17,6 +17,7 @@
|
||||
package top.continew.starter.log.core.model;
|
||||
|
||||
import top.continew.starter.log.core.enums.Include;
|
||||
import top.continew.starter.log.core.http.recordable.RecordableHttpResponse;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 {
|
||||
}
|
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.log.core.annotation;
|
||||
package top.continew.starter.log.interceptor.annotation;
|
||||
|
||||
import top.continew.starter.log.core.enums.Include;
|
||||
|
@@ -28,6 +28,7 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import top.continew.starter.log.core.dao.LogDao;
|
||||
import top.continew.starter.log.core.dao.impl.LogDaoDefaultImpl;
|
||||
import top.continew.starter.log.interceptor.annotation.ConditionalOnEnabledLog;
|
||||
import top.continew.starter.log.interceptor.handler.LogFilter;
|
||||
import top.continew.starter.log.interceptor.handler.LogInterceptor;
|
||||
|
||||
@@ -75,6 +76,6 @@ public class LogAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Log' completed initialization.");
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Log-interceptor' completed initialization.");
|
||||
}
|
||||
}
|
||||
|
@@ -28,7 +28,9 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import top.continew.starter.log.core.annotation.Log;
|
||||
import top.continew.starter.log.core.http.recordable.impl.RecordableServletHttpRequest;
|
||||
import top.continew.starter.log.core.http.recordable.impl.RecordableServletHttpResponse;
|
||||
import top.continew.starter.log.interceptor.annotation.Log;
|
||||
import top.continew.starter.log.core.dao.LogDao;
|
||||
import top.continew.starter.log.core.enums.Include;
|
||||
import top.continew.starter.log.core.model.LogRecord;
|
||||
|
@@ -16,6 +16,7 @@
|
||||
<modules>
|
||||
<module>continew-starter-log-core</module>
|
||||
<module>continew-starter-log-interceptor</module>
|
||||
<module>continew-starter-log-aop</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
|
Reference in New Issue
Block a user