Polish
This commit is contained in:
@@ -1,153 +1,153 @@
|
||||
/*
|
||||
* 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.async;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.interceptor.AsyncExecutionAspectSupport;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
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.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.async.LazyTraceExecutor;
|
||||
import org.springframework.cloud.sleuth.instrument.async.TraceAsyncAspect;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} enabling async related processing.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.0.0
|
||||
* @see LazyTraceExecutor
|
||||
* @see TraceAsyncAspect
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(SleuthAsyncProperties.class)
|
||||
@ConditionalOnProperty(value = "spring.sleuth.async.enabled", matchIfMissing = true)
|
||||
@ConditionalOnBean(Tracer.class)
|
||||
@AutoConfigureAfter(BraveAutoConfiguration.class)
|
||||
public class TraceAsyncDefaultAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "spring.sleuth.scheduled.enabled", matchIfMissing = true)
|
||||
static ExecutorBeanPostProcessor executorBeanPostProcessor(BeanFactory beanFactory) {
|
||||
return new ExecutorBeanPostProcessor(beanFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
TraceAsyncAspect traceAsyncAspect(Tracer tracer, SpanNamer spanNamer) {
|
||||
return new TraceAsyncAspect(tracer, spanNamer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for the async executor.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(AsyncConfigurer.class)
|
||||
@ConditionalOnMissingBean(AsyncConfigurer.class)
|
||||
@ConditionalOnProperty(value = "spring.sleuth.async.configurer.enabled", matchIfMissing = true)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
static class DefaultAsyncConfigurerSupport extends AsyncConfigurerSupport {
|
||||
|
||||
private static final Log log = LogFactory.getLog(DefaultAsyncConfigurerSupport.class);
|
||||
|
||||
@Autowired
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
public Executor getAsyncExecutor() {
|
||||
Executor delegate = getDefaultExecutor();
|
||||
return new LazyTraceExecutor(this.beanFactory, delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve or build a default executor for this advice instance. An executor
|
||||
* returned from here will be cached for further use.
|
||||
* <p>
|
||||
* The default implementation searches for a unique {@link TaskExecutor} bean in
|
||||
* the context, or for an {@link Executor} bean named "taskExecutor" otherwise. If
|
||||
* neither of the two is resolvable, this implementation will return {@code null}.
|
||||
* @return the default executor, or {@code null} if none available
|
||||
* @see AsyncExecutionAspectSupport#getDefaultExecutor(org.springframework.beans.factory.BeanFactory)
|
||||
*/
|
||||
private Executor getDefaultExecutor() {
|
||||
try {
|
||||
// Search for TaskExecutor bean... not plain Executor since that would
|
||||
// match with ScheduledExecutorService as well, which is unusable for
|
||||
// our purposes here. TaskExecutor is more clearly designed for it.
|
||||
return this.beanFactory.getBean(TaskExecutor.class);
|
||||
}
|
||||
catch (NoUniqueBeanDefinitionException ex) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Could not find unique TaskExecutor bean", ex);
|
||||
}
|
||||
try {
|
||||
return this.beanFactory.getBean(AsyncExecutionAspectSupport.DEFAULT_TASK_EXECUTOR_BEAN_NAME,
|
||||
Executor.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex2) {
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("More than one TaskExecutor bean found within the context, and none is named "
|
||||
+ "'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly "
|
||||
+ "as an alias) in order to use it for async processing: " + ex.getBeanNamesFound());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
log.debug("Could not find default TaskExecutor bean", ex);
|
||||
try {
|
||||
return this.beanFactory.getBean(AsyncExecutionAspectSupport.DEFAULT_TASK_EXECUTOR_BEAN_NAME,
|
||||
Executor.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex2) {
|
||||
log.info("No task executor bean found for async processing: "
|
||||
+ "no bean of type TaskExecutor and no bean named 'taskExecutor' either");
|
||||
}
|
||||
// Giving up -> either using local default executor or none at all...
|
||||
}
|
||||
// backward compatibility
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info(
|
||||
"For backward compatibility, will fallback to the default, SimpleAsyncTaskExecutor implementation");
|
||||
}
|
||||
return new SimpleAsyncTaskExecutor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.async;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.interceptor.AsyncExecutionAspectSupport;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
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.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.async.LazyTraceExecutor;
|
||||
import org.springframework.cloud.sleuth.instrument.async.TraceAsyncAspect;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} enabling async related processing.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.0.0
|
||||
* @see LazyTraceExecutor
|
||||
* @see TraceAsyncAspect
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(SleuthAsyncProperties.class)
|
||||
@ConditionalOnProperty(value = "spring.sleuth.async.enabled", matchIfMissing = true)
|
||||
@ConditionalOnBean(Tracer.class)
|
||||
@AutoConfigureAfter(BraveAutoConfiguration.class)
|
||||
public class TraceAsyncDefaultAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "spring.sleuth.scheduled.enabled", matchIfMissing = true)
|
||||
static ExecutorBeanPostProcessor executorBeanPostProcessor(BeanFactory beanFactory) {
|
||||
return new ExecutorBeanPostProcessor(beanFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
TraceAsyncAspect traceAsyncAspect(Tracer tracer, SpanNamer spanNamer) {
|
||||
return new TraceAsyncAspect(tracer, spanNamer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for the async executor.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(AsyncConfigurer.class)
|
||||
@ConditionalOnMissingBean(AsyncConfigurer.class)
|
||||
@ConditionalOnProperty(value = "spring.sleuth.async.configurer.enabled", matchIfMissing = true)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
static class DefaultAsyncConfigurerSupport extends AsyncConfigurerSupport {
|
||||
|
||||
private static final Log log = LogFactory.getLog(DefaultAsyncConfigurerSupport.class);
|
||||
|
||||
@Autowired
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
public Executor getAsyncExecutor() {
|
||||
Executor delegate = getDefaultExecutor();
|
||||
return new LazyTraceExecutor(this.beanFactory, delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve or build a default executor for this advice instance. An executor
|
||||
* returned from here will be cached for further use.
|
||||
* <p>
|
||||
* The default implementation searches for a unique {@link TaskExecutor} bean in
|
||||
* the context, or for an {@link Executor} bean named "taskExecutor" otherwise. If
|
||||
* neither of the two is resolvable, this implementation will return {@code null}.
|
||||
* @return the default executor, or {@code null} if none available
|
||||
* @see AsyncExecutionAspectSupport#getDefaultExecutor(org.springframework.beans.factory.BeanFactory)
|
||||
*/
|
||||
private Executor getDefaultExecutor() {
|
||||
try {
|
||||
// Search for TaskExecutor bean... not plain Executor since that would
|
||||
// match with ScheduledExecutorService as well, which is unusable for
|
||||
// our purposes here. TaskExecutor is more clearly designed for it.
|
||||
return this.beanFactory.getBean(TaskExecutor.class);
|
||||
}
|
||||
catch (NoUniqueBeanDefinitionException ex) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Could not find unique TaskExecutor bean", ex);
|
||||
}
|
||||
try {
|
||||
return this.beanFactory.getBean(AsyncExecutionAspectSupport.DEFAULT_TASK_EXECUTOR_BEAN_NAME,
|
||||
Executor.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex2) {
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("More than one TaskExecutor bean found within the context, and none is named "
|
||||
+ "'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly "
|
||||
+ "as an alias) in order to use it for async processing: " + ex.getBeanNamesFound());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
log.debug("Could not find default TaskExecutor bean", ex);
|
||||
try {
|
||||
return this.beanFactory.getBean(AsyncExecutionAspectSupport.DEFAULT_TASK_EXECUTOR_BEAN_NAME,
|
||||
Executor.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex2) {
|
||||
log.info("No task executor bean found for async processing: "
|
||||
+ "no bean of type TaskExecutor and no bean named 'taskExecutor' either");
|
||||
}
|
||||
// Giving up -> either using local default executor or none at all...
|
||||
}
|
||||
// backward compatibility
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info(
|
||||
"For backward compatibility, will fallback to the default, SimpleAsyncTaskExecutor implementation");
|
||||
}
|
||||
return new SimpleAsyncTaskExecutor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,112 +1,111 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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,78 +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.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));
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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,188 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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 - 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;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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,71 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,104 +1,103 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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,371 +1,370 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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,278 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2013-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth.autoconfig.instrument.jdbc;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.p6spy.engine.common.ConnectionInformation;
|
||||
import com.p6spy.engine.common.P6LogQuery;
|
||||
import com.p6spy.engine.event.CompoundJdbcEventListener;
|
||||
import com.p6spy.engine.event.JdbcEventListener;
|
||||
import com.p6spy.engine.logging.Category;
|
||||
import com.p6spy.engine.logging.LoggingEventListener;
|
||||
import com.p6spy.engine.spy.JdbcEventListenerFactory;
|
||||
import com.p6spy.engine.spy.P6DataSource;
|
||||
import com.p6spy.engine.spy.appender.CustomLineFormat;
|
||||
import com.p6spy.engine.spy.appender.FormattedLogger;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.sleuth.autoconfig.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,239 +1,238 @@
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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,66 +1,65 @@
|
||||
/*
|
||||
* 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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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,69 +1,68 @@
|
||||
/*
|
||||
* 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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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,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 {
|
||||
|
||||
/**
|
||||
* Related to JDBC connections.
|
||||
*/
|
||||
CONNECTION,
|
||||
|
||||
/**
|
||||
* Related to query executions.
|
||||
*/
|
||||
QUERY,
|
||||
|
||||
/**
|
||||
* Related to ResultSets.
|
||||
*/
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
@@ -1,60 +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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,60 +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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,237 +1,238 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
import brave.handler.MutableSpan;
|
||||
import brave.handler.SpanHandler;
|
||||
import brave.sampler.Sampler;
|
||||
import brave.test.TestSpanHandler;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.sleuth.SpanName;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
@SpringBootTest(classes = { TraceAsyncIntegrationTests.TraceAsyncITestConfiguration.class })
|
||||
public class TraceAsyncIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
ClassPerformingAsyncLogic classPerformingAsyncLogic;
|
||||
|
||||
@Autowired
|
||||
Tracer tracer;
|
||||
|
||||
@Autowired
|
||||
TestSpanHandler spans;
|
||||
|
||||
@BeforeEach
|
||||
public void cleanup() {
|
||||
this.spans.clear();
|
||||
this.classPerformingAsyncLogic.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_set_span_on_an_async_annotated_method() {
|
||||
whenAsyncProcessingTakesPlace();
|
||||
|
||||
thenANewAsyncSpanGetsCreated();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_set_span_with_custom_method_on_an_async_annotated_method() {
|
||||
whenAsyncProcessingTakesPlaceWithCustomSpanName();
|
||||
|
||||
thenAsyncSpanHasCustomName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_continue_a_span_on_an_async_annotated_method() {
|
||||
Span span = givenASpanInCurrentThread();
|
||||
|
||||
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(span)) {
|
||||
whenAsyncProcessingTakesPlace();
|
||||
}
|
||||
finally {
|
||||
span.finish();
|
||||
}
|
||||
|
||||
thenTraceIdIsPassedFromTheCurrentThreadToTheAsyncOne(span);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_continue_a_span_with_custom_method_on_an_async_annotated_method() {
|
||||
Span span = givenASpanInCurrentThread();
|
||||
|
||||
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(span)) {
|
||||
whenAsyncProcessingTakesPlaceWithCustomSpanName();
|
||||
}
|
||||
finally {
|
||||
span.finish();
|
||||
}
|
||||
|
||||
thenTraceIdIsPassedFromTheCurrentThreadToTheAsyncOneAndSpanHasCustomName(span);
|
||||
}
|
||||
|
||||
private Span givenASpanInCurrentThread() {
|
||||
return this.tracer.nextSpan().name("http:existing");
|
||||
}
|
||||
|
||||
private void whenAsyncProcessingTakesPlace() {
|
||||
this.classPerformingAsyncLogic.invokeAsynchronousLogic();
|
||||
}
|
||||
|
||||
private void whenAsyncProcessingTakesPlaceWithCustomSpanName() {
|
||||
this.classPerformingAsyncLogic.customNameInvokeAsynchronousLogic();
|
||||
}
|
||||
|
||||
private void thenTraceIdIsPassedFromTheCurrentThreadToTheAsyncOne(final Span span) {
|
||||
Awaitility.await().atMost(5, SECONDS).untilAsserted(() -> {
|
||||
then(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getSpan().context().traceId())
|
||||
.isEqualTo(span.context().traceId());
|
||||
List<MutableSpan> webSpans = this.spans.spans().stream().filter(mutableSpan -> mutableSpan.traceId().equalsIgnoreCase(span.context().traceIdString()))
|
||||
.collect(Collectors.toList());
|
||||
then(webSpans).hasSize(2);
|
||||
// HTTP
|
||||
then(webSpans.get(0).name()).isEqualTo("http:existing");
|
||||
// ASYNC
|
||||
then(webSpans.get(1).tags()).containsEntry("class", "ClassPerformingAsyncLogic").containsEntry("method",
|
||||
"invokeAsynchronousLogic");
|
||||
});
|
||||
}
|
||||
|
||||
private void thenANewAsyncSpanGetsCreated() {
|
||||
Awaitility.await().atMost(5, SECONDS).untilAsserted(() -> {
|
||||
then(this.spans).hasSize(1);
|
||||
MutableSpan storedSpan = this.spans.get(0);
|
||||
then(storedSpan.name()).isEqualTo("invoke-asynchronous-logic");
|
||||
then(storedSpan.tags()).containsEntry("class", "ClassPerformingAsyncLogic").containsEntry("method",
|
||||
"invokeAsynchronousLogic");
|
||||
});
|
||||
}
|
||||
|
||||
private void thenTraceIdIsPassedFromTheCurrentThreadToTheAsyncOneAndSpanHasCustomName(final Span span) {
|
||||
Awaitility.await().atMost(5, SECONDS).untilAsserted(() -> {
|
||||
then(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getSpan()).isNotNull();
|
||||
then(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getSpan().context().traceId())
|
||||
.isEqualTo(span.context().traceId());
|
||||
then(this.spans).hasSize(2);
|
||||
// HTTP
|
||||
then(this.spans.get(0).name()).isEqualTo("http:existing");
|
||||
// ASYNC
|
||||
then(this.spans.get(1).tags()).containsEntry("class", "ClassPerformingAsyncLogic").containsEntry("method",
|
||||
"customNameInvokeAsynchronousLogic");
|
||||
});
|
||||
}
|
||||
|
||||
private void thenAsyncSpanHasCustomName() {
|
||||
Awaitility.await().atMost(5, SECONDS).untilAsserted(() -> {
|
||||
then(this.spans).hasSize(1);
|
||||
MutableSpan storedSpan = this.spans.get(0);
|
||||
then(storedSpan.name()).isEqualTo("foo");
|
||||
then(storedSpan.tags()).containsEntry("class", "ClassPerformingAsyncLogic").containsEntry("method",
|
||||
"customNameInvokeAsynchronousLogic");
|
||||
});
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanTrace() {
|
||||
this.spans.clear();
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@EnableAsync
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TraceAsyncITestConfiguration {
|
||||
|
||||
@Bean
|
||||
ClassPerformingAsyncLogic asyncClass(Tracer tracer) {
|
||||
return new ClassPerformingAsyncLogic(tracer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
Sampler defaultSampler() {
|
||||
return Sampler.ALWAYS_SAMPLE;
|
||||
}
|
||||
|
||||
@Bean
|
||||
SpanHandler testSpanHandler() {
|
||||
return new TestSpanHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Executor fooExecutor() {
|
||||
return new SimpleAsyncTaskExecutor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Executor barExecutor() {
|
||||
return new SimpleAsyncTaskExecutor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ClassPerformingAsyncLogic {
|
||||
|
||||
private final Tracer tracer;
|
||||
|
||||
AtomicReference<Span> span = new AtomicReference<>();
|
||||
|
||||
ClassPerformingAsyncLogic(Tracer tracer) {
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
@Async("fooExecutor")
|
||||
public void invokeAsynchronousLogic() {
|
||||
this.span.set(this.tracer.currentSpan());
|
||||
}
|
||||
|
||||
@Async
|
||||
@SpanName("foo")
|
||||
public void customNameInvokeAsynchronousLogic() {
|
||||
this.span.set(this.tracer.currentSpan());
|
||||
}
|
||||
|
||||
public Span getSpan() {
|
||||
return this.span.get();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.span.set(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.brave.instrument.web;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
import brave.handler.MutableSpan;
|
||||
import brave.handler.SpanHandler;
|
||||
import brave.sampler.Sampler;
|
||||
import brave.test.TestSpanHandler;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.sleuth.SpanName;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
@SpringBootTest(classes = { TraceAsyncIntegrationTests.TraceAsyncITestConfiguration.class })
|
||||
public class TraceAsyncIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
ClassPerformingAsyncLogic classPerformingAsyncLogic;
|
||||
|
||||
@Autowired
|
||||
Tracer tracer;
|
||||
|
||||
@Autowired
|
||||
TestSpanHandler spans;
|
||||
|
||||
@BeforeEach
|
||||
public void cleanup() {
|
||||
this.spans.clear();
|
||||
this.classPerformingAsyncLogic.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_set_span_on_an_async_annotated_method() {
|
||||
whenAsyncProcessingTakesPlace();
|
||||
|
||||
thenANewAsyncSpanGetsCreated();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_set_span_with_custom_method_on_an_async_annotated_method() {
|
||||
whenAsyncProcessingTakesPlaceWithCustomSpanName();
|
||||
|
||||
thenAsyncSpanHasCustomName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_continue_a_span_on_an_async_annotated_method() {
|
||||
Span span = givenASpanInCurrentThread();
|
||||
|
||||
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(span)) {
|
||||
whenAsyncProcessingTakesPlace();
|
||||
}
|
||||
finally {
|
||||
span.finish();
|
||||
}
|
||||
|
||||
thenTraceIdIsPassedFromTheCurrentThreadToTheAsyncOne(span);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_continue_a_span_with_custom_method_on_an_async_annotated_method() {
|
||||
Span span = givenASpanInCurrentThread();
|
||||
|
||||
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(span)) {
|
||||
whenAsyncProcessingTakesPlaceWithCustomSpanName();
|
||||
}
|
||||
finally {
|
||||
span.finish();
|
||||
}
|
||||
|
||||
thenTraceIdIsPassedFromTheCurrentThreadToTheAsyncOneAndSpanHasCustomName(span);
|
||||
}
|
||||
|
||||
private Span givenASpanInCurrentThread() {
|
||||
return this.tracer.nextSpan().name("http:existing");
|
||||
}
|
||||
|
||||
private void whenAsyncProcessingTakesPlace() {
|
||||
this.classPerformingAsyncLogic.invokeAsynchronousLogic();
|
||||
}
|
||||
|
||||
private void whenAsyncProcessingTakesPlaceWithCustomSpanName() {
|
||||
this.classPerformingAsyncLogic.customNameInvokeAsynchronousLogic();
|
||||
}
|
||||
|
||||
private void thenTraceIdIsPassedFromTheCurrentThreadToTheAsyncOne(final Span span) {
|
||||
Awaitility.await().atMost(5, SECONDS).untilAsserted(() -> {
|
||||
then(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getSpan().context().traceId())
|
||||
.isEqualTo(span.context().traceId());
|
||||
List<MutableSpan> webSpans = this.spans.spans().stream()
|
||||
.filter(mutableSpan -> mutableSpan.traceId().equalsIgnoreCase(span.context().traceIdString()))
|
||||
.collect(Collectors.toList());
|
||||
then(webSpans).hasSize(2);
|
||||
// HTTP
|
||||
then(webSpans.get(0).name()).isEqualTo("http:existing");
|
||||
// ASYNC
|
||||
then(webSpans.get(1).tags()).containsEntry("class", "ClassPerformingAsyncLogic").containsEntry("method",
|
||||
"invokeAsynchronousLogic");
|
||||
});
|
||||
}
|
||||
|
||||
private void thenANewAsyncSpanGetsCreated() {
|
||||
Awaitility.await().atMost(5, SECONDS).untilAsserted(() -> {
|
||||
then(this.spans).hasSize(1);
|
||||
MutableSpan storedSpan = this.spans.get(0);
|
||||
then(storedSpan.name()).isEqualTo("invoke-asynchronous-logic");
|
||||
then(storedSpan.tags()).containsEntry("class", "ClassPerformingAsyncLogic").containsEntry("method",
|
||||
"invokeAsynchronousLogic");
|
||||
});
|
||||
}
|
||||
|
||||
private void thenTraceIdIsPassedFromTheCurrentThreadToTheAsyncOneAndSpanHasCustomName(final Span span) {
|
||||
Awaitility.await().atMost(5, SECONDS).untilAsserted(() -> {
|
||||
then(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getSpan()).isNotNull();
|
||||
then(TraceAsyncIntegrationTests.this.classPerformingAsyncLogic.getSpan().context().traceId())
|
||||
.isEqualTo(span.context().traceId());
|
||||
then(this.spans).hasSize(2);
|
||||
// HTTP
|
||||
then(this.spans.get(0).name()).isEqualTo("http:existing");
|
||||
// ASYNC
|
||||
then(this.spans.get(1).tags()).containsEntry("class", "ClassPerformingAsyncLogic").containsEntry("method",
|
||||
"customNameInvokeAsynchronousLogic");
|
||||
});
|
||||
}
|
||||
|
||||
private void thenAsyncSpanHasCustomName() {
|
||||
Awaitility.await().atMost(5, SECONDS).untilAsserted(() -> {
|
||||
then(this.spans).hasSize(1);
|
||||
MutableSpan storedSpan = this.spans.get(0);
|
||||
then(storedSpan.name()).isEqualTo("foo");
|
||||
then(storedSpan.tags()).containsEntry("class", "ClassPerformingAsyncLogic").containsEntry("method",
|
||||
"customNameInvokeAsynchronousLogic");
|
||||
});
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanTrace() {
|
||||
this.spans.clear();
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@EnableAsync
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TraceAsyncITestConfiguration {
|
||||
|
||||
@Bean
|
||||
ClassPerformingAsyncLogic asyncClass(Tracer tracer) {
|
||||
return new ClassPerformingAsyncLogic(tracer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
Sampler defaultSampler() {
|
||||
return Sampler.ALWAYS_SAMPLE;
|
||||
}
|
||||
|
||||
@Bean
|
||||
SpanHandler testSpanHandler() {
|
||||
return new TestSpanHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Executor fooExecutor() {
|
||||
return new SimpleAsyncTaskExecutor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Executor barExecutor() {
|
||||
return new SimpleAsyncTaskExecutor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ClassPerformingAsyncLogic {
|
||||
|
||||
private final Tracer tracer;
|
||||
|
||||
AtomicReference<Span> span = new AtomicReference<>();
|
||||
|
||||
ClassPerformingAsyncLogic(Tracer tracer) {
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
@Async("fooExecutor")
|
||||
public void invokeAsynchronousLogic() {
|
||||
this.span.set(this.tracer.currentSpan());
|
||||
}
|
||||
|
||||
@Async
|
||||
@SpanName("foo")
|
||||
public void customNameInvokeAsynchronousLogic() {
|
||||
this.span.set(this.tracer.currentSpan());
|
||||
}
|
||||
|
||||
public Span getSpan() {
|
||||
return this.span.get();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.span.set(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,60 +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.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);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,79 +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.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");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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,39 +1,40 @@
|
||||
/*
|
||||
* 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"));
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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