JDBC tracing context not leaking
without this change there were cases (that we didn't test) where the tracing context would leak and pollute other parts of the code (including tests) with this change we ensure that in case of errors we don't allow any dangling tracing context
This commit is contained in:
@@ -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<String> MESSAGES = new ArrayList<>();
|
||||
static final List<Exception> 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<String> MESSAGES = new ArrayList<>();
|
||||
static final List<Exception> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<QueryInfo> queryInfoList) {
|
||||
System.out.println("beforeQuery");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterQuery(ExecutionInfo execInfo, List<QueryInfo> 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<QueryInfo> queryInfoList) {
|
||||
System.out.println("beforeQuery");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterQuery(ExecutionInfo execInfo, List<QueryInfo> queryInfoList) {
|
||||
System.out.println("afterQuery");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user