forked from spring-projects/spring-boot
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 spring-projectsgh-1013
- Loading branch information
Showing
19 changed files
with
1,325 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
...ava/org/springframework/boot/actuate/autoconfigure/MetricDataSourceAutoConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} | ||
|
||
} |
141 changes: 141 additions & 0 deletions
141
...ator/src/main/java/org/springframework/boot/actuate/endpoint/DataSourcePublicMetrics.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
...c/main/java/org/springframework/boot/actuate/metrics/jdbc/AbstractDataSourceMetadata.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
|
||
} |
49 changes: 49 additions & 0 deletions
49
...ain/java/org/springframework/boot/actuate/metrics/jdbc/CommonsDbcpDataSourceMetadata.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} | ||
|
||
} |
67 changes: 67 additions & 0 deletions
67
...va/org/springframework/boot/actuate/metrics/jdbc/CompositeDataSourceMetadataProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
|
||
} |
Oops, something went wrong.