DataSource metrics
This commit adds an abstraction that provides a standard manner to retrieve various metadata that are shared by most data sources. DataSourceMetadata is implemented by the three data source implementations that boot supports out-of-the-box: Tomcat, Hikari and Commons dbcp. This abstraction is used to provide two additional metrics per data source defined in the application: the number of allocated connection(s) (.active) and the current usage of the connection pool (.usage). All such metrics share the 'datasource.' prefix. The prefix is further qualified for each data source: * If the data source is the primary data source (that is either the only available data source or the one flagged @Primary amongst the existing ones), the prefix is "datasource.primary" * If the data source bean name ends with "dataSource", the prefix is the name of the bean without it (i.e. batchDataSource becomes batch) * In all other cases, the name of the bean is used It is possible to override part or all of those defaults by registering a bean with a customized version of DataSourcePublicMetrics. Additional DataSourceMetadata implementations for other data source types can be added very easily, check DataourceMetadataProvidersConfiguration for more details. Fixes gh-1013pull/1476/head
parent
85c95744f9
commit
3dc932db88
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.autoconfigure;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.endpoint.DataSourcePublicMetrics;
|
||||||
|
import org.springframework.boot.actuate.metrics.jdbc.DataSourceMetadataProvider;
|
||||||
|
import org.springframework.boot.actuate.metrics.jdbc.DataSourceMetadataProvidersConfiguration;
|
||||||
|
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.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link EnableAutoConfiguration Auto-configuration} that provides
|
||||||
|
* metrics on dataSource usage.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
@ConditionalOnBean(DataSource.class)
|
||||||
|
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
|
||||||
|
@Import(DataSourceMetadataProvidersConfiguration.class)
|
||||||
|
public class MetricDataSourceAutoConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnBean(DataSourceMetadataProvider.class)
|
||||||
|
@ConditionalOnMissingBean(DataSourcePublicMetrics.class)
|
||||||
|
DataSourcePublicMetrics dataSourcePublicMetrics() {
|
||||||
|
return new DataSourcePublicMetrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.endpoint;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.actuate.metrics.Metric;
|
||||||
|
import org.springframework.boot.actuate.metrics.jdbc.CompositeDataSourceMetadataProvider;
|
||||||
|
import org.springframework.boot.actuate.metrics.jdbc.DataSourceMetadata;
|
||||||
|
import org.springframework.boot.actuate.metrics.jdbc.DataSourceMetadataProvider;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link PublicMetrics} implementation that provides data source usage
|
||||||
|
* statistics.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public class DataSourcePublicMetrics implements PublicMetrics {
|
||||||
|
|
||||||
|
private static final String DATASOURCE_SUFFIX = "dataSource";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Collection<DataSourceMetadataProvider> dataSourceMetadataProviders;
|
||||||
|
|
||||||
|
private final Map<String, DataSourceMetadata> dataSourceMetadataByPrefix
|
||||||
|
= new HashMap<String, DataSourceMetadata>();
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void initialize() {
|
||||||
|
Map<String, DataSource> dataSources = this.applicationContext.getBeansOfType(DataSource.class);
|
||||||
|
DataSource primaryDataSource = getPrimaryDataSource();
|
||||||
|
|
||||||
|
|
||||||
|
DataSourceMetadataProvider provider = new CompositeDataSourceMetadataProvider(this.dataSourceMetadataProviders);
|
||||||
|
for (Map.Entry<String, DataSource> entry : dataSources.entrySet()) {
|
||||||
|
String prefix = createPrefix(entry.getKey(), entry.getValue(), entry.getValue().equals(primaryDataSource));
|
||||||
|
DataSourceMetadata dataSourceMetadata = provider.getDataSourceMetadata(entry.getValue());
|
||||||
|
if (dataSourceMetadata != null) {
|
||||||
|
dataSourceMetadataByPrefix.put(prefix, dataSourceMetadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Metric<?>> metrics() {
|
||||||
|
Collection<Metric<?>> result = new LinkedHashSet<Metric<?>>();
|
||||||
|
for (Map.Entry<String, DataSourceMetadata> entry : dataSourceMetadataByPrefix.entrySet()) {
|
||||||
|
String prefix = entry.getKey();
|
||||||
|
// Make sure the prefix ends with a dot
|
||||||
|
if (!prefix.endsWith(".")) {
|
||||||
|
prefix = prefix + ".";
|
||||||
|
}
|
||||||
|
DataSourceMetadata dataSourceMetadata = entry.getValue();
|
||||||
|
Integer poolSize = dataSourceMetadata.getPoolSize();
|
||||||
|
if (poolSize != null) {
|
||||||
|
result.add(new Metric<Integer>(prefix + "active", poolSize));
|
||||||
|
}
|
||||||
|
Float poolUsage = dataSourceMetadata.getPoolUsage();
|
||||||
|
if (poolUsage != null) {
|
||||||
|
result.add(new Metric<Float>(prefix + "usage", poolUsage));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the prefix to use for the metrics to associate with the given {@link DataSource}.
|
||||||
|
* @param dataSourceName the name of the data source bean
|
||||||
|
* @param dataSource the data source to configure
|
||||||
|
* @param primary if this data source is the primary data source
|
||||||
|
* @return a prefix for the given data source
|
||||||
|
*/
|
||||||
|
protected String createPrefix(String dataSourceName, DataSource dataSource, boolean primary) {
|
||||||
|
StringBuilder sb = new StringBuilder("datasource.");
|
||||||
|
if (primary) {
|
||||||
|
sb.append("primary");
|
||||||
|
}
|
||||||
|
else if (endWithDataSource(dataSourceName)) { // Strip the data source part out of the name
|
||||||
|
sb.append(dataSourceName.substring(0, dataSourceName.length() - DATASOURCE_SUFFIX.length()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sb.append(dataSourceName);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify if the given value ends with {@value #DATASOURCE_SUFFIX}.
|
||||||
|
*/
|
||||||
|
protected boolean endWithDataSource(String value) {
|
||||||
|
int suffixLength = DATASOURCE_SUFFIX.length();
|
||||||
|
int valueLength = value.length();
|
||||||
|
if (valueLength > suffixLength) {
|
||||||
|
String suffix = value.substring(valueLength - suffixLength, valueLength);
|
||||||
|
return suffix.equalsIgnoreCase(DATASOURCE_SUFFIX);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to locate the primary {@link DataSource} (i.e. either the only data source
|
||||||
|
* available or the one amongst the candidates marked as {@link Primary}. Return
|
||||||
|
* {@code null} if there no primary data source could be found.
|
||||||
|
*/
|
||||||
|
private DataSource getPrimaryDataSource() {
|
||||||
|
try {
|
||||||
|
return applicationContext.getBean(DataSource.class);
|
||||||
|
}
|
||||||
|
catch (NoSuchBeanDefinitionException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base {@link DataSourceMetadata} implementation.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public abstract class AbstractDataSourceMetadata<D extends DataSource> implements DataSourceMetadata {
|
||||||
|
|
||||||
|
private final D dataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance with the data source to use.
|
||||||
|
*/
|
||||||
|
protected AbstractDataSourceMetadata(D dataSource) {
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float getPoolUsage() {
|
||||||
|
Integer max = getMaxPoolSize();
|
||||||
|
if (max == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (max < 0) {
|
||||||
|
return -1F;
|
||||||
|
}
|
||||||
|
Integer current = getPoolSize();
|
||||||
|
if (current == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (current == 0) {
|
||||||
|
return 0F;
|
||||||
|
}
|
||||||
|
return (float) current / max; // something like that
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final D getDataSource() {
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import org.apache.commons.dbcp.BasicDataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link DataSourceMetadata} implementation for the commons dbcp
|
||||||
|
* data source.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public class CommonsDbcpDataSourceMetadata extends AbstractDataSourceMetadata<BasicDataSource> {
|
||||||
|
|
||||||
|
public CommonsDbcpDataSourceMetadata(BasicDataSource dataSource) {
|
||||||
|
super(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getPoolSize() {
|
||||||
|
return getDataSource().getNumActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getMaxPoolSize() {
|
||||||
|
return getDataSource().getMaxActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getMinPoolSize() {
|
||||||
|
return getDataSource().getMinIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link DataSourceMetadataProvider} implementation that returns the first
|
||||||
|
* {@link DataSourceMetadata} that is found by one of its delegate.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public class CompositeDataSourceMetadataProvider implements DataSourceMetadataProvider {
|
||||||
|
|
||||||
|
private final Collection<DataSourceMetadataProvider> providers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance with an initial collection of delegates to use.
|
||||||
|
*/
|
||||||
|
public CompositeDataSourceMetadataProvider(Collection<DataSourceMetadataProvider> providers) {
|
||||||
|
this.providers = providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance with no delegate.
|
||||||
|
*/
|
||||||
|
public CompositeDataSourceMetadataProvider() {
|
||||||
|
this(new ArrayList<DataSourceMetadataProvider>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceMetadata getDataSourceMetadata(DataSource dataSource) {
|
||||||
|
for (DataSourceMetadataProvider provider : providers) {
|
||||||
|
DataSourceMetadata dataSourceMetadata = provider.getDataSourceMetadata(dataSource);
|
||||||
|
if (dataSourceMetadata != null) {
|
||||||
|
return dataSourceMetadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a {@link DataSourceMetadataProvider} delegate to the list.
|
||||||
|
*/
|
||||||
|
public void addDataSourceMetadataProvider(DataSourceMetadataProvider provider) {
|
||||||
|
this.providers.add(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide various metadata regarding a {@link DataSource} that
|
||||||
|
* are shared by most data source types but not accessible in a
|
||||||
|
* standard manner.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public interface DataSourceMetadata {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the usage of the pool as a double value between
|
||||||
|
* 0 and 1.
|
||||||
|
* <ul>
|
||||||
|
* <li>1 means that the maximum number of connections
|
||||||
|
* have been allocated</li>
|
||||||
|
* <li>0 means that no connection is currently active</li>
|
||||||
|
* <li>-1 means there is not limit to the number of connections
|
||||||
|
* that can be allocated</li>
|
||||||
|
* </ul>
|
||||||
|
* This may also return {@code null} if the data source does
|
||||||
|
* not provide the necessary information to compute the poll usage.
|
||||||
|
*/
|
||||||
|
Float getPoolUsage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current number of active connections that
|
||||||
|
* have been allocated from the data source or {@code null}
|
||||||
|
* if that information is not available.
|
||||||
|
*/
|
||||||
|
Integer getPoolSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the maximum number of active connections that can be
|
||||||
|
* allocated at the same time or {@code -1} if there is no
|
||||||
|
* limit. Can also return {@code null} if that information is
|
||||||
|
* not available.
|
||||||
|
*/
|
||||||
|
Integer getMaxPoolSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the minimum number of idle connections in the pool
|
||||||
|
* or {@code null} if that information is not available.
|
||||||
|
*/
|
||||||
|
Integer getMinPoolSize();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide a {@link DataSourceMetadata} based on a {@link DataSource}.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public interface DataSourceMetadataProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the {@link DataSourceMetadata} instance able to manage the
|
||||||
|
* specified {@link DataSource} or {@code null} if the given data
|
||||||
|
* source could not be handled.
|
||||||
|
*/
|
||||||
|
DataSourceMetadata getDataSourceMetadata(DataSource dataSource);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import org.apache.commons.dbcp.BasicDataSource;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the {@link DataSourceMetadataProvider} instances for the supported
|
||||||
|
* data sources.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class DataSourceMetadataProvidersConfiguration {
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
|
||||||
|
static class TomcatDataSourceProviderConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSourceMetadataProvider tomcatDataSourceProvider() {
|
||||||
|
return new DataSourceMetadataProvider() {
|
||||||
|
@Override
|
||||||
|
public DataSourceMetadata getDataSourceMetadata(DataSource dataSource) {
|
||||||
|
if (dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource) {
|
||||||
|
return new TomcatDataSourceMetadata((org.apache.tomcat.jdbc.pool.DataSource) dataSource);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(HikariDataSource.class)
|
||||||
|
static class HikariDataSourceProviderConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSourceMetadataProvider hikariDataSourceProvider() {
|
||||||
|
return new DataSourceMetadataProvider() {
|
||||||
|
@Override
|
||||||
|
public DataSourceMetadata getDataSourceMetadata(DataSource dataSource) {
|
||||||
|
if (dataSource instanceof HikariDataSource) {
|
||||||
|
return new HikariDataSourceMetadata((HikariDataSource) dataSource);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(BasicDataSource.class)
|
||||||
|
static class CommonsDbcpDataSourceProviderConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSourceMetadataProvider commonsDbcpDataSourceProvider() {
|
||||||
|
return new DataSourceMetadataProvider() {
|
||||||
|
@Override
|
||||||
|
public DataSourceMetadata getDataSourceMetadata(DataSource dataSource) {
|
||||||
|
if (dataSource instanceof BasicDataSource) {
|
||||||
|
return new CommonsDbcpDataSourceMetadata((BasicDataSource) dataSource);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import com.zaxxer.hikari.pool.HikariPool;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.DirectFieldAccessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link DataSourceMetadata} implementation for the hikari
|
||||||
|
* data source.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public class HikariDataSourceMetadata extends AbstractDataSourceMetadata<HikariDataSource> {
|
||||||
|
|
||||||
|
|
||||||
|
private final HikariPoolProvider hikariPoolProvider;
|
||||||
|
|
||||||
|
public HikariDataSourceMetadata(HikariDataSource dataSource) {
|
||||||
|
super(dataSource);
|
||||||
|
this.hikariPoolProvider = new HikariPoolProvider(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getPoolSize() {
|
||||||
|
HikariPool hikariPool = hikariPoolProvider.getHikariPool();
|
||||||
|
if (hikariPool != null) {
|
||||||
|
return hikariPool.getActiveConnections();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMaxPoolSize() {
|
||||||
|
return getDataSource().getMaximumPoolSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getMinPoolSize() {
|
||||||
|
return getDataSource().getMinimumIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide the {@link HikariPool} instance managed internally by
|
||||||
|
* the {@link HikariDataSource} as there is no other way to retrieve
|
||||||
|
* that information except JMX access.
|
||||||
|
*/
|
||||||
|
private static class HikariPoolProvider {
|
||||||
|
private final HikariDataSource dataSource;
|
||||||
|
|
||||||
|
private boolean poolAvailable;
|
||||||
|
|
||||||
|
private HikariPoolProvider(HikariDataSource dataSource) {
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
this.poolAvailable = isHikariPoolAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HikariPool getHikariPool() {
|
||||||
|
if (!poolAvailable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object value = doGetValue();
|
||||||
|
if (value instanceof HikariPool) {
|
||||||
|
return (HikariPool) value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isHikariPoolAvailable() {
|
||||||
|
try {
|
||||||
|
doGetValue();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (BeansException e) { // No such field
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (SecurityException e) { // Security manager prevents to read the value
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object doGetValue() {
|
||||||
|
DirectFieldAccessor accessor = new DirectFieldAccessor(this.dataSource);
|
||||||
|
return accessor.getPropertyValue("pool");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import org.apache.tomcat.jdbc.pool.ConnectionPool;
|
||||||
|
import org.apache.tomcat.jdbc.pool.DataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A {@link DataSourceMetadata} implementation for the tomcat
|
||||||
|
* data source.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
public class TomcatDataSourceMetadata extends AbstractDataSourceMetadata<DataSource> {
|
||||||
|
|
||||||
|
public TomcatDataSourceMetadata(DataSource dataSource) {
|
||||||
|
super(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getPoolSize() {
|
||||||
|
ConnectionPool pool = getDataSource().getPool();
|
||||||
|
return (pool == null ? 0 : pool.getActive());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getMaxPoolSize() {
|
||||||
|
return getDataSource().getMaxActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getMinPoolSize() {
|
||||||
|
return getDataSource().getMinIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.autoconfigure;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import org.apache.commons.dbcp.BasicDataSource;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.endpoint.DataSourcePublicMetrics;
|
||||||
|
import org.springframework.boot.actuate.endpoint.PublicMetrics;
|
||||||
|
import org.springframework.boot.actuate.metrics.Metric;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.jdbc.core.ConnectionCallback;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
public class MetricDataSourceAutoConfigurationTests {
|
||||||
|
|
||||||
|
private AnnotationConfigApplicationContext context;
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() {
|
||||||
|
if (this.context != null) {
|
||||||
|
this.context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noDataSource() {
|
||||||
|
load();
|
||||||
|
assertEquals(0, this.context.getBeansOfType(PublicMetrics.class).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void autoDataSource() {
|
||||||
|
load(DataSourceAutoConfiguration.class);
|
||||||
|
PublicMetrics bean = this.context.getBean(PublicMetrics.class);
|
||||||
|
Collection<Metric<?>> metrics = bean.metrics();
|
||||||
|
assertMetrics(metrics, "datasource.primary.active", "datasource.primary.usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void multipleDataSources() {
|
||||||
|
load(MultipleDataSourcesConfig.class);
|
||||||
|
PublicMetrics bean = this.context.getBean(PublicMetrics.class);
|
||||||
|
Collection<Metric<?>> metrics = bean.metrics();
|
||||||
|
assertMetrics(metrics,
|
||||||
|
"datasource.tomcat.active", "datasource.tomcat.usage",
|
||||||
|
"datasource.commonsDbcp.active", "datasource.commonsDbcp.usage");
|
||||||
|
|
||||||
|
// Hikari won't work unless a first connection has been retrieved
|
||||||
|
JdbcTemplate jdbcTemplate = new JdbcTemplate(context.getBean("hikariDS", DataSource.class));
|
||||||
|
jdbcTemplate.execute(new ConnectionCallback<Void>() {
|
||||||
|
@Override
|
||||||
|
public Void doInConnection(Connection connection) throws SQLException, DataAccessException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Collection<Metric<?>> anotherMetrics = bean.metrics();
|
||||||
|
assertMetrics(anotherMetrics,
|
||||||
|
"datasource.tomcat.active", "datasource.tomcat.usage",
|
||||||
|
"datasource.hikariDS.active", "datasource.hikariDS.usage",
|
||||||
|
"datasource.commonsDbcp.active", "datasource.commonsDbcp.usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void multipleDataSourcesWithPrimary() {
|
||||||
|
load(MultipleDataSourcesWithPrimaryConfig.class);
|
||||||
|
PublicMetrics bean = this.context.getBean(PublicMetrics.class);
|
||||||
|
Collection<Metric<?>> metrics = bean.metrics();
|
||||||
|
assertMetrics(metrics,
|
||||||
|
"datasource.primary.active", "datasource.primary.usage",
|
||||||
|
"datasource.commonsDbcp.active", "datasource.commonsDbcp.usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customPrefix() {
|
||||||
|
load(MultipleDataSourcesWithPrimaryConfig.class, CustomDataSourcePublicMetrics.class);
|
||||||
|
PublicMetrics bean = this.context.getBean(PublicMetrics.class);
|
||||||
|
Collection<Metric<?>> metrics = bean.metrics();
|
||||||
|
assertMetrics(metrics,
|
||||||
|
"ds.first.active", "ds.first.usage",
|
||||||
|
"ds.second.active", "ds.second.usage");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertMetrics(Collection<Metric<?>> metrics, String... keys) {
|
||||||
|
Map<String, Number> content = new HashMap<String, Number>();
|
||||||
|
for (Metric<?> metric : metrics) {
|
||||||
|
content.put(metric.getName(), metric.getValue());
|
||||||
|
}
|
||||||
|
for (String key : keys) {
|
||||||
|
assertTrue("Key '" + key + "' was not found", content.containsKey(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void load(Class<?>... config) {
|
||||||
|
this.context = new AnnotationConfigApplicationContext();
|
||||||
|
if (config.length > 0) {
|
||||||
|
this.context.register(config);
|
||||||
|
}
|
||||||
|
this.context.register(MetricDataSourceAutoConfiguration.class);
|
||||||
|
this.context.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class MultipleDataSourcesConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSource tomcatDataSource() {
|
||||||
|
return initializeBuilder().type(org.apache.tomcat.jdbc.pool.DataSource.class).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSource hikariDS() {
|
||||||
|
return initializeBuilder().type(HikariDataSource.class).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSource commonsDbcpDataSource() {
|
||||||
|
return initializeBuilder().type(BasicDataSource.class).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class MultipleDataSourcesWithPrimaryConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Primary
|
||||||
|
public DataSource myDataSource() {
|
||||||
|
return initializeBuilder().type(org.apache.tomcat.jdbc.pool.DataSource.class).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSource commonsDbcpDataSource() {
|
||||||
|
return initializeBuilder().type(BasicDataSource.class).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class CustomDataSourcePublicMetrics {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSourcePublicMetrics myDataSourcePublicMetrics() {
|
||||||
|
return new DataSourcePublicMetrics() {
|
||||||
|
@Override
|
||||||
|
protected String createPrefix(String dataSourceName, DataSource dataSource, boolean primary) {
|
||||||
|
return (primary ? "ds.first." : "ds.second");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DataSourceBuilder initializeBuilder() {
|
||||||
|
return DataSourceBuilder.create()
|
||||||
|
.driverClassName("org.hsqldb.jdbc.JDBCDriver")
|
||||||
|
.url("jdbc:hsqldb:mem:test")
|
||||||
|
.username("sa");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.jdbc.core.ConnectionCallback;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
public abstract class AbstractDataSourceMetadataTests<D extends AbstractDataSourceMetadata> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a data source metadata instance with a min size of 0 and max size of 2.
|
||||||
|
*/
|
||||||
|
protected abstract D getDataSourceMetadata();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getMaxPoolSize() {
|
||||||
|
assertEquals(Integer.valueOf(2), getDataSourceMetadata().getMaxPoolSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getMinPoolSize() {
|
||||||
|
assertEquals(Integer.valueOf(0), getDataSourceMetadata().getMinPoolSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPoolSizeNoConnection() {
|
||||||
|
// Make sure the pool is initialized
|
||||||
|
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata().getDataSource());
|
||||||
|
jdbcTemplate.execute(new ConnectionCallback<Void>() {
|
||||||
|
@Override
|
||||||
|
public Void doInConnection(Connection connection) throws SQLException, DataAccessException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assertEquals(Integer.valueOf(0), getDataSourceMetadata().getPoolSize());
|
||||||
|
assertEquals(Float.valueOf(0), getDataSourceMetadata().getPoolUsage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPoolSizeOneConnection() {
|
||||||
|
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata().getDataSource());
|
||||||
|
jdbcTemplate.execute(new ConnectionCallback<Void>() {
|
||||||
|
@Override
|
||||||
|
public Void doInConnection(Connection connection) throws SQLException, DataAccessException {
|
||||||
|
assertEquals(Integer.valueOf(1), getDataSourceMetadata().getPoolSize());
|
||||||
|
assertEquals(Float.valueOf(0.5F), getDataSourceMetadata().getPoolUsage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPoolSizeTwoConnections() {
|
||||||
|
final JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata().getDataSource());
|
||||||
|
jdbcTemplate.execute(new ConnectionCallback<Void>() {
|
||||||
|
@Override
|
||||||
|
public Void doInConnection(Connection connection) throws SQLException, DataAccessException {
|
||||||
|
jdbcTemplate.execute(new ConnectionCallback<Void>() {
|
||||||
|
@Override
|
||||||
|
public Void doInConnection(Connection connection) throws SQLException, DataAccessException {
|
||||||
|
assertEquals(Integer.valueOf(2), getDataSourceMetadata().getPoolSize());
|
||||||
|
assertEquals(Float.valueOf(1F), getDataSourceMetadata().getPoolUsage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DataSourceBuilder initializeBuilder() {
|
||||||
|
return DataSourceBuilder.create()
|
||||||
|
.driverClassName("org.hsqldb.jdbc.JDBCDriver")
|
||||||
|
.url("jdbc:hsqldb:mem:test")
|
||||||
|
.username("sa");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.apache.commons.dbcp.BasicDataSource;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
public class CommonsDbcpDataSourceMetadataTests extends AbstractDataSourceMetadataTests<CommonsDbcpDataSourceMetadata> {
|
||||||
|
|
||||||
|
private CommonsDbcpDataSourceMetadata dataSourceMetadata;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
this.dataSourceMetadata = createDataSourceMetadata(0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CommonsDbcpDataSourceMetadata getDataSourceMetadata() {
|
||||||
|
return this.dataSourceMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPoolUsageWithNoCurrent() {
|
||||||
|
CommonsDbcpDataSourceMetadata dsm = new CommonsDbcpDataSourceMetadata(createDataSource()) {
|
||||||
|
@Override
|
||||||
|
public Integer getPoolSize() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assertNull(dsm.getPoolUsage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPoolUsageWithNoMax() {
|
||||||
|
CommonsDbcpDataSourceMetadata dsm = new CommonsDbcpDataSourceMetadata(createDataSource()) {
|
||||||
|
@Override
|
||||||
|
public Integer getMaxPoolSize() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assertNull(dsm.getPoolUsage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPoolUsageWithUnlimitedPool() {
|
||||||
|
DataSourceMetadata unlimitedDataSource = createDataSourceMetadata(0, -1);
|
||||||
|
assertEquals(Float.valueOf(-1F), unlimitedDataSource.getPoolUsage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommonsDbcpDataSourceMetadata createDataSourceMetadata(int minSize, int maxSize) {
|
||||||
|
BasicDataSource dataSource = createDataSource();
|
||||||
|
dataSource.setMinIdle(minSize);
|
||||||
|
dataSource.setMaxActive(maxSize);
|
||||||
|
return new CommonsDbcpDataSourceMetadata(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BasicDataSource createDataSource() {
|
||||||
|
return (BasicDataSource) initializeBuilder().type(BasicDataSource.class).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.BDDMockito.*;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
public class CompositeDataSourceMetadataProviderTests {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DataSourceMetadataProvider firstProvider;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DataSourceMetadata first;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DataSource firstDataSource;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DataSourceMetadataProvider secondProvider;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DataSourceMetadata second;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DataSource secondDataSource;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DataSource unknownDataSource;
|
||||||
|
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
given(firstProvider.getDataSourceMetadata(firstDataSource)).willReturn(first);
|
||||||
|
given(firstProvider.getDataSourceMetadata(secondDataSource)).willReturn(second);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithProviders() {
|
||||||
|
CompositeDataSourceMetadataProvider provider =
|
||||||
|
new CompositeDataSourceMetadataProvider(Arrays.asList(firstProvider, secondProvider));
|
||||||
|
assertSame(first, provider.getDataSourceMetadata(firstDataSource));
|
||||||
|
assertSame(second, provider.getDataSourceMetadata(secondDataSource));
|
||||||
|
assertNull(provider.getDataSourceMetadata(unknownDataSource));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addProvider() {
|
||||||
|
CompositeDataSourceMetadataProvider provider =
|
||||||
|
new CompositeDataSourceMetadataProvider();
|
||||||
|
assertNull(provider.getDataSourceMetadata(firstDataSource));
|
||||||
|
provider.addDataSourceMetadataProvider(firstProvider);
|
||||||
|
assertSame(first, provider.getDataSourceMetadata(firstDataSource));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
public class HikariDataSourceMetadataTests extends AbstractDataSourceMetadataTests<HikariDataSourceMetadata> {
|
||||||
|
|
||||||
|
private HikariDataSourceMetadata dataSourceMetadata;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
this.dataSourceMetadata = createDataSourceMetadata(0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HikariDataSourceMetadata getDataSourceMetadata() {
|
||||||
|
return this.dataSourceMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HikariDataSourceMetadata createDataSourceMetadata(int minSize, int maxSize) {
|
||||||
|
HikariDataSource dataSource = (HikariDataSource) initializeBuilder().type(HikariDataSource.class).build();
|
||||||
|
dataSource.setMinimumIdle(minSize);
|
||||||
|
dataSource.setMaximumPoolSize(maxSize);
|
||||||
|
|
||||||
|
return new HikariDataSourceMetadata(dataSource);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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
|
||||||
|
*
|
||||||
|
* http://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.boot.actuate.metrics.jdbc;
|
||||||
|
|
||||||
|
import org.apache.tomcat.jdbc.pool.DataSource;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
public class TomcatDataSourceMetadataTests extends AbstractDataSourceMetadataTests<TomcatDataSourceMetadata> {
|
||||||
|
|
||||||
|
private TomcatDataSourceMetadata dataSourceMetadata;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
this.dataSourceMetadata = createDataSourceMetadata(0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TomcatDataSourceMetadata getDataSourceMetadata() {
|
||||||
|
return this.dataSourceMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TomcatDataSourceMetadata createDataSourceMetadata(int minSize, int maxSize) {
|
||||||
|
DataSource dataSource = (DataSource) initializeBuilder().type(DataSource.class).build();
|
||||||
|
dataSource.setMinIdle(minSize);
|
||||||
|
dataSource.setMaxActive(maxSize);
|
||||||
|
|
||||||
|
// Avoid warnings
|
||||||
|
dataSource.setInitialSize(minSize);
|
||||||
|
dataSource.setMaxIdle(maxSize);
|
||||||
|
return new TomcatDataSourceMetadata(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue