diff --git a/spring-cloud-sleuth-api/src/main/java/org/springframework/cloud/sleuth/SpanAndScope.java b/spring-cloud-sleuth-api/src/main/java/org/springframework/cloud/sleuth/SpanAndScope.java index b61826426..d981cba7f 100644 --- a/spring-cloud-sleuth-api/src/main/java/org/springframework/cloud/sleuth/SpanAndScope.java +++ b/spring-cloud-sleuth-api/src/main/java/org/springframework/cloud/sleuth/SpanAndScope.java @@ -18,6 +18,9 @@ package org.springframework.cloud.sleuth; import java.io.Closeable; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + /** * Container object for {@link Span} and its corresponding {@link Tracer.SpanInScope}. * @@ -26,6 +29,8 @@ import java.io.Closeable; */ public class SpanAndScope implements Closeable { + private static final Log log = LogFactory.getLog(SpanAndScope.class); + private final Span span; private final Tracer.SpanInScope scope; @@ -50,6 +55,9 @@ public class SpanAndScope implements Closeable { @Override public void close() { + if (log.isTraceEnabled()) { + log.trace("Closing span [" + this.span + "]"); + } this.scope.close(); this.span.end(); } diff --git a/spring-cloud-sleuth-api/src/main/java/org/springframework/cloud/sleuth/docs/AssertingSpanBuilder.java b/spring-cloud-sleuth-api/src/main/java/org/springframework/cloud/sleuth/docs/AssertingSpanBuilder.java index 3ba8e793c..0363928d2 100644 --- a/spring-cloud-sleuth-api/src/main/java/org/springframework/cloud/sleuth/docs/AssertingSpanBuilder.java +++ b/spring-cloud-sleuth-api/src/main/java/org/springframework/cloud/sleuth/docs/AssertingSpanBuilder.java @@ -130,6 +130,11 @@ public interface AssertingSpanBuilder extends Span.Builder { public boolean isStarted() { return true; } + + @Override + public String toString() { + return getDelegate().toString(); + } }; } diff --git a/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/P6SpyConfigurationTests.java b/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/P6SpyConfigurationTests.java index d790fa2f0..c626017e4 100644 --- a/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/P6SpyConfigurationTests.java +++ b/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/P6SpyConfigurationTests.java @@ -1,277 +1,281 @@ -/* - * Copyright 2013-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * 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 org.springframework.cloud.sleuth.autoconfig.instrument.jdbc; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; - -import javax.sql.DataSource; - -import com.p6spy.engine.common.ConnectionInformation; -import com.p6spy.engine.common.P6LogQuery; -import com.p6spy.engine.event.CompoundJdbcEventListener; -import com.p6spy.engine.event.JdbcEventListener; -import com.p6spy.engine.logging.Category; -import com.p6spy.engine.logging.LoggingEventListener; -import com.p6spy.engine.spy.JdbcEventListenerFactory; -import com.p6spy.engine.spy.P6DataSource; -import com.p6spy.engine.spy.appender.CustomLineFormat; -import com.p6spy.engine.spy.appender.FormattedLogger; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.test.context.FilteredClassLoader; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration; -import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceWrapper; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import static org.assertj.core.api.Assertions.assertThat; - -class P6SpyConfigurationTests { - - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, - TraceDataSourceDecoratorAutoConfiguration.class, BraveAutoConfiguration.class, - TestSpanHandlerConfiguration.class, PropertyPlaceholderAutoConfiguration.class)) - .withPropertyValues("spring.datasource.initialization-mode=never", - "spring.datasource.url:jdbc:h2:mem:testdb-" + ThreadLocalRandom.current().nextInt()) - .withClassLoader(new FilteredClassLoader("net.ttddyy.dsproxy")); - - @BeforeEach - @AfterEach - void resetLogAccumulator() { - LogAccumulator.reset(); - } - - @Test - void testCustomListeners() { - ApplicationContextRunner contextRunner = this.contextRunner - .withUserConfiguration(CustomListenerConfiguration.class); - - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - JdbcEventListenerFactory jdbcEventListenerFactory = context.getBean(JdbcEventListenerFactory.class); - GetCountingListener getCountingListener = context.getBean(GetCountingListener.class); - ClosingCountingListener closingCountingListener = context.getBean(ClosingCountingListener.class); - P6DataSource p6DataSource = (P6DataSource) ((DataSourceWrapper) dataSource).getDecoratedDataSource(); - assertThat(p6DataSource).extracting("jdbcEventListenerFactory").isEqualTo(jdbcEventListenerFactory); - - CompoundJdbcEventListener jdbcEventListener = (CompoundJdbcEventListener) jdbcEventListenerFactory - .createJdbcEventListener(); - - assertThat(jdbcEventListener.getEventListeners()).contains(getCountingListener, closingCountingListener); - assertThat(getCountingListener.connectionCount).isEqualTo(0); - - Connection connection1 = p6DataSource.getConnection(); - - assertThat(getCountingListener.connectionCount).isEqualTo(1); - assertThat(closingCountingListener.connectionCount).isEqualTo(0); - - Connection connection2 = p6DataSource.getConnection(); - - assertThat(getCountingListener.connectionCount).isEqualTo(2); - - connection1.close(); - - assertThat(closingCountingListener.connectionCount).isEqualTo(1); - - connection2.close(); - - assertThat(closingCountingListener.connectionCount).isEqualTo(2); - }); - } - - @Test - void testDoesNotRegisterLoggingListenerIfDisabled() { - ApplicationContextRunner contextRunner = this.contextRunner - .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.p6spy.enable-logging:false"); - - contextRunner.run(context -> { - JdbcEventListenerFactory jdbcEventListenerFactory = context.getBean(JdbcEventListenerFactory.class); - CompoundJdbcEventListener jdbcEventListener = (CompoundJdbcEventListener) jdbcEventListenerFactory - .createJdbcEventListener(); - - assertThat(jdbcEventListener.getEventListeners()).extracting("class") - .doesNotContain(LoggingEventListener.class); - }); - } - - @Test - void testCanSetCustomLoggingFormat() { - ApplicationContextRunner contextRunner = this.contextRunner - .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.p6spy.log-format:test %{connectionId}"); - - contextRunner.run(context -> { - JdbcEventListenerFactory jdbcEventListenerFactory = context.getBean(JdbcEventListenerFactory.class); - CompoundJdbcEventListener jdbcEventListener = (CompoundJdbcEventListener) jdbcEventListenerFactory - .createJdbcEventListener(); - - assertThat(jdbcEventListener.getEventListeners()).extracting("class").contains(LoggingEventListener.class); - assertThat(P6LogQuery.getLogger()).extracting("strategy").extracting("class") - .isEqualTo(CustomLineFormat.class); - }); - } - - @Test - void testMultilineShouldNotOverrideCustomProperties() { - System.setProperty("p6spy.config.logMessageFormat", "com.p6spy.engine.spy.appender.CustomLineFormat"); - System.setProperty("p6spy.config.excludecategories", "debug"); - ApplicationContextRunner contextRunner = this.contextRunner - .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.p6spy.multiline:true"); - - contextRunner.run(context -> { - JdbcEventListenerFactory jdbcEventListenerFactory = context.getBean(JdbcEventListenerFactory.class); - CompoundJdbcEventListener jdbcEventListener = (CompoundJdbcEventListener) jdbcEventListenerFactory - .createJdbcEventListener(); - - assertThat(jdbcEventListener.getEventListeners()).extracting("class").contains(LoggingEventListener.class); - assertThat(P6LogQuery.getLogger()).extracting("strategy").extracting("class") - .isEqualTo(CustomLineFormat.class); - }); - } - - @Test - void testUseCustomLogger() { - ApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues( - "spring.sleuth.jdbc.decorator.datasource.p6spy.logging:custom", - "spring.sleuth.jdbc.decorator.datasource.p6spy.custom-appender-class:" - + LogAccumulator.class.getName()); - - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - dataSource.getConnection().close(); - - assertThat(P6LogQuery.getLogger()).isInstanceOf(LogAccumulator.class); - }); - } - - @Test - void testLogFilterPattern() { - ApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues( - "spring.sleuth.jdbc.decorator.datasource.p6spy.logging:custom", - "spring.sleuth.jdbc.decorator.datasource.p6spy.custom-appender-class:" + LogAccumulator.class.getName(), - "spring.sleuth.jdbc.decorator.datasource.p6spy.log-filter.pattern:.*table1.*"); - - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - try (Connection connection = dataSource.getConnection(); - PreparedStatement ps1 = connection.prepareStatement("select 1 /* from table1 */"); - PreparedStatement ps2 = connection.prepareStatement("select 1 /* from table2 */")) { - ps1.execute(); - ps2.execute(); - } - - assertThat(LogAccumulator.MESSAGES).hasSize(1); - assertThat(LogAccumulator.MESSAGES).allMatch(message -> message.contains("table1")); - }); - } - - @Test - void testLogFilterPatternMatchAll() { - ApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues( - "spring.sleuth.jdbc.decorator.datasource.p6spy.logging:custom", - "spring.sleuth.jdbc.decorator.datasource.p6spy.custom-appender-class:" + LogAccumulator.class.getName(), - "spring.sleuth.jdbc.decorator.datasource.p6spy.log-filter.pattern:.*"); - - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - try (Connection connection = dataSource.getConnection(); - PreparedStatement ps1 = connection.prepareStatement("select 1 /* from table1 */"); - PreparedStatement ps2 = connection.prepareStatement("select 1 /* from table2 */")) { - ps1.execute(); - ps2.execute(); - } - - assertThat(LogAccumulator.MESSAGES).hasSize(2); - }); - } - - @Configuration - static class CustomListenerConfiguration { - - @Bean - public GetCountingListener wrappingCountingListener() { - return new GetCountingListener(); - } - - @Bean - public ClosingCountingListener closingCountingListener() { - return new ClosingCountingListener(); - } - - } - - static class GetCountingListener extends JdbcEventListener { - - int connectionCount = 0; - - @Override - public void onAfterGetConnection(ConnectionInformation connectionInformation, SQLException e) { - connectionCount++; - } - - } - - static class ClosingCountingListener extends JdbcEventListener { - - int connectionCount = 0; - - @Override - public void onAfterConnectionClose(ConnectionInformation connectionInformation, SQLException e) { - connectionCount++; - } - - } - - public static class LogAccumulator extends FormattedLogger { - - static final List MESSAGES = new ArrayList<>(); - static final List EXCEPTIONS = new ArrayList<>(); - - public static void reset() { - MESSAGES.clear(); - EXCEPTIONS.clear(); - } - - @Override - public void logException(Exception e) { - EXCEPTIONS.add(e); - } - - @Override - public void logText(String text) { - MESSAGES.add(text); - } - - @Override - public boolean isCategoryEnabled(Category category) { - return true; - } - - } - -} +/* + * Copyright 2013-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * 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 org.springframework.cloud.sleuth.autoconfig.instrument.jdbc; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +import javax.sql.DataSource; + +import com.p6spy.engine.common.ConnectionInformation; +import com.p6spy.engine.common.P6LogQuery; +import com.p6spy.engine.event.CompoundJdbcEventListener; +import com.p6spy.engine.event.JdbcEventListener; +import com.p6spy.engine.logging.Category; +import com.p6spy.engine.logging.LoggingEventListener; +import com.p6spy.engine.spy.JdbcEventListenerFactory; +import com.p6spy.engine.spy.P6DataSource; +import com.p6spy.engine.spy.appender.CustomLineFormat; +import com.p6spy.engine.spy.appender.FormattedLogger; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.sleuth.Tracer; +import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration; +import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceWrapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +class P6SpyConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + TraceDataSourceDecoratorAutoConfiguration.class, BraveAutoConfiguration.class, + TestSpanHandlerConfiguration.class, PropertyPlaceholderAutoConfiguration.class)) + .withPropertyValues("spring.datasource.initialization-mode=never", + "spring.datasource.url:jdbc:h2:mem:testdb-" + ThreadLocalRandom.current().nextInt()) + .withClassLoader(new FilteredClassLoader("net.ttddyy.dsproxy")); + + @BeforeEach + @AfterEach + void resetLogAccumulator() { + LogAccumulator.reset(); + } + + @Test + void testCustomListeners() { + ApplicationContextRunner contextRunner = this.contextRunner + .withUserConfiguration(CustomListenerConfiguration.class); + + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + JdbcEventListenerFactory jdbcEventListenerFactory = context.getBean(JdbcEventListenerFactory.class); + GetCountingListener getCountingListener = context.getBean(GetCountingListener.class); + ClosingCountingListener closingCountingListener = context.getBean(ClosingCountingListener.class); + P6DataSource p6DataSource = (P6DataSource) ((DataSourceWrapper) dataSource).getDecoratedDataSource(); + assertThat(p6DataSource).extracting("jdbcEventListenerFactory").isEqualTo(jdbcEventListenerFactory); + + CompoundJdbcEventListener jdbcEventListener = (CompoundJdbcEventListener) jdbcEventListenerFactory + .createJdbcEventListener(); + + assertThat(jdbcEventListener.getEventListeners()).contains(getCountingListener, closingCountingListener); + assertThat(getCountingListener.connectionCount).isEqualTo(0); + + Connection connection1 = p6DataSource.getConnection(); + + assertThat(getCountingListener.connectionCount).isEqualTo(1); + assertThat(closingCountingListener.connectionCount).isEqualTo(0); + + Connection connection2 = p6DataSource.getConnection(); + + assertThat(getCountingListener.connectionCount).isEqualTo(2); + + // order matters! + connection2.close(); + + assertThat(closingCountingListener.connectionCount).isEqualTo(1); + + // order matters! + connection1.close(); + + assertThat(closingCountingListener.connectionCount).isEqualTo(2); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); + }); + } + + @Test + void testDoesNotRegisterLoggingListenerIfDisabled() { + ApplicationContextRunner contextRunner = this.contextRunner + .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.p6spy.enable-logging:false"); + + contextRunner.run(context -> { + JdbcEventListenerFactory jdbcEventListenerFactory = context.getBean(JdbcEventListenerFactory.class); + CompoundJdbcEventListener jdbcEventListener = (CompoundJdbcEventListener) jdbcEventListenerFactory + .createJdbcEventListener(); + + assertThat(jdbcEventListener.getEventListeners()).extracting("class") + .doesNotContain(LoggingEventListener.class); + }); + } + + @Test + void testCanSetCustomLoggingFormat() { + ApplicationContextRunner contextRunner = this.contextRunner + .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.p6spy.log-format:test %{connectionId}"); + + contextRunner.run(context -> { + JdbcEventListenerFactory jdbcEventListenerFactory = context.getBean(JdbcEventListenerFactory.class); + CompoundJdbcEventListener jdbcEventListener = (CompoundJdbcEventListener) jdbcEventListenerFactory + .createJdbcEventListener(); + + assertThat(jdbcEventListener.getEventListeners()).extracting("class").contains(LoggingEventListener.class); + assertThat(P6LogQuery.getLogger()).extracting("strategy").extracting("class") + .isEqualTo(CustomLineFormat.class); + }); + } + + @Test + void testMultilineShouldNotOverrideCustomProperties() { + System.setProperty("p6spy.config.logMessageFormat", "com.p6spy.engine.spy.appender.CustomLineFormat"); + System.setProperty("p6spy.config.excludecategories", "debug"); + ApplicationContextRunner contextRunner = this.contextRunner + .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.p6spy.multiline:true"); + + contextRunner.run(context -> { + JdbcEventListenerFactory jdbcEventListenerFactory = context.getBean(JdbcEventListenerFactory.class); + CompoundJdbcEventListener jdbcEventListener = (CompoundJdbcEventListener) jdbcEventListenerFactory + .createJdbcEventListener(); + + assertThat(jdbcEventListener.getEventListeners()).extracting("class").contains(LoggingEventListener.class); + assertThat(P6LogQuery.getLogger()).extracting("strategy").extracting("class") + .isEqualTo(CustomLineFormat.class); + }); + } + + @Test + void testUseCustomLogger() { + ApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues( + "spring.sleuth.jdbc.decorator.datasource.p6spy.logging:custom", + "spring.sleuth.jdbc.decorator.datasource.p6spy.custom-appender-class:" + + LogAccumulator.class.getName()); + + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + dataSource.getConnection().close(); + + assertThat(P6LogQuery.getLogger()).isInstanceOf(LogAccumulator.class); + }); + } + + @Test + void testLogFilterPattern() { + ApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues( + "spring.sleuth.jdbc.decorator.datasource.p6spy.logging:custom", + "spring.sleuth.jdbc.decorator.datasource.p6spy.custom-appender-class:" + LogAccumulator.class.getName(), + "spring.sleuth.jdbc.decorator.datasource.p6spy.log-filter.pattern:.*table1.*"); + + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + try (Connection connection = dataSource.getConnection(); + PreparedStatement ps1 = connection.prepareStatement("select 1 /* from table1 */"); + PreparedStatement ps2 = connection.prepareStatement("select 1 /* from table2 */")) { + ps1.execute(); + ps2.execute(); + } + + assertThat(LogAccumulator.MESSAGES).hasSize(1); + assertThat(LogAccumulator.MESSAGES).allMatch(message -> message.contains("table1")); + }); + } + + @Test + void testLogFilterPatternMatchAll() { + ApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues( + "spring.sleuth.jdbc.decorator.datasource.p6spy.logging:custom", + "spring.sleuth.jdbc.decorator.datasource.p6spy.custom-appender-class:" + LogAccumulator.class.getName(), + "spring.sleuth.jdbc.decorator.datasource.p6spy.log-filter.pattern:.*"); + + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + try (Connection connection = dataSource.getConnection(); + PreparedStatement ps1 = connection.prepareStatement("select 1 /* from table1 */"); + PreparedStatement ps2 = connection.prepareStatement("select 1 /* from table2 */")) { + ps1.execute(); + ps2.execute(); + } + + assertThat(LogAccumulator.MESSAGES).hasSize(2); + }); + } + + @Configuration + static class CustomListenerConfiguration { + + @Bean + public GetCountingListener wrappingCountingListener() { + return new GetCountingListener(); + } + + @Bean + public ClosingCountingListener closingCountingListener() { + return new ClosingCountingListener(); + } + + } + + static class GetCountingListener extends JdbcEventListener { + + int connectionCount = 0; + + @Override + public void onAfterGetConnection(ConnectionInformation connectionInformation, SQLException e) { + connectionCount++; + } + + } + + static class ClosingCountingListener extends JdbcEventListener { + + int connectionCount = 0; + + @Override + public void onAfterConnectionClose(ConnectionInformation connectionInformation, SQLException e) { + connectionCount++; + } + + } + + public static class LogAccumulator extends FormattedLogger { + + static final List MESSAGES = new ArrayList<>(); + static final List EXCEPTIONS = new ArrayList<>(); + + public static void reset() { + MESSAGES.clear(); + EXCEPTIONS.clear(); + } + + @Override + public void logException(Exception e) { + EXCEPTIONS.add(e); + } + + @Override + public void logText(String text) { + MESSAGES.add(text); + } + + @Override + public boolean isCategoryEnabled(Category category) { + return true; + } + + } + +} diff --git a/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/ProxyDataSourceConfigurationTests.java b/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/ProxyDataSourceConfigurationTests.java index d9103ae27..898a0de7a 100644 --- a/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/ProxyDataSourceConfigurationTests.java +++ b/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/ProxyDataSourceConfigurationTests.java @@ -1,238 +1,246 @@ -/* - * Copyright 2013-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * 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 org.springframework.cloud.sleuth.autoconfig.instrument.jdbc; - -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; - -import javax.sql.DataSource; - -import net.ttddyy.dsproxy.ExecutionInfo; -import net.ttddyy.dsproxy.QueryInfo; -import net.ttddyy.dsproxy.listener.ChainListener; -import net.ttddyy.dsproxy.listener.QueryExecutionListener; -import net.ttddyy.dsproxy.listener.logging.CommonsQueryLoggingListener; -import net.ttddyy.dsproxy.listener.logging.CommonsSlowQueryListener; -import net.ttddyy.dsproxy.listener.logging.JULQueryLoggingListener; -import net.ttddyy.dsproxy.listener.logging.JULSlowQueryListener; -import net.ttddyy.dsproxy.listener.logging.SLF4JQueryLoggingListener; -import net.ttddyy.dsproxy.listener.logging.SLF4JSlowQueryListener; -import net.ttddyy.dsproxy.listener.logging.SystemOutQueryLoggingListener; -import net.ttddyy.dsproxy.listener.logging.SystemOutSlowQueryListener; -import net.ttddyy.dsproxy.proxy.DefaultConnectionIdManager; -import net.ttddyy.dsproxy.proxy.GlobalConnectionIdManager; -import net.ttddyy.dsproxy.support.ProxyDataSource; -import net.ttddyy.dsproxy.transform.ParameterTransformer; -import net.ttddyy.dsproxy.transform.QueryTransformer; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.test.context.FilteredClassLoader; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration; -import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceProxyConnectionIdManagerProvider; -import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceWrapper; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; - -import static org.assertj.core.api.Assertions.assertThat; - -class ProxyDataSourceConfigurationTests { - - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, - TraceDataSourceDecoratorAutoConfiguration.class, BraveAutoConfiguration.class, - TestSpanHandlerConfiguration.class, PropertyPlaceholderAutoConfiguration.class)) - .withPropertyValues("spring.datasource.initialization-mode=never", - "spring.datasource.url:jdbc:h2:mem:testdb-" + ThreadLocalRandom.current().nextInt()) - .withClassLoader(new FilteredClassLoader("com.p6spy")); - - @Test - void testRegisterLogAndSlowQueryLogByDefaultToSlf4j() { - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) - .getDecoratedDataSource(); - ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); - assertThat(chainListener.getListeners()).extracting("class").contains(SLF4JSlowQueryListener.class); - assertThat(chainListener.getListeners()).extracting("class").contains(SLF4JQueryLoggingListener.class); - }); - } - - @Test - void testRegisterLogAndSlowQueryLogByUsingSlf4j() { - ApplicationContextRunner contextRunner = this.contextRunner - .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.datasource-proxy.logging:slf4j"); - - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) - .getDecoratedDataSource(); - ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); - assertThat(chainListener.getListeners()).extracting("class").contains(SLF4JSlowQueryListener.class); - assertThat(chainListener.getListeners()).extracting("class").contains(SLF4JQueryLoggingListener.class); - }); - } - - @Test - void testRegisterLogAndSlowQueryLogUsingSystemOut() { - ApplicationContextRunner contextRunner = this.contextRunner - .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.datasource-proxy.logging:sysout"); - - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) - .getDecoratedDataSource(); - ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); - assertThat(chainListener.getListeners()).extracting("class").contains(SystemOutSlowQueryListener.class); - assertThat(chainListener.getListeners()).extracting("class").contains(SystemOutQueryLoggingListener.class); - }); - } - - @Test - void testRegisterLogAndSlowQueryLogUsingJUL() { - ApplicationContextRunner contextRunner = this.contextRunner - .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.datasourceProxy.logging:jul"); - - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) - .getDecoratedDataSource(); - ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); - assertThat(chainListener.getListeners()).extracting("class").contains(JULSlowQueryListener.class); - assertThat(chainListener.getListeners()).extracting("class").contains(JULQueryLoggingListener.class); - }); - } - - @Test - void testRegisterLogAndSlowQueryLogUsingApacheCommons() { - ApplicationContextRunner contextRunner = this.contextRunner - .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.datasourceProxy.logging:commons"); - - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) - .getDecoratedDataSource(); - ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); - assertThat(chainListener.getListeners()).extracting("class").contains(CommonsSlowQueryListener.class); - assertThat(chainListener.getListeners()).extracting("class").contains(CommonsQueryLoggingListener.class); - }); - } - - @Test - void testCustomParameterAndQueryTransformer() { - ApplicationContextRunner contextRunner = this.contextRunner - .withUserConfiguration(CustomDataSourceProxyConfiguration.class); - - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) - .getDecoratedDataSource(); - ParameterTransformer parameterTransformer = context.getBean(ParameterTransformer.class); - QueryTransformer queryTransformer = context.getBean(QueryTransformer.class); - assertThat(proxyDataSource.getProxyConfig().getParameterTransformer()).isSameAs(parameterTransformer); - assertThat(proxyDataSource.getProxyConfig().getQueryTransformer()).isSameAs(queryTransformer); - }); - } - - @Test - void testCustomListeners() { - ApplicationContextRunner contextRunner = this.contextRunner - .withUserConfiguration(CustomListenerConfiguration.class); - - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) - .getDecoratedDataSource(); - QueryExecutionListener queryExecutionListener = context.getBean(QueryExecutionListener.class); - - ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); - assertThat(chainListener.getListeners()).contains(queryExecutionListener); - }); - } - - @Test - void testGlobalConnectionIdManagerByDefault() { - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) - .getDecoratedDataSource(); - - assertThat(proxyDataSource.getConnectionIdManager()).isInstanceOf(GlobalConnectionIdManager.class); - }); - } - - @Test - void testCustomConnectionIdManager() { - ApplicationContextRunner contextRunner = this.contextRunner - .withUserConfiguration(CustomDataSourceProxyConfiguration.class); - - contextRunner.run(context -> { - DataSource dataSource = context.getBean(DataSource.class); - ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) - .getDecoratedDataSource(); - - assertThat(proxyDataSource.getConnectionIdManager()).isInstanceOf(DefaultConnectionIdManager.class); - }); - } - - @Configuration - static class CustomDataSourceProxyConfiguration { - - @Bean - public ParameterTransformer parameterTransformer() { - return (replacer, transformInfo) -> { - }; - } - - @Bean - public QueryTransformer queryTransformer() { - return (transformInfo) -> "TestQuery"; - } - - @Bean - public DataSourceProxyConnectionIdManagerProvider connectionIdManagerProvider() { - return DefaultConnectionIdManager::new; - } - - } - - @Configuration - static class CustomListenerConfiguration { - - @Bean - @Primary - public QueryExecutionListener queryExecutionListener() { - return new QueryExecutionListener() { - @Override - public void beforeQuery(ExecutionInfo execInfo, List queryInfoList) { - System.out.println("beforeQuery"); - } - - @Override - public void afterQuery(ExecutionInfo execInfo, List queryInfoList) { - System.out.println("afterQuery"); - } - }; - } - - } - -} +/* + * Copyright 2013-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * 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 org.springframework.cloud.sleuth.autoconfig.instrument.jdbc; + +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +import javax.sql.DataSource; + +import net.ttddyy.dsproxy.ExecutionInfo; +import net.ttddyy.dsproxy.QueryInfo; +import net.ttddyy.dsproxy.listener.ChainListener; +import net.ttddyy.dsproxy.listener.QueryExecutionListener; +import net.ttddyy.dsproxy.listener.logging.CommonsQueryLoggingListener; +import net.ttddyy.dsproxy.listener.logging.CommonsSlowQueryListener; +import net.ttddyy.dsproxy.listener.logging.JULQueryLoggingListener; +import net.ttddyy.dsproxy.listener.logging.JULSlowQueryListener; +import net.ttddyy.dsproxy.listener.logging.SLF4JQueryLoggingListener; +import net.ttddyy.dsproxy.listener.logging.SLF4JSlowQueryListener; +import net.ttddyy.dsproxy.listener.logging.SystemOutQueryLoggingListener; +import net.ttddyy.dsproxy.listener.logging.SystemOutSlowQueryListener; +import net.ttddyy.dsproxy.proxy.DefaultConnectionIdManager; +import net.ttddyy.dsproxy.proxy.GlobalConnectionIdManager; +import net.ttddyy.dsproxy.support.ProxyDataSource; +import net.ttddyy.dsproxy.transform.ParameterTransformer; +import net.ttddyy.dsproxy.transform.QueryTransformer; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.sleuth.Tracer; +import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration; +import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceProxyConnectionIdManagerProvider; +import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceWrapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +import static org.assertj.core.api.Assertions.assertThat; + +class ProxyDataSourceConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + TraceDataSourceDecoratorAutoConfiguration.class, BraveAutoConfiguration.class, + TestSpanHandlerConfiguration.class, PropertyPlaceholderAutoConfiguration.class)) + .withPropertyValues("spring.datasource.initialization-mode=never", + "spring.datasource.url:jdbc:h2:mem:testdb-" + ThreadLocalRandom.current().nextInt()) + .withClassLoader(new FilteredClassLoader("com.p6spy")); + + @Test + void testRegisterLogAndSlowQueryLogByDefaultToSlf4j() { + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) + .getDecoratedDataSource(); + ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); + assertThat(chainListener.getListeners()).extracting("class").contains(SLF4JSlowQueryListener.class); + assertThat(chainListener.getListeners()).extracting("class").contains(SLF4JQueryLoggingListener.class); + }); + } + + @Test + void testRegisterLogAndSlowQueryLogByUsingSlf4j() { + ApplicationContextRunner contextRunner = this.contextRunner + .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.datasource-proxy.logging:slf4j"); + + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) + .getDecoratedDataSource(); + ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); + assertThat(chainListener.getListeners()).extracting("class").contains(SLF4JSlowQueryListener.class); + assertThat(chainListener.getListeners()).extracting("class").contains(SLF4JQueryLoggingListener.class); + }); + } + + @Test + void testRegisterLogAndSlowQueryLogUsingSystemOut() { + ApplicationContextRunner contextRunner = this.contextRunner + .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.datasource-proxy.logging:sysout"); + + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) + .getDecoratedDataSource(); + ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); + assertThat(chainListener.getListeners()).extracting("class").contains(SystemOutSlowQueryListener.class); + assertThat(chainListener.getListeners()).extracting("class").contains(SystemOutQueryLoggingListener.class); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); + }); + } + + @Test + void testRegisterLogAndSlowQueryLogUsingJUL() { + ApplicationContextRunner contextRunner = this.contextRunner + .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.datasourceProxy.logging:jul"); + + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) + .getDecoratedDataSource(); + ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); + assertThat(chainListener.getListeners()).extracting("class").contains(JULSlowQueryListener.class); + assertThat(chainListener.getListeners()).extracting("class").contains(JULQueryLoggingListener.class); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); + }); + } + + @Test + void testRegisterLogAndSlowQueryLogUsingApacheCommons() { + ApplicationContextRunner contextRunner = this.contextRunner + .withPropertyValues("spring.sleuth.jdbc.decorator.datasource.datasourceProxy.logging:commons"); + + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) + .getDecoratedDataSource(); + ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); + assertThat(chainListener.getListeners()).extracting("class").contains(CommonsSlowQueryListener.class); + assertThat(chainListener.getListeners()).extracting("class").contains(CommonsQueryLoggingListener.class); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); + }); + } + + @Test + void testCustomParameterAndQueryTransformer() { + ApplicationContextRunner contextRunner = this.contextRunner + .withUserConfiguration(CustomDataSourceProxyConfiguration.class); + + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) + .getDecoratedDataSource(); + ParameterTransformer parameterTransformer = context.getBean(ParameterTransformer.class); + QueryTransformer queryTransformer = context.getBean(QueryTransformer.class); + assertThat(proxyDataSource.getProxyConfig().getParameterTransformer()).isSameAs(parameterTransformer); + assertThat(proxyDataSource.getProxyConfig().getQueryTransformer()).isSameAs(queryTransformer); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); + }); + } + + @Test + void testCustomListeners() { + ApplicationContextRunner contextRunner = this.contextRunner + .withUserConfiguration(CustomListenerConfiguration.class); + + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) + .getDecoratedDataSource(); + QueryExecutionListener queryExecutionListener = context.getBean(QueryExecutionListener.class); + + ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); + assertThat(chainListener.getListeners()).contains(queryExecutionListener); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); + }); + } + + @Test + void testGlobalConnectionIdManagerByDefault() { + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) + .getDecoratedDataSource(); + + assertThat(proxyDataSource.getConnectionIdManager()).isInstanceOf(GlobalConnectionIdManager.class); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); + }); + } + + @Test + void testCustomConnectionIdManager() { + ApplicationContextRunner contextRunner = this.contextRunner + .withUserConfiguration(CustomDataSourceProxyConfiguration.class); + + contextRunner.run(context -> { + DataSource dataSource = context.getBean(DataSource.class); + ProxyDataSource proxyDataSource = (ProxyDataSource) ((DataSourceWrapper) dataSource) + .getDecoratedDataSource(); + + assertThat(proxyDataSource.getConnectionIdManager()).isInstanceOf(DefaultConnectionIdManager.class); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); + }); + } + + @Configuration + static class CustomDataSourceProxyConfiguration { + + @Bean + public ParameterTransformer parameterTransformer() { + return (replacer, transformInfo) -> { + }; + } + + @Bean + public QueryTransformer queryTransformer() { + return (transformInfo) -> "TestQuery"; + } + + @Bean + public DataSourceProxyConnectionIdManagerProvider connectionIdManagerProvider() { + return DefaultConnectionIdManager::new; + } + + } + + @Configuration + static class CustomListenerConfiguration { + + @Bean + @Primary + public QueryExecutionListener queryExecutionListener() { + return new QueryExecutionListener() { + @Override + public void beforeQuery(ExecutionInfo execInfo, List queryInfoList) { + System.out.println("beforeQuery"); + } + + @Override + public void afterQuery(ExecutionInfo execInfo, List queryInfoList) { + System.out.println("afterQuery"); + } + }; + } + + } + +} diff --git a/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/SleuthP6SpyListenerAutoConfigurationTests.java b/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/SleuthP6SpyListenerAutoConfigurationTests.java index 8255031a5..5a9af8e3f 100644 --- a/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/SleuthP6SpyListenerAutoConfigurationTests.java +++ b/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/SleuthP6SpyListenerAutoConfigurationTests.java @@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoCon import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.sleuth.Tracer; import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration; import org.springframework.cloud.sleuth.instrument.jdbc.TraceJdbcEventListener; @@ -50,6 +51,7 @@ class SleuthP6SpyListenerAutoConfigurationTests { .createJdbcEventListener(); assertThat(jdbcEventListener.getEventListeners()).extracting("class") .contains(TraceJdbcEventListener.class); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } diff --git a/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/SleuthProxyDataSourceListenerAutoConfigurationTests.java b/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/SleuthProxyDataSourceListenerAutoConfigurationTests.java index 9b190eb57..f359bd951 100644 --- a/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/SleuthProxyDataSourceListenerAutoConfigurationTests.java +++ b/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/SleuthProxyDataSourceListenerAutoConfigurationTests.java @@ -29,6 +29,7 @@ import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoCon import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.sleuth.Tracer; import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration; import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceWrapper; import org.springframework.cloud.sleuth.instrument.jdbc.TraceQueryExecutionListener; @@ -53,6 +54,7 @@ class SleuthProxyDataSourceListenerAutoConfigurationTests { .getDecoratedDataSource(); ChainListener chainListener = proxyDataSource.getProxyConfig().getQueryListener(); assertThat(chainListener.getListeners()).extracting("class").contains(TraceQueryExecutionListener.class); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } diff --git a/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/TracingJdbcEventListenerTests.java b/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/TracingJdbcEventListenerTests.java index 6a7c231eb..446a620e7 100644 --- a/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/TracingJdbcEventListenerTests.java +++ b/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/TracingJdbcEventListenerTests.java @@ -36,22 +36,16 @@ import static org.assertj.core.api.Assertions.assertThat; class TracingJdbcEventListenerTests extends TracingListenerStrategyTests { - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + private static final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, TraceDataSourceDecoratorAutoConfiguration.class, BraveAutoConfiguration.class, TestSpanHandlerConfiguration.class, PropertyPlaceholderAutoConfiguration.class)) .withPropertyValues("spring.datasource.initialization-mode=never", - "spring.datasource.url:jdbc:h2:mem:testdb-baz", "spring.datasource.hikari.pool-name=test") + "spring.datasource.url=jdbc:h2:mem:testdb-baz", "spring.datasource.hikari.pool-name=test") .withClassLoader(new FilteredClassLoader("net.ttddyy.dsproxy")); protected TracingJdbcEventListenerTests() { - super(new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, - TraceDataSourceDecoratorAutoConfiguration.class, BraveAutoConfiguration.class, - TestSpanHandlerConfiguration.class, PropertyPlaceholderAutoConfiguration.class)) - .withPropertyValues("spring.datasource.initialization-mode=never", - "spring.datasource.url:jdbc:h2:mem:testdb-baz", "spring.datasource.hikari.pool-name=test") - .withClassLoader(new FilteredClassLoader("net.ttddyy.dsproxy"))); + super(contextRunner); } @Test diff --git a/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/TracingListenerStrategyTests.java b/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/TracingListenerStrategyTests.java index a33d0ec90..604eee779 100644 --- a/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/TracingListenerStrategyTests.java +++ b/spring-cloud-sleuth-autoconfigure/src/test/java/org/springframework/cloud/sleuth/autoconfig/instrument/jdbc/TracingListenerStrategyTests.java @@ -35,6 +35,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.sleuth.Tracer; import org.springframework.cloud.sleuth.instrument.jdbc.TraceJdbcEventListener; import org.springframework.cloud.sleuth.instrument.jdbc.TraceQueryExecutionListener; import org.springframework.context.annotation.Bean; @@ -71,6 +72,7 @@ abstract class TracingListenerStrategyTests { assertThat(connectionSpan.remoteServiceName()).isEqualTo("TESTDB-BAZ"); assertThat(connectionSpan.annotations()).extracting("value").contains("jdbc.commit"); assertThat(connectionSpan.annotations()).extracting("value").contains("jdbc.rollback"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -92,6 +94,7 @@ abstract class TracingListenerStrategyTests { assertThat(connectionSpan.remoteServiceName()).isEqualTo("aaaabbbb"); assertThat(connectionSpan.annotations()).extracting("value").contains("jdbc.commit"); assertThat(connectionSpan.annotations()).extracting("value").contains("jdbc.rollback"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -112,6 +115,7 @@ abstract class TracingListenerStrategyTests { assertThat(statementSpan.name()).isEqualTo("select"); assertThat(statementSpan.remoteServiceName()).isEqualTo("TESTDB-BAZ"); assertThat(statementSpan.tags()).containsEntry(SPAN_SQL_QUERY_TAG_NAME, "SELECT NOW()"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -134,6 +138,7 @@ abstract class TracingListenerStrategyTests { assertThat(statementSpan.tags()).containsEntry(SPAN_SQL_QUERY_TAG_NAME, "UPDATE INFORMATION_SCHEMA.TABLES SET table_Name = '' WHERE 0 = 1"); assertThat(statementSpan.tags()).containsEntry(SPAN_ROW_COUNT_TAG_NAME, "0"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -156,6 +161,7 @@ abstract class TracingListenerStrategyTests { assertThat(statementSpan.tags()).containsEntry(SPAN_SQL_QUERY_TAG_NAME, "UPDATE INFORMATION_SCHEMA.TABLES SET table_Name = '' WHERE 0 = 1"); assertThat(statementSpan.tags()).containsEntry(SPAN_ROW_COUNT_TAG_NAME, "0"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -185,6 +191,7 @@ abstract class TracingListenerStrategyTests { if (isP6Spy(context)) { assertThat(resultSetSpan.tags()).containsEntry(SPAN_ROW_COUNT_TAG_NAME, "2"); } + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -212,6 +219,7 @@ abstract class TracingListenerStrategyTests { if (isP6Spy(context)) { assertThat(resultSetSpan.tags()).containsEntry(SPAN_ROW_COUNT_TAG_NAME, "1"); } + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -236,6 +244,7 @@ abstract class TracingListenerStrategyTests { assertThat(statementSpan.name()).isEqualTo("select"); assertThat(resultSetSpan.name()).isEqualTo("result-set"); assertThat(statementSpan.tags()).containsEntry(SPAN_SQL_QUERY_TAG_NAME, "SELECT NOW()"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -259,6 +268,7 @@ abstract class TracingListenerStrategyTests { assertThat(statementSpan.name()).isEqualTo("select"); assertThat(resultSetSpan.name()).isEqualTo("result-set"); assertThat(statementSpan.tags()).containsEntry(SPAN_SQL_QUERY_TAG_NAME, "SELECT NOW()"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -284,6 +294,7 @@ abstract class TracingListenerStrategyTests { assertThat(statementSpan.name()).isEqualTo("select"); assertThat(resultSetSpan.name()).isEqualTo("result-set"); assertThat(statementSpan.tags()).containsEntry(SPAN_SQL_QUERY_TAG_NAME, "SELECT NOW()"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -312,6 +323,7 @@ abstract class TracingListenerStrategyTests { assertThat(statementSpan.name()).isEqualTo("select"); assertThat(resultSetSpan.name()).isEqualTo("result-set"); assertThat(statementSpan.tags()).containsEntry(SPAN_SQL_QUERY_TAG_NAME, "SELECT NOW()"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -330,6 +342,7 @@ abstract class TracingListenerStrategyTests { assertThat(spanReporter.spans()).hasSize(1); MutableSpan connectionSpan = spanReporter.spans().get(0); assertThat(connectionSpan.name()).isEqualTo("connection"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -345,6 +358,7 @@ abstract class TracingListenerStrategyTests { statement.executeQuery("SELECT NOW()"); }).isInstanceOf(SQLException.class); connection.close(); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -362,6 +376,7 @@ abstract class TracingListenerStrategyTests { }).isInstanceOf(SQLException.class); statement.close(); connection.close(); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -373,14 +388,15 @@ abstract class TracingListenerStrategyTests { Connection connection1 = dataSource.getConnection(); Connection connection2 = dataSource.getConnection(); - connection1.close(); connection2.close(); + connection1.close(); assertThat(spanReporter.spans()).hasSize(2); MutableSpan connection1Span = spanReporter.spans().get(0); MutableSpan connection2Span = spanReporter.spans().get(1); assertThat(connection1Span.name()).isEqualTo("connection"); assertThat(connection2Span.name()).isEqualTo("connection"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -406,6 +422,7 @@ abstract class TracingListenerStrategyTests { assertThat(statementSpan.name()).isEqualTo("select"); assertThat(resultSetSpan.name()).isEqualTo("result-set"); assertThat(statementSpan.tags()).containsEntry(SPAN_SQL_QUERY_TAG_NAME, "SELECT NOW()"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -428,6 +445,7 @@ abstract class TracingListenerStrategyTests { assertThat(listener).extracting("strategy").extracting("openConnections") .isInstanceOfSatisfying(Map.class, map -> assertThat(map).isEmpty()); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -466,6 +484,7 @@ abstract class TracingListenerStrategyTests { assertThat(spanReporter.spans()).hasSize(1 + 2 * 5); assertThat(spanReporter.spans()).extracting("name").contains("select", "result-set", "connection"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -487,6 +506,7 @@ abstract class TracingListenerStrategyTests { assertThat(spanReporter.spans()).hasSize(1); MutableSpan connectionSpan = spanReporter.spans().get(0); assertThat(connectionSpan.name()).isEqualTo("connection"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -507,6 +527,7 @@ abstract class TracingListenerStrategyTests { assertThat(spanReporter.spans()).hasSize(1); MutableSpan statementSpan = spanReporter.spans().get(0); assertThat(statementSpan.name()).isEqualTo("select"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -527,6 +548,7 @@ abstract class TracingListenerStrategyTests { assertThat(spanReporter.spans()).hasSize(1); MutableSpan resultSetSpan = spanReporter.spans().get(0); assertThat(resultSetSpan.name()).isEqualTo("result-set"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -550,6 +572,7 @@ abstract class TracingListenerStrategyTests { MutableSpan statementSpan = spanReporter.spans().get(0); assertThat(connectionSpan.name()).isEqualTo("connection"); assertThat(statementSpan.name()).isEqualTo("select"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -573,6 +596,7 @@ abstract class TracingListenerStrategyTests { MutableSpan resultSetSpan = spanReporter.spans().get(0); assertThat(connectionSpan.name()).isEqualTo("connection"); assertThat(resultSetSpan.name()).isEqualTo("result-set"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -596,6 +620,7 @@ abstract class TracingListenerStrategyTests { MutableSpan statementSpan = spanReporter.spans().get(0); assertThat(statementSpan.name()).isEqualTo("select"); assertThat(resultSetSpan.name()).isEqualTo("result-set"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -608,12 +633,14 @@ abstract class TracingListenerStrategyTests { Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement("SELECT NOW()"); connection.close(); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); assertThatThrownBy(statement::executeQuery).isInstanceOf(SQLException.class); assertThat(spanReporter.spans()).hasSize(1); MutableSpan connectionSpan = spanReporter.spans().get(0); assertThat(connectionSpan.name()).isEqualTo("connection"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -634,6 +661,7 @@ abstract class TracingListenerStrategyTests { MutableSpan statementSpan = spanReporter.spans().get(0); assertThat(connectionSpan.name()).isEqualTo("connection"); assertThat(statementSpan.name()).isEqualTo("select"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } @@ -659,6 +687,7 @@ abstract class TracingListenerStrategyTests { assertThat(statementSpan.name()).isEqualTo("select"); assertThat(resultSetSpan.name()).isEqualTo("result-set"); assertThat(statementSpan.tags()).containsEntry(SPAN_SQL_QUERY_TAG_NAME, "SELECT NOW()"); + assertThat(context.getBean(Tracer.class).currentSpan()).isNull(); }); } diff --git a/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/jdbc/TraceListenerStrategy.java b/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/jdbc/TraceListenerStrategy.java index 735c0a6f7..9ebe8e830 100644 --- a/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/jdbc/TraceListenerStrategy.java +++ b/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/jdbc/TraceListenerStrategy.java @@ -1,402 +1,506 @@ -/* - * Copyright 2013-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * 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 org.springframework.cloud.sleuth.instrument.jdbc; - -import java.net.URI; -import java.sql.Connection; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.sql.CommonDataSource; - -import org.springframework.cloud.sleuth.Span; -import org.springframework.cloud.sleuth.SpanAndScope; -import org.springframework.cloud.sleuth.Tracer; -import org.springframework.cloud.sleuth.docs.AssertingSpan; -import org.springframework.cloud.sleuth.docs.AssertingSpanBuilder; -import org.springframework.lang.Nullable; -import org.springframework.util.StringUtils; - -/** - * Partially taken from - * https://github.com/openzipkin/brave/blob/v5.6.4/instrumentation/p6spy/src/main/java/brave/p6spy/TracingJdbcEventListener.java. - * - * @param connection type - * @param statement - * @param result set - */ -class TraceListenerStrategy { - - private final Map openConnections = new ConcurrentHashMap<>(); - - // Captures all the characters between = and either the next & or the end of the - // string. - private static final Pattern URL_SERVICE_NAME_FINDER = Pattern.compile("sleuthServiceName=(.*?)(?:&|$)"); - - private final Tracer tracer; - - private final List traceTypes; - - private final List customizers; - - TraceListenerStrategy(Tracer tracer, List traceTypes, - List customizers) { - this.tracer = tracer; - this.traceTypes = traceTypes; - this.customizers = customizers; - } - - void beforeGetConnection(CON connectionKey, @Nullable CommonDataSource dataSource, String dataSourceName) { - SpanAndScope spanAndScope = null; - if (this.traceTypes.contains(TraceType.CONNECTION)) { - AssertingSpanBuilder connectionSpanBuilder = AssertingSpanBuilder - .of(SleuthJdbcSpan.JDBC_CONNECTION_SPAN, tracer.spanBuilder()) - .name(SleuthJdbcSpan.JDBC_CONNECTION_SPAN.getName()); - connectionSpanBuilder.remoteServiceName(dataSourceName); - connectionSpanBuilder.kind(Span.Kind.CLIENT); - this.customizers.stream().filter(customizer -> customizer.isApplicable(dataSource)) - .forEach(customizer -> customizer.customizeConnectionSpan(dataSource, connectionSpanBuilder)); - Span connectionSpan = connectionSpanBuilder.start(); - spanAndScope = new SpanAndScope(connectionSpan, tracer.withSpan(connectionSpan)); - } - ConnectionInfo connectionInfo = new ConnectionInfo(spanAndScope); - this.openConnections.put(connectionKey, connectionInfo); - } - - void afterGetConnection(CON connectionKey, Connection connection, Throwable t) { - if (t != null) { - ConnectionInfo connectionInfo = this.openConnections.remove(connectionKey); - connectionInfo.getSpan().ifPresent(connectionSpan -> { - parseServerIpAndPort(connection, connectionSpan.getSpan()); - connectionSpan.getSpan().error(t); - connectionSpan.close(); - }); - return; - } - this.openConnections.get(connectionKey).getSpan().ifPresent(spanAndScope -> { - parseServerIpAndPort(connection, spanAndScope.getSpan()); - }); - } - - void beforeQuery(CON connectionKey, Connection connection, STMT statementKey, String dataSourceName) { - SpanAndScope SpanAndScope = null; - if (traceTypes.contains(TraceType.QUERY)) { - Span.Builder statementSpanBuilder = AssertingSpanBuilder - .of(SleuthJdbcSpan.JDBC_QUERY_SPAN, tracer.spanBuilder()) - .name(SleuthJdbcSpan.JDBC_QUERY_SPAN.getName()); - statementSpanBuilder.remoteServiceName(dataSourceName); - parseServerIpAndPort(connection, statementSpanBuilder); - statementSpanBuilder.kind(Span.Kind.CLIENT); - Span statementSpan = statementSpanBuilder.start(); - SpanAndScope = new SpanAndScope(statementSpan, tracer.withSpan(statementSpan)); - } - StatementInfo statementInfo = new StatementInfo(SpanAndScope); - ConnectionInfo connectionInfo = openConnections.get(connectionKey); - if (connectionInfo == null) { - // Connection may be closed after statement preparation, but before statement - // execution. - return; - } - connectionInfo.getNestedStatements().put(statementKey, statementInfo); - } - - void addQueryRowCount(CON connectionKey, STMT statementKey, int rowCount) { - ConnectionInfo connectionInfo = openConnections.get(connectionKey); - if (connectionInfo == null) { - // Connection is already closed - return; - } - StatementInfo statementInfo = connectionInfo.getNestedStatements().get(statementKey); - statementInfo.getSpan() - .ifPresent(statementSpan -> AssertingSpan.of(SleuthJdbcSpan.JDBC_QUERY_SPAN, statementSpan.getSpan()) - .tag(SleuthJdbcSpan.QueryTags.ROW_COUNT, String.valueOf(rowCount))); - } - - void afterQuery(CON connectionKey, STMT statementKey, String sql, Throwable t) { - ConnectionInfo connectionInfo = openConnections.get(connectionKey); - if (connectionInfo == null) { - // Connection may be closed after statement preparation, but before statement - // execution. - return; - } - StatementInfo statementInfo = connectionInfo.getNestedStatements().get(statementKey); - statementInfo.getSpan().ifPresent(statementSpan -> { - AssertingSpan.of(SleuthJdbcSpan.JDBC_QUERY_SPAN, statementSpan.getSpan()) - .tag(SleuthJdbcSpan.QueryTags.QUERY, sql).name(spanName(sql)); - if (t != null) { - statementSpan.getSpan().error(t); - } - statementSpan.close(); - }); - } - - void beforeResultSetNext(CON connectionKey, Connection connection, STMT statementKey, RS resultSetKey, - String dataSourceName) { - if (!traceTypes.contains(TraceType.FETCH)) { - return; - } - ConnectionInfo connectionInfo = openConnections.get(connectionKey); - // ConnectionInfo may be null if Connection was closed before ResultSet - if (connectionInfo == null) { - return; - } - if (connectionInfo.getNestedResultSetSpans().containsKey(resultSetKey)) { - // ResultSet span is already created - return; - } - AssertingSpanBuilder resultSetSpanBuilder = AssertingSpanBuilder - .of(SleuthJdbcSpan.JDBC_RESULT_SET_SPAN, tracer.spanBuilder()) - .name(SleuthJdbcSpan.JDBC_RESULT_SET_SPAN.getName()); - resultSetSpanBuilder.remoteServiceName(dataSourceName); - resultSetSpanBuilder.kind(Span.Kind.CLIENT); - parseServerIpAndPort(connection, resultSetSpanBuilder); - Span resultSetSpan = resultSetSpanBuilder.start(); - SpanAndScope SpanAndScope = new SpanAndScope(resultSetSpan, tracer.withSpan(resultSetSpan)); - connectionInfo.getNestedResultSetSpans().put(resultSetKey, SpanAndScope); - StatementInfo statementInfo = connectionInfo.getNestedStatements().get(statementKey); - // StatementInfo may be null when Statement is proxied and instance returned from - // ResultSet is different from instance returned in query method - // in this case if Statement is closed before ResultSet span won't be finished - // immediately, but when Connection is closed - if (statementInfo != null) { - statementInfo.getNestedResultSetSpans().put(resultSetKey, SpanAndScope); - } - } - - void afterResultSetClose(CON connectionKey, RS resultSetKey, int rowCount, Throwable t) { - ConnectionInfo connectionInfo = openConnections.get(connectionKey); - // ConnectionInfo may be null if Connection was closed before ResultSet - if (connectionInfo == null) { - return; - } - SpanAndScope resultSetSpan = connectionInfo.getNestedResultSetSpans().remove(resultSetKey); - // ResultSet span may be null if Statement or ResultSet were already closed - if (resultSetSpan == null) { - return; - } - if (rowCount != -1) { - AssertingSpan.of(SleuthJdbcSpan.JDBC_RESULT_SET_SPAN, resultSetSpan.getSpan()) - .tag(SleuthJdbcSpan.QueryTags.ROW_COUNT, String.valueOf(rowCount)); - } - if (t != null) { - resultSetSpan.getSpan().error(t); - } - resultSetSpan.close(); - } - - void afterStatementClose(CON connectionKey, STMT statementKey) { - ConnectionInfo connectionInfo = openConnections.get(connectionKey); - // ConnectionInfo may be null if Connection was closed before Statement - if (connectionInfo == null) { - return; - } - StatementInfo statementInfo = connectionInfo.getNestedStatements().remove(statementKey); - if (statementInfo != null) { - statementInfo.getNestedResultSetSpans().forEach((resultSetKey, span) -> { - connectionInfo.getNestedResultSetSpans().remove(resultSetKey); - span.close(); - }); - statementInfo.getNestedResultSetSpans().clear(); - } - } - - void afterCommit(CON connectionKey, Throwable t) { - ConnectionInfo connectionInfo = openConnections.get(connectionKey); - if (connectionInfo == null) { - // Connection is already closed - return; - } - connectionInfo.getSpan().ifPresent(connectionSpan -> { - if (t != null) { - connectionSpan.getSpan().error(t); - } - AssertingSpan.of(SleuthJdbcSpan.JDBC_QUERY_SPAN, connectionSpan.getSpan()) - .event(SleuthJdbcSpan.QueryEvents.COMMIT); - }); - } - - void afterRollback(CON connectionKey, Throwable t) { - ConnectionInfo connectionInfo = openConnections.get(connectionKey); - if (connectionInfo == null) { - // Connection is already closed - return; - } - connectionInfo.getSpan().ifPresent(connectionSpan -> { - if (t != null) { - connectionSpan.getSpan().error(t); - } - else { - connectionSpan.getSpan().error(new JdbcException("Transaction rolled back")); - } - AssertingSpan.of(SleuthJdbcSpan.JDBC_QUERY_SPAN, connectionSpan.getSpan()) - .event(SleuthJdbcSpan.QueryEvents.ROLLBACK); - }); - } - - void afterConnectionClose(CON connectionKey, Throwable t) { - ConnectionInfo connectionInfo = openConnections.remove(connectionKey); - if (connectionInfo == null) { - // connection is already closed - return; - } - connectionInfo.getNestedResultSetSpans().values().forEach(SpanAndScope::close); - connectionInfo.getNestedStatements().values() - .forEach(statementInfo -> statementInfo.getSpan().ifPresent(SpanAndScope::close)); - connectionInfo.getSpan().ifPresent(connectionSpan -> { - if (t != null) { - connectionSpan.getSpan().error(t); - } - connectionSpan.close(); - }); - } - - private String spanName(String sql) { - return sql.substring(0, sql.indexOf(' ')).toLowerCase(Locale.ROOT); - } - - private void parseServerIpAndPort(Connection connection, Span.Builder span) { - if (connection == null) { - return; - } - UrlAndRemoteServiceName urlAndRemoteServiceName = parseServerIpAndPort(connection); - span.remoteServiceName(urlAndRemoteServiceName.remoteServiceName); - URI url = urlAndRemoteServiceName.url; - if (url != null) { - span.remoteIpAndPort(url.getHost(), url.getPort()); - } - } - - private void parseServerIpAndPort(Connection connection, Span span) { - if (connection == null) { - return; - } - UrlAndRemoteServiceName urlAndRemoteServiceName = parseServerIpAndPort(connection); - span.remoteServiceName(urlAndRemoteServiceName.remoteServiceName); - URI url = urlAndRemoteServiceName.url; - if (url != null) { - span.remoteIpAndPort(url.getHost(), url.getPort()); - } - } - - /** - * This attempts to get the ip and port from the JDBC URL. Ex. localhost and 5555 from - * {@code - * jdbc:mysql://localhost:5555/mydatabase}. - * - * Taken from Brave. - */ - private UrlAndRemoteServiceName parseServerIpAndPort(Connection connection) { - String remoteServiceName = ""; - try { - String urlAsString = connection.getMetaData().getURL().substring(5); // strip - // "jdbc:" - URI url = URI.create(urlAsString.replace(" ", "")); // Remove all white space - // according to RFC 2396 - Matcher matcher = URL_SERVICE_NAME_FINDER.matcher(url.toString()); - if (matcher.find() && matcher.groupCount() == 1) { - String parsedServiceName = matcher.group(1); - if (parsedServiceName != null && !parsedServiceName.isEmpty()) { - remoteServiceName = parsedServiceName; - } - } - if (!StringUtils.hasText(remoteServiceName)) { - String databaseName = connection.getCatalog(); - if (databaseName != null && !databaseName.isEmpty()) { - remoteServiceName = databaseName; - } - } - return new UrlAndRemoteServiceName(url, remoteServiceName); - } - catch (Exception e) { - // remote address is optional - return new UrlAndRemoteServiceName(null, remoteServiceName); - } - } - - private final class ConnectionInfo { - - private final SpanAndScope span; - - private final Map nestedStatements = new ConcurrentHashMap<>(); - - private final Map nestedResultSetSpans = new ConcurrentHashMap<>(); - - private ConnectionInfo(@Nullable SpanAndScope span) { - this.span = span; - } - - Optional getSpan() { - return Optional.ofNullable(span); - } - - Map getNestedStatements() { - return nestedStatements; - } - - Map getNestedResultSetSpans() { - return nestedResultSetSpans; - } - - } - - private final class StatementInfo { - - private final SpanAndScope span; - - private final Map nestedResultSetSpans = new ConcurrentHashMap<>(); - - private StatementInfo(SpanAndScope span) { - this.span = span; - } - - Optional getSpan() { - return Optional.ofNullable(span); - } - - Map getNestedResultSetSpans() { - return nestedResultSetSpans; - } - - } - - private final class UrlAndRemoteServiceName { - - final URI url; - - final String remoteServiceName; - - private UrlAndRemoteServiceName(@Nullable URI url, String remoteServiceName) { - this.url = url; - this.remoteServiceName = remoteServiceName; - } - - } - - private static final class JdbcException extends RuntimeException { - - JdbcException(String message) { - super(message); - } - - } - -} +/* + * Copyright 2013-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * 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 org.springframework.cloud.sleuth.instrument.jdbc; + +import java.net.URI; +import java.sql.Connection; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.sql.CommonDataSource; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanAndScope; +import org.springframework.cloud.sleuth.Tracer; +import org.springframework.cloud.sleuth.docs.AssertingSpan; +import org.springframework.cloud.sleuth.docs.AssertingSpanBuilder; +import org.springframework.lang.Nullable; +import org.springframework.util.StringUtils; + +/** + * Partially taken from + * https://github.com/openzipkin/brave/blob/v5.6.4/instrumentation/p6spy/src/main/java/brave/p6spy/TracingJdbcEventListener.java. + * + * @param connection type + * @param statement + * @param result set + */ +class TraceListenerStrategy { + + private static final Log log = LogFactory.getLog(TraceListenerStrategy.class); + + private final Map openConnections = new ConcurrentHashMap<>(); + + // Captures all the characters between = and either the next & or the end of the + // string. + private static final Pattern URL_SERVICE_NAME_FINDER = Pattern.compile("sleuthServiceName=(.*?)(?:&|$)"); + + private final Tracer tracer; + + private final List traceTypes; + + private final List customizers; + + TraceListenerStrategy(Tracer tracer, List traceTypes, + List customizers) { + this.tracer = tracer; + this.traceTypes = traceTypes; + this.customizers = customizers; + } + + void beforeGetConnection(CON connectionKey, @Nullable CommonDataSource dataSource, String dataSourceName) { + if (log.isTraceEnabled()) { + log.trace("Before get connection key [" + connectionKey + "] - current span is [" + tracer.currentSpan() + + "]"); + } + SpanAndScope spanAndScope = null; + if (this.traceTypes.contains(TraceType.CONNECTION)) { + AssertingSpanBuilder connectionSpanBuilder = AssertingSpanBuilder + .of(SleuthJdbcSpan.JDBC_CONNECTION_SPAN, tracer.spanBuilder()) + .name(SleuthJdbcSpan.JDBC_CONNECTION_SPAN.getName()); + connectionSpanBuilder.remoteServiceName(dataSourceName); + connectionSpanBuilder.kind(Span.Kind.CLIENT); + this.customizers.stream().filter(customizer -> customizer.isApplicable(dataSource)) + .forEach(customizer -> customizer.customizeConnectionSpan(dataSource, connectionSpanBuilder)); + Span connectionSpan = connectionSpanBuilder.start(); + spanAndScope = new SpanAndScope(connectionSpan, tracer.withSpan(connectionSpan)); + if (log.isTraceEnabled()) { + log.trace("Started client span before connection [" + connectionSpan + "] - current span is [" + + tracer.currentSpan() + "]"); + } + } + ConnectionInfo connectionInfo = new ConnectionInfo(spanAndScope); + this.openConnections.put(connectionKey, connectionInfo); + } + + void afterGetConnection(CON connectionKey, Connection connection, Throwable t) { + if (log.isTraceEnabled()) { + log.trace("After get connection [" + connectionKey + "]. Current span is [" + tracer.currentSpan() + "]"); + } + this.openConnections.get(connectionKey).getSpan().ifPresent(spanAndScope -> { + parseServerIpAndPort(connection, spanAndScope.getSpan()); + }); + if (t != null) { + ConnectionInfo connectionInfo = this.openConnections.remove(connectionKey); + connectionInfo.getSpan().ifPresent(connectionSpan -> { + parseServerIpAndPort(connection, connectionSpan.getSpan()); + if (log.isTraceEnabled()) { + log.trace("Closing client span due to exception [" + connectionSpan.getSpan() + + "] - current span is [" + tracer.currentSpan() + "]"); + } + connectionSpan.getSpan().error(t); + connectionSpan.close(); + if (log.isTraceEnabled()) { + log.trace("Current span [" + tracer.currentSpan() + "]"); + } + }); + } + } + + void beforeQuery(CON connectionKey, Connection connection, STMT statementKey, String dataSourceName) { + if (log.isTraceEnabled()) { + log.trace("Before query - connection [" + connectionKey + "] and current span [" + tracer.currentSpan() + + "]"); + } + ConnectionInfo connectionInfo = openConnections.get(connectionKey); + if (connectionInfo == null) { + if (log.isTraceEnabled()) { + log.trace("Connection may be closed after statement preparation, but before statement execution"); + } + return; + } + SpanAndScope spanAndScope = null; + if (traceTypes.contains(TraceType.QUERY)) { + Span.Builder statementSpanBuilder = AssertingSpanBuilder + .of(SleuthJdbcSpan.JDBC_QUERY_SPAN, tracer.spanBuilder()) + .name(String.format(SleuthJdbcSpan.JDBC_QUERY_SPAN.getName(), "query")); + statementSpanBuilder.remoteServiceName(dataSourceName); + parseServerIpAndPort(connection, statementSpanBuilder); + statementSpanBuilder.kind(Span.Kind.CLIENT); + Span statementSpan = statementSpanBuilder.start(); + spanAndScope = new SpanAndScope(statementSpan, tracer.withSpan(statementSpan)); + if (log.isTraceEnabled()) { + log.trace("Started client span before query [" + statementSpan + "] - current span is [" + + tracer.currentSpan() + "]"); + } + } + StatementInfo statementInfo = new StatementInfo(spanAndScope); + connectionInfo.getNestedStatements().put(statementKey, statementInfo); + } + + void addQueryRowCount(CON connectionKey, STMT statementKey, int rowCount) { + if (log.isTraceEnabled()) { + log.trace("Add query row count for connection key [" + connectionKey + "]"); + } + ConnectionInfo connectionInfo = openConnections.get(connectionKey); + if (connectionInfo == null) { + if (log.isTraceEnabled()) { + log.trace("Connection is already closed"); + } + return; + } + StatementInfo statementInfo = connectionInfo.getNestedStatements().get(statementKey); + statementInfo.getSpan() + .ifPresent(statementSpan -> AssertingSpan.of(SleuthJdbcSpan.JDBC_QUERY_SPAN, statementSpan.getSpan()) + .tag(SleuthJdbcSpan.QueryTags.ROW_COUNT, String.valueOf(rowCount))); + } + + void afterQuery(CON connectionKey, STMT statementKey, String sql, Throwable t) { + if (log.isTraceEnabled()) { + log.trace("After query for connection key [" + connectionKey + "]"); + } + ConnectionInfo connectionInfo = openConnections.get(connectionKey); + if (connectionInfo == null) { + if (log.isTraceEnabled()) { + log.trace( + "Connection may be closed after statement preparation, but before statement execution. Current span is [" + + tracer.currentSpan() + "]"); + } + return; + } + StatementInfo statementInfo = connectionInfo.getNestedStatements().get(statementKey); + statementInfo.getSpan().ifPresent(statementSpan -> { + updateQuerySpan(sql, t, statementSpan); + statementSpan.close(); + if (log.isTraceEnabled()) { + log.trace("Current span [" + tracer.currentSpan() + "]"); + } + }); + } + + private void updateQuerySpan(String sql, Throwable t, SpanAndScope statementSpan) { + AssertingSpan.of(SleuthJdbcSpan.JDBC_QUERY_SPAN, statementSpan.getSpan()) + .tag(SleuthJdbcSpan.QueryTags.QUERY, sql).name(spanName(sql)); + if (t != null) { + statementSpan.getSpan().error(t); + } + if (log.isTraceEnabled()) { + log.trace( + "Closing statement span [" + statementSpan + "] - current span is [" + tracer.currentSpan() + "]"); + } + } + + void beforeResultSetNext(CON connectionKey, Connection connection, STMT statementKey, RS resultSetKey, + String dataSourceName) { + if (log.isTraceEnabled()) { + log.trace("Before result set next"); + } + if (!traceTypes.contains(TraceType.FETCH)) { + return; + } + ConnectionInfo connectionInfo = openConnections.get(connectionKey); + // ConnectionInfo may be null if Connection was closed before ResultSet + if (connectionInfo == null) { + if (log.isTraceEnabled()) { + log.trace("No connection info, skipping"); + } + return; + } + if (connectionInfo.getNestedResultSetSpans().containsKey(resultSetKey)) { + if (log.isTraceEnabled()) { + log.trace("ResultSet span is already created"); + } + return; + } + AssertingSpanBuilder resultSetSpanBuilder = AssertingSpanBuilder + .of(SleuthJdbcSpan.JDBC_RESULT_SET_SPAN, tracer.spanBuilder()) + .name(SleuthJdbcSpan.JDBC_RESULT_SET_SPAN.getName()); + resultSetSpanBuilder.remoteServiceName(dataSourceName); + resultSetSpanBuilder.kind(Span.Kind.CLIENT); + parseServerIpAndPort(connection, resultSetSpanBuilder); + Span resultSetSpan = resultSetSpanBuilder.start(); + SpanAndScope SpanAndScope = new SpanAndScope(resultSetSpan, tracer.withSpan(resultSetSpan)); + if (log.isTraceEnabled()) { + log.trace("Started client result set span [" + resultSetSpan + "] - current span is [" + + tracer.currentSpan() + "]"); + } + connectionInfo.getNestedResultSetSpans().put(resultSetKey, SpanAndScope); + StatementInfo statementInfo = connectionInfo.getNestedStatements().get(statementKey); + // StatementInfo may be null when Statement is proxied and instance returned from + // ResultSet is different from instance returned in query method + // in this case if Statement is closed before ResultSet span won't be finished + // immediately, but when Connection is closed + if (statementInfo != null) { + statementInfo.getNestedResultSetSpans().put(resultSetKey, SpanAndScope); + } + } + + void afterResultSetClose(CON connectionKey, RS resultSetKey, int rowCount, Throwable t) { + if (log.isTraceEnabled()) { + log.trace("After result set close"); + } + ConnectionInfo connectionInfo = openConnections.get(connectionKey); + // ConnectionInfo may be null if Connection was closed before ResultSet + if (connectionInfo == null) { + return; + } + SpanAndScope resultSetSpan = connectionInfo.getNestedResultSetSpans().remove(resultSetKey); + // ResultSet span may be null if Statement or ResultSet were already closed + if (resultSetSpan == null) { + return; + } + if (rowCount != -1) { + AssertingSpan.of(SleuthJdbcSpan.JDBC_RESULT_SET_SPAN, resultSetSpan.getSpan()) + .tag(SleuthJdbcSpan.QueryTags.ROW_COUNT, String.valueOf(rowCount)); + } + if (t != null) { + resultSetSpan.getSpan().error(t); + } + if (log.isTraceEnabled()) { + log.trace("Closing client result set span [" + resultSetSpan + "] - current span is [" + + tracer.currentSpan() + "]"); + } + resultSetSpan.close(); + if (log.isTraceEnabled()) { + log.trace("Current span [" + tracer.currentSpan() + "]"); + } + } + + void afterStatementClose(CON connectionKey, STMT statementKey) { + if (log.isTraceEnabled()) { + log.trace("After statement close"); + } + ConnectionInfo connectionInfo = openConnections.get(connectionKey); + // ConnectionInfo may be null if Connection was closed before Statement + if (connectionInfo == null) { + return; + } + StatementInfo statementInfo = connectionInfo.getNestedStatements().remove(statementKey); + if (statementInfo != null) { + statementInfo.getNestedResultSetSpans().forEach((resultSetKey, span) -> { + connectionInfo.getNestedResultSetSpans().remove(resultSetKey); + if (log.isTraceEnabled()) { + log.trace("Closing span after statement close [" + span.getSpan() + "] - current span is [" + + tracer.currentSpan() + "]"); + } + span.close(); + if (log.isTraceEnabled()) { + log.trace("Current span [" + tracer.currentSpan() + "]"); + } + }); + statementInfo.getNestedResultSetSpans().clear(); + } + } + + void afterCommit(CON connectionKey, Throwable t) { + if (log.isTraceEnabled()) { + log.trace("After commit"); + } + ConnectionInfo connectionInfo = openConnections.get(connectionKey); + if (connectionInfo == null) { + // Connection is already closed + return; + } + connectionInfo.getSpan().ifPresent(connectionSpan -> { + if (t != null) { + connectionSpan.getSpan().error(t); + } + AssertingSpan.of(SleuthJdbcSpan.JDBC_QUERY_SPAN, connectionSpan.getSpan()) + .event(SleuthJdbcSpan.QueryEvents.COMMIT); + }); + } + + void afterRollback(CON connectionKey, Throwable t) { + if (log.isTraceEnabled()) { + log.trace("After rollback"); + } + ConnectionInfo connectionInfo = openConnections.get(connectionKey); + if (connectionInfo == null) { + // Connection is already closed + return; + } + connectionInfo.getSpan().ifPresent(connectionSpan -> { + if (t != null) { + connectionSpan.getSpan().error(t); + } + else { + connectionSpan.getSpan().error(new JdbcException("Transaction rolled back")); + } + AssertingSpan.of(SleuthJdbcSpan.JDBC_QUERY_SPAN, connectionSpan.getSpan()) + .event(SleuthJdbcSpan.QueryEvents.ROLLBACK); + }); + } + + void afterConnectionClose(CON connectionKey, Throwable t) { + if (log.isTraceEnabled()) { + log.trace("After connection close with key [" + connectionKey + "]"); + } + ConnectionInfo connectionInfo = openConnections.remove(connectionKey); + if (connectionInfo == null) { + // connection is already closed + return; + } + connectionInfo.getNestedResultSetSpans().values().forEach(SpanAndScope::close); + connectionInfo.getNestedStatements().values() + .forEach(statementInfo -> statementInfo.getSpan().ifPresent(SpanAndScope::close)); + if (log.isTraceEnabled()) { + log.trace("Current span after closing statements [" + tracer.currentSpan() + "]"); + } + connectionInfo.getSpan().ifPresent(connectionSpan -> { + if (t != null) { + connectionSpan.getSpan().error(t); + } + if (log.isTraceEnabled()) { + log.trace("Closing span after connection close [" + connectionSpan.getSpan() + "] - current span is [" + + tracer.currentSpan() + "]"); + } + connectionSpan.close(); + if (log.isTraceEnabled()) { + log.trace("Current span [" + tracer.currentSpan() + "]"); + } + }); + } + + private String spanName(String sql) { + return sql.substring(0, sql.indexOf(' ')).toLowerCase(Locale.ROOT); + } + + private void parseServerIpAndPort(Connection connection, Span.Builder span) { + if (connection == null) { + return; + } + UrlAndRemoteServiceName urlAndRemoteServiceName = parseServerIpAndPort(connection); + span.remoteServiceName(urlAndRemoteServiceName.remoteServiceName); + URI url = urlAndRemoteServiceName.url; + if (url != null) { + span.remoteIpAndPort(url.getHost(), url.getPort()); + } + } + + private void parseServerIpAndPort(Connection connection, Span span) { + if (connection == null) { + return; + } + UrlAndRemoteServiceName urlAndRemoteServiceName = parseServerIpAndPort(connection); + span.remoteServiceName(urlAndRemoteServiceName.remoteServiceName); + URI url = urlAndRemoteServiceName.url; + if (url != null) { + span.remoteIpAndPort(url.getHost(), url.getPort()); + } + } + + /** + * This attempts to get the ip and port from the JDBC URL. Ex. localhost and 5555 from + * {@code + * jdbc:mysql://localhost:5555/mydatabase}. + * + * Taken from Brave. + */ + private UrlAndRemoteServiceName parseServerIpAndPort(Connection connection) { + String remoteServiceName = ""; + try { + String urlAsString = connection.getMetaData().getURL().substring(5); // strip + // "jdbc:" + URI url = URI.create(urlAsString.replace(" ", "")); // Remove all white space + // according to RFC 2396 + Matcher matcher = URL_SERVICE_NAME_FINDER.matcher(url.toString()); + if (matcher.find() && matcher.groupCount() == 1) { + String parsedServiceName = matcher.group(1); + if (parsedServiceName != null && !parsedServiceName.isEmpty()) { + remoteServiceName = parsedServiceName; + } + } + if (!StringUtils.hasText(remoteServiceName)) { + String databaseName = connection.getCatalog(); + if (databaseName != null && !databaseName.isEmpty()) { + remoteServiceName = databaseName; + } + } + return new UrlAndRemoteServiceName(url, remoteServiceName); + } + catch (Exception e) { + // remote address is optional + return new UrlAndRemoteServiceName(null, remoteServiceName); + } + } + + private final class ConnectionInfo { + + private final SpanAndScope span; + + private final Map nestedStatements = new ConcurrentHashMap<>(); + + private final Map nestedResultSetSpans = new ConcurrentHashMap<>(); + + private ConnectionInfo(@Nullable SpanAndScope span) { + this.span = span; + } + + Optional getSpan() { + return Optional.ofNullable(span); + } + + Map getNestedStatements() { + return nestedStatements; + } + + Map getNestedResultSetSpans() { + return nestedResultSetSpans; + } + + } + + private final class StatementInfo { + + private final SpanAndScope span; + + private final Map nestedResultSetSpans = new ConcurrentHashMap<>(); + + private StatementInfo(SpanAndScope span) { + this.span = span; + } + + Optional getSpan() { + return Optional.ofNullable(span); + } + + Map getNestedResultSetSpans() { + return nestedResultSetSpans; + } + + } + + private final class UrlAndRemoteServiceName { + + final URI url; + + final String remoteServiceName; + + private UrlAndRemoteServiceName(@Nullable URI url, String remoteServiceName) { + this.url = url; + this.remoteServiceName = remoteServiceName; + } + + } + + private static final class JdbcException extends RuntimeException { + + JdbcException(String message) { + super(message); + } + + } + +} diff --git a/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/jdbc/TraceQueryExecutionListener.java b/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/jdbc/TraceQueryExecutionListener.java index df4bfa8f3..2206a287e 100644 --- a/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/jdbc/TraceQueryExecutionListener.java +++ b/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/jdbc/TraceQueryExecutionListener.java @@ -121,6 +121,9 @@ public class TraceQueryExecutionListener implements QueryExecutionListener, Meth try { DataSource source = targetDataSource instanceof ProxyDataSource ? (targetDataSource).unwrap(DataSource.class) : targetDataSource; + if (source == null) { + return null; + } return source.getConnection(); } catch (Exception ex) { diff --git a/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/internal/SleuthContextListener.java b/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/internal/SleuthContextListener.java index b4daa79f7..587ffc163 100644 --- a/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/internal/SleuthContextListener.java +++ b/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/internal/SleuthContextListener.java @@ -81,8 +81,8 @@ public class SleuthContextListener implements SmartApplicationListener { @Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ContextRefreshedEvent || event instanceof ContextClosedEvent) { - if (log.isDebugEnabled()) { - log.debug("Context refreshed or closed [" + event + "]"); + if (log.isTraceEnabled()) { + log.trace("Context refreshed or closed [" + event + "]"); } ApplicationContextEvent contextEvent = (ApplicationContextEvent) event; ApplicationContext context = contextEvent.getApplicationContext();