Moved tests to common
This commit is contained in:
@@ -1,119 +1,112 @@
|
||||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.ttddyy.dsproxy.listener.MethodExecutionListener;
|
||||
import net.ttddyy.dsproxy.listener.QueryCountStrategy;
|
||||
import net.ttddyy.dsproxy.listener.QueryExecutionListener;
|
||||
import net.ttddyy.dsproxy.listener.SingleQueryCountHolder;
|
||||
import net.ttddyy.dsproxy.proxy.GlobalConnectionIdManager;
|
||||
import net.ttddyy.dsproxy.proxy.ResultSetProxyLogicFactory;
|
||||
import net.ttddyy.dsproxy.proxy.SimpleResultSetProxyLogicFactory;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSource;
|
||||
import net.ttddyy.dsproxy.transform.ParameterTransformer;
|
||||
import net.ttddyy.dsproxy.transform.QueryTransformer;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceNameResolver;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceProxyBuilderCustomizer;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceProxyConnectionIdManagerProvider;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceProxyDataSourceDecorator;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceProxyProperties;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceListenerStrategySpanCustomizer;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceQueryExecutionListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* Configuration for integration with datasource-proxy, allows to use define custom
|
||||
* {@link QueryExecutionListener}, {@link ParameterTransformer} and
|
||||
* {@link QueryTransformer}.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
*/
|
||||
@ConditionalOnClass(ProxyDataSource.class)
|
||||
class DataSourceProxyConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
DataSourceProxyConnectionIdManagerProvider traceConnectionIdManagerProvider() {
|
||||
return GlobalConnectionIdManager::new;
|
||||
}
|
||||
|
||||
@Bean
|
||||
DataSourceProxyBuilderCustomizer proxyDataSourceBuilderConfigurer(
|
||||
ObjectProvider<QueryCountStrategy> queryCountStrategy,
|
||||
ObjectProvider<List<QueryExecutionListener>> listeners,
|
||||
ObjectProvider<List<MethodExecutionListener>> methodExecutionListeners,
|
||||
ObjectProvider<ParameterTransformer> parameterTransformer,
|
||||
ObjectProvider<QueryTransformer> queryTransformer,
|
||||
ObjectProvider<ResultSetProxyLogicFactory> resultSetProxyLogicFactory,
|
||||
ObjectProvider<DataSourceProxyConnectionIdManagerProvider> dataSourceProxyConnectionIdManagerProvider,
|
||||
TraceDataSourceDecoratorProperties dataSourceDecoratorProperties) {
|
||||
return new DataSourceProxyBuilderCustomizer(queryCountStrategy.getIfAvailable(() -> null),
|
||||
listeners.getIfAvailable(() -> null), methodExecutionListeners.getIfAvailable(() -> null),
|
||||
parameterTransformer.getIfAvailable(() -> null), queryTransformer.getIfAvailable(() -> null),
|
||||
resultSetProxyLogicFactory.getIfAvailable(() -> null),
|
||||
dataSourceProxyConnectionIdManagerProvider.getIfAvailable(() -> null),
|
||||
props(dataSourceDecoratorProperties));
|
||||
}
|
||||
|
||||
private DataSourceProxyProperties props(TraceDataSourceDecoratorProperties dataSourceDecoratorProperties) {
|
||||
TraceDataSourceDecoratorProperties.DataSourceProxyProperties originalProxy = dataSourceDecoratorProperties
|
||||
.getDatasourceProxy();
|
||||
DataSourceProxyProperties props = new DataSourceProxyProperties();
|
||||
BeanUtils.copyProperties(originalProxy, props);
|
||||
props.setLogging(DataSourceProxyProperties.DataSourceProxyLogging.valueOf(originalProxy.getLogging().name()));
|
||||
return props;
|
||||
}
|
||||
|
||||
@Bean
|
||||
DataSourceProxyDataSourceDecorator proxyDataSourceDecorator(
|
||||
DataSourceProxyBuilderCustomizer dataSourceProxyBuilderCustomizer,
|
||||
DataSourceNameResolver dataSourceNameResolver) {
|
||||
return new DataSourceProxyDataSourceDecorator(dataSourceProxyBuilderCustomizer, dataSourceNameResolver);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(value = "spring.sleuth.jdbc.datasource-proxy.count-query", havingValue = "true")
|
||||
QueryCountStrategy queryCountStrategy() {
|
||||
return new SingleQueryCountHolder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
TraceQueryExecutionListener traceQueryExecutionListener(Tracer tracer,
|
||||
TraceDataSourceDecoratorProperties dataSourceDecoratorProperties,
|
||||
ObjectProvider<List<TraceListenerStrategySpanCustomizer>> customizers) {
|
||||
return new TraceQueryExecutionListener(tracer, dataSourceDecoratorProperties.getIncludes(),
|
||||
customizers.getIfAvailable(ArrayList::new));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ResultSetProxyLogicFactory traceResultSetProxyLogicFactory() {
|
||||
return new SimpleResultSetProxyLogicFactory();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.ttddyy.dsproxy.listener.MethodExecutionListener;
|
||||
import net.ttddyy.dsproxy.listener.QueryCountStrategy;
|
||||
import net.ttddyy.dsproxy.listener.QueryExecutionListener;
|
||||
import net.ttddyy.dsproxy.proxy.GlobalConnectionIdManager;
|
||||
import net.ttddyy.dsproxy.proxy.ResultSetProxyLogicFactory;
|
||||
import net.ttddyy.dsproxy.proxy.SimpleResultSetProxyLogicFactory;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSource;
|
||||
import net.ttddyy.dsproxy.transform.ParameterTransformer;
|
||||
import net.ttddyy.dsproxy.transform.QueryTransformer;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceNameResolver;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceProxyBuilderCustomizer;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceProxyConnectionIdManagerProvider;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceProxyDataSourceDecorator;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceProxyProperties;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceListenerStrategySpanCustomizer;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceQueryExecutionListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* Configuration for integration with datasource-proxy, allows to use define custom
|
||||
* {@link QueryExecutionListener}, {@link ParameterTransformer} and
|
||||
* {@link QueryTransformer}.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
*/
|
||||
@ConditionalOnClass(ProxyDataSource.class)
|
||||
@ConditionalOnProperty(name = "spring.sleuth.jdbc.datasource-proxy.enabled", havingValue = "true", matchIfMissing = true)
|
||||
class DataSourceProxyConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
DataSourceProxyConnectionIdManagerProvider traceConnectionIdManagerProvider() {
|
||||
return GlobalConnectionIdManager::new;
|
||||
}
|
||||
|
||||
@Bean
|
||||
DataSourceProxyBuilderCustomizer proxyDataSourceBuilderConfigurer(
|
||||
ObjectProvider<QueryCountStrategy> queryCountStrategy,
|
||||
ObjectProvider<List<QueryExecutionListener>> listeners,
|
||||
ObjectProvider<List<MethodExecutionListener>> methodExecutionListeners,
|
||||
ObjectProvider<ParameterTransformer> parameterTransformer,
|
||||
ObjectProvider<QueryTransformer> queryTransformer,
|
||||
ObjectProvider<ResultSetProxyLogicFactory> resultSetProxyLogicFactory,
|
||||
ObjectProvider<DataSourceProxyConnectionIdManagerProvider> dataSourceProxyConnectionIdManagerProvider,
|
||||
TraceJdbcProperties traceJdbcProperties) {
|
||||
return new DataSourceProxyBuilderCustomizer(queryCountStrategy.getIfAvailable(() -> null),
|
||||
listeners.getIfAvailable(() -> null), methodExecutionListeners.getIfAvailable(() -> null),
|
||||
parameterTransformer.getIfAvailable(() -> null), queryTransformer.getIfAvailable(() -> null),
|
||||
resultSetProxyLogicFactory.getIfAvailable(() -> null),
|
||||
dataSourceProxyConnectionIdManagerProvider.getIfAvailable(() -> null),
|
||||
props(traceJdbcProperties));
|
||||
}
|
||||
|
||||
private DataSourceProxyProperties props(TraceJdbcProperties traceJdbcProperties) {
|
||||
TraceJdbcProperties.DataSourceProxyProperties originalProxy = traceJdbcProperties
|
||||
.getDatasourceProxy();
|
||||
DataSourceProxyProperties props = new DataSourceProxyProperties();
|
||||
BeanUtils.copyProperties(originalProxy, props);
|
||||
props.setLogging(DataSourceProxyProperties.DataSourceProxyLogging.valueOf(originalProxy.getLogging().name()));
|
||||
return props;
|
||||
}
|
||||
|
||||
@Bean
|
||||
DataSourceProxyDataSourceDecorator proxyDataSourceDecorator(
|
||||
DataSourceProxyBuilderCustomizer dataSourceProxyBuilderCustomizer,
|
||||
DataSourceNameResolver dataSourceNameResolver) {
|
||||
return new DataSourceProxyDataSourceDecorator(dataSourceProxyBuilderCustomizer, dataSourceNameResolver);
|
||||
}
|
||||
|
||||
@Bean
|
||||
TraceQueryExecutionListener traceQueryExecutionListener(Tracer tracer,
|
||||
TraceJdbcProperties dataSourceDecoratorProperties,
|
||||
ObjectProvider<List<TraceListenerStrategySpanCustomizer>> customizers) {
|
||||
return new TraceQueryExecutionListener(tracer, dataSourceDecoratorProperties.getIncludes(),
|
||||
customizers.getIfAvailable(ArrayList::new));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ResultSetProxyLogicFactory traceResultSetProxyLogicFactory() {
|
||||
return new SimpleResultSetProxyLogicFactory();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,76 +1,78 @@
|
||||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.p6spy.engine.event.JdbcEventListener;
|
||||
import com.p6spy.engine.spy.DefaultJdbcEventListenerFactory;
|
||||
import com.p6spy.engine.spy.JdbcEventListenerFactory;
|
||||
import com.p6spy.engine.spy.P6DataSource;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceNameResolver;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.P6SpyContextJdbcEventListenerFactory;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.P6SpyDataSourceDecorator;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceJdbcEventListener;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceListenerStrategySpanCustomizer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* Configuration for integration with p6spy, allows to define custom
|
||||
* {@link JdbcEventListener}.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
*/
|
||||
@ConditionalOnClass(P6DataSource.class)
|
||||
class P6SpyConfiguration {
|
||||
|
||||
@Bean
|
||||
static P6SpyPropertiesSetter p6SpyPropertiesSetter(ConfigurableApplicationContext context) {
|
||||
return new P6SpyPropertiesSetter(context);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
JdbcEventListenerFactory traceJdbcEventListenerFactory(ObjectProvider<List<JdbcEventListener>> listeners) {
|
||||
JdbcEventListenerFactory jdbcEventListenerFactory = new DefaultJdbcEventListenerFactory();
|
||||
List<JdbcEventListener> listenerList = listeners.getIfAvailable(() -> null);
|
||||
return listenerList != null ? new P6SpyContextJdbcEventListenerFactory(jdbcEventListenerFactory, listenerList)
|
||||
: jdbcEventListenerFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
P6SpyDataSourceDecorator p6SpyDataSourceDecorator(JdbcEventListenerFactory jdbcEventListenerFactory) {
|
||||
return new P6SpyDataSourceDecorator(jdbcEventListenerFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
TraceJdbcEventListener tracingJdbcEventListener(Tracer tracer, DataSourceNameResolver dataSourceNameResolver,
|
||||
TraceDataSourceDecoratorProperties dataSourceDecoratorProperties,
|
||||
ObjectProvider<List<TraceListenerStrategySpanCustomizer>> customizers) {
|
||||
return new TraceJdbcEventListener(tracer, dataSourceNameResolver, dataSourceDecoratorProperties.getIncludes(),
|
||||
dataSourceDecoratorProperties.getP6spy().getTracing().isIncludeParameterValues(),
|
||||
customizers.getIfAvailable(ArrayList::new));
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.p6spy.engine.event.JdbcEventListener;
|
||||
import com.p6spy.engine.spy.DefaultJdbcEventListenerFactory;
|
||||
import com.p6spy.engine.spy.JdbcEventListenerFactory;
|
||||
import com.p6spy.engine.spy.P6DataSource;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceNameResolver;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.P6SpyContextJdbcEventListenerFactory;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.P6SpyDataSourceDecorator;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceJdbcEventListener;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceListenerStrategySpanCustomizer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* Configuration for integration with p6spy, allows to define custom
|
||||
* {@link JdbcEventListener}.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
*/
|
||||
@ConditionalOnClass(P6DataSource.class)
|
||||
@ConditionalOnProperty(name = "spring.sleuth.jdbc.p6spy.enabled", havingValue = "true", matchIfMissing = true)
|
||||
class P6SpyConfiguration {
|
||||
|
||||
@Bean
|
||||
static P6SpyPropertiesSetter p6SpyPropertiesSetter(ConfigurableApplicationContext context) {
|
||||
return new P6SpyPropertiesSetter(context);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
JdbcEventListenerFactory traceJdbcEventListenerFactory(ObjectProvider<List<JdbcEventListener>> listeners) {
|
||||
JdbcEventListenerFactory jdbcEventListenerFactory = new DefaultJdbcEventListenerFactory();
|
||||
List<JdbcEventListener> listenerList = listeners.getIfAvailable(() -> null);
|
||||
return listenerList != null ? new P6SpyContextJdbcEventListenerFactory(jdbcEventListenerFactory, listenerList)
|
||||
: jdbcEventListenerFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
P6SpyDataSourceDecorator p6SpyDataSourceDecorator(JdbcEventListenerFactory jdbcEventListenerFactory) {
|
||||
return new P6SpyDataSourceDecorator(jdbcEventListenerFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
TraceJdbcEventListener tracingJdbcEventListener(Tracer tracer, DataSourceNameResolver dataSourceNameResolver,
|
||||
TraceJdbcProperties traceJdbcProperties,
|
||||
ObjectProvider<List<TraceListenerStrategySpanCustomizer>> customizers) {
|
||||
return new TraceJdbcEventListener(tracer, dataSourceNameResolver, traceJdbcProperties.getIncludes(),
|
||||
traceJdbcProperties.getP6spy().getTracing().isIncludeParameterValues(),
|
||||
customizers.getIfAvailable(ArrayList::new));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,187 +1,187 @@
|
||||
/*
|
||||
* 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.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.p6spy.engine.logging.P6LogFactory;
|
||||
import com.p6spy.engine.spy.P6ModuleManager;
|
||||
import com.p6spy.engine.spy.P6SpyFactory;
|
||||
import com.p6spy.engine.spy.option.EnvironmentVariables;
|
||||
import com.p6spy.engine.spy.option.P6OptionsSource;
|
||||
import com.p6spy.engine.spy.option.SpyDotProperties;
|
||||
import com.p6spy.engine.spy.option.SystemProperties;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
/**
|
||||
* Sets p6spy properties to / from system properties.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
* @since 3.1.0
|
||||
*/
|
||||
class P6SpyPropertiesSetter implements BeanDefinitionRegistryPostProcessor, Closeable {
|
||||
|
||||
private static final Logger log = getLogger(P6SpyPropertiesSetter.class);
|
||||
|
||||
private final ConfigurableApplicationContext context;
|
||||
|
||||
private final Map<String, String> initialP6SpyOptions;
|
||||
|
||||
P6SpyPropertiesSetter(ConfigurableApplicationContext context) {
|
||||
this.context = context;
|
||||
this.initialP6SpyOptions = findDefinedOptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
ConfigurableEnvironment environment = this.context.getEnvironment();
|
||||
String customModuleList = initialP6SpyOptions.get("modulelist");
|
||||
boolean isEnableLogging = environment.getProperty("spring.sleuth.jdbc.p6spy.enable-logging", Boolean.class,
|
||||
true);
|
||||
if (customModuleList != null) {
|
||||
log.info("P6Spy modulelist is overridden, some p6spy configuration features will not be applied");
|
||||
}
|
||||
else {
|
||||
List<String> moduleList = new ArrayList<>();
|
||||
// default factory, holds P6Spy configuration
|
||||
moduleList.add(P6SpyFactory.class.getName());
|
||||
if (isEnableLogging) {
|
||||
moduleList.add(P6LogFactory.class.getName());
|
||||
}
|
||||
System.setProperty("p6spy.config.modulelist", String.join(",", moduleList));
|
||||
}
|
||||
if (!initialP6SpyOptions.containsKey("logMessageFormat")) {
|
||||
String logFormat = logFormat(environment);
|
||||
boolean isMultiline = multiLine(environment);
|
||||
if (logFormat != null) {
|
||||
System.setProperty("p6spy.config.logMessageFormat", "com.p6spy.engine.spy.appender.CustomLineFormat");
|
||||
System.setProperty("p6spy.config.customLogMessageFormat", logFormat);
|
||||
}
|
||||
else if (isMultiline) {
|
||||
System.setProperty("p6spy.config.logMessageFormat", "com.p6spy.engine.spy.appender.MultiLineFormat");
|
||||
}
|
||||
}
|
||||
if (isEnableLogging && !initialP6SpyOptions.containsKey("appender")) {
|
||||
TraceDataSourceDecoratorProperties.P6SpyProperties.P6SpyLogging logging = TraceDataSourceDecoratorProperties.P6SpyProperties.P6SpyLogging
|
||||
.valueOf(environment
|
||||
.getProperty("spring.sleuth.jdbc.p6spy.logging", String.class,
|
||||
TraceDataSourceDecoratorProperties.P6SpyProperties.P6SpyLogging.SLF4J.toString())
|
||||
.toUpperCase());
|
||||
switch (logging) {
|
||||
case SYSOUT:
|
||||
System.setProperty("p6spy.config.appender", "com.p6spy.engine.spy.appender.StdoutLogger");
|
||||
break;
|
||||
case SLF4J:
|
||||
System.setProperty("p6spy.config.appender", "com.p6spy.engine.spy.appender.Slf4JLogger");
|
||||
break;
|
||||
case FILE:
|
||||
System.setProperty("p6spy.config.appender", "com.p6spy.engine.spy.appender.FileLogger");
|
||||
break;
|
||||
case CUSTOM:
|
||||
String customAppender = environment.getProperty("spring.sleuth.jdbc.p6spy.custom-appender-class",
|
||||
String.class, "");
|
||||
System.setProperty("p6spy.config.appender", customAppender);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!initialP6SpyOptions.containsKey("logfile")) {
|
||||
String logFile = environment.getProperty("spring.sleuth.jdbc.p6spy.log-file", String.class, "spy.log");
|
||||
System.setProperty("p6spy.config.logfile", logFile);
|
||||
}
|
||||
String pattern = environment.getProperty("spring.sleuth.jdbc.p6spy.log-filter.pattern", String.class);
|
||||
if (pattern != null) {
|
||||
System.setProperty("p6spy.config.filter", "true");
|
||||
System.setProperty("p6spy.config.sqlexpression", pattern);
|
||||
}
|
||||
// If factories were loaded before this method is initialized changing properties
|
||||
// will not be applied
|
||||
// Changes done in this method could not override anything user specified,
|
||||
// therefore it is safe to call reload
|
||||
P6ModuleManager.getInstance().reload();
|
||||
}
|
||||
|
||||
private Boolean multiLine(ConfigurableEnvironment environment) {
|
||||
return environment.getProperty("spring.sleuth.jdbc.p6spy.multiline", Boolean.class, true);
|
||||
}
|
||||
|
||||
private String logFormat(ConfigurableEnvironment environment) {
|
||||
return environment.getProperty("spring.sleuth.jdbc.p6spy.log-format", String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (!initialP6SpyOptions.containsKey("modulelist")) {
|
||||
System.clearProperty("p6spy.config.modulelist");
|
||||
}
|
||||
if (!initialP6SpyOptions.containsKey("logMessageFormat")) {
|
||||
ConfigurableEnvironment environment = this.context.getEnvironment();
|
||||
String logFormat = logFormat(environment);
|
||||
boolean isMultiline = multiLine(environment);
|
||||
if (logFormat != null) {
|
||||
System.clearProperty("p6spy.config.logMessageFormat");
|
||||
System.clearProperty("p6spy.config.customLogMessageFormat");
|
||||
}
|
||||
else if (isMultiline) {
|
||||
System.clearProperty("p6spy.config.logMessageFormat");
|
||||
}
|
||||
}
|
||||
if (!initialP6SpyOptions.containsKey("appender")) {
|
||||
System.clearProperty("p6spy.config.appender");
|
||||
}
|
||||
if (!initialP6SpyOptions.containsKey("logfile")) {
|
||||
System.clearProperty("p6spy.config.logfile");
|
||||
}
|
||||
P6ModuleManager.getInstance().reload();
|
||||
}
|
||||
|
||||
private Map<String, String> findDefinedOptions() {
|
||||
SpyDotProperties spyDotProperties = null;
|
||||
try {
|
||||
spyDotProperties = new SpyDotProperties();
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
return Stream.of(spyDotProperties, new EnvironmentVariables(), new SystemProperties()).filter(Objects::nonNull)
|
||||
.map(P6OptionsSource::getOptions).filter(Objects::nonNull)
|
||||
.flatMap(options -> options.entrySet().stream())
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
|
||||
// always using value from the first P6OptionsSource
|
||||
(value1, value2) -> value1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.p6spy.engine.logging.P6LogFactory;
|
||||
import com.p6spy.engine.spy.P6ModuleManager;
|
||||
import com.p6spy.engine.spy.P6SpyFactory;
|
||||
import com.p6spy.engine.spy.option.EnvironmentVariables;
|
||||
import com.p6spy.engine.spy.option.P6OptionsSource;
|
||||
import com.p6spy.engine.spy.option.SpyDotProperties;
|
||||
import com.p6spy.engine.spy.option.SystemProperties;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
/**
|
||||
* Sets p6spy properties to / from system properties.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
* @since 3.1.0
|
||||
*/
|
||||
class P6SpyPropertiesSetter implements BeanDefinitionRegistryPostProcessor, Closeable {
|
||||
|
||||
private static final Logger log = getLogger(P6SpyPropertiesSetter.class);
|
||||
|
||||
private final ConfigurableApplicationContext context;
|
||||
|
||||
private final Map<String, String> initialP6SpyOptions;
|
||||
|
||||
P6SpyPropertiesSetter(ConfigurableApplicationContext context) {
|
||||
this.context = context;
|
||||
this.initialP6SpyOptions = findDefinedOptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
ConfigurableEnvironment environment = this.context.getEnvironment();
|
||||
String customModuleList = initialP6SpyOptions.get("modulelist");
|
||||
boolean isEnableLogging = environment.getProperty("spring.sleuth.jdbc.p6spy.enable-logging", Boolean.class,
|
||||
true);
|
||||
if (customModuleList != null) {
|
||||
log.info("P6Spy modulelist is overridden, some p6spy configuration features will not be applied");
|
||||
}
|
||||
else {
|
||||
List<String> moduleList = new ArrayList<>();
|
||||
// default factory, holds P6Spy configuration
|
||||
moduleList.add(P6SpyFactory.class.getName());
|
||||
if (isEnableLogging) {
|
||||
moduleList.add(P6LogFactory.class.getName());
|
||||
}
|
||||
System.setProperty("p6spy.config.modulelist", String.join(",", moduleList));
|
||||
}
|
||||
if (!initialP6SpyOptions.containsKey("logMessageFormat")) {
|
||||
String logFormat = logFormat(environment);
|
||||
boolean isMultiline = multiLine(environment);
|
||||
if (logFormat != null) {
|
||||
System.setProperty("p6spy.config.logMessageFormat", "com.p6spy.engine.spy.appender.CustomLineFormat");
|
||||
System.setProperty("p6spy.config.customLogMessageFormat", logFormat);
|
||||
}
|
||||
else if (isMultiline) {
|
||||
System.setProperty("p6spy.config.logMessageFormat", "com.p6spy.engine.spy.appender.MultiLineFormat");
|
||||
}
|
||||
}
|
||||
if (isEnableLogging && !initialP6SpyOptions.containsKey("appender")) {
|
||||
TraceJdbcProperties.P6SpyProperties.P6SpyLogging logging = TraceJdbcProperties.P6SpyProperties.P6SpyLogging
|
||||
.valueOf(environment
|
||||
.getProperty("spring.sleuth.jdbc.p6spy.logging", String.class,
|
||||
TraceJdbcProperties.P6SpyProperties.P6SpyLogging.SLF4J.toString())
|
||||
.toUpperCase());
|
||||
switch (logging) {
|
||||
case SYSOUT:
|
||||
System.setProperty("p6spy.config.appender", "com.p6spy.engine.spy.appender.StdoutLogger");
|
||||
break;
|
||||
case SLF4J:
|
||||
System.setProperty("p6spy.config.appender", "com.p6spy.engine.spy.appender.Slf4JLogger");
|
||||
break;
|
||||
case FILE:
|
||||
System.setProperty("p6spy.config.appender", "com.p6spy.engine.spy.appender.FileLogger");
|
||||
break;
|
||||
case CUSTOM:
|
||||
String customAppender = environment.getProperty("spring.sleuth.jdbc.p6spy.custom-appender-class",
|
||||
String.class, "");
|
||||
System.setProperty("p6spy.config.appender", customAppender);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!initialP6SpyOptions.containsKey("logfile")) {
|
||||
String logFile = environment.getProperty("spring.sleuth.jdbc.p6spy.log-file", String.class, "spy.log");
|
||||
System.setProperty("p6spy.config.logfile", logFile);
|
||||
}
|
||||
String pattern = environment.getProperty("spring.sleuth.jdbc.p6spy.log-filter.pattern", String.class);
|
||||
if (pattern != null) {
|
||||
System.setProperty("p6spy.config.filter", "true");
|
||||
System.setProperty("p6spy.config.sqlexpression", pattern);
|
||||
}
|
||||
// If factories were loaded before this method is initialized changing properties
|
||||
// will not be applied
|
||||
// Changes done in this method could not override anything user specified,
|
||||
// therefore it is safe to call reload
|
||||
P6ModuleManager.getInstance().reload();
|
||||
}
|
||||
|
||||
private Boolean multiLine(ConfigurableEnvironment environment) {
|
||||
return environment.getProperty("spring.sleuth.jdbc.p6spy.multiline", Boolean.class, true);
|
||||
}
|
||||
|
||||
private String logFormat(ConfigurableEnvironment environment) {
|
||||
return environment.getProperty("spring.sleuth.jdbc.p6spy.log-format", String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (!initialP6SpyOptions.containsKey("modulelist")) {
|
||||
System.clearProperty("p6spy.config.modulelist");
|
||||
}
|
||||
if (!initialP6SpyOptions.containsKey("logMessageFormat")) {
|
||||
ConfigurableEnvironment environment = this.context.getEnvironment();
|
||||
String logFormat = logFormat(environment);
|
||||
boolean isMultiline = multiLine(environment);
|
||||
if (logFormat != null) {
|
||||
System.clearProperty("p6spy.config.logMessageFormat");
|
||||
System.clearProperty("p6spy.config.customLogMessageFormat");
|
||||
}
|
||||
else if (isMultiline) {
|
||||
System.clearProperty("p6spy.config.logMessageFormat");
|
||||
}
|
||||
}
|
||||
if (!initialP6SpyOptions.containsKey("appender")) {
|
||||
System.clearProperty("p6spy.config.appender");
|
||||
}
|
||||
if (!initialP6SpyOptions.containsKey("logfile")) {
|
||||
System.clearProperty("p6spy.config.logfile");
|
||||
}
|
||||
P6ModuleManager.getInstance().reload();
|
||||
}
|
||||
|
||||
private Map<String, String> findDefinedOptions() {
|
||||
SpyDotProperties spyDotProperties = null;
|
||||
try {
|
||||
spyDotProperties = new SpyDotProperties();
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
return Stream.of(spyDotProperties, new EnvironmentVariables(), new SystemProperties()).filter(Objects::nonNull)
|
||||
.map(P6OptionsSource::getOptions).filter(Objects::nonNull)
|
||||
.flatMap(options -> options.entrySet().stream())
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
|
||||
// always using value from the first P6OptionsSource
|
||||
(value1, value2) -> value1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,140 +1,140 @@
|
||||
/*
|
||||
* 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.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.scope.ScopedProxyUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceDecorator;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceNameResolver;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceWrapper;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link BeanPostProcessor} that wraps all data source beans in {@link DataSource}
|
||||
* proxies specified in property 'spring.datasource.type'.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public class TraceDataSourceDecoratorBeanPostProcessor implements BeanPostProcessor, Ordered, ApplicationContextAware {
|
||||
|
||||
private static final Log log = LogFactory.getLog(TraceDataSourceDecoratorBeanPostProcessor.class);
|
||||
|
||||
private final static boolean HIKARI_AVAILABLE = ClassUtils.isPresent("com.zaxxer.hikari.HikariDataSource",
|
||||
DataSourceNameResolver.class.getClassLoader());
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private DataSourceNameResolver dataSourceNameResolver;
|
||||
|
||||
private final Collection<String> excludedBeans;
|
||||
|
||||
public TraceDataSourceDecoratorBeanPostProcessor(Collection<String> excludedBeans) {
|
||||
this.excludedBeans = excludedBeans;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof DataSource && !ScopedProxyUtils.isScopedTarget(beanName)
|
||||
&& !this.excludedBeans.contains(beanName)) {
|
||||
// TODO: This might be a problem
|
||||
Map<String, DataSourceDecorator> decorators = this.applicationContext
|
||||
.getBeansOfType(DataSourceDecorator.class).entrySet().stream()
|
||||
.sorted(Entry.comparingByValue(AnnotationAwareOrderComparator.INSTANCE))
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, (v1, v2) -> v2, LinkedHashMap::new));
|
||||
return decorate((DataSource) bean, getDataSourceName(bean, beanName), decorators);
|
||||
}
|
||||
else {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
private String getDataSourceName(Object bean, String beanName) {
|
||||
if (HIKARI_AVAILABLE && bean instanceof HikariDataSource) {
|
||||
HikariDataSource hikariDataSource = (HikariDataSource) bean;
|
||||
if (hikariDataSource.getPoolName() != null && !hikariDataSource.getPoolName().startsWith("HikariPool-")) {
|
||||
return hikariDataSource.getPoolName();
|
||||
}
|
||||
}
|
||||
return beanName;
|
||||
}
|
||||
|
||||
private DataSource decorate(DataSource dataSource, String name, Map<String, DataSourceDecorator> decorators) {
|
||||
getDataSourceNameResolver().addDataSource(name, dataSource);
|
||||
DataSource decoratedDataSource = dataSource;
|
||||
for (Entry<String, DataSourceDecorator> decoratorEntry : decorators.entrySet()) {
|
||||
String decoratorBeanName = decoratorEntry.getKey();
|
||||
DataSourceDecorator decorator = decoratorEntry.getValue();
|
||||
DataSource dataSourceBeforeDecorating = decoratedDataSource;
|
||||
decoratedDataSource = Objects.requireNonNull(decorator.decorate(name, decoratedDataSource),
|
||||
"DataSourceDecorator (" + decoratorBeanName + ", " + decorator + ") should not return null");
|
||||
if (dataSourceBeforeDecorating != decoratedDataSource) {
|
||||
getDataSourceNameResolver().addDataSource(name, decoratedDataSource);
|
||||
}
|
||||
}
|
||||
if (dataSource != decoratedDataSource) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("The decorated data source [" + decoratedDataSource + "] will replace the original one ["
|
||||
+ dataSource + "]");
|
||||
}
|
||||
decoratedDataSource = new DataSourceWrapper(dataSource, decoratedDataSource);
|
||||
getDataSourceNameResolver().addDataSource(name, decoratedDataSource);
|
||||
}
|
||||
return decoratedDataSource;
|
||||
}
|
||||
|
||||
private DataSourceNameResolver getDataSourceNameResolver() {
|
||||
if (this.dataSourceNameResolver == null) {
|
||||
this.dataSourceNameResolver = this.applicationContext.getBean(DataSourceNameResolver.class);
|
||||
}
|
||||
return this.dataSourceNameResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE - 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.scope.ScopedProxyUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceDecorator;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceNameResolver;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceWrapper;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link BeanPostProcessor} that wraps all data source beans in {@link DataSource}
|
||||
* proxies specified in property 'spring.datasource.type'.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public class TraceDataSourceDecoratorBeanPostProcessor implements BeanPostProcessor, Ordered, ApplicationContextAware {
|
||||
|
||||
private static final Log log = LogFactory.getLog(TraceDataSourceDecoratorBeanPostProcessor.class);
|
||||
|
||||
private final static boolean HIKARI_AVAILABLE = ClassUtils.isPresent("com.zaxxer.hikari.HikariDataSource",
|
||||
DataSourceNameResolver.class.getClassLoader());
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private DataSourceNameResolver dataSourceNameResolver;
|
||||
|
||||
private final Collection<String> excludedBeans;
|
||||
|
||||
public TraceDataSourceDecoratorBeanPostProcessor(Collection<String> excludedBeans) {
|
||||
this.excludedBeans = excludedBeans;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof DataSource && !ScopedProxyUtils.isScopedTarget(beanName)
|
||||
&& !this.excludedBeans.contains(beanName)) {
|
||||
// TODO: This might be a problem - it can lead to eager bean init
|
||||
Map<String, DataSourceDecorator> decorators = this.applicationContext
|
||||
.getBeansOfType(DataSourceDecorator.class).entrySet().stream()
|
||||
.sorted(Entry.comparingByValue(AnnotationAwareOrderComparator.INSTANCE))
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, (v1, v2) -> v2, LinkedHashMap::new));
|
||||
return decorate((DataSource) bean, getDataSourceName(bean, beanName), decorators);
|
||||
}
|
||||
else {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
private String getDataSourceName(Object bean, String beanName) {
|
||||
if (HIKARI_AVAILABLE && bean instanceof HikariDataSource) {
|
||||
HikariDataSource hikariDataSource = (HikariDataSource) bean;
|
||||
if (hikariDataSource.getPoolName() != null && !hikariDataSource.getPoolName().startsWith("HikariPool-")) {
|
||||
return hikariDataSource.getPoolName();
|
||||
}
|
||||
}
|
||||
return beanName;
|
||||
}
|
||||
|
||||
private DataSource decorate(DataSource dataSource, String name, Map<String, DataSourceDecorator> decorators) {
|
||||
getDataSourceNameResolver().addDataSource(name, dataSource);
|
||||
DataSource decoratedDataSource = dataSource;
|
||||
for (Entry<String, DataSourceDecorator> decoratorEntry : decorators.entrySet()) {
|
||||
String decoratorBeanName = decoratorEntry.getKey();
|
||||
DataSourceDecorator decorator = decoratorEntry.getValue();
|
||||
DataSource dataSourceBeforeDecorating = decoratedDataSource;
|
||||
decoratedDataSource = Objects.requireNonNull(decorator.decorate(name, decoratedDataSource),
|
||||
"DataSourceDecorator (" + decoratorBeanName + ", " + decorator + ") should not return null");
|
||||
if (dataSourceBeforeDecorating != decoratedDataSource) {
|
||||
getDataSourceNameResolver().addDataSource(name, decoratedDataSource);
|
||||
}
|
||||
}
|
||||
if (dataSource != decoratedDataSource) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("The decorated data source [" + decoratedDataSource + "] will replace the original one ["
|
||||
+ dataSource + "]");
|
||||
}
|
||||
decoratedDataSource = new DataSourceWrapper(dataSource, decoratedDataSource);
|
||||
getDataSourceNameResolver().addDataSource(name, decoratedDataSource);
|
||||
}
|
||||
return decoratedDataSource;
|
||||
}
|
||||
|
||||
private DataSourceNameResolver getDataSourceNameResolver() {
|
||||
if (this.dataSourceNameResolver == null) {
|
||||
this.dataSourceNameResolver = this.applicationContext.getBean(DataSourceNameResolver.class);
|
||||
}
|
||||
return this.dataSourceNameResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE - 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,70 +1,70 @@
|
||||
/*
|
||||
* 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 javax.sql.DataSource;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceDecorator;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceNameResolver;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceHikariListenerStrategySpanCustomizer;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceListenerStrategySpanCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for proxying DataSource.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(TraceDataSourceDecoratorProperties.class)
|
||||
@ConditionalOnProperty(name = "spring.sleuth.jdbc.enabled", havingValue = "true", matchIfMissing = true)
|
||||
@ConditionalOnBean({ DataSource.class, Tracer.class })
|
||||
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
|
||||
@Import({ P6SpyConfiguration.class, DataSourceProxyConfiguration.class })
|
||||
public class TraceDataSourceDecoratorAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(DataSourceDecorator.class)
|
||||
static TraceDataSourceDecoratorBeanPostProcessor traceDataSourceDecoratorBeanPostProcessor(
|
||||
TraceDataSourceDecoratorProperties dataSourceDecoratorProperties) {
|
||||
return new TraceDataSourceDecoratorBeanPostProcessor(dataSourceDecoratorProperties.getExcludedBeans());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
DataSourceNameResolver traceDataSourceNameResolver() {
|
||||
return new DataSourceNameResolver();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "com.zaxxer.hikari.HikariDataSource")
|
||||
TraceListenerStrategySpanCustomizer hikariTraceListenerStrategySpanCustomizer() {
|
||||
return new TraceHikariListenerStrategySpanCustomizer();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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 javax.sql.DataSource;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceDecorator;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceNameResolver;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceHikariListenerStrategySpanCustomizer;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceListenerStrategySpanCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for proxying DataSource.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(TraceJdbcProperties.class)
|
||||
@ConditionalOnProperty(name = "spring.sleuth.jdbc.enabled", havingValue = "true", matchIfMissing = true)
|
||||
@ConditionalOnBean({ DataSource.class, Tracer.class })
|
||||
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
|
||||
@Import({ P6SpyConfiguration.class, DataSourceProxyConfiguration.class })
|
||||
public class TraceJdbcAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(DataSourceDecorator.class)
|
||||
static TraceDataSourceDecoratorBeanPostProcessor traceDataSourceDecoratorBeanPostProcessor(
|
||||
TraceJdbcProperties dataSourceDecoratorProperties) {
|
||||
return new TraceDataSourceDecoratorBeanPostProcessor(dataSourceDecoratorProperties.getExcludedDataSourceBeanNames());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
DataSourceNameResolver traceDataSourceNameResolver() {
|
||||
return new DataSourceNameResolver();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "com.zaxxer.hikari.HikariDataSource")
|
||||
TraceListenerStrategySpanCustomizer hikariTraceListenerStrategySpanCustomizer() {
|
||||
return new TraceHikariListenerStrategySpanCustomizer();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,485 +1,511 @@
|
||||
/*
|
||||
* 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.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceType;
|
||||
|
||||
/**
|
||||
* Properties for configuring proxy providers.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
* @since 3.1.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "spring.sleuth.jdbc")
|
||||
public class TraceDataSourceDecoratorProperties {
|
||||
|
||||
/**
|
||||
* Enables data source decorating.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* Beans that won't be decorated.
|
||||
*/
|
||||
private Collection<String> excludedBeans = Collections.emptyList();
|
||||
|
||||
/**
|
||||
* Which types of tracing we would like to include.
|
||||
*/
|
||||
private List<TraceType> includes = Arrays.asList(TraceType.CONNECTION, TraceType.QUERY, TraceType.FETCH);
|
||||
|
||||
private DataSourceProxyProperties datasourceProxy = new DataSourceProxyProperties();
|
||||
|
||||
private P6SpyProperties p6spy = new P6SpyProperties();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public Collection<String> getExcludedBeans() {
|
||||
return excludedBeans;
|
||||
}
|
||||
|
||||
public List<TraceType> getIncludes() {
|
||||
return includes;
|
||||
}
|
||||
|
||||
public void setIncludes(List<TraceType> includes) {
|
||||
this.includes = includes;
|
||||
}
|
||||
|
||||
public DataSourceProxyProperties getDatasourceProxy() {
|
||||
return datasourceProxy;
|
||||
}
|
||||
|
||||
public P6SpyProperties getP6spy() {
|
||||
return p6spy;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public void setExcludedBeans(Collection<String> excludedBeans) {
|
||||
this.excludedBeans = excludedBeans;
|
||||
}
|
||||
|
||||
public void setDatasourceProxy(DataSourceProxyProperties datasourceProxy) {
|
||||
this.datasourceProxy = datasourceProxy;
|
||||
}
|
||||
|
||||
public void setP6spy(P6SpyProperties p6spy) {
|
||||
this.p6spy = p6spy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties for datasource-proxy.
|
||||
*/
|
||||
public static class DataSourceProxyProperties {
|
||||
|
||||
/**
|
||||
* Logging to use for logging queries.
|
||||
*/
|
||||
private DataSourceProxyLogging logging = DataSourceProxyLogging.SLF4J;
|
||||
|
||||
/**
|
||||
* Query configuration.
|
||||
*/
|
||||
private Query query = new Query();
|
||||
|
||||
/**
|
||||
* Slow query configuration.
|
||||
*/
|
||||
private SlowQuery slowQuery = new SlowQuery();
|
||||
|
||||
/**
|
||||
* Use multiline output for logging query.
|
||||
*
|
||||
* @see ProxyDataSourceBuilder#multiline()
|
||||
*/
|
||||
private boolean multiline = true;
|
||||
|
||||
/**
|
||||
* Use json output for logging query.
|
||||
*
|
||||
* @see ProxyDataSourceBuilder#asJson()
|
||||
*/
|
||||
private boolean jsonFormat = false;
|
||||
|
||||
public DataSourceProxyLogging getLogging() {
|
||||
return logging;
|
||||
}
|
||||
|
||||
public void setLogging(DataSourceProxyLogging logging) {
|
||||
this.logging = logging;
|
||||
}
|
||||
|
||||
public Query getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
public void setQuery(Query query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
public SlowQuery getSlowQuery() {
|
||||
return slowQuery;
|
||||
}
|
||||
|
||||
public void setSlowQuery(SlowQuery slowQuery) {
|
||||
this.slowQuery = slowQuery;
|
||||
}
|
||||
|
||||
public boolean isMultiline() {
|
||||
return multiline;
|
||||
}
|
||||
|
||||
public void setMultiline(boolean multiline) {
|
||||
this.multiline = multiline;
|
||||
}
|
||||
|
||||
public boolean isJsonFormat() {
|
||||
return jsonFormat;
|
||||
}
|
||||
|
||||
public void setJsonFormat(boolean jsonFormat) {
|
||||
this.jsonFormat = jsonFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties to configure query logging listener.
|
||||
*/
|
||||
public static class Query {
|
||||
|
||||
/**
|
||||
* Enable logging all queries to the log.
|
||||
*/
|
||||
private boolean enableLogging = true;
|
||||
|
||||
/**
|
||||
* Name of query logger.
|
||||
*/
|
||||
private String loggerName;
|
||||
|
||||
/**
|
||||
* Severity of query logger.
|
||||
*/
|
||||
private String logLevel = "DEBUG";
|
||||
|
||||
public boolean isEnableLogging() {
|
||||
return enableLogging;
|
||||
}
|
||||
|
||||
public void setEnableLogging(boolean enableLogging) {
|
||||
this.enableLogging = enableLogging;
|
||||
}
|
||||
|
||||
public String getLoggerName() {
|
||||
return loggerName;
|
||||
}
|
||||
|
||||
public void setLoggerName(String loggerName) {
|
||||
this.loggerName = loggerName;
|
||||
}
|
||||
|
||||
public String getLogLevel() {
|
||||
return logLevel;
|
||||
}
|
||||
|
||||
public void setLogLevel(String logLevel) {
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties to configure slow query logging listener.
|
||||
*/
|
||||
public static class SlowQuery {
|
||||
|
||||
/**
|
||||
* Enable logging slow queries to the log.
|
||||
*/
|
||||
private boolean enableLogging = true;
|
||||
|
||||
/**
|
||||
* Name of slow query logger.
|
||||
*/
|
||||
private String loggerName;
|
||||
|
||||
/**
|
||||
* Severity of slow query logger.
|
||||
*/
|
||||
private String logLevel = "WARN";
|
||||
|
||||
/**
|
||||
* Number of seconds to consider query as slow.
|
||||
*/
|
||||
private long threshold = 300;
|
||||
|
||||
boolean isEnableLogging() {
|
||||
return enableLogging;
|
||||
}
|
||||
|
||||
public void setEnableLogging(boolean enableLogging) {
|
||||
this.enableLogging = enableLogging;
|
||||
}
|
||||
|
||||
public String getLoggerName() {
|
||||
return loggerName;
|
||||
}
|
||||
|
||||
public void setLoggerName(String loggerName) {
|
||||
this.loggerName = loggerName;
|
||||
}
|
||||
|
||||
public String getLogLevel() {
|
||||
return logLevel;
|
||||
}
|
||||
|
||||
public void setLogLevel(String logLevel) {
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
|
||||
public long getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
public void setThreshold(long threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Query logging listener is the most used listener that logs executing query with
|
||||
* actual parameters to. You can pick one of the following proxy logging
|
||||
* mechanisms.
|
||||
*/
|
||||
public enum DataSourceProxyLogging {
|
||||
|
||||
/**
|
||||
* Log using System.out.
|
||||
*/
|
||||
SYSOUT,
|
||||
|
||||
/**
|
||||
* Log using SLF4J.
|
||||
*/
|
||||
SLF4J,
|
||||
|
||||
/**
|
||||
* Log using Commons.
|
||||
*/
|
||||
COMMONS,
|
||||
|
||||
/**
|
||||
* Log using Java Util Logging.
|
||||
*/
|
||||
JUL
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties for configuring p6spy.
|
||||
*/
|
||||
public static class P6SpyProperties {
|
||||
|
||||
/**
|
||||
* Enables logging JDBC events.
|
||||
*/
|
||||
private boolean enableLogging = true;
|
||||
|
||||
/**
|
||||
* Enables multiline output.
|
||||
*/
|
||||
private boolean multiline = true;
|
||||
|
||||
/**
|
||||
* Logging to use for logging queries.
|
||||
*/
|
||||
private P6SpyLogging logging = P6SpyLogging.SLF4J;
|
||||
|
||||
/**
|
||||
* Name of log file to use (only with logging=file).
|
||||
*/
|
||||
private String logFile = "spy.log";
|
||||
|
||||
/**
|
||||
* Custom log format.
|
||||
*/
|
||||
private String logFormat;
|
||||
|
||||
/**
|
||||
* Tracing related properties.
|
||||
*/
|
||||
private P6SpyTracing tracing = new P6SpyTracing();
|
||||
|
||||
/**
|
||||
* Class file to use (only with logging=custom). The class must implement
|
||||
* {@link com.p6spy.engine.spy.appender.FormattedLogger}.
|
||||
*/
|
||||
private String customAppenderClass;
|
||||
|
||||
/**
|
||||
* Log filtering related properties.
|
||||
*/
|
||||
private P6SpyLogFilter logFilter = new P6SpyLogFilter();
|
||||
|
||||
public boolean isEnableLogging() {
|
||||
return enableLogging;
|
||||
}
|
||||
|
||||
public void setEnableLogging(boolean enableLogging) {
|
||||
this.enableLogging = enableLogging;
|
||||
}
|
||||
|
||||
public boolean isMultiline() {
|
||||
return multiline;
|
||||
}
|
||||
|
||||
public void setMultiline(boolean multiline) {
|
||||
this.multiline = multiline;
|
||||
}
|
||||
|
||||
public P6SpyLogging getLogging() {
|
||||
return logging;
|
||||
}
|
||||
|
||||
public void setLogging(P6SpyLogging logging) {
|
||||
this.logging = logging;
|
||||
}
|
||||
|
||||
public String getLogFile() {
|
||||
return logFile;
|
||||
}
|
||||
|
||||
public void setLogFile(String logFile) {
|
||||
this.logFile = logFile;
|
||||
}
|
||||
|
||||
public String getLogFormat() {
|
||||
return logFormat;
|
||||
}
|
||||
|
||||
public void setLogFormat(String logFormat) {
|
||||
this.logFormat = logFormat;
|
||||
}
|
||||
|
||||
public P6SpyTracing getTracing() {
|
||||
return tracing;
|
||||
}
|
||||
|
||||
public void setTracing(P6SpyTracing tracing) {
|
||||
this.tracing = tracing;
|
||||
}
|
||||
|
||||
public String getCustomAppenderClass() {
|
||||
return customAppenderClass;
|
||||
}
|
||||
|
||||
public void setCustomAppenderClass(String customAppenderClass) {
|
||||
this.customAppenderClass = customAppenderClass;
|
||||
}
|
||||
|
||||
public P6SpyLogFilter getLogFilter() {
|
||||
return logFilter;
|
||||
}
|
||||
|
||||
public void setLogFilter(P6SpyLogFilter logFilter) {
|
||||
this.logFilter = logFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* P6Spy logging options.
|
||||
*/
|
||||
public enum P6SpyLogging {
|
||||
|
||||
/**
|
||||
* Log using System.out.
|
||||
*/
|
||||
SYSOUT,
|
||||
|
||||
/**
|
||||
* Log using SLF4J.
|
||||
*/
|
||||
SLF4J,
|
||||
|
||||
/**
|
||||
* Log to file.
|
||||
*/
|
||||
FILE,
|
||||
|
||||
/**
|
||||
* Custom logging.
|
||||
*/
|
||||
CUSTOM
|
||||
|
||||
}
|
||||
|
||||
public static class P6SpyTracing {
|
||||
|
||||
/**
|
||||
* Report the effective sql string (with '?' replaced with real values) to
|
||||
* tracing systems.
|
||||
* <p>
|
||||
* NOTE this setting does not affect the logging message.
|
||||
*/
|
||||
private boolean includeParameterValues = true;
|
||||
|
||||
public boolean isIncludeParameterValues() {
|
||||
return includeParameterValues;
|
||||
}
|
||||
|
||||
public void setIncludeParameterValues(boolean includeParameterValues) {
|
||||
this.includeParameterValues = includeParameterValues;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class P6SpyLogFilter {
|
||||
|
||||
/**
|
||||
* Use regex pattern to filter log messages. Only matched messages will be
|
||||
* logged.
|
||||
*/
|
||||
private Pattern pattern;
|
||||
|
||||
public Pattern getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public void setPattern(Pattern pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceType;
|
||||
|
||||
/**
|
||||
* Properties for JDBC instrumentation.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
* @since 3.1.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "spring.sleuth.jdbc")
|
||||
public class TraceJdbcProperties {
|
||||
|
||||
/**
|
||||
* Enables JDBC instrumentation.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* List of DataSource bean names that will not be decorated.
|
||||
*/
|
||||
private Collection<String> excludedDataSourceBeanNames = Collections.emptyList();
|
||||
|
||||
/**
|
||||
* Which types of tracing we would like to include.
|
||||
*/
|
||||
private List<TraceType> includes = Arrays.asList(TraceType.CONNECTION, TraceType.QUERY, TraceType.FETCH);
|
||||
|
||||
private DataSourceProxyProperties datasourceProxy = new DataSourceProxyProperties();
|
||||
|
||||
private P6SpyProperties p6spy = new P6SpyProperties();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public Collection<String> getExcludedDataSourceBeanNames() {
|
||||
return this.excludedDataSourceBeanNames;
|
||||
}
|
||||
|
||||
public List<TraceType> getIncludes() {
|
||||
return this.includes;
|
||||
}
|
||||
|
||||
public void setIncludes(List<TraceType> includes) {
|
||||
this.includes = includes;
|
||||
}
|
||||
|
||||
public DataSourceProxyProperties getDatasourceProxy() {
|
||||
return datasourceProxy;
|
||||
}
|
||||
|
||||
public P6SpyProperties getP6spy() {
|
||||
return this.p6spy;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public void setExcludedDataSourceBeanNames(Collection<String> excludedDataSourceBeanNames) {
|
||||
this.excludedDataSourceBeanNames = excludedDataSourceBeanNames;
|
||||
}
|
||||
|
||||
public void setDatasourceProxy(DataSourceProxyProperties datasourceProxy) {
|
||||
this.datasourceProxy = datasourceProxy;
|
||||
}
|
||||
|
||||
public void setP6spy(P6SpyProperties p6spy) {
|
||||
this.p6spy = p6spy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties for datasource-proxy.
|
||||
*/
|
||||
public static class DataSourceProxyProperties {
|
||||
|
||||
/**
|
||||
* Should the datasource-proxy tracing be enabled?
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* Logging to use for logging queries.
|
||||
*/
|
||||
private DataSourceProxyLogging logging = DataSourceProxyLogging.SLF4J;
|
||||
|
||||
/**
|
||||
* Query configuration.
|
||||
*/
|
||||
private Query query = new Query();
|
||||
|
||||
/**
|
||||
* Slow query configuration.
|
||||
*/
|
||||
private SlowQuery slowQuery = new SlowQuery();
|
||||
|
||||
/**
|
||||
* Use multiline output for logging query.
|
||||
*
|
||||
* @see ProxyDataSourceBuilder#multiline()
|
||||
*/
|
||||
private boolean multiline = true;
|
||||
|
||||
/**
|
||||
* Use json output for logging query.
|
||||
*
|
||||
* @see ProxyDataSourceBuilder#asJson()
|
||||
*/
|
||||
private boolean jsonFormat = false;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public DataSourceProxyLogging getLogging() {
|
||||
return this.logging;
|
||||
}
|
||||
|
||||
public void setLogging(DataSourceProxyLogging logging) {
|
||||
this.logging = logging;
|
||||
}
|
||||
|
||||
public Query getQuery() {
|
||||
return this.query;
|
||||
}
|
||||
|
||||
public void setQuery(Query query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
public SlowQuery getSlowQuery() {
|
||||
return this.slowQuery;
|
||||
}
|
||||
|
||||
public void setSlowQuery(SlowQuery slowQuery) {
|
||||
this.slowQuery = slowQuery;
|
||||
}
|
||||
|
||||
public boolean isMultiline() {
|
||||
return this.multiline;
|
||||
}
|
||||
|
||||
public void setMultiline(boolean multiline) {
|
||||
this.multiline = multiline;
|
||||
}
|
||||
|
||||
public boolean isJsonFormat() {
|
||||
return this.jsonFormat;
|
||||
}
|
||||
|
||||
public void setJsonFormat(boolean jsonFormat) {
|
||||
this.jsonFormat = jsonFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties to configure query logging listener.
|
||||
*/
|
||||
public static class Query {
|
||||
|
||||
/**
|
||||
* Enable logging all queries to the log.
|
||||
*/
|
||||
private boolean enableLogging = true;
|
||||
|
||||
/**
|
||||
* Name of query logger.
|
||||
*/
|
||||
private String loggerName;
|
||||
|
||||
/**
|
||||
* Severity of query logger.
|
||||
*/
|
||||
private String logLevel = "DEBUG";
|
||||
|
||||
public boolean isEnableLogging() {
|
||||
return this.enableLogging;
|
||||
}
|
||||
|
||||
public void setEnableLogging(boolean enableLogging) {
|
||||
this.enableLogging = enableLogging;
|
||||
}
|
||||
|
||||
public String getLoggerName() {
|
||||
return this.loggerName;
|
||||
}
|
||||
|
||||
public void setLoggerName(String loggerName) {
|
||||
this.loggerName = loggerName;
|
||||
}
|
||||
|
||||
public String getLogLevel() {
|
||||
return this.logLevel;
|
||||
}
|
||||
|
||||
public void setLogLevel(String logLevel) {
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties to configure slow query logging listener.
|
||||
*/
|
||||
public static class SlowQuery {
|
||||
|
||||
/**
|
||||
* Enable logging slow queries to the log.
|
||||
*/
|
||||
private boolean enableLogging = true;
|
||||
|
||||
/**
|
||||
* Name of slow query logger.
|
||||
*/
|
||||
private String loggerName;
|
||||
|
||||
/**
|
||||
* Severity of slow query logger.
|
||||
*/
|
||||
private String logLevel = "WARN";
|
||||
|
||||
/**
|
||||
* Number of seconds to consider query as slow.
|
||||
*/
|
||||
private long threshold = 300;
|
||||
|
||||
boolean isEnableLogging() {
|
||||
return enableLogging;
|
||||
}
|
||||
|
||||
public void setEnableLogging(boolean enableLogging) {
|
||||
this.enableLogging = enableLogging;
|
||||
}
|
||||
|
||||
public String getLoggerName() {
|
||||
return loggerName;
|
||||
}
|
||||
|
||||
public void setLoggerName(String loggerName) {
|
||||
this.loggerName = loggerName;
|
||||
}
|
||||
|
||||
public String getLogLevel() {
|
||||
return logLevel;
|
||||
}
|
||||
|
||||
public void setLogLevel(String logLevel) {
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
|
||||
public long getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
public void setThreshold(long threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Query logging listener is the most used listener that logs executing query with
|
||||
* actual parameters to. You can pick one of the following proxy logging
|
||||
* mechanisms.
|
||||
*/
|
||||
public enum DataSourceProxyLogging {
|
||||
|
||||
/**
|
||||
* Log using System.out.
|
||||
*/
|
||||
SYSOUT,
|
||||
|
||||
/**
|
||||
* Log using SLF4J.
|
||||
*/
|
||||
SLF4J,
|
||||
|
||||
/**
|
||||
* Log using Commons.
|
||||
*/
|
||||
COMMONS,
|
||||
|
||||
/**
|
||||
* Log using Java Util Logging.
|
||||
*/
|
||||
JUL
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties for configuring p6spy.
|
||||
*/
|
||||
public static class P6SpyProperties {
|
||||
|
||||
/**
|
||||
* Should the p6spy tracing be enabled?
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* Enables logging JDBC events.
|
||||
*/
|
||||
private boolean enableLogging = true;
|
||||
|
||||
/**
|
||||
* Enables multiline output.
|
||||
*/
|
||||
private boolean multiline = true;
|
||||
|
||||
/**
|
||||
* Logging to use for logging queries.
|
||||
*/
|
||||
private P6SpyLogging logging = P6SpyLogging.SLF4J;
|
||||
|
||||
/**
|
||||
* Name of log file to use (only with logging=file).
|
||||
*/
|
||||
private String logFile = "spy.log";
|
||||
|
||||
/**
|
||||
* Custom log format.
|
||||
*/
|
||||
private String logFormat;
|
||||
|
||||
/**
|
||||
* Tracing related properties.
|
||||
*/
|
||||
private P6SpyTracing tracing = new P6SpyTracing();
|
||||
|
||||
/**
|
||||
* Class file to use (only with logging=custom). The class must implement
|
||||
* {@link com.p6spy.engine.spy.appender.FormattedLogger}.
|
||||
*/
|
||||
private String customAppenderClass;
|
||||
|
||||
/**
|
||||
* Log filtering related properties.
|
||||
*/
|
||||
private P6SpyLogFilter logFilter = new P6SpyLogFilter();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isEnableLogging() {
|
||||
return this.enableLogging;
|
||||
}
|
||||
|
||||
public void setEnableLogging(boolean enableLogging) {
|
||||
this.enableLogging = enableLogging;
|
||||
}
|
||||
|
||||
public boolean isMultiline() {
|
||||
return this.multiline;
|
||||
}
|
||||
|
||||
public void setMultiline(boolean multiline) {
|
||||
this.multiline = multiline;
|
||||
}
|
||||
|
||||
public P6SpyLogging getLogging() {
|
||||
return this.logging;
|
||||
}
|
||||
|
||||
public void setLogging(P6SpyLogging logging) {
|
||||
this.logging = logging;
|
||||
}
|
||||
|
||||
public String getLogFile() {
|
||||
return this.logFile;
|
||||
}
|
||||
|
||||
public void setLogFile(String logFile) {
|
||||
this.logFile = logFile;
|
||||
}
|
||||
|
||||
public String getLogFormat() {
|
||||
return this.logFormat;
|
||||
}
|
||||
|
||||
public void setLogFormat(String logFormat) {
|
||||
this.logFormat = logFormat;
|
||||
}
|
||||
|
||||
public P6SpyTracing getTracing() {
|
||||
return this.tracing;
|
||||
}
|
||||
|
||||
public void setTracing(P6SpyTracing tracing) {
|
||||
this.tracing = tracing;
|
||||
}
|
||||
|
||||
public String getCustomAppenderClass() {
|
||||
return this.customAppenderClass;
|
||||
}
|
||||
|
||||
public void setCustomAppenderClass(String customAppenderClass) {
|
||||
this.customAppenderClass = customAppenderClass;
|
||||
}
|
||||
|
||||
public P6SpyLogFilter getLogFilter() {
|
||||
return this.logFilter;
|
||||
}
|
||||
|
||||
public void setLogFilter(P6SpyLogFilter logFilter) {
|
||||
this.logFilter = logFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* P6Spy logging options.
|
||||
*/
|
||||
public enum P6SpyLogging {
|
||||
|
||||
/**
|
||||
* Log using System.out.
|
||||
*/
|
||||
SYSOUT,
|
||||
|
||||
/**
|
||||
* Log using SLF4J.
|
||||
*/
|
||||
SLF4J,
|
||||
|
||||
/**
|
||||
* Log to file.
|
||||
*/
|
||||
FILE,
|
||||
|
||||
/**
|
||||
* Custom logging.
|
||||
*/
|
||||
CUSTOM
|
||||
|
||||
}
|
||||
|
||||
public static class P6SpyTracing {
|
||||
|
||||
/**
|
||||
* Report the effective sql string (with '?' replaced with real values) to
|
||||
* tracing systems.
|
||||
* <p>
|
||||
* NOTE this setting does not affect the logging message.
|
||||
*/
|
||||
private boolean includeParameterValues = true;
|
||||
|
||||
public boolean isIncludeParameterValues() {
|
||||
return this.includeParameterValues;
|
||||
}
|
||||
|
||||
public void setIncludeParameterValues(boolean includeParameterValues) {
|
||||
this.includeParameterValues = includeParameterValues;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class P6SpyLogFilter {
|
||||
|
||||
/**
|
||||
* Use regex pattern to filter log messages. Only matched messages will be
|
||||
* logged.
|
||||
*/
|
||||
private Pattern pattern;
|
||||
|
||||
public Pattern getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
public void setPattern(Pattern pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,7 @@ org.springframework.cloud.sleuth.autoconfig.instrument.batch.TraceBatchAutoConfi
|
||||
org.springframework.cloud.sleuth.autoconfig.instrument.config.TraceSpringCloudConfigAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.autoconfig.instrument.circuitbreaker.TraceCircuitBreakerAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.autoconfig.instrument.deployer.TraceDeployerAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.autoconfig.instrument.jdbc.TraceDataSourceDecoratorAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.autoconfig.instrument.jdbc.TraceJdbcAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.autoconfig.instrument.rxjava.TraceRxJavaAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.autoconfig.instrument.quartz.TraceQuartzAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.autoconfig.instrument.task.TraceTaskAutoConfiguration,\
|
||||
|
||||
@@ -1,88 +1,104 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.CurrentTraceContext;
|
||||
import org.springframework.cloud.sleuth.SpanCustomizer;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.autoconfig.instrument.web.ConditionalOnSleuthWeb;
|
||||
import org.springframework.cloud.sleuth.autoconfig.instrument.web.client.ConditionalnOnSleuthWebClient;
|
||||
import org.springframework.cloud.sleuth.http.HttpClientHandler;
|
||||
import org.springframework.cloud.sleuth.http.HttpServerHandler;
|
||||
import org.springframework.cloud.sleuth.propagation.Propagator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} to enable tracing via Spring Cloud Sleuth.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Tim Ysewyn
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnProperty("spring.sleuth.noop.enabled")
|
||||
@AutoConfigureBefore(BraveAutoConfiguration.class)
|
||||
@Import(TraceConfiguration.class)
|
||||
public class TraceNoOpAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
Tracer defaultTracer() {
|
||||
return new NoOpTracer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Propagator defaultPropagator() {
|
||||
return new NoOpPropagator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
CurrentTraceContext defaultCurrentTraceContext() {
|
||||
return new NoOpCurrentTraceContext();
|
||||
}
|
||||
|
||||
@Bean
|
||||
SpanCustomizer defaultSpanCustomizer() {
|
||||
return new NoOpSpanCustomizer();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TraceHttpConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalnOnSleuthWebClient
|
||||
HttpClientHandler defaultHttpClientHandler() {
|
||||
return new NoOpHttpClientHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnSleuthWeb
|
||||
HttpServerHandler defaultHttpServerHandler() {
|
||||
return new NoOpHttpServerHandler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.CurrentTraceContext;
|
||||
import org.springframework.cloud.sleuth.SpanCustomizer;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.autoconfig.instrument.web.ConditionalOnSleuthWeb;
|
||||
import org.springframework.cloud.sleuth.autoconfig.instrument.web.client.ConditionalnOnSleuthWebClient;
|
||||
import org.springframework.cloud.sleuth.http.HttpClientHandler;
|
||||
import org.springframework.cloud.sleuth.http.HttpServerHandler;
|
||||
import org.springframework.cloud.sleuth.propagation.Propagator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} to enable tracing via Spring Cloud Sleuth.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Tim Ysewyn
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnSleuth
|
||||
@ConditionalOnProperty("spring.sleuth.noop.enabled")
|
||||
@AutoConfigureBefore(BraveAutoConfiguration.class)
|
||||
@Import(TraceConfiguration.class)
|
||||
public class TraceNoOpAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
Tracer defaultTracer() {
|
||||
return new NoOpTracer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Propagator defaultPropagator() {
|
||||
return new NoOpPropagator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
CurrentTraceContext defaultCurrentTraceContext() {
|
||||
return new NoOpCurrentTraceContext();
|
||||
}
|
||||
|
||||
@Bean
|
||||
SpanCustomizer defaultSpanCustomizer() {
|
||||
return new NoOpSpanCustomizer();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TraceHttpConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalnOnSleuthWebClient
|
||||
HttpClientHandler defaultHttpClientHandler() {
|
||||
return new NoOpHttpClientHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnSleuthWeb
|
||||
HttpServerHandler defaultHttpServerHandler() {
|
||||
return new NoOpHttpServerHandler();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Documented
|
||||
@ConditionalOnProperty(value = "spring.sleuth.enabled", matchIfMissing = true)
|
||||
@interface ConditionalOnSleuth {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,370 +1,371 @@
|
||||
/*
|
||||
* 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.io.PrintWriter;
|
||||
import java.sql.Connection;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.p6spy.engine.spy.P6DataSource;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSource;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
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.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceDecorator;
|
||||
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 org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.annotation.ScopedProxyMode;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class DataSourceDecoratorAutoConfigurationTests {
|
||||
|
||||
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());
|
||||
|
||||
@Test
|
||||
void testDecoratingInDefaultOrder() {
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
assertThat(dataSource).isInstanceOf(DataSourceWrapper.class);
|
||||
|
||||
DataSourceWrapper DataSourceWrapper = (DataSourceWrapper) dataSource;
|
||||
assertThat(DataSourceWrapper.getDecoratedDataSource()).isInstanceOf(P6DataSource.class);
|
||||
P6DataSource p6DataSource = (P6DataSource) DataSourceWrapper.getDecoratedDataSource();
|
||||
|
||||
DataSource p6WrappedDataSource = (DataSource) ReflectionTestUtils.getField(p6DataSource, "realDataSource");
|
||||
assertThat(p6WrappedDataSource).isInstanceOf(ProxyDataSource.class);
|
||||
ProxyDataSource proxyDataSource = (ProxyDataSource) p6WrappedDataSource;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoDecoratingForExcludeBeans() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withPropertyValues("spring.sleuth.jdbc.excluded-beans:dataSource");
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
|
||||
assertThat(dataSource).isInstanceOf(HikariDataSource.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecoratingWhenDefaultProxyProviderNotAvailable() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner;
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
|
||||
assertThat(((DataSourceWrapper) dataSource).getOriginalDataSource()).isInstanceOf(HikariDataSource.class);
|
||||
|
||||
DataSourceWrapper DataSourceWrapper = (DataSourceWrapper) dataSource;
|
||||
assertThat(DataSourceWrapper.getDecoratedDataSource()).isInstanceOf(P6DataSource.class);
|
||||
P6DataSource p6DataSource = (P6DataSource) DataSourceWrapper.getDecoratedDataSource();
|
||||
|
||||
DataSource p6WrappedDataSource = (DataSource) ReflectionTestUtils.getField(p6DataSource, "realDataSource");
|
||||
assertThat(p6WrappedDataSource).isInstanceOf(ProxyDataSource.class);
|
||||
ProxyDataSource proxyDataSource = (ProxyDataSource) p6WrappedDataSource;
|
||||
|
||||
DataSource dsProxyWrappedDataSource = (DataSource) ReflectionTestUtils.getField(proxyDataSource,
|
||||
"dataSource");
|
||||
assertThat(dsProxyWrappedDataSource).isEqualTo(DataSourceWrapper.getOriginalDataSource());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecoratedHikariSpecificPropertiesIsSet() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues(
|
||||
"spring.datasource.type:" + HikariDataSource.class.getName(),
|
||||
"spring.datasource.hikari.catalog:test_catalog");
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
assertThat(dataSource).isNotNull();
|
||||
assertThat(dataSource).isInstanceOf(DataSourceWrapper.class);
|
||||
DataSource realDataSource = ((DataSourceWrapper) dataSource).getOriginalDataSource();
|
||||
assertThat(realDataSource).isInstanceOf(HikariDataSource.class);
|
||||
assertThat(((HikariDataSource) realDataSource).getCatalog()).isEqualTo("test_catalog");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomDataSourceIsDecorated() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withUserConfiguration(TestDataSourceConfiguration.class);
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
assertThat(dataSource).isInstanceOf(DataSourceWrapper.class);
|
||||
DataSource realDataSource = ((DataSourceWrapper) dataSource).getOriginalDataSource();
|
||||
assertThat(realDataSource).isInstanceOf(BasicDataSource.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testScopedDataSourceIsNotDecorated() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withUserConfiguration(TestScopedDataSourceConfiguration.class);
|
||||
|
||||
contextRunner.run(context -> {
|
||||
assertThat(context).getBeanNames(DataSource.class).containsOnly("dataSource", "scopedTarget.dataSource");
|
||||
assertThat(context).getBean("dataSource").isInstanceOf(DataSourceWrapper.class);
|
||||
assertThat(context).getBean("scopedTarget.dataSource").isNotInstanceOf(DataSourceWrapper.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomDataSourceDecoratorApplied() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withUserConfiguration(TestDataSourceDecoratorConfiguration.class);
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
assertThat(dataSource).isNotNull();
|
||||
|
||||
DataSource customDataSource = ((DataSourceWrapper) dataSource).getDecoratedDataSource();
|
||||
assertThat(customDataSource).isInstanceOf(CustomDataSourceProxy.class);
|
||||
|
||||
DataSource realDataSource = ((DataSourceWrapper) dataSource).getOriginalDataSource();
|
||||
assertThat(realDataSource).isInstanceOf(HikariDataSource.class);
|
||||
|
||||
assertThat(dataSource).isInstanceOf(DataSourceWrapper.class);
|
||||
|
||||
DataSourceWrapper DataSourceWrapper = (DataSourceWrapper) dataSource;
|
||||
|
||||
assertThat(DataSourceWrapper.getDecoratedDataSource()).isInstanceOf(CustomDataSourceProxy.class);
|
||||
CustomDataSourceProxy customDataSourceProxy = (CustomDataSourceProxy) DataSourceWrapper
|
||||
.getDecoratedDataSource();
|
||||
|
||||
assertThat(customDataSourceProxy.delegate).isInstanceOf(P6DataSource.class);
|
||||
P6DataSource p6DataSource = (P6DataSource) customDataSourceProxy.delegate;
|
||||
|
||||
DataSource p6WrappedDataSource = (DataSource) ReflectionTestUtils.getField(p6DataSource, "realDataSource");
|
||||
assertThat(p6WrappedDataSource).isInstanceOf(ProxyDataSource.class);
|
||||
ProxyDataSource proxyDataSource = (ProxyDataSource) p6WrappedDataSource;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecoratingCanBeDisabled() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withPropertyValues("spring.sleuth.jdbc.enabled:false");
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
assertThat(dataSource).isInstanceOf(HikariDataSource.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecoratingCanBeDisabledForSpecificBeans() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withPropertyValues("spring.sleuth.jdbc.excluded-beans:secondDataSource")
|
||||
.withUserConfiguration(TestMultiDataSourceConfiguration.class);
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean("dataSource", DataSource.class);
|
||||
assertThat(dataSource).isInstanceOf(DataSourceWrapper.class);
|
||||
|
||||
DataSource secondDataSource = context.getBean("secondDataSource", DataSource.class);
|
||||
assertThat(secondDataSource).isInstanceOf(BasicDataSource.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecoratingChainBuiltCorrectly() {
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
|
||||
DataSourceWrapper dataSource1 = context.getBean(DataSourceWrapper.class);
|
||||
assertThat(dataSource1).isNotNull();
|
||||
|
||||
DataSource p6DataSource = dataSource1.getDecoratedDataSource();
|
||||
assertThat(p6DataSource).isNotNull();
|
||||
assertThat(p6DataSource).isInstanceOf(P6DataSource.class);
|
||||
|
||||
DataSource proxyDataSource = (DataSource) new DirectFieldAccessor(p6DataSource)
|
||||
.getPropertyValue("realDataSource");
|
||||
assertThat(proxyDataSource).isNotNull();
|
||||
assertThat(proxyDataSource).isInstanceOf(ProxyDataSource.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecorateDynamicallyRegisteredBeans() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner.withInitializer(context -> {
|
||||
GenericApplicationContext gac = (GenericApplicationContext) context;
|
||||
gac.registerBean("ds1", DataSource.class, () -> new HikariDataSource());
|
||||
gac.registerBean("ds2", DataSource.class, () -> new HikariDataSource());
|
||||
});
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource1 = context.getBean("ds1", DataSource.class);
|
||||
assertThat(dataSource1).isNotNull();
|
||||
assertThat(dataSource1).isInstanceOf(DataSourceWrapper.class);
|
||||
|
||||
DataSource dataSource2 = context.getBean("ds2", DataSource.class);
|
||||
assertThat(dataSource2).isNotNull();
|
||||
assertThat(dataSource2).isInstanceOf(DataSourceWrapper.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestDataSourceConfiguration {
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
BasicDataSource pool = new BasicDataSource();
|
||||
pool.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
pool.setUrl("jdbc:hsqldb:target/overridedb");
|
||||
pool.setUsername("sa");
|
||||
return pool;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestDataSourceDecoratorConfiguration {
|
||||
|
||||
@Bean
|
||||
public DataSourceDecorator customDataSourceDecorator() {
|
||||
return (beanName, dataSource) -> new CustomDataSourceProxy(dataSource);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestMultiDataSourceConfiguration {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public DataSource dataSource() {
|
||||
BasicDataSource pool = new BasicDataSource();
|
||||
pool.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
pool.setUrl("jdbc:hsqldb:target/db");
|
||||
pool.setUsername("sa");
|
||||
return pool;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource secondDataSource() {
|
||||
BasicDataSource pool = new BasicDataSource();
|
||||
pool.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
pool.setUrl("jdbc:hsqldb:target/db2");
|
||||
pool.setUsername("sa");
|
||||
return pool;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestScopedDataSourceConfiguration {
|
||||
|
||||
@Bean
|
||||
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
public DataSource dataSource() {
|
||||
BasicDataSource pool = new BasicDataSource();
|
||||
pool.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
pool.setUrl("jdbc:hsqldb:target/overridedb");
|
||||
pool.setUsername("sa");
|
||||
return pool;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom proxy data source for tests.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
*/
|
||||
static class CustomDataSourceProxy implements DataSource {
|
||||
|
||||
private final DataSource delegate;
|
||||
|
||||
CustomDataSourceProxy(DataSource delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection(String username, String password) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getLogWriter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogWriter(PrintWriter out) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoginTimeout(int seconds) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoginTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.io.PrintWriter;
|
||||
import java.sql.Connection;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.p6spy.engine.spy.P6DataSource;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSource;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
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.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceNoOpAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceDecorator;
|
||||
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 org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.annotation.ScopedProxyMode;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class DataSourceDecoratorAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
TraceJdbcAutoConfiguration.class, TraceNoOpAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class))
|
||||
.withPropertyValues("spring.datasource.initialization-mode=never",
|
||||
"spring.sleuth.noop.enabled=true",
|
||||
"spring.datasource.url:jdbc:h2:mem:testdb-" + ThreadLocalRandom.current().nextInt());
|
||||
|
||||
@Test
|
||||
void testDecoratingInDefaultOrder() {
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
assertThat(dataSource).isInstanceOf(DataSourceWrapper.class);
|
||||
|
||||
DataSourceWrapper DataSourceWrapper = (DataSourceWrapper) dataSource;
|
||||
assertThat(DataSourceWrapper.getDecoratedDataSource()).isInstanceOf(P6DataSource.class);
|
||||
P6DataSource p6DataSource = (P6DataSource) DataSourceWrapper.getDecoratedDataSource();
|
||||
|
||||
DataSource p6WrappedDataSource = (DataSource) ReflectionTestUtils.getField(p6DataSource, "realDataSource");
|
||||
assertThat(p6WrappedDataSource).isInstanceOf(ProxyDataSource.class);
|
||||
ProxyDataSource proxyDataSource = (ProxyDataSource) p6WrappedDataSource;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoDecoratingForExcludeBeans() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withPropertyValues("spring.sleuth.jdbc.excluded-data-source-bean-names:dataSource");
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
|
||||
assertThat(dataSource).isInstanceOf(HikariDataSource.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecoratingWhenDefaultProxyProviderNotAvailable() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner;
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
|
||||
assertThat(((DataSourceWrapper) dataSource).getOriginalDataSource()).isInstanceOf(HikariDataSource.class);
|
||||
|
||||
DataSourceWrapper DataSourceWrapper = (DataSourceWrapper) dataSource;
|
||||
assertThat(DataSourceWrapper.getDecoratedDataSource()).isInstanceOf(P6DataSource.class);
|
||||
P6DataSource p6DataSource = (P6DataSource) DataSourceWrapper.getDecoratedDataSource();
|
||||
|
||||
DataSource p6WrappedDataSource = (DataSource) ReflectionTestUtils.getField(p6DataSource, "realDataSource");
|
||||
assertThat(p6WrappedDataSource).isInstanceOf(ProxyDataSource.class);
|
||||
ProxyDataSource proxyDataSource = (ProxyDataSource) p6WrappedDataSource;
|
||||
|
||||
DataSource dsProxyWrappedDataSource = (DataSource) ReflectionTestUtils.getField(proxyDataSource,
|
||||
"dataSource");
|
||||
assertThat(dsProxyWrappedDataSource).isEqualTo(DataSourceWrapper.getOriginalDataSource());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecoratedHikariSpecificPropertiesIsSet() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues(
|
||||
"spring.datasource.type:" + HikariDataSource.class.getName(),
|
||||
"spring.datasource.hikari.catalog:test_catalog");
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
assertThat(dataSource).isNotNull();
|
||||
assertThat(dataSource).isInstanceOf(DataSourceWrapper.class);
|
||||
DataSource realDataSource = ((DataSourceWrapper) dataSource).getOriginalDataSource();
|
||||
assertThat(realDataSource).isInstanceOf(HikariDataSource.class);
|
||||
assertThat(((HikariDataSource) realDataSource).getCatalog()).isEqualTo("test_catalog");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomDataSourceIsDecorated() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withUserConfiguration(TestDataSourceConfiguration.class);
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
assertThat(dataSource).isInstanceOf(DataSourceWrapper.class);
|
||||
DataSource realDataSource = ((DataSourceWrapper) dataSource).getOriginalDataSource();
|
||||
assertThat(realDataSource).isInstanceOf(BasicDataSource.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testScopedDataSourceIsNotDecorated() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withUserConfiguration(TestScopedDataSourceConfiguration.class);
|
||||
|
||||
contextRunner.run(context -> {
|
||||
assertThat(context).getBeanNames(DataSource.class).containsOnly("dataSource", "scopedTarget.dataSource");
|
||||
assertThat(context).getBean("dataSource").isInstanceOf(DataSourceWrapper.class);
|
||||
assertThat(context).getBean("scopedTarget.dataSource").isNotInstanceOf(DataSourceWrapper.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomDataSourceDecoratorApplied() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withUserConfiguration(TestDataSourceDecoratorConfiguration.class);
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
assertThat(dataSource).isNotNull();
|
||||
|
||||
DataSource customDataSource = ((DataSourceWrapper) dataSource).getDecoratedDataSource();
|
||||
assertThat(customDataSource).isInstanceOf(CustomDataSourceProxy.class);
|
||||
|
||||
DataSource realDataSource = ((DataSourceWrapper) dataSource).getOriginalDataSource();
|
||||
assertThat(realDataSource).isInstanceOf(HikariDataSource.class);
|
||||
|
||||
assertThat(dataSource).isInstanceOf(DataSourceWrapper.class);
|
||||
|
||||
DataSourceWrapper DataSourceWrapper = (DataSourceWrapper) dataSource;
|
||||
|
||||
assertThat(DataSourceWrapper.getDecoratedDataSource()).isInstanceOf(CustomDataSourceProxy.class);
|
||||
CustomDataSourceProxy customDataSourceProxy = (CustomDataSourceProxy) DataSourceWrapper
|
||||
.getDecoratedDataSource();
|
||||
|
||||
assertThat(customDataSourceProxy.delegate).isInstanceOf(P6DataSource.class);
|
||||
P6DataSource p6DataSource = (P6DataSource) customDataSourceProxy.delegate;
|
||||
|
||||
DataSource p6WrappedDataSource = (DataSource) ReflectionTestUtils.getField(p6DataSource, "realDataSource");
|
||||
assertThat(p6WrappedDataSource).isInstanceOf(ProxyDataSource.class);
|
||||
ProxyDataSource proxyDataSource = (ProxyDataSource) p6WrappedDataSource;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecoratingCanBeDisabled() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withPropertyValues("spring.sleuth.jdbc.enabled:false");
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
assertThat(dataSource).isInstanceOf(HikariDataSource.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecoratingCanBeDisabledForSpecificBeans() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withPropertyValues("spring.sleuth.jdbc.excluded-data-source-bean-names:secondDataSource")
|
||||
.withUserConfiguration(TestMultiDataSourceConfiguration.class);
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean("dataSource", DataSource.class);
|
||||
assertThat(dataSource).isInstanceOf(DataSourceWrapper.class);
|
||||
|
||||
DataSource secondDataSource = context.getBean("secondDataSource", DataSource.class);
|
||||
assertThat(secondDataSource).isInstanceOf(BasicDataSource.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecoratingChainBuiltCorrectly() {
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
|
||||
DataSourceWrapper dataSource1 = context.getBean(DataSourceWrapper.class);
|
||||
assertThat(dataSource1).isNotNull();
|
||||
|
||||
DataSource p6DataSource = dataSource1.getDecoratedDataSource();
|
||||
assertThat(p6DataSource).isNotNull();
|
||||
assertThat(p6DataSource).isInstanceOf(P6DataSource.class);
|
||||
|
||||
DataSource proxyDataSource = (DataSource) new DirectFieldAccessor(p6DataSource)
|
||||
.getPropertyValue("realDataSource");
|
||||
assertThat(proxyDataSource).isNotNull();
|
||||
assertThat(proxyDataSource).isInstanceOf(ProxyDataSource.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecorateDynamicallyRegisteredBeans() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner.withInitializer(context -> {
|
||||
GenericApplicationContext gac = (GenericApplicationContext) context;
|
||||
gac.registerBean("ds1", DataSource.class, () -> new HikariDataSource());
|
||||
gac.registerBean("ds2", DataSource.class, () -> new HikariDataSource());
|
||||
});
|
||||
|
||||
contextRunner.run(context -> {
|
||||
DataSource dataSource1 = context.getBean("ds1", DataSource.class);
|
||||
assertThat(dataSource1).isNotNull();
|
||||
assertThat(dataSource1).isInstanceOf(DataSourceWrapper.class);
|
||||
|
||||
DataSource dataSource2 = context.getBean("ds2", DataSource.class);
|
||||
assertThat(dataSource2).isNotNull();
|
||||
assertThat(dataSource2).isInstanceOf(DataSourceWrapper.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestDataSourceConfiguration {
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
BasicDataSource pool = new BasicDataSource();
|
||||
pool.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
pool.setUrl("jdbc:hsqldb:target/overridedb");
|
||||
pool.setUsername("sa");
|
||||
return pool;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestDataSourceDecoratorConfiguration {
|
||||
|
||||
@Bean
|
||||
public DataSourceDecorator customDataSourceDecorator() {
|
||||
return (beanName, dataSource) -> new CustomDataSourceProxy(dataSource);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestMultiDataSourceConfiguration {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public DataSource dataSource() {
|
||||
BasicDataSource pool = new BasicDataSource();
|
||||
pool.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
pool.setUrl("jdbc:hsqldb:target/db");
|
||||
pool.setUsername("sa");
|
||||
return pool;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource secondDataSource() {
|
||||
BasicDataSource pool = new BasicDataSource();
|
||||
pool.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
pool.setUrl("jdbc:hsqldb:target/db2");
|
||||
pool.setUsername("sa");
|
||||
return pool;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestScopedDataSourceConfiguration {
|
||||
|
||||
@Bean
|
||||
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
public DataSource dataSource() {
|
||||
BasicDataSource pool = new BasicDataSource();
|
||||
pool.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
pool.setUrl("jdbc:hsqldb:target/overridedb");
|
||||
pool.setUsername("sa");
|
||||
return pool;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom proxy data source for tests.
|
||||
*
|
||||
* @author Arthur Gavlyukovskiy
|
||||
*/
|
||||
static class CustomDataSourceProxy implements DataSource {
|
||||
|
||||
private final DataSource delegate;
|
||||
|
||||
CustomDataSourceProxy(DataSource delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection(String username, String password) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getLogWriter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogWriter(PrintWriter out) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoginTimeout(int seconds) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoginTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,280 +1,280 @@
|
||||
/*
|
||||
* 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.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.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.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.p6spy.logging:custom",
|
||||
"spring.sleuth.jdbc.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.p6spy.logging:custom",
|
||||
"spring.sleuth.jdbc.p6spy.custom-appender-class:" + LogAccumulator.class.getName(),
|
||||
"spring.sleuth.jdbc.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.p6spy.logging:custom",
|
||||
"spring.sleuth.jdbc.p6spy.custom-appender-class:" + LogAccumulator.class.getName(),
|
||||
"spring.sleuth.jdbc.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.TraceNoOpAutoConfiguration;
|
||||
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,
|
||||
TraceJdbcAutoConfiguration.class, TraceNoOpAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class))
|
||||
.withPropertyValues("spring.datasource.initialization-mode=never",
|
||||
"spring.sleuth.noop.enabled=true",
|
||||
"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);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoesNotRegisterLoggingListenerIfDisabled() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withPropertyValues("spring.sleuth.jdbc.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.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.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.p6spy.logging=custom",
|
||||
"spring.sleuth.jdbc.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.p6spy.logging=custom",
|
||||
"spring.sleuth.jdbc.p6spy.custom-appender-class:" + LogAccumulator.class.getName(),
|
||||
"spring.sleuth.jdbc.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.p6spy.logging=custom",
|
||||
"spring.sleuth.jdbc.p6spy.custom-appender-class:" + LogAccumulator.class.getName(),
|
||||
"spring.sleuth.jdbc.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,246 +1,239 @@
|
||||
/*
|
||||
* 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.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.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.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.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");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.TraceNoOpAutoConfiguration;
|
||||
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,
|
||||
TraceJdbcAutoConfiguration.class, TraceNoOpAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class))
|
||||
.withPropertyValues("spring.datasource.initialization-mode=never",
|
||||
"spring.sleuth.noop.enabled=true",
|
||||
"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.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.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.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.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");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,67 +1,66 @@
|
||||
/*
|
||||
* 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.concurrent.ThreadLocalRandom;
|
||||
|
||||
import com.p6spy.engine.event.CompoundJdbcEventListener;
|
||||
import com.p6spy.engine.spy.JdbcEventListenerFactory;
|
||||
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.TraceJdbcEventListener;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class SleuthP6SpyListenerAutoConfigurationTests {
|
||||
|
||||
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"));
|
||||
|
||||
@Test
|
||||
void testAddsP6SpyListener() {
|
||||
contextRunner.run(context -> {
|
||||
JdbcEventListenerFactory jdbcEventListenerFactory = context.getBean(JdbcEventListenerFactory.class);
|
||||
CompoundJdbcEventListener jdbcEventListener = (CompoundJdbcEventListener) jdbcEventListenerFactory
|
||||
.createJdbcEventListener();
|
||||
assertThat(jdbcEventListener.getEventListeners()).extracting("class")
|
||||
.contains(TraceJdbcEventListener.class);
|
||||
assertThat(context.getBean(Tracer.class).currentSpan()).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoesNotAddP6SpyListenerIfNoTracer() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues("spring.sleuth.enabled:false");
|
||||
|
||||
contextRunner.run(context -> {
|
||||
assertThat(context).doesNotHaveBean(JdbcEventListenerFactory.class);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.concurrent.ThreadLocalRandom;
|
||||
|
||||
import com.p6spy.engine.event.CompoundJdbcEventListener;
|
||||
import com.p6spy.engine.spy.JdbcEventListenerFactory;
|
||||
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.TraceNoOpAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceJdbcEventListener;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class SleuthP6SpyListenerAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
TraceJdbcAutoConfiguration.class, TraceNoOpAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class))
|
||||
.withPropertyValues("spring.datasource.initialization-mode=never",
|
||||
"spring.sleuth.noop.enabled=true",
|
||||
"spring.datasource.url=jdbc:h2:mem:testdb-" + ThreadLocalRandom.current().nextInt())
|
||||
.withClassLoader(new FilteredClassLoader("net.ttddyy.dsproxy"));
|
||||
|
||||
@Test
|
||||
void testAddsP6SpyListener() {
|
||||
contextRunner.run(context -> {
|
||||
JdbcEventListenerFactory jdbcEventListenerFactory = context.getBean(JdbcEventListenerFactory.class);
|
||||
CompoundJdbcEventListener jdbcEventListener = (CompoundJdbcEventListener) jdbcEventListenerFactory
|
||||
.createJdbcEventListener();
|
||||
assertThat(jdbcEventListener.getEventListeners()).extracting("class")
|
||||
.contains(TraceJdbcEventListener.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoesNotAddP6SpyListenerIfNoTracer() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues("spring.sleuth.enabled=false");
|
||||
|
||||
contextRunner.run(context -> {
|
||||
assertThat(context).doesNotHaveBean(JdbcEventListenerFactory.class);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,70 +1,69 @@
|
||||
/*
|
||||
* 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.concurrent.ThreadLocalRandom;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import net.ttddyy.dsproxy.listener.ChainListener;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSource;
|
||||
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.cloud.sleuth.instrument.jdbc.TraceQueryExecutionListener;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class SleuthProxyDataSourceListenerAutoConfigurationTests {
|
||||
|
||||
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 testAddsDatasourceProxyListener() {
|
||||
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(TraceQueryExecutionListener.class);
|
||||
assertThat(context.getBean(Tracer.class).currentSpan()).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoesNotAddDatasourceProxyListenerIfNoTracer() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues("spring.sleuth.enabled:false");
|
||||
|
||||
contextRunner.run(context -> {
|
||||
assertThat(context).doesNotHaveBean(DataSourceWrapper.class);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.concurrent.ThreadLocalRandom;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import net.ttddyy.dsproxy.listener.ChainListener;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSource;
|
||||
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.TraceNoOpAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.DataSourceWrapper;
|
||||
import org.springframework.cloud.sleuth.instrument.jdbc.TraceQueryExecutionListener;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class SleuthProxyDataSourceListenerAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
TraceJdbcAutoConfiguration.class, TraceNoOpAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class))
|
||||
.withPropertyValues("spring.datasource.initialization-mode=never",
|
||||
"spring.sleuth.noop.enabled=true",
|
||||
"spring.datasource.url:jdbc:h2:mem:testdb-" + ThreadLocalRandom.current().nextInt())
|
||||
.withClassLoader(new FilteredClassLoader("com.p6spy"));
|
||||
|
||||
@Test
|
||||
void testAddsDatasourceProxyListener() {
|
||||
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(TraceQueryExecutionListener.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoesNotAddDatasourceProxyListenerIfNoTracer() {
|
||||
ApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues("spring.sleuth.enabled:false");
|
||||
|
||||
contextRunner.run(context -> {
|
||||
assertThat(context).doesNotHaveBean(DataSourceWrapper.class);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* 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 brave.sampler.Sampler;
|
||||
import brave.test.TestSpanHandler;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
class TestSpanHandlerConfiguration {
|
||||
|
||||
@Bean
|
||||
public TestSpanHandler spanHandler() {
|
||||
return new TestSpanHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Sampler sampler() {
|
||||
return Sampler.ALWAYS_SAMPLE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +1,43 @@
|
||||
/*
|
||||
* 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 javax.sql.CommonDataSource;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
|
||||
/**
|
||||
* Customizer for {@link TraceListenerStrategy} client span.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public interface TraceListenerStrategySpanCustomizer<T extends CommonDataSource> {
|
||||
|
||||
/**
|
||||
* Customizes the client database span.
|
||||
* @param spanBuilder span builder
|
||||
*/
|
||||
void customizeConnectionSpan(T dataSource, Span.Builder spanBuilder);
|
||||
|
||||
/**
|
||||
* @param dataSource data source for which we're building the span
|
||||
* @return {@code true} when this customizer can be applied
|
||||
*/
|
||||
boolean isApplicable(CommonDataSource dataSource);
|
||||
|
||||
}
|
||||
/*
|
||||
* 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 javax.sql.CommonDataSource;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
|
||||
/**
|
||||
* Customizer for {@link TraceListenerStrategy} client span.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public interface TraceListenerStrategySpanCustomizer<T extends CommonDataSource> {
|
||||
|
||||
/**
|
||||
* Customizes the client database span.
|
||||
* @param spanBuilder span builder
|
||||
*/
|
||||
void customizeConnectionSpan(T dataSource, Span.Builder spanBuilder);
|
||||
|
||||
/**
|
||||
* @param dataSource data source for which we're building the span
|
||||
* @return {@code true} when this customizer can be applied
|
||||
*/
|
||||
boolean isApplicable(CommonDataSource dataSource);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Trace types.
|
||||
*/
|
||||
public enum TraceType {
|
||||
|
||||
/**
|
||||
* Connection.
|
||||
*/
|
||||
CONNECTION,
|
||||
|
||||
/**
|
||||
* Query.
|
||||
*/
|
||||
QUERY,
|
||||
|
||||
/**
|
||||
* Fetch.
|
||||
*/
|
||||
FETCH
|
||||
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Trace types.
|
||||
*/
|
||||
public enum TraceType {
|
||||
|
||||
/**
|
||||
* Related to JDBC connections.
|
||||
*/
|
||||
CONNECTION,
|
||||
|
||||
/**
|
||||
* Related to query executions.
|
||||
*/
|
||||
QUERY,
|
||||
|
||||
/**
|
||||
* Related to ResultSets.
|
||||
*/
|
||||
FETCH
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
<module>spring-cloud-sleuth-instrumentation-feign-tests</module>
|
||||
<module>spring-cloud-sleuth-instrumentation-gateway-tests</module>
|
||||
<module>spring-cloud-sleuth-instrumentation-grpc-tests</module>
|
||||
<module>spring-cloud-sleuth-instrumentation-jdbc-tests</module>
|
||||
<module>spring-cloud-sleuth-instrumentation-kafka-tests</module>
|
||||
<module>spring-cloud-sleuth-instrumentation-lettuce-tests</module>
|
||||
<module>spring-cloud-sleuth-instrumentation-messaging-tests</module>
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
~
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-sleuth-instrumentation-jdbc-tests</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Sleuth Brave Jdbc Instrumentation Tests</name>
|
||||
<description>Spring Cloud Sleuth Brave Jdbc Instrumentation Tests</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-tests-brave</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<sonar.skip>true</sonar.skip>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<!--skip deploy -->
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-tests-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-dbcp2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-jdbc</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>p6spy</groupId>
|
||||
<artifactId>p6spy</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ttddyy</groupId>
|
||||
<artifactId>datasource-proxy</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-sleuth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.brave</groupId>
|
||||
<artifactId>brave-tests</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.brave.instrument.jdbc;
|
||||
|
||||
import brave.sampler.Sampler;
|
||||
|
||||
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.brave.BraveTestSpanHandler;
|
||||
import org.springframework.cloud.sleuth.test.TestSpanHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
public class TracingJdbcEventListenerTests
|
||||
extends org.springframework.cloud.sleuth.instrument.jdbc.TracingJdbcEventListenerTests {
|
||||
|
||||
@Override
|
||||
protected Class autoConfiguration() {
|
||||
return BraveAutoConfiguration.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class testConfiguration() {
|
||||
return Config.class;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
TestSpanHandler testSpanHandlerSupplier(brave.test.TestSpanHandler testSpanHandler) {
|
||||
return new BraveTestSpanHandler(testSpanHandler);
|
||||
}
|
||||
|
||||
@Bean
|
||||
Sampler alwaysSampler() {
|
||||
return Sampler.ALWAYS_SAMPLE;
|
||||
}
|
||||
|
||||
@Bean
|
||||
brave.test.TestSpanHandler braveTestSpanHandler() {
|
||||
return new brave.test.TestSpanHandler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.brave.instrument.jdbc;
|
||||
|
||||
import brave.sampler.Sampler;
|
||||
|
||||
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.brave.BraveTestSpanHandler;
|
||||
import org.springframework.cloud.sleuth.test.TestSpanHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
public class TracingQueryExecutionListenerTests
|
||||
extends org.springframework.cloud.sleuth.instrument.jdbc.TracingQueryExecutionListenerTests {
|
||||
|
||||
@Override
|
||||
protected Class autoConfiguration() {
|
||||
return BraveAutoConfiguration.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class testConfiguration() {
|
||||
return Config.class;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
TestSpanHandler testSpanHandlerSupplier(brave.test.TestSpanHandler testSpanHandler) {
|
||||
return new BraveTestSpanHandler(testSpanHandler);
|
||||
}
|
||||
|
||||
@Bean
|
||||
Sampler alwaysSampler() {
|
||||
return Sampler.ALWAYS_SAMPLE;
|
||||
}
|
||||
|
||||
@Bean
|
||||
brave.test.TestSpanHandler braveTestSpanHandler() {
|
||||
return new brave.test.TestSpanHandler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
logging.level.org.springframework.cloud: DEBUG
|
||||
logging.level.com.netflix.discovery.InstanceInfoReplicator: ERROR
|
||||
logging.level.org.springframework.cloud.sleuth.brave.instrument.web.client.feign: TRACE
|
||||
|
||||
spring.autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration, org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration, org.springframework.cloud.gateway.config.GatewayAutoConfiguration, org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration, org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration
|
||||
@@ -1,59 +1,60 @@
|
||||
/*
|
||||
* 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.brave.instrument.web.view;
|
||||
|
||||
import brave.test.TestSpanHandler;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
@SpringBootTest(classes = Issue469.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@TestPropertySource(properties = { "spring.mvc.view.prefix=/WEB-INF/jsp/", "spring.mvc.view.suffix=.jsp" })
|
||||
public class Issue469Tests {
|
||||
|
||||
@Autowired
|
||||
TestSpanHandler spans;
|
||||
|
||||
@Autowired
|
||||
Environment environment;
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
@Test
|
||||
public void should_not_result_in_tracing_exceptions_when_using_view_controllers() {
|
||||
try {
|
||||
this.restTemplate.getForObject("http://localhost:" + port() + "/welcome", String.class);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// JSPs are not rendered
|
||||
then(e).hasMessageContaining("404");
|
||||
}
|
||||
|
||||
then(this.spans).isNotEmpty();
|
||||
}
|
||||
|
||||
private int port() {
|
||||
return this.environment.getProperty("local.server.port", Integer.class);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.brave.instrument.web.view;
|
||||
|
||||
import brave.test.TestSpanHandler;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
@SpringBootTest(classes = Issue469.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@TestPropertySource(properties = { "spring.mvc.view.prefix=/WEB-INF/jsp/", "spring.mvc.view.suffix=.jsp" })
|
||||
public class Issue469Tests {
|
||||
|
||||
@Autowired
|
||||
TestSpanHandler spans;
|
||||
|
||||
@Autowired
|
||||
Environment environment;
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
@Test
|
||||
public void should_not_result_in_tracing_exceptions_when_using_view_controllers() {
|
||||
try {
|
||||
this.restTemplate.getForObject("http://localhost:" + port() + "/welcome", String.class);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// JSPs are not rendered
|
||||
then(e).hasMessageContaining("404");
|
||||
}
|
||||
|
||||
Awaitility.await().untilAsserted(() -> then(this.spans).isNotEmpty());
|
||||
}
|
||||
|
||||
private int port() {
|
||||
return this.environment.getProperty("local.server.port", Integer.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -189,6 +189,16 @@
|
||||
<artifactId>spring-boot-starter-rsocket</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>p6spy</groupId>
|
||||
<artifactId>p6spy</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ttddyy</groupId>
|
||||
<artifactId>datasource-proxy</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
|
||||
|
||||
@@ -1,77 +1,79 @@
|
||||
/*
|
||||
* 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 javax.sql.DataSource;
|
||||
|
||||
import brave.handler.MutableSpan;
|
||||
import brave.test.TestSpanHandler;
|
||||
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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class TracingJdbcEventListenerTests extends TracingListenerStrategyTests {
|
||||
|
||||
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")
|
||||
.withClassLoader(new FilteredClassLoader("net.ttddyy.dsproxy"));
|
||||
|
||||
protected TracingJdbcEventListenerTests() {
|
||||
super(contextRunner);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldUsePlaceholderInSqlTagOfSpansForPreparedStatementIfIncludeParameterValuesIsSetToFalse() {
|
||||
contextRunner.withPropertyValues("spring.sleuth.jdbc.p6spy.tracing.include-parameter-values=false")
|
||||
.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
TestSpanHandler spanReporter = context.getBean(TestSpanHandler.class);
|
||||
|
||||
Connection connection = dataSource.getConnection();
|
||||
PreparedStatement preparedStatement = connection
|
||||
.prepareStatement("UPDATE INFORMATION_SCHEMA.TABLES SET table_Name = ? WHERE 0 = ?");
|
||||
preparedStatement.setString(1, "");
|
||||
preparedStatement.setInt(2, 1);
|
||||
preparedStatement.executeUpdate();
|
||||
connection.close();
|
||||
|
||||
assertThat(spanReporter.spans()).hasSize(2);
|
||||
MutableSpan connectionSpan = spanReporter.spans().get(1);
|
||||
MutableSpan statementSpan = spanReporter.spans().get(0);
|
||||
assertThat(connectionSpan.name()).isEqualTo("connection");
|
||||
assertThat(statementSpan.name()).isEqualTo("update");
|
||||
assertThat(statementSpan.tags()).containsEntry(SPAN_SQL_QUERY_TAG_NAME,
|
||||
"UPDATE INFORMATION_SCHEMA.TABLES SET table_Name = ? WHERE 0 = ?");
|
||||
assertThat(statementSpan.tags()).containsEntry(SPAN_ROW_COUNT_TAG_NAME, "0");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import brave.handler.MutableSpan;
|
||||
import brave.test.TestSpanHandler;
|
||||
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.instrument.jdbc.TraceJdbcAutoConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public abstract class TracingJdbcEventListenerTests extends TracingListenerStrategyTests {
|
||||
|
||||
protected final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
TraceJdbcAutoConfiguration.class, autoConfiguration(),
|
||||
PropertyPlaceholderAutoConfiguration.class))
|
||||
.withUserConfiguration(testConfiguration())
|
||||
.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"));
|
||||
|
||||
@Override
|
||||
ApplicationContextRunner parentContextRunner() {
|
||||
return this.contextRunner;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldUsePlaceholderInSqlTagOfSpansForPreparedStatementIfIncludeParameterValuesIsSetToFalse() {
|
||||
contextRunner.withPropertyValues("spring.sleuth.jdbc.p6spy.tracing.include-parameter-values=false")
|
||||
.run(context -> {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
TestSpanHandler spanReporter = context.getBean(TestSpanHandler.class);
|
||||
|
||||
Connection connection = dataSource.getConnection();
|
||||
PreparedStatement preparedStatement = connection
|
||||
.prepareStatement("UPDATE INFORMATION_SCHEMA.TABLES SET table_Name = ? WHERE 0 = ?");
|
||||
preparedStatement.setString(1, "");
|
||||
preparedStatement.setInt(2, 1);
|
||||
preparedStatement.executeUpdate();
|
||||
connection.close();
|
||||
|
||||
assertThat(spanReporter.spans()).hasSize(2);
|
||||
MutableSpan connectionSpan = spanReporter.spans().get(1);
|
||||
MutableSpan statementSpan = spanReporter.spans().get(0);
|
||||
assertThat(connectionSpan.name()).isEqualTo("connection");
|
||||
assertThat(statementSpan.name()).isEqualTo("update");
|
||||
assertThat(statementSpan.tags()).containsEntry(SPAN_SQL_QUERY_TAG_NAME,
|
||||
"UPDATE INFORMATION_SCHEMA.TABLES SET table_Name = ? WHERE 0 = ?");
|
||||
assertThat(statementSpan.tags()).containsEntry(SPAN_ROW_COUNT_TAG_NAME, "0");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,38 +1,39 @@
|
||||
/*
|
||||
* 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 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;
|
||||
|
||||
class TracingQueryExecutionListenerTests extends TracingListenerStrategyTests {
|
||||
|
||||
TracingQueryExecutionListenerTests() {
|
||||
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("com.p6spy")));
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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 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.instrument.jdbc.TraceJdbcAutoConfiguration;
|
||||
|
||||
public abstract class TracingQueryExecutionListenerTests extends TracingListenerStrategyTests {
|
||||
|
||||
@Override
|
||||
ApplicationContextRunner parentContextRunner() {
|
||||
return new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
TraceJdbcAutoConfiguration.class, autoConfiguration(), PropertyPlaceholderAutoConfiguration.class))
|
||||
.withUserConfiguration(testConfiguration())
|
||||
.withPropertyValues("spring.datasource.initialization-mode=never",
|
||||
"spring.datasource.url:jdbc:h2:mem:testdb-baz", "spring.datasource.hikari.pool-name=test")
|
||||
.withClassLoader(new FilteredClassLoader("com.p6spy"));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user