Skip to content

Commit 9ab8609

Browse files
committed
DataSource metrics
This commit adds an abstraction that provides a standard manner to retrieve various information that are shared by most data sources. DataSourceInfo 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) and the current usage of the connection pool. Additional DataSourceInfo implementations for other data source types can be added very easily, check DataourceInfoProvidersConfiguration for more details. Fixes spring-projectsgh-1013
1 parent c5d46d0 commit 9ab8609

17 files changed

+1164
-0
lines changed

spring-boot-actuator/pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,21 @@
121121
<artifactId>spring-rabbit</artifactId>
122122
<optional>true</optional>
123123
</dependency>
124+
<dependency>
125+
<groupId>org.apache.tomcat</groupId>
126+
<artifactId>tomcat-jdbc</artifactId>
127+
<optional>true</optional>
128+
</dependency>
129+
<dependency>
130+
<groupId>com.zaxxer</groupId>
131+
<artifactId>HikariCP</artifactId>
132+
<optional>true</optional>
133+
</dependency>
134+
<dependency>
135+
<groupId>commons-dbcp</groupId>
136+
<artifactId>commons-dbcp</artifactId>
137+
<optional>true</optional>
138+
</dependency>
124139
<!-- Test -->
125140
<dependency>
126141
<groupId>ch.qos.logback</groupId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure;
18+
19+
import java.util.Collection;
20+
import java.util.HashMap;
21+
import java.util.LinkedHashSet;
22+
import java.util.Map;
23+
24+
import javax.annotation.PostConstruct;
25+
import javax.sql.DataSource;
26+
27+
import org.springframework.beans.factory.annotation.Autowired;
28+
import org.springframework.boot.actuate.endpoint.PublicMetrics;
29+
import org.springframework.boot.actuate.metrics.Metric;
30+
import org.springframework.boot.actuate.metrics.jdbc.CompositeDataSourceInfoProvider;
31+
import org.springframework.boot.actuate.metrics.jdbc.DataSourceInfo;
32+
import org.springframework.boot.actuate.metrics.jdbc.DataSourceInfoProvider;
33+
import org.springframework.boot.actuate.metrics.jdbc.DataSourceInfoProvidersConfiguration;
34+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
35+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
36+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
37+
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
38+
import org.springframework.context.annotation.Bean;
39+
import org.springframework.context.annotation.Import;
40+
41+
/**
42+
* {@link EnableAutoConfiguration Auto-configuration} that provides
43+
* metrics on dataSource usage.
44+
*
45+
* @author Stephane Nicoll
46+
* @since 1.2.0
47+
*/
48+
@ConditionalOnBean(DataSource.class)
49+
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
50+
@Import(DataSourceInfoProvidersConfiguration.class)
51+
public class MetricDataSourceAutoConfiguration {
52+
53+
@Bean
54+
@ConditionalOnBean(DataSourceInfoProvider.class)
55+
PublicMetrics dataSourcePublicMetrics() {
56+
return new DataSourcePublicMetrics();
57+
}
58+
59+
60+
private class DataSourcePublicMetrics implements PublicMetrics {
61+
62+
@Autowired
63+
private Map<String, DataSource> dataSources;
64+
65+
@Autowired
66+
private Collection<DataSourceInfoProvider> dataSourceInfoProviders;
67+
68+
private final Map<String, DataSourceInfo> dataSourceInfoByPrefix
69+
= new HashMap<String, DataSourceInfo>();
70+
71+
@PostConstruct
72+
public void initialize() {
73+
DataSourceInfoProvider provider = new CompositeDataSourceInfoProvider(this.dataSourceInfoProviders);
74+
for (Map.Entry<String, DataSource> entry : dataSources.entrySet()) {
75+
String prefix = "ds." + entry.getKey() + ".";
76+
DataSourceInfo dataSourceInfo = provider.getDataSourceInfo(entry.getValue());
77+
if (dataSourceInfo != null) {
78+
dataSourceInfoByPrefix.put(prefix, dataSourceInfo);
79+
}
80+
}
81+
}
82+
83+
@Override
84+
public Collection<Metric<?>> metrics() {
85+
Collection<Metric<?>> result = new LinkedHashSet<Metric<?>>();
86+
for (Map.Entry<String, DataSourceInfo> entry : dataSourceInfoByPrefix.entrySet()) {
87+
String prefix = entry.getKey();
88+
DataSourceInfo dataSourceInfo = entry.getValue();
89+
Integer poolSize = dataSourceInfo.getPoolSize();
90+
if (poolSize != null) {
91+
result.add(new Metric<Integer>(prefix + "active", poolSize));
92+
}
93+
Float poolUsage = dataSourceInfo.getPoolUsage();
94+
if (poolUsage != null) {
95+
result.add(new Metric<Float>(prefix + "usage", poolUsage));
96+
}
97+
}
98+
return result;
99+
}
100+
}
101+
102+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.metrics.jdbc;
18+
19+
import javax.sql.DataSource;
20+
21+
/**
22+
* A base {@link DataSourceInfo} implementation.
23+
*
24+
* @author Stephane Nicoll
25+
* @since 1.2.0
26+
*/
27+
public abstract class AbstractDataSourceInfo<D extends DataSource> implements DataSourceInfo {
28+
29+
private final D dataSource;
30+
31+
/**
32+
* Create an instance with the data source to use.
33+
*/
34+
protected AbstractDataSourceInfo(D dataSource) {
35+
this.dataSource = dataSource;
36+
}
37+
38+
@Override
39+
public Float getPoolUsage() {
40+
Integer max = getMaxPoolSize();
41+
if (max == null) {
42+
return null;
43+
}
44+
if (max < 0) {
45+
return -1F;
46+
}
47+
Integer current = getPoolSize();
48+
if (current == null) {
49+
return null;
50+
}
51+
if (current == 0) {
52+
return 0F;
53+
}
54+
return (float) current / max; // something like that
55+
}
56+
57+
protected final D getDataSource() {
58+
return dataSource;
59+
}
60+
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.metrics.jdbc;
18+
19+
import org.apache.commons.dbcp.BasicDataSource;
20+
21+
/**
22+
* A {@link DataSourceInfo} implementation for the commons dbcp
23+
* data source.
24+
*
25+
* @author Stephane Nicoll
26+
* @since 1.2.0
27+
*/
28+
public class CommonsDbcpDataSourceInfo extends AbstractDataSourceInfo<BasicDataSource> {
29+
30+
public CommonsDbcpDataSourceInfo(BasicDataSource dataSource) {
31+
super(dataSource);
32+
}
33+
34+
@Override
35+
public Integer getPoolSize() {
36+
return getDataSource().getNumActive();
37+
}
38+
39+
@Override
40+
public Integer getMaxPoolSize() {
41+
return getDataSource().getMaxActive();
42+
}
43+
44+
@Override
45+
public Integer getMinPoolSize() {
46+
return getDataSource().getMinIdle();
47+
}
48+
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.metrics.jdbc;
18+
19+
import java.util.ArrayList;
20+
import java.util.Collection;
21+
22+
import javax.sql.DataSource;
23+
24+
/**
25+
* A {@link DataSourceInfoProvider} implementation that returns the first
26+
* {@link DataSourceInfo} that is found by one of its delegate.
27+
*
28+
* @author Stephane Nicoll
29+
* @since 1.2.0
30+
*/
31+
public class CompositeDataSourceInfoProvider implements DataSourceInfoProvider {
32+
33+
private final Collection<DataSourceInfoProvider> providers;
34+
35+
/**
36+
* Create an instance with an initial collection of delegates to use.
37+
*/
38+
public CompositeDataSourceInfoProvider(Collection<DataSourceInfoProvider> providers) {
39+
this.providers = providers;
40+
}
41+
42+
/**
43+
* Create an instance with no delegate.
44+
*/
45+
public CompositeDataSourceInfoProvider() {
46+
this(new ArrayList<DataSourceInfoProvider>());
47+
}
48+
49+
@Override
50+
public DataSourceInfo getDataSourceInfo(DataSource dataSource) {
51+
for (DataSourceInfoProvider provider : providers) {
52+
DataSourceInfo dataSourceInfo = provider.getDataSourceInfo(dataSource);
53+
if (dataSourceInfo != null) {
54+
return dataSourceInfo;
55+
}
56+
}
57+
return null;
58+
}
59+
60+
/**
61+
* Add a {@link DataSourceInfoProvider} delegate to the list.
62+
*/
63+
public void addDataSourceInfoProvider(DataSourceInfoProvider provider) {
64+
this.providers.add(provider);
65+
}
66+
67+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.metrics.jdbc;
18+
19+
import javax.sql.DataSource;
20+
21+
/**
22+
* Provide various information regarding a {@link DataSource} that
23+
* are shared by most data source types but not accessible in a
24+
* standard manner.
25+
*
26+
* @author Stephane Nicoll
27+
* @since 1.2.0
28+
*/
29+
public interface DataSourceInfo {
30+
31+
/**
32+
* Return the usage of the pool as a double value between
33+
* 0 and 1.
34+
* <ul>
35+
* <li>1 means that the maximum number of connections
36+
* have been allocated</li>
37+
* <li>0 means that no connection is currently active</li>
38+
* <li>-1 means there is not limit to the number of connections
39+
* that can be allocated</li>
40+
* </ul>
41+
* This may also return {@code null} if the data source does
42+
* not provide the necessary information to compute the poll usage.
43+
*/
44+
Float getPoolUsage();
45+
46+
/**
47+
* Return the current number of active connections that
48+
* have been allocated from the data source or {@code null}
49+
* if that information is not available.
50+
*/
51+
Integer getPoolSize();
52+
53+
/**
54+
* Return the maximum number of active connections that can be
55+
* allocated at the same time or {@code -1} if there is no
56+
* limit. Can also return {@code null} if that information is
57+
* not available.
58+
*/
59+
Integer getMaxPoolSize();
60+
61+
/**
62+
* Return the minimum number of idle connections in the pool
63+
* or {@code null} if that information is not available.
64+
*/
65+
Integer getMinPoolSize();
66+
67+
}

0 commit comments

Comments
 (0)