From 3a2f6baed3f0a48565c523b498d631474eb1feab Mon Sep 17 00:00:00 2001 From: orange Date: Fri, 30 Jul 2021 23:56:15 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=9A=B8=20=E6=96=B0=E5=A2=9ESlf4JLogIn?= =?UTF-8?q?terceptor=20=20=20=E4=BD=BF=E7=94=A8slf4j=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E6=97=A5=E5=BF=97=20=20=20=E5=9C=A8beetlsql-core.pom=E4=B8=AD?= =?UTF-8?q?=E5=BC=95=E5=85=A5slf4j-api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql-core/pom.xml | 56 +++-- .../beetl/sql/ext/Slf4JLogInterceptor.java | 223 ++++++++++++++++++ 2 files changed, 254 insertions(+), 25 deletions(-) create mode 100644 sql-core/src/main/java/org/beetl/sql/ext/Slf4JLogInterceptor.java diff --git a/sql-core/pom.xml b/sql-core/pom.xml index ffe8d5b6..8ff0f259 100644 --- a/sql-core/pom.xml +++ b/sql-core/pom.xml @@ -12,6 +12,7 @@ sql-core 3.6.3-RELEASE + 1.7.32 @@ -19,33 +20,38 @@ sql-util 3.6.3-RELEASE + + org.slf4j + slf4j-api + ${slf4j.version} + - - - maven-resources-plugin - - - copy-properties - process-sources - - copy-resources - - - ${basedir}/target/classes - - - ${basedir}/src/main/resources - - **/*.properties - - - - - - - - + + + maven-resources-plugin + + + copy-properties + process-sources + + copy-resources + + + ${basedir}/target/classes + + + ${basedir}/src/main/resources + + **/*.properties + + + + + + + + \ No newline at end of file diff --git a/sql-core/src/main/java/org/beetl/sql/ext/Slf4JLogInterceptor.java b/sql-core/src/main/java/org/beetl/sql/ext/Slf4JLogInterceptor.java new file mode 100644 index 00000000..08415462 --- /dev/null +++ b/sql-core/src/main/java/org/beetl/sql/ext/Slf4JLogInterceptor.java @@ -0,0 +1,223 @@ +package org.beetl.sql.ext; + +import lombok.extern.slf4j.Slf4j; +import org.beetl.sql.clazz.EnumKit; +import org.beetl.sql.clazz.SQLType; +import org.beetl.sql.clazz.kit.JavaType; +import org.beetl.sql.core.ExecuteContext; +import org.beetl.sql.core.Interceptor; +import org.beetl.sql.core.InterceptorContext; +import org.beetl.sql.core.SQLManager; +import org.beetl.sql.core.engine.SQLParameter; +import org.beetl.sql.core.query.LambdaQuery; +import org.beetl.sql.core.query.Query; +import org.beetl.sql.core.query.interfacer.QueryExecuteI; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; + +/** + * Debug重新美化版本,把sql执行语句,参数,时间,以及此sql在代码中执行的位置(可选)打印到控制台 + * 如果对性能有要求,不建议使用此Interceptor + * + * @author xiandafu + * @author darren + * @author 最后的夏天 + * @version 2016年8月25日 + */ +@Slf4j +public class Slf4JLogInterceptor implements Interceptor { + + protected static final String LINE_SEPARATOR = System.lineSeparator(); + + protected static String mapperName = "org.beetl.sql.mapper.MapperJavaProxy"; + + protected static String sqlManager = SQLManager.class.getName(); + + protected static String queryClassName = Query.class.getName(); + + protected static String lambdaQueryName = LambdaQuery.class.getName(); + + protected static String defaultQueryMethod = QueryExecuteI.class.getName(); + + /** + * 显示sql所在行号, 开销较大 + * // TODO 预留,后面需要做配置 + */ + protected boolean showLineNum; + + /** + * 自定义输出行号时优先输出的类,而不是SQLManager或者是BaseMapper + * // TODO 预留,后面需要做配置 + */ + protected String preferredShowClass; + + public Slf4JLogInterceptor() { + + } + + public Slf4JLogInterceptor(boolean showLineNum, String preferredShowClass) { + this.showLineNum = showLineNum; + this.preferredShowClass = preferredShowClass; + } + + public static String formatSql(String sql) { + return sql.replaceAll("--.*", "").replaceAll("\\n", "").replaceAll("\\s+", " "); + } + + /** + * SQL执行前调用 + * + * @param ctx {@code InterceptorContext} + */ + @Override + public void before(InterceptorContext ctx) { + if (!log.isDebugEnabled()) { + return; + } + + ExecuteContext executeContext = ctx.getExecuteContext(); + String sqlId = executeContext.sqlId.toString(); + String jdbcSql = ctx.getExecuteContext().sqlResult.jdbcSql; + ctx.put("debug.time", System.currentTimeMillis()); + + StringBuilder sb = new StringBuilder(formatSqlId(sqlId)).append(LINE_SEPARATOR); + sb.append("┌ SQL:\t").append(formatSql(jdbcSql)).append(LINE_SEPARATOR) + .append("├ 参数:\t").append(formatParas(ctx.getExecuteContext().sqlResult.jdbcPara)) + .append(LINE_SEPARATOR); + if (showLineNum) { + RuntimeException ex = new RuntimeException(); + StackTraceElement[] traces = ex.getStackTrace(); + int index = lookBusinessCodeInTrace(traces); + StackTraceElement businessCode = traces[index]; + String className = businessCode.getClassName(); + String methodName = businessCode.getMethodName(); + int line = businessCode.getLineNumber(); + sb.append("├ 位置:\t").append(className).append('.').append(methodName) + .append('(').append(businessCode.getFileName()).append(':') + .append(line).append(')').append(LINE_SEPARATOR); + } + ctx.put("logs", sb); + } + + /** + * SQL正常执行后调用 + * + * @param ctx {@code InterceptorContext} + */ + @Override + public void after(InterceptorContext ctx) { + if (!log.isDebugEnabled()) { + return; + } + + long start = (long) ctx.get("debug.time"); + StringBuilder sb = (StringBuilder) ctx.get("logs"); + sb.append("├ 时间:\t").append(System.currentTimeMillis() - start).append("ms").append(LINE_SEPARATOR); + SQLType sqlType = ctx.getExecuteContext().sqlSource.sqlType; + Object result = ctx.getExecuteContext().executeResult; + if (sqlType.isUpdate()) { + sb.append("├ 更新:\t["); + if (result.getClass().isArray()) { + int[] ret = (int[]) result; + for (int i = 0; i < ret.length; i++) { + if (i > 0) { + sb.append(','); + } + sb.append(ret[i]); + } + } else { + sb.append(result); + } + sb.append(']').append(LINE_SEPARATOR); + } else { + if (result instanceof Collection) { + sb.append("└ 结果:\t[").append(((Collection) result).size()).append(']'); + } else { + sb.append("└ 结果:\t[").append(result).append(']'); + } + } + print(sb.toString()); + } + + /** + * SQL执行异常后调用 + * + * @param ctx {@code InterceptorContext} + * @param ex SQL执行异常信息 + */ + @Override + public void exception(InterceptorContext ctx, Exception ex) { + if (log.isDebugEnabled()) { + StringBuilder sb = (StringBuilder) ctx.get("logs"); + sb.append("└ 异常:\t").append(ex.getMessage()); + error(sb.toString()); + } + } + + protected String formatSqlId(String id) { + String sql = formatSql(id); + return sql.length() > 50 ? sql.substring(0, 50) + "..." : sql; + } + + protected int lookBusinessCodeInTrace(StackTraceElement[] traces) { + for (int i = traces.length - 1; i >= 0; i--) { + String name = traces[i].getClassName(); + if (preferredShowClass != null && preferredShowClass.equals(name)) { + return i; + } else if (name.equals(mapperName)) { + // 越过sun jdk 代理 + int skipLine = JavaType.isJdk8() ? 3 : 2; + return i + skipLine; + } else if (name.equals(lambdaQueryName)) { + return i + 1; + } else if (name.equals(queryClassName)) { + return i + 1; + } else if (name.equals(defaultQueryMethod)) { + return i + 1; + } else if (name.equals(sqlManager)) { + return i + 1; + } + } + // 不可能到这里 + throw new IllegalStateException(); + } + + protected List formatParas(List list) { + List data = new ArrayList<>(list.size()); + for (SQLParameter para : list) { + Object obj = para.value; + if (obj == null) { + data.add(null); + } else if (obj instanceof String) { + String str = (String) obj; + if (str.length() > 60) { + data.add(str.substring(0, 60) + "...(" + str.length() + ")"); + } else { + data.add(str); + } + } else if (obj instanceof Date) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd (HH:mm:ss.SSS)"); + data.add(sdf.format((Date) obj)); + } else if (obj instanceof Enum) { + Object value = EnumKit.getValueByEnum(obj); + data.add(String.valueOf(value)); + } else { + data.add(obj.toString()); + } + } + return data; + } + + protected void print(String str) { + log.debug(str); + } + + protected void error(String str) { + log.error(str); + } + +} -- Gitee From 1b1416e0e01791b3b38b8aea4af44fdc2127818f Mon Sep 17 00:00:00 2001 From: orange Date: Sat, 31 Jul 2021 00:47:08 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=85=20BaseTest=E5=A2=9E=E5=8A=A0Slf4J?= =?UTF-8?q?LogInterceptor=E6=B5=8B=E8=AF=95=20=20=20=E5=9C=A8sql-test.pom?= =?UTF-8?q?=E4=B8=AD=E5=BC=95=E5=85=A5log4j-slf4j-impl=20=20=20resources?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0log4j2-test.xml=E4=BD=9C=E4=B8=BASlf4JLogInte?= =?UTF-8?q?rceptor=E7=9A=84=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql-test/pom.xml | 9 +- sql-test/src/main/resources/log4j2-test.xml | 16 ++ .../src/test/java/org/beetl/sql/BaseTest.java | 170 +++++++++--------- sql-test/src/test/resources/log4j2-test.xml | 16 ++ 4 files changed, 122 insertions(+), 89 deletions(-) create mode 100644 sql-test/src/main/resources/log4j2-test.xml create mode 100644 sql-test/src/test/resources/log4j2-test.xml diff --git a/sql-test/pom.xml b/sql-test/pom.xml index 909fbcfd..6f1ce883 100644 --- a/sql-test/pom.xml +++ b/sql-test/pom.xml @@ -18,6 +18,7 @@ 8.0.20 1.14.2 4.6.1 + 2.14.1 @@ -49,7 +50,12 @@ 8.0.12 provided - + + org.apache.logging.log4j + log4j-slf4j-impl + ${log4j2.version} + test + @@ -73,5 +79,4 @@ - \ No newline at end of file diff --git a/sql-test/src/main/resources/log4j2-test.xml b/sql-test/src/main/resources/log4j2-test.xml new file mode 100644 index 00000000..65b4f0a2 --- /dev/null +++ b/sql-test/src/main/resources/log4j2-test.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sql-test/src/test/java/org/beetl/sql/BaseTest.java b/sql-test/src/test/java/org/beetl/sql/BaseTest.java index 7cef32ee..502f4ce0 100644 --- a/sql-test/src/test/java/org/beetl/sql/BaseTest.java +++ b/sql-test/src/test/java/org/beetl/sql/BaseTest.java @@ -5,105 +5,101 @@ import org.beetl.sql.core.*; import org.beetl.sql.core.db.H2Style; import org.beetl.sql.ext.DebugInterceptor; import org.beetl.sql.ext.SimpleDebugInterceptor; +import org.beetl.sql.ext.Slf4JLogInterceptor; import org.junit.BeforeClass; import javax.sql.DataSource; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; /** * 单元测试基础类,用于初始化database 和 SQLManager - * + *

* https://www.testcontainers.org/ */ -public class BaseTest { - - public static String testSqlFile ="/db/db-init.sql"; - public static SQLManager sqlManager; - public static HikariDataSource dataSource ; - - - public BaseTest(){ - - } - @BeforeClass - public static void start(){ - datasource(); - initSQLManager(); - } - - - - public static void datasource() { - dataSource = new HikariDataSource(); - dataSource.setJdbcUrl("jdbc:h2:mem:dbtest;DB_CLOSE_ON_EXIT=FALSE"); - dataSource.setUsername("sa"); - dataSource.setPassword(""); - dataSource.setDriverClassName("org.h2.Driver"); - dataSource.setMaximumPoolSize(5); - - } - - public static void initSQLManager(){ - ConnectionSource source = ConnectionSourceHelper.getSingle(dataSource); - SQLManagerBuilder builder = new SQLManagerBuilder(source); - builder.setNc(new UnderlinedNameConversion()); - builder.setInters(new Interceptor[]{new DebugInterceptor()}); - builder.setDbStyle(new H2Style()); - builder.setInters(new Interceptor[]{new SimpleDebugInterceptor()}); - sqlManager = builder.build(); - } - - public static void initTable(String file){ - initData(dataSource,file); - } - - public static void initData(DataSource ds,String file) { - Connection conn = null; - try{ - conn = ds.getConnection(); - String[] sqls = getSqlFromFile(file); - for(String sql:sqls ){ - runSql(conn,sql); - } - - }catch (SQLException sqlException){ - throw new RuntimeException(sqlException); - } - finally { - try { - if(conn!=null)conn.close(); - } catch (SQLException sqlException) { - //ignore - } - } - } - - private static String[] getSqlFromFile(String file){ - try{ - InputStream ins = BaseTest.class.getResourceAsStream(file); - if(ins==null){ - throw new IllegalArgumentException("无法加载文件 "+file); - } - int len = ins.available(); - byte[] bs = new byte[len]; - ins.read(bs); - String str = new String(bs,"UTF-8"); - String[] sql = str.split(";"); - return sql; - }catch(Exception ex){ - throw new RuntimeException(ex); - } - - } - - private static void runSql(Connection conn,String sql) throws SQLException { - PreparedStatement ps = conn.prepareStatement(sql); - ps.executeUpdate(); - ps.close(); - } +public class BaseTest { + + public static String testSqlFile = "/db/db-init.sql"; + public static SQLManager sqlManager; + public static HikariDataSource dataSource; + + + public BaseTest() { + + } + + @BeforeClass + public static void start() { + datasource(); + initSQLManager(); + } + + + public static void datasource() { + dataSource = new HikariDataSource(); + dataSource.setJdbcUrl("jdbc:h2:mem:dbtest;DB_CLOSE_ON_EXIT=FALSE"); + dataSource.setUsername("sa"); + dataSource.setPassword(""); + dataSource.setDriverClassName("org.h2.Driver"); + dataSource.setMaximumPoolSize(5); + + } + + public static void initSQLManager() { + ConnectionSource source = ConnectionSourceHelper.getSingle(dataSource); + SQLManagerBuilder builder = new SQLManagerBuilder(source); + builder.setNc(new UnderlinedNameConversion()); + builder.setDbStyle(new H2Style()); + builder.setInters(new Interceptor[]{new DebugInterceptor()}); + builder.setInters(new Interceptor[]{new SimpleDebugInterceptor()}); + // slf4j-beetlsql-log +// builder.setInters(new Interceptor[]{new Slf4JLogInterceptor()}); + sqlManager = builder.build(); + } + + public static void initTable(String file) { + initData(dataSource, file); + } + + public static void initData(DataSource ds, String file) { + try (Connection conn = ds.getConnection()) { + String[] sqls = getSqlFromFile(file); + for (String sql : sqls) { + runSql(conn, sql); + } + + } catch (SQLException sqlException) { + throw new RuntimeException(sqlException); + } + //ignore + } + + private static String[] getSqlFromFile(String file) { + try { + InputStream ins = BaseTest.class.getResourceAsStream(file); + if (ins == null) { + throw new IllegalArgumentException("无法加载文件 " + file); + } + int len = ins.available(); + byte[] bs = new byte[len]; + ins.read(bs); + String str = new String(bs, StandardCharsets.UTF_8); + String[] sql = str.split(";"); + return sql; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + } + + private static void runSql(Connection conn, String sql) throws SQLException { + PreparedStatement ps = conn.prepareStatement(sql); + ps.executeUpdate(); + ps.close(); + } } diff --git a/sql-test/src/test/resources/log4j2-test.xml b/sql-test/src/test/resources/log4j2-test.xml new file mode 100644 index 00000000..65b4f0a2 --- /dev/null +++ b/sql-test/src/test/resources/log4j2-test.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file -- Gitee