diff --git a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/annotation/IgnoreLog.java b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/annotation/IgnoreLog.java
index 1e9b5682..7db9ae62 100644
--- a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/annotation/IgnoreLog.java
+++ b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/annotation/IgnoreLog.java
@@ -9,7 +9,7 @@ import java.lang.annotation.*;
* @version 1.0.0
* @since 2022/4/20 10:33
*/
-@Target({ElementType.METHOD})
+@Target({ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreLog {
diff --git a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/utils/AnsiCode.java b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/utils/AnsiCode.java
index 5a0624fb..fe8eb9b0 100644
--- a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/utils/AnsiCode.java
+++ b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/utils/AnsiCode.java
@@ -28,7 +28,7 @@ package com.orion.ops.framework.common.utils;
* \033[?25l 隐藏光标
* \033[?25h 显示光标
*
- * TODO 后续直接使用kit
+ * FIXME KIT
*
* @author Jiahang Li
* @version 1.0.0
diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/java/com/orion/ops/framework/mybatis/type/ITypeHandler.java b/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/java/com/orion/ops/framework/mybatis/type/ITypeHandler.java
index ab888ca3..14bd48b2 100644
--- a/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/java/com/orion/ops/framework/mybatis/type/ITypeHandler.java
+++ b/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/java/com/orion/ops/framework/mybatis/type/ITypeHandler.java
@@ -13,7 +13,7 @@ import java.util.List;
*/
public interface ITypeHandler
extends TypeHandler {
- // TODO KIT
+ // FIXME KIT
String COMMA = ",";
/**
@@ -25,7 +25,7 @@ public interface ITypeHandler extends TypeHandler {
R getResult(P param);
/**
- * // TODO kit
+ * // FIXME kit
* 用 , 连接
*
* @param list list
diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-swagger/src/main/resources/META-INF/spring-configuration-metadata.json b/orion-ops-framework/orion-ops-spring-boot-starter-swagger/src/main/resources/META-INF/spring-configuration-metadata.json
new file mode 100644
index 00000000..d08ae3df
--- /dev/null
+++ b/orion-ops-framework/orion-ops-spring-boot-starter-swagger/src/main/resources/META-INF/spring-configuration-metadata.json
@@ -0,0 +1,46 @@
+{
+ "groups": [
+ {
+ "name": "orion.swagger",
+ "type": "com.orion.ops.framework.swagger.config.SwaggerProperties",
+ "sourceType": "com.orion.ops.framework.swagger.config.SwaggerProperties"
+ }
+ ],
+ "properties": [
+ {
+ "name": "orion.swagger.title",
+ "type": "java.lang.String",
+ "description": "swagger 项目标题."
+ },
+ {
+ "name": "orion.swagger.description",
+ "type": "java.lang.String",
+ "description": "swagger 项目描述."
+ },
+ {
+ "name": "orion.swagger.version",
+ "type": "java.lang.String",
+ "description": "swagger 项目版本."
+ },
+ {
+ "name": "orion.swagger.url",
+ "type": "java.lang.String",
+ "description": "swagger 项目url."
+ },
+ {
+ "name": "orion.swagger.email",
+ "type": "java.lang.String",
+ "description": "swagger 项目email."
+ },
+ {
+ "name": "orion.swagger.license",
+ "type": "java.lang.String",
+ "description": "swagger 项目license."
+ },
+ {
+ "name": "orion.swagger.license-url",
+ "type": "java.lang.String",
+ "description": "swagger 项目license-url."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-web/pom.xml b/orion-ops-framework/orion-ops-spring-boot-starter-web/pom.xml
index b7f5b1a1..2d283970 100644
--- a/orion-ops-framework/orion-ops-spring-boot-starter-web/pom.xml
+++ b/orion-ops-framework/orion-ops-spring-boot-starter-web/pom.xml
@@ -38,6 +38,20 @@
spring-boot-starter-jdbc
provided
+
+
+
+ org.springdoc
+ springdoc-openapi-ui
+ provided
+
+
+
+
+ com.github.xiaoymin
+ knife4j-openapi3-spring-boot-starter
+ provided
+
\ No newline at end of file
diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/config/OrionLogPrinterConfiguration.java b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/config/OrionLogPrinterConfiguration.java
index e668151b..f9ffdf4a 100644
--- a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/config/OrionLogPrinterConfiguration.java
+++ b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/config/OrionLogPrinterConfiguration.java
@@ -1,9 +1,16 @@
package com.orion.ops.framework.web.config;
import com.orion.ops.framework.common.constant.InterceptorOrderConst;
-import com.orion.ops.framework.web.core.interceptor.LogPrintInterceptor;
+import com.orion.ops.framework.web.core.config.LogPrinterConfig;
+import com.orion.ops.framework.web.core.interceptor.LogPrinterInterceptor;
+import com.orion.ops.framework.web.core.interceptor.PrettyLogPrinterInterceptor;
+import com.orion.ops.framework.web.core.interceptor.RowLogPrinterInterceptor;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
/**
@@ -14,18 +21,41 @@ import org.springframework.context.annotation.Bean;
* @since 2023/6/16 18:18
*/
@AutoConfiguration
+@EnableConfigurationProperties(LogPrinterConfig.class)
public class OrionLogPrinterConfiguration {
+ /**
+ * @param config config
+ * @return 美化日志打印器
+ */
@Bean
- public LogPrintInterceptor logPrintInterceptor() {
- return new LogPrintInterceptor();
+ @ConditionalOnProperty(value = "logging.printer.mode", havingValue = "pretty")
+ public LogPrinterInterceptor prettyPrinter(LogPrinterConfig config) {
+ return new PrettyLogPrinterInterceptor(config);
}
+ /**
+ * @param config config
+ * @return 单行日志打印器
+ */
@Bean
- public AspectJExpressionPointcutAdvisor logPrinterAdvisor(LogPrintInterceptor logPrintInterceptor) {
+ @ConditionalOnProperty(value = "logging.printer.mode", havingValue = "row")
+ public LogPrinterInterceptor rowPrinter(LogPrinterConfig config) {
+ return new RowLogPrinterInterceptor(config);
+ }
+
+ /**
+ * @param logPrinterInterceptor logPrinterInterceptor
+ * @param expression 切面表达式
+ * @return 日志打印切面
+ */
+ @Bean
+ @ConditionalOnBean(LogPrinterInterceptor.class)
+ public AspectJExpressionPointcutAdvisor logPrinterAdvisor(LogPrinterInterceptor logPrinterInterceptor,
+ @Value("${logging.printer.expression}") String expression) {
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
- advisor.setExpression("execution (* com.orion.ops.**.controller.*.*(..)) && !@annotation(com.orion.ops.framework.common.annotation.IgnoreLog)");
- advisor.setAdvice(logPrintInterceptor);
+ advisor.setExpression(expression);
+ advisor.setAdvice(logPrinterInterceptor);
advisor.setOrder(InterceptorOrderConst.LOG_FILTER);
return advisor;
}
diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/config/LogPrinterConfig.java b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/config/LogPrinterConfig.java
new file mode 100644
index 00000000..a4be5fea
--- /dev/null
+++ b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/config/LogPrinterConfig.java
@@ -0,0 +1,38 @@
+package com.orion.ops.framework.web.core.config;
+
+import com.orion.ops.framework.web.core.utils.Utils;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.List;
+
+/**
+ * 日志打印配置
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2023/6/28 22:36
+ */
+@Data
+@ConfigurationProperties("logging.printer")
+public class LogPrinterConfig {
+
+ /**
+ * 字段配置
+ */
+ private LogPrinterFieldConfig field;
+
+ /**
+ * 显示的请求头
+ */
+ private List headers;
+
+ public void setField(LogPrinterFieldConfig field) {
+ this.field = field;
+ }
+
+ public void setHeaders(List headers) {
+ this.headers = Utils.parseStringList(headers, String::toLowerCase);
+ }
+
+}
diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/config/LogPrinterFieldConfig.java b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/config/LogPrinterFieldConfig.java
new file mode 100644
index 00000000..38713941
--- /dev/null
+++ b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/config/LogPrinterFieldConfig.java
@@ -0,0 +1,36 @@
+package com.orion.ops.framework.web.core.config;
+
+import com.orion.ops.framework.web.core.utils.Utils;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 日志打印字段配置
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2023/6/28 22:36
+ */
+@Data
+public class LogPrinterFieldConfig {
+
+ /**
+ * 忽略的字段
+ */
+ private List ignore;
+
+ /**
+ * 脱敏的字段
+ */
+ private List desensitization;
+
+ public void setIgnore(List ignore) {
+ this.ignore = Utils.parseStringList(ignore);
+ }
+
+ public void setDesensitization(List desensitization) {
+ this.desensitization = Utils.parseStringList(desensitization);
+ }
+
+}
diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/interceptor/BaseLogPrinterInterceptor.java b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/interceptor/BaseLogPrinterInterceptor.java
new file mode 100644
index 00000000..92935e33
--- /dev/null
+++ b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/interceptor/BaseLogPrinterInterceptor.java
@@ -0,0 +1,269 @@
+package com.orion.ops.framework.web.core.interceptor;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.serializer.PropertyFilter;
+import com.alibaba.fastjson.serializer.SerializeFilter;
+import com.alibaba.fastjson.serializer.ValueFilter;
+import com.orion.lang.utils.Objects1;
+import com.orion.lang.utils.collect.Maps;
+import com.orion.lang.utils.reflect.Annotations;
+import com.orion.lang.utils.reflect.Classes;
+import com.orion.ops.framework.common.annotation.IgnoreLog;
+import com.orion.ops.framework.common.constant.Const;
+import com.orion.ops.framework.common.meta.TraceIdHolder;
+import com.orion.ops.framework.web.core.config.LogPrinterConfig;
+import io.swagger.v3.oas.annotations.Operation;
+import org.aopalliance.intercept.MethodInvocation;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Date;
+import java.util.Map;
+import java.util.function.Predicate;
+
+/**
+ * 日志打印拦截器 基类
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2023/6/29 10:36
+ */
+public abstract class BaseLogPrinterInterceptor implements LogPrinterInterceptor {
+
+ private static final String EMPTY_ARG = "";
+
+ private static final String ERROR_ARG = "";
+
+ /**
+ * 请求头过滤器
+ */
+ protected Predicate headerFilter;
+
+ /**
+ * 字段过滤器
+ */
+ protected SerializeFilter[] fieldFilter;
+
+ /**
+ * api 描述
+ */
+ private final Map summaryMapping;
+
+ /**
+ * 忽略的参数
+ */
+ private final Map ignoreParameter;
+
+ public BaseLogPrinterInterceptor(LogPrinterConfig config) {
+ this.summaryMapping = Maps.newMap();
+ this.ignoreParameter = Maps.newMap();
+ this.init(config);
+ }
+
+ /**
+ * 初始化
+ *
+ * @param config config
+ */
+ protected void init(LogPrinterConfig config) {
+ // 请求头过滤器
+ this.headerFilter = header -> config.getHeaders().contains(header);
+ // 忽略字段过滤器
+ PropertyFilter ignoreFilter = (Object object, String name, Object value) -> !config.getField().getIgnore().contains(name);
+ // 脱敏字段过滤器
+ ValueFilter desensitizationFilter = (Object object, String name, Object value) -> {
+ if (config.getField().getDesensitization().contains(name)) {
+ String s = Objects1.toString(value);
+ // Safes.mix()
+ // TODO
+ return "xxxxxx";
+ } else {
+ return value;
+ }
+ };
+ this.fieldFilter = new SerializeFilter[]{ignoreFilter, desensitizationFilter};
+ }
+
+ @Override
+ public Object invoke(MethodInvocation invocation) throws Throwable {
+ Date startTime = new Date();
+ String traceId = TraceIdHolder.get();
+ // 打印请求日志
+ this.requestPrinter(startTime, traceId, invocation);
+ try {
+ // 执行方法
+ Object ret = invocation.proceed();
+ // 打印响应日志
+ this.responsePrinter(startTime, traceId, ret);
+ return ret;
+ } catch (Throwable t) {
+ // 打印异常日志
+ this.errorPrinter(startTime, traceId, t);
+ throw t;
+ }
+ }
+
+ /**
+ * 打印请求信息
+ *
+ * @param startTime 开始时间
+ * @param traceId traceId
+ * @param invocation invocation
+ */
+ protected abstract void requestPrinter(Date startTime, String traceId, MethodInvocation invocation);
+
+ /**
+ * 打印响应信息
+ *
+ * @param startTime 开始时间
+ * @param traceId traceId
+ * @param ret return
+ */
+ protected abstract void responsePrinter(Date startTime, String traceId, Object ret);
+
+ /**
+ * 打印异常信息
+ *
+ * @param startTime 开始时间
+ * @param traceId traceId
+ * @param throwable ex
+ */
+ protected abstract void errorPrinter(Date startTime, String traceId, Throwable throwable);
+
+ /**
+ * 获取 api 描述
+ *
+ * @param m method
+ * @return summary
+ */
+ protected String getApiSummary(Method m) {
+ // 缓存中获取描述
+ String key = m.toString();
+ String cache = summaryMapping.get(key);
+ if (cache != null) {
+ return cache;
+ }
+ // 获取注解描述
+ Operation operation = Annotations.getAnnotation(m, Operation.class);
+ String summary = Const.EMPTY;
+ if (operation != null) {
+ summary = operation.summary();
+ }
+ summaryMapping.put(key, summary);
+ return summary;
+ }
+
+ /**
+ * 请求参数 json
+ *
+ * @param method method
+ * @param args object
+ * @return json
+ */
+ protected String requestToString(Method method, Object[] args) {
+ int length = args.length;
+ if (length == 0) {
+ return EMPTY_ARG;
+ }
+ try {
+ // 检查是否需要忽略字段
+ boolean[] ignored = this.getParameterIgnoreConfig(method, args);
+ int printCount = 0;
+ int lastPrintIndex = 0;
+ for (int i = 0; i < ignored.length; i++) {
+ if (!ignored[i]) {
+ printCount++;
+ lastPrintIndex = i;
+ }
+ }
+ if (printCount == 0) {
+ // 无打印参数
+ return EMPTY_ARG;
+ } else if (printCount == 1) {
+ // 单个打印参数
+ return JSON.toJSONString(args[lastPrintIndex], fieldFilter);
+ } else {
+ // 多个打印参数
+ JSONArray arr = new JSONArray();
+ for (int i = 0; i < ignored.length; i++) {
+ if (!ignored[i]) {
+ arr.add(args[i]);
+ }
+ }
+ return JSON.toJSONString(arr, fieldFilter);
+ }
+ } catch (Exception e) {
+ return ERROR_ARG;
+ }
+ }
+
+ /**
+ * 响应结果 json
+ *
+ * @param o object
+ * @return json
+ */
+ protected String responseToString(Object o) {
+ try {
+ return JSON.toJSONString(o, fieldFilter);
+ } catch (Exception e) {
+ return ERROR_ARG;
+ }
+ }
+
+ /**
+ * 获取参数忽略字段配置
+ *
+ * @param method method
+ * @param args args
+ * @return ignoreArr
+ */
+ private boolean[] getParameterIgnoreConfig(Method method, Object[] args) {
+ int length = args.length;
+ // 获取缓存
+ String key = method.toString();
+ boolean[] ignored = ignoreParameter.get(key);
+ if (ignored != null) {
+ return ignored;
+ }
+ ignored = new boolean[length];
+ ignoreParameter.put(key, ignored);
+ // 检查是否有忽略字段注解
+ Annotation[][] annotations = method.getParameterAnnotations();
+ for (int parameterIndex = 0; parameterIndex < length; parameterIndex++) {
+ boolean ignore = false;
+ Annotation[] parameterAnnotations = annotations[parameterIndex];
+ for (Annotation parameterAnnotation : parameterAnnotations) {
+ // 需要忽略该字段
+ if (parameterAnnotation.annotationType().equals(IgnoreLog.class)) {
+ ignore = true;
+ break;
+ }
+ }
+ ignored[parameterIndex] = ignore;
+ }
+ // 检查是否可以序列化
+ for (int i = 0; i < args.length; i++) {
+ if (ignored[i]) {
+ continue;
+ }
+ Object arg = args[i];
+ // 是否为 request / response
+ if (arg instanceof ServletRequest || arg instanceof ServletResponse) {
+ ignored[i] = true;
+ continue;
+ }
+ // 是否为代理对象 (bean)
+ if (arg != null) {
+ if (Classes.isJdkProxy(arg) || Classes.isCglibProxy(arg)) {
+ ignored[i] = true;
+ }
+ }
+ }
+ return ignored;
+ }
+
+}
diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/interceptor/LogPrintInterceptor.java b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/interceptor/LogPrintInterceptor.java
deleted file mode 100644
index 660b4514..00000000
--- a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/interceptor/LogPrintInterceptor.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package com.orion.ops.framework.web.core.interceptor;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.PropertyFilter;
-import com.orion.lang.constant.Const;
-import com.orion.lang.utils.Arrays1;
-import com.orion.lang.utils.Exceptions;
-import com.orion.lang.utils.time.Dates;
-import com.orion.ops.framework.common.meta.TraceIdHolder;
-import com.orion.web.servlet.web.Servlets;
-import lombok.extern.slf4j.Slf4j;
-import org.aopalliance.intercept.MethodInterceptor;
-import org.aopalliance.intercept.MethodInvocation;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.core.annotation.Order;
-import org.springframework.stereotype.Component;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
-
-import java.lang.reflect.Method;
-import java.util.Date;
-import java.util.Optional;
-
-/**
- * 日志打印拦截器
- *
- * @author Jiahang Li
- * @version 1.0.0
- * @since 2022/7/14 18:25
- */
-@Slf4j
-@Order(10)
-public class LogPrintInterceptor implements MethodInterceptor {
-
- // TODO @OperatorLog(bizName = "")
- // TODO 日志规格模型 SIMPLIFY FULL
-
- // https://blog.csdn.net/gaojie_csdn/article/details/127810618
- // 加注解
-
- // TODO 改为正则?
- @Value("#{'${log.interceptor.ignore.fields:}'.split(',')}")
- private String[] ignoreFields;
-
- @Override
- public Object invoke(MethodInvocation invocation) throws Throwable {
- Date startTime = new Date();
- String traceId = TraceIdHolder.get();
- // 打印开始日志
- this.beforeLogPrint(startTime, traceId, invocation);
- try {
- // 执行方法
- Object ret = invocation.proceed();
- // 返回打印
- this.afterReturnLogPrint(startTime, traceId, ret);
- return ret;
- } catch (Throwable t) {
- // 异常打印
- this.afterThrowingLogPrint(startTime, traceId, t);
- throw t;
- }
- }
-
- /**
- * 方法进入打印
- *
- * @param startTime 开始时间
- * @param traceId trace
- * @param invocation invocation
- */
- public void beforeLogPrint(Date startTime, String traceId, MethodInvocation invocation) {
- StringBuilder requestLog = new StringBuilder("\napi请求-开始-traceId: ").append(traceId).append('\n');
- // TODO 登陆用户
- // requestLog.append("\t当前用户: ").append(JSON.toJSONString(UserHolder.get())).append('\n');
- // TODO @OperatorLog
- // http请求信息
- Optional.ofNullable(RequestContextHolder.getRequestAttributes())
- .map(s -> (ServletRequestAttributes) s)
- .map(ServletRequestAttributes::getRequest)
- .ifPresent(request -> {
- // url
- requestLog.append("\t").append(Servlets.getMethod(request)).append(" ")
- .append(Servlets.getRequestUrl(request)).append('\n');
- // query
- requestLog.append("\tip: ").append(Servlets.getRemoteAddr(request)).append('\n')
- .append("\tquery: ").append(Servlets.getQueryString(request)).append('\n');
- // header
- Servlets.getHeaderMap(request).forEach((hk, hv) -> requestLog.append('\t')
- .append(hk).append(": ")
- .append(hv).append('\n'));
- });
- // 方法信息
- Method method = invocation.getMethod();
- requestLog.append("\t开始时间: ").append(Dates.format(startTime, Dates.YMD_HMSS)).append('\n')
- .append("\t方法签名: ").append(method.getDeclaringClass().getName()).append('#')
- .append(method.getName()).append("\n")
- .append("\t请求参数: ").append(this.argsToString(invocation.getArguments()));
- log.info(requestLog.toString());
- }
-
- /**
- * 返回打印
- *
- * @param startTime 开始时间
- * @param traceId traceId
- * @param ret return
- */
- private void afterReturnLogPrint(Date startTime, String traceId, Object ret) {
- Date endTime = new Date();
- // 响应日志
- StringBuilder responseLog = new StringBuilder("\napi请求-结束-traceId: ").append(traceId).append('\n');
- responseLog.append("\t结束时间: ").append(Dates.format(endTime, Dates.YMD_HMSS))
- .append(" used: ").append(endTime.getTime() - startTime.getTime()).append("ms \n")
- .append("\t响应结果: ").append(this.argsToString(ret));
- log.info(responseLog.toString());
- }
-
- /**
- * 异常打印
- *
- * @param startTime 开始时间
- * @param traceId trace
- * @param throwable ex
- */
- private void afterThrowingLogPrint(Date startTime, String traceId, Throwable throwable) {
- Date endTime = new Date();
- // 响应日志
- StringBuilder responseLog = new StringBuilder("\napi请求-异常-traceId: ").append(traceId).append('\n');
- responseLog.append("\t结束时间: ").append(Dates.format(endTime, Dates.YMD_HMSS))
- .append(" used: ").append(endTime.getTime() - startTime.getTime()).append("ms \n")
- .append("\t异常摘要: ").append(Exceptions.getDigest(throwable));
- log.error(responseLog.toString());
- }
-
- /**
- * 参数转json
- *
- * @param o object
- * @return json
- */
- private String argsToString(Object o) {
- try {
- if (ignoreFields.length == 1 && Const.EMPTY.equals(ignoreFields[0])) {
- // 不过滤
- return JSON.toJSONString(o);
- } else {
- return JSON.toJSONString(o, (PropertyFilter) (object, name, value) -> !Arrays1.contains(ignoreFields, name));
- }
- } catch (Exception e) {
- return String.valueOf(o);
- }
- }
-
-}
diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/interceptor/LogPrinterInterceptor.java b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/interceptor/LogPrinterInterceptor.java
new file mode 100644
index 00000000..1b242b37
--- /dev/null
+++ b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/interceptor/LogPrinterInterceptor.java
@@ -0,0 +1,14 @@
+package com.orion.ops.framework.web.core.interceptor;
+
+import org.aopalliance.intercept.MethodInterceptor;
+
+/**
+ * 日志打印拦截器
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2023/6/29 10:36
+ */
+public interface LogPrinterInterceptor extends MethodInterceptor {
+
+}
diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/interceptor/PrettyLogPrinterInterceptor.java b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/interceptor/PrettyLogPrinterInterceptor.java
new file mode 100644
index 00000000..84f4e1b9
--- /dev/null
+++ b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/interceptor/PrettyLogPrinterInterceptor.java
@@ -0,0 +1,101 @@
+package com.orion.ops.framework.web.core.interceptor;
+
+import com.orion.lang.utils.Exceptions;
+import com.orion.lang.utils.Strings;
+import com.orion.lang.utils.time.Dates;
+import com.orion.ops.framework.web.core.config.LogPrinterConfig;
+import com.orion.web.servlet.web.Servlets;
+import lombok.extern.slf4j.Slf4j;
+import org.aopalliance.intercept.MethodInvocation;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+import java.util.Date;
+import java.util.Optional;
+
+/**
+ * 美化 日志打印拦截器
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2023/6/29 10:36
+ */
+@Slf4j
+public class PrettyLogPrinterInterceptor extends BaseLogPrinterInterceptor {
+
+ public PrettyLogPrinterInterceptor(LogPrinterConfig config) {
+ super(config);
+ }
+
+ @Override
+ protected void requestPrinter(Date startTime, String traceId, MethodInvocation invocation) {
+ StringBuilder requestLog = new StringBuilder("\napi请求-开始\n");
+ // http请求信息
+ HttpServletRequest request = Optional.ofNullable(RequestContextHolder.getRequestAttributes())
+ .map(s -> (ServletRequestAttributes) s)
+ .map(ServletRequestAttributes::getRequest)
+ .orElse(null);
+ // url
+ if (request != null) {
+ requestLog.append("\t").append(Servlets.getMethod(request)).append(" ")
+ .append(Servlets.getRequestUrl(request)).append('\n');
+ }
+ // traceId
+ requestLog.append("\ttraceId: ").append(traceId).append("\n");
+ // 开始时间
+ requestLog.append("\tstart: ").append(Dates.format(startTime, Dates.YMD_HMSS)).append('\n');
+ // api 描述
+ String summary = this.getApiSummary(invocation.getMethod());
+ if (!Strings.isEmpty(summary)) {
+ requestLog.append("\tsummary: ").append(summary).append('\n');
+ }
+ // TODO 登陆用户
+ // http
+ if (request != null) {
+ // remoteAddr
+ requestLog.append("\tremoteAddr: ").append(Servlets.getRemoteAddr(request)).append('\n');
+ // header
+ Servlets.getHeaderMap(request).forEach((hk, hv) -> {
+ if (headerFilter.test(hk.toLowerCase())) {
+ requestLog.append('\t')
+ .append(hk).append(": ")
+ .append(hv).append('\n');
+ }
+ });
+ }
+ Method method = invocation.getMethod();
+ // 方法签名
+ requestLog.append("\tmethodSign: ").append(method.getDeclaringClass().getName()).append('#')
+ .append(method.getName()).append("\n");
+ // 参数
+ requestLog.append("\tparameter: ").append(this.requestToString(method, invocation.getArguments()));
+ log.info(requestLog.toString());
+ }
+
+ @Override
+ protected void responsePrinter(Date startTime, String traceId, Object ret) {
+ Date endTime = new Date();
+ // 响应日志
+ StringBuilder responseLog = new StringBuilder("\napi请求-结束\n")
+ .append("\ttraceId: ").append(traceId).append('\n')
+ .append("\tend: ").append(Dates.format(endTime, Dates.YMD_HMSS)).append('\n')
+ .append("\tused: ").append(endTime.getTime() - startTime.getTime()).append("ms \n")
+ .append("\tresponse: ").append(this.responseToString(ret));
+ log.info(responseLog.toString());
+ }
+
+ @Override
+ protected void errorPrinter(Date startTime, String traceId, Throwable throwable) {
+ Date endTime = new Date();
+ // 异常日志
+ StringBuilder errorLog = new StringBuilder("\napi请求-异常\n")
+ .append("\ttraceId: ").append(traceId).append('\n')
+ .append("\tend: ").append(Dates.format(endTime, Dates.YMD_HMSS)).append('\n')
+ .append("\tused: ").append(endTime.getTime() - startTime.getTime()).append("ms \n")
+ .append("\terrorDigest: ").append(Exceptions.getDigest(throwable));
+ log.error(errorLog.toString());
+ }
+
+}
diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/utils/Utils.java b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/utils/Utils.java
new file mode 100644
index 00000000..5a782041
--- /dev/null
+++ b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/utils/Utils.java
@@ -0,0 +1,45 @@
+package com.orion.ops.framework.web.core.utils;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * 工具类
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2023/6/28 23:21
+ */
+public class Utils {
+
+ private Utils() {
+ }
+
+ public static List parseStringList(List list) {
+ return parseStringList(list, Function.identity());
+ }
+
+ /**
+ * 解析配置 List
+ *
+ * @param list list
+ * @param mapper mapper
+ * @return config
+ */
+ public static List parseStringList(List list, Function mapper) {
+ return Optional.ofNullable(list)
+ .map(List::stream)
+ .orElseGet(Stream::empty)
+ // FIXME kit
+ .map(s -> s.split(","))
+ .flatMap(Arrays::stream)
+ .map(String::trim)
+ .map(mapper)
+ .collect(Collectors.toList());
+ }
+
+}
diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/resources/META-INF/spring-configuration-metadata.json b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/resources/META-INF/spring-configuration-metadata.json
new file mode 100644
index 00000000..ad804169
--- /dev/null
+++ b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/resources/META-INF/spring-configuration-metadata.json
@@ -0,0 +1,52 @@
+{
+ "groups": [
+ {
+ "name": "logging.printer",
+ "type": "com.orion.ops.framework.web.core.config.LogPrinterConfig",
+ "sourceType": "com.orion.ops.framework.web.core.config.LogPrinterConfig"
+ }
+ ],
+ "properties": [
+ {
+ "name": "logging.printer.mode",
+ "type": "com.orion.ops.framework.web.core.enums.LogPrinterMode",
+ "description": "日志打印模型.",
+ "defaultValue": "NONE"
+ },
+ {
+ "name": "logging.printer.expression",
+ "type": "java.lang.String",
+ "description": "aspectj 表达式."
+ },
+ {
+ "name": "logging.printer.headers",
+ "type": "java.util.List",
+ "description": "需要打印的 HttpHandlers."
+ },
+ {
+ "name": "logging.printer.field.ignore",
+ "type": "java.util.List",
+ "description": "忽略打印的字段."
+ },
+ {
+ "name": "logging.printer.field.desensitization",
+ "type": "java.util.List",
+ "description": "需要脱敏的字段."
+ },
+ {
+ "name": "orion.version",
+ "type": "java.lang.String",
+ "description": "项目版本."
+ },
+ {
+ "name": "orion.api.prefix",
+ "type": "java.lang.String",
+ "description": "项目 api 前缀."
+ },
+ {
+ "name": "orion.api.cors",
+ "type": "java.lang.Boolean",
+ "description": "是否开启 cors 过滤器."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/orion-ops-launch/src/main/resources/application.yaml b/orion-ops-launch/src/main/resources/application.yaml
index 57912249..416cfafe 100644
--- a/orion-ops-launch/src/main/resources/application.yaml
+++ b/orion-ops-launch/src/main/resources/application.yaml
@@ -108,6 +108,19 @@ logging:
pattern:
console: '%clr(%d{${LOG_DATEFORMAT_PATTERN:yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %boldBlue([%X{tid}]) %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}'
file: "%d{${LOG_DATEFORMAT_PATTERN:yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} [%X{tid}] [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}"
+ printer:
+ mode: PRETTY
+ expression: 'execution (* com.orion.ops.**.controller.*.*(..)) && !@annotation(com.orion.ops.framework.common.annotation.IgnoreLog)'
+ headers:
+ - user-agent,accept
+ - content-type
+ field:
+ ignore:
+ - password,newPassword
+ - metrics
+ desensitization:
+ - phone,phoneNumber
+ - email,sendEmail
orion:
# 版本
@@ -118,7 +131,6 @@ orion:
prefix: /orion-api
# 是否开启跨域
cors: true
- # 文档配置
swagger:
title: orion-ops-pro 运维平台
description: 一站式提供运维功能