diff --git a/src/main/java/jp/co/future/uroborosql/SqlAgentImpl.java b/src/main/java/jp/co/future/uroborosql/SqlAgentImpl.java index 2c753921..d6094e74 100644 --- a/src/main/java/jp/co/future/uroborosql/SqlAgentImpl.java +++ b/src/main/java/jp/co/future/uroborosql/SqlAgentImpl.java @@ -36,7 +36,6 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -import jp.co.future.uroborosql.client.SqlParamUtils; import jp.co.future.uroborosql.config.SqlConfig; import jp.co.future.uroborosql.connection.ConnectionContext; import jp.co.future.uroborosql.context.ExecutionContext; @@ -82,14 +81,12 @@ import jp.co.future.uroborosql.fluent.SqlUpdate; import jp.co.future.uroborosql.log.support.CoverageLoggingSupport; import jp.co.future.uroborosql.log.support.PerformanceLoggingSupport; -import jp.co.future.uroborosql.log.support.ReplLoggingSupport; import jp.co.future.uroborosql.log.support.ServiceLoggingSupport; import jp.co.future.uroborosql.log.support.SqlLoggingSupport; import jp.co.future.uroborosql.mapping.EntityHandler; import jp.co.future.uroborosql.mapping.MappingColumn; import jp.co.future.uroborosql.mapping.MappingUtils; import jp.co.future.uroborosql.mapping.TableMetadata; -import jp.co.future.uroborosql.parameter.Parameter; import jp.co.future.uroborosql.parser.SqlParserImpl; import jp.co.future.uroborosql.store.SqlResourceManager; import jp.co.future.uroborosql.tx.LocalTransactionManager; @@ -103,7 +100,7 @@ * @author H.Sugimoto */ public class SqlAgentImpl implements SqlAgent, ServiceLoggingSupport, PerformanceLoggingSupport, SqlLoggingSupport, - CoverageLoggingSupport, ReplLoggingSupport { + CoverageLoggingSupport { /** ExecutionContext属性キー:リトライカウント */ private static final String CTX_ATTR_KEY_RETRY_COUNT = "__retryCount"; @@ -1355,9 +1352,6 @@ public ResultSet query(final ExecutionContext executionContext) throws SQLExcept // INパラメータ設定 executionContext.bindParams(stmt); - // REPLで実行するための文字列をREPLログに出力する - outputReplLog(executionContext); - debugWith(LOG) .setMessage("Execute query sql. sqlName: {}") .addArgument(executionContext.getSqlName()) @@ -1512,9 +1506,6 @@ public int update(final ExecutionContext executionContext) throws SQLException { // INパラメータ設定 executionContext.bindParams(stmt); - // REPLで実行するための文字列をREPLログに出力する - outputReplLog(executionContext); - debugWith(LOG) .setMessage("Execute update sql. sqlName: {}") .addArgument(executionContext.getSqlName()) @@ -2004,43 +1995,6 @@ private void handleException(final ExecutionContext executionContext, final SQLE throw cause; } - /** - * REPLでSQLを実行するためのコマンドをログとしてREPL_LOGに出力する. - * - * @param executionContext executionContext - */ - private void outputReplLog(final ExecutionContext executionContext) { - if (!(REPL_LOG.isInfoEnabled() && executionContext.getSqlName() != null && - (SqlKind.SELECT.equals(executionContext.getSqlKind()) || - SqlKind.UPDATE.equals(executionContext.getSqlKind())))) { - // REPLログ出力対象でない場合は何もしない - return; - } - - var builder = new StringBuilder(); - - if (SqlKind.SELECT.equals(executionContext.getSqlKind())) { - builder.append("query "); - } else { - builder.append("update "); - } - - builder.append(executionContext.getSqlName()); - - var params = new ArrayList(); - for (var bindName : executionContext.getBindNames()) { - params.add(executionContext.getParam(bindName)); - } - if (!params.isEmpty()) { - builder.append(" "); - builder.append(SqlParamUtils.formatPrams(params)); - } - infoWith(REPL_LOG) - .setMessage("REPL command: {}") - .addArgument(builder.toString()) - .log(); - } - /** * * {@inheritDoc} diff --git a/src/main/java/jp/co/future/uroborosql/event/subscriber/ReplCommandLogEventSubscriber.java b/src/main/java/jp/co/future/uroborosql/event/subscriber/ReplCommandLogEventSubscriber.java new file mode 100644 index 00000000..4ed46004 --- /dev/null +++ b/src/main/java/jp/co/future/uroborosql/event/subscriber/ReplCommandLogEventSubscriber.java @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2017-present, Future Corporation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package jp.co.future.uroborosql.event.subscriber; + +import java.util.stream.Collectors; + +import org.slf4j.Logger; + +import jp.co.future.uroborosql.client.SqlParamUtils; +import jp.co.future.uroborosql.context.ExecutionContext; +import jp.co.future.uroborosql.enums.SqlKind; +import jp.co.future.uroborosql.event.AfterSqlQueryEvent; +import jp.co.future.uroborosql.event.AfterSqlUpdateEvent; +import jp.co.future.uroborosql.log.support.EventLoggingSupport; + +/** + * SQL実行結果を再現するREPLコマンドのログを出力するEventSubscriber + * + * @author H.Sugimoto + * @since v1.0.0 + */ +public class ReplCommandLogEventSubscriber extends EventSubscriber implements EventLoggingSupport { + /** ロガー */ + private static final Logger EVENT_LOG = EventLoggingSupport.getEventLogger("replcommand"); + + @Override + public void initialize() { + afterSqlQueryListener(this::afterSqlQuery); + afterSqlUpdateListener(this::afterSqlUpdate); + } + + void afterSqlQuery(final AfterSqlQueryEvent evt) { + outputReplLog(evt.getExecutionContext()); + } + + void afterSqlUpdate(final AfterSqlUpdateEvent evt) { + outputReplLog(evt.getExecutionContext()); + } + + /** + * REPLでSQLを実行するためのコマンドをログとしてREPL_LOGに出力する. + * + * @param executionContext executionContext + */ + private void outputReplLog(final ExecutionContext executionContext) { + if (!EVENT_LOG.isInfoEnabled() || executionContext.getSqlName() == null + || (!SqlKind.SELECT.equals(executionContext.getSqlKind()) + && !SqlKind.UPDATE.equals(executionContext.getSqlKind()))) { + // REPLログ出力対象でない場合は何もしない + return; + } + + var builder = new StringBuilder(); + + if (SqlKind.SELECT.equals(executionContext.getSqlKind())) { + builder.append("query "); + } else { + builder.append("update "); + } + + builder.append(executionContext.getSqlName()); + + var params = executionContext.getBindNames().stream() + .map(bindName -> executionContext.getParam(bindName)) + .collect(Collectors.toList()); + if (!params.isEmpty()) { + builder.append(" "); + builder.append(SqlParamUtils.formatPrams(params)); + } + infoWith(EVENT_LOG) + .setMessage("REPL command: {}") + .addArgument(builder.toString()) + .log(); + } + +} \ No newline at end of file diff --git a/src/test/java/jp/co/future/uroborosql/event/subscriber/ReplCommandLogEventSubscriberTest.java b/src/test/java/jp/co/future/uroborosql/event/subscriber/ReplCommandLogEventSubscriberTest.java new file mode 100644 index 00000000..c80d58fb --- /dev/null +++ b/src/test/java/jp/co/future/uroborosql/event/subscriber/ReplCommandLogEventSubscriberTest.java @@ -0,0 +1,79 @@ +package jp.co.future.uroborosql.event.subscriber; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.io.IOException; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.sql.JDBCType; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import jp.co.future.uroborosql.AbstractDbTest; +import jp.co.future.uroborosql.testlog.TestAppender; + +public class ReplCommandLogEventSubscriberTest extends AbstractDbTest { + private ReplCommandLogEventSubscriber eventSubscriber; + + @BeforeEach + public void setUpLocal() throws SQLException, IOException { + eventSubscriber = new ReplCommandLogEventSubscriber(); + config.getEventListenerHolder().addEventSubscriber(eventSubscriber); + } + + @AfterEach + public void tearDownLocal() throws Exception { + config.getEventListenerHolder().removeEventSubscriber(eventSubscriber); + } + + @Test + void testExecuteQueryEvent() throws Exception { + cleanInsert(Paths.get("src/test/resources/data/setup", "testExecuteQuery.ltsv")); + + var log = TestAppender.getLogbackLogs(() -> { + var ctx = agent.context().setSqlName("example/select_product") + .param("product_id", new BigDecimal("0")) + .param("_userName", "testUserName") + .param("_funcId", "testFunction") + .setSqlId("111"); + ctx.setResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE); + + agent.query(ctx); + }); + + assertThat(log, + is(Files.readAllLines( + Paths.get("src/test/resources/data/expected/ReplCommandLogEventSubscriber", + "testExecuteQueryEvent.txt"), + StandardCharsets.UTF_8))); + } + + @Test + void testExecuteUpdateEvent() throws Exception { + cleanInsert(Paths.get("src/test/resources/data/setup", "testExecuteUpdate.ltsv")); + var log = TestAppender.getLogbackLogs(() -> { + var ctx = agent.context().setSqlName("example/selectinsert_product") + .setSqlId("222") + .param("_userName", "testUserName") + .param("_funcId", "testFunction") + .param("product_id", new BigDecimal("0"), JDBCType.DECIMAL) + .param("jan_code", "1234567890123", Types.CHAR); + agent.update(ctx); + }); + + assertThat(log, + is(Files.readAllLines( + Paths.get("src/test/resources/data/expected/ReplCommandLogEventSubscriber", + "testExecuteUpdateEvent.txt"), + StandardCharsets.UTF_8))); + } + +} diff --git a/src/test/resources/data/expected/ReplCommandLogEventSubscriber/testExecuteQueryEvent.txt b/src/test/resources/data/expected/ReplCommandLogEventSubscriber/testExecuteQueryEvent.txt new file mode 100644 index 00000000..65738bb6 --- /dev/null +++ b/src/test/resources/data/expected/ReplCommandLogEventSubscriber/testExecuteQueryEvent.txt @@ -0,0 +1 @@ +REPL command: query example/select_product product_id=0 \ No newline at end of file diff --git a/src/test/resources/data/expected/ReplCommandLogEventSubscriber/testExecuteUpdateEvent.txt b/src/test/resources/data/expected/ReplCommandLogEventSubscriber/testExecuteUpdateEvent.txt new file mode 100644 index 00000000..a3e0c44c --- /dev/null +++ b/src/test/resources/data/expected/ReplCommandLogEventSubscriber/testExecuteUpdateEvent.txt @@ -0,0 +1 @@ +REPL command: update example/selectinsert_product product_id=0 jan_code=1234567890123 \ No newline at end of file