refactor(log): 优化日志模块

This commit is contained in:
2024-12-24 21:50:59 +08:00
parent 5ff9391485
commit c5cb203532
8 changed files with 57 additions and 94 deletions

View File

@@ -33,6 +33,7 @@ import top.continew.starter.log.handler.InterceptorLogHandler;
import top.continew.starter.log.handler.LogFilter;
import top.continew.starter.log.handler.LogHandler;
import top.continew.starter.log.interceptor.LogInterceptor;
import top.continew.starter.log.model.LogProperties;
/**
* 日志自动配置

View File

@@ -1,101 +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.autoconfigure;
import org.springframework.boot.context.properties.ConfigurationProperties;
import top.continew.starter.core.constant.PropertiesConstants;
import top.continew.starter.log.enums.Include;
import top.continew.starter.web.util.SpringWebUtils;
import java.util.ArrayList;
import java.util.List;
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();
/**
* 放行路由
*/
private List<String> excludePatterns = new ArrayList<>();
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;
}
public List<String> getExcludePatterns() {
return excludePatterns;
}
public void setExcludePatterns(List<String> excludePatterns) {
this.excludePatterns = excludePatterns;
}
/**
* 是否匹配放行路由
*
* @param uri 请求 URI
* @return 是否匹配
*/
public boolean isMatch(String uri) {
return this.getExcludePatterns().stream().anyMatch(pattern -> SpringWebUtils.isMatch(uri, pattern));
}
}

View File

@@ -1,148 +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.handler;
import cn.hutool.extra.spring.SpringUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.core.Ordered;
import org.springframework.lang.NonNull;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;
import top.continew.starter.log.autoconfigure.LogProperties;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;
/**
* 日志过滤器
*
* @author Dave SyerSpring Boot Actuator
* @author Wallace WadgeSpring Boot Actuator
* @author Andy WilkinsonSpring Boot Actuator
* @author Venil NoronhaSpring Boot Actuator
* @author Madhura BhaveSpring Boot Actuator
* @author Charles7c
* @since 1.1.0
*/
public class LogFilter extends OncePerRequestFilter implements Ordered {
private final LogProperties logProperties;
public LogFilter(LogProperties logProperties) {
this.logProperties = logProperties;
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 10;
}
@Override
protected void doFilterInternal(@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain) throws ServletException, IOException {
if (!this.isFilter(request)) {
filterChain.doFilter(request, response);
return;
}
boolean isMatch = logProperties.isMatch(request.getRequestURI());
// 包装输入流,可重复读取
if (!isMatch && this.isRequestWrapper(request)) {
request = new ContentCachingRequestWrapper(request);
}
// 包装输出流,可重复读取
boolean isResponseWrapper = !isMatch && this.isResponseWrapper(response);
if (isResponseWrapper) {
response = new ContentCachingResponseWrapper(response);
}
filterChain.doFilter(request, response);
// 更新响应(不操作这一步,会导致接口响应空白)
if (isResponseWrapper) {
this.updateResponse(response);
}
}
/**
* 是否过滤请求
*
* @param request 请求对象
* @return 是否过滤请求
*/
private boolean isFilter(HttpServletRequest request) {
if (!isRequestValid(request)) {
return false;
}
// 不拦截 /error
ServerProperties serverProperties = SpringUtil.getBean(ServerProperties.class);
return !request.getRequestURI().equals(serverProperties.getError().getPath());
}
/**
* 请求是否有效
*
* @param request 请求对象
* @return truefalse
*/
private boolean isRequestValid(HttpServletRequest request) {
try {
new URI(request.getRequestURL().toString());
return true;
} catch (URISyntaxException e) {
return false;
}
}
/**
* 是否需要包装输入流
*
* @param request 请求对象
* @return truefalse
*/
private boolean isRequestWrapper(HttpServletRequest request) {
return !(request instanceof ContentCachingRequestWrapper);
}
/**
* 是否需要包装输出流
*
* @param response 响应对象
* @return truefalse
*/
private boolean isResponseWrapper(HttpServletResponse response) {
return !(response instanceof ContentCachingResponseWrapper);
}
/**
* 更新响应
*
* @param response 响应对象
* @throws IOException /
*/
private void updateResponse(HttpServletResponse response) throws IOException {
ContentCachingResponseWrapper responseWrapper = WebUtils
.getNativeResponse(response, ContentCachingResponseWrapper.class);
Objects.requireNonNull(responseWrapper).copyBodyToResponse();
}
}

View File

@@ -27,7 +27,7 @@ import org.springframework.lang.NonNull;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import top.continew.starter.log.annotation.Log;
import top.continew.starter.log.autoconfigure.LogProperties;
import top.continew.starter.log.model.LogProperties;
import top.continew.starter.log.dao.LogDao;
import top.continew.starter.log.handler.LogHandler;
import top.continew.starter.log.model.LogRecord;