Skip to content

Commit 20c4795

Browse files
committed
Merge branch 'disk-space-health-indicator'
2 parents 1dbc94d + 9717891 commit 20c4795

File tree

6 files changed

+233
-4
lines changed

6 files changed

+233
-4
lines changed

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
3131
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
3232
import org.springframework.boot.actuate.health.DataSourceHealthIndicator;
33+
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicator;
34+
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties;
3335
import org.springframework.boot.actuate.health.HealthAggregator;
3436
import org.springframework.boot.actuate.health.HealthIndicator;
3537
import org.springframework.boot.actuate.health.MongoHealthIndicator;
@@ -52,6 +54,7 @@
5254
import org.springframework.boot.autoconfigure.mongo.MongoDataAutoConfiguration;
5355
import org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration;
5456
import org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration;
57+
import org.springframework.boot.context.properties.ConfigurationProperties;
5558
import org.springframework.context.annotation.Bean;
5659
import org.springframework.context.annotation.Configuration;
5760
import org.springframework.data.mongodb.core.MongoTemplate;
@@ -256,4 +259,22 @@ public HealthIndicator rabbitHealthIndicator() {
256259
}
257260
}
258261

262+
@Configuration
263+
@ConditionalOnExpression("${health.diskspace.enabled:true}")
264+
public static class DiskSpaceHealthIndicatorConfiguration {
265+
266+
@Bean
267+
@ConditionalOnMissingBean(name = "diskSpaceHealthIndicator")
268+
public HealthIndicator diskSpaceHealthIndicator(
269+
DiskSpaceHealthIndicatorProperties properties) {
270+
return new DiskSpaceHealthIndicator(properties);
271+
}
272+
273+
@Bean
274+
@ConfigurationProperties("health.diskspace")
275+
public DiskSpaceHealthIndicatorProperties diskSpaceHealthIndicatorProperties() {
276+
return new DiskSpaceHealthIndicatorProperties();
277+
}
278+
}
279+
259280
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 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.health;
18+
19+
import org.apache.commons.logging.Log;
20+
import org.apache.commons.logging.LogFactory;
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
23+
/**
24+
* A {@link HealthIndicator} that checks available disk space and reports a status of
25+
* {@link Status#DOWN} when it drops below a configurable threshold.
26+
*
27+
* @author Mattias Severson
28+
* @author Andy Wilkinson
29+
* @since 1.2.0
30+
*/
31+
public class DiskSpaceHealthIndicator extends AbstractHealthIndicator {
32+
33+
private static Log logger = LogFactory.getLog(DiskSpaceHealthIndicator.class);
34+
35+
private final DiskSpaceHealthIndicatorProperties properties;
36+
37+
/**
38+
* Create a new {@code DiskSpaceHealthIndicator}
39+
*/
40+
@Autowired
41+
public DiskSpaceHealthIndicator(DiskSpaceHealthIndicatorProperties properties) {
42+
this.properties = properties;
43+
}
44+
45+
@Override
46+
protected void doHealthCheck(Health.Builder builder) throws Exception {
47+
long diskFreeInBytes = this.properties.getPath().getFreeSpace();
48+
if (diskFreeInBytes >= this.properties.getThreshold()) {
49+
builder.up();
50+
}
51+
else {
52+
logger.warn(String.format("Free disk space below threshold. "
53+
+ "Available: %d bytes (threshold: %d bytes)", diskFreeInBytes,
54+
this.properties.getThreshold()));
55+
builder.down();
56+
}
57+
builder.withDetail("free", diskFreeInBytes).withDetail("threshold",
58+
this.properties.getThreshold());
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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.health;
18+
19+
import java.io.File;
20+
21+
import org.springframework.util.Assert;
22+
23+
/**
24+
* External configuration properties for {@link DiskSpaceHealthIndicator}
25+
*
26+
* @author Andy Wilkinson
27+
* @since 1.2.0
28+
*/
29+
public class DiskSpaceHealthIndicatorProperties {
30+
31+
private File path = new File(".");
32+
33+
private long threshold = 10 * 1024 * 1024;
34+
35+
public File getPath() {
36+
return this.path;
37+
}
38+
39+
public void setPath(File path) {
40+
if (!path.exists()) {
41+
throw new IllegalArgumentException(String.format("Path '%s' does not exist",
42+
path));
43+
}
44+
if (!path.canRead()) {
45+
throw new IllegalStateException(String.format("Path '%s' cannot be read",
46+
path));
47+
}
48+
this.path = path;
49+
}
50+
51+
public long getThreshold() {
52+
53+
return this.threshold;
54+
}
55+
56+
public void setThreshold(long threshold) {
57+
Assert.isTrue(threshold >= 0, "threshold must be greater than 0");
58+
this.threshold = threshold;
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 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.health;
18+
19+
import java.io.File;
20+
21+
import org.junit.Before;
22+
import org.junit.Rule;
23+
import org.junit.Test;
24+
import org.junit.rules.ExpectedException;
25+
import org.junit.runner.RunWith;
26+
import org.mockito.Mock;
27+
import org.mockito.runners.MockitoJUnitRunner;
28+
29+
import static org.junit.Assert.assertEquals;
30+
import static org.mockito.Mockito.when;
31+
32+
/**
33+
* Tests for {@link DiskSpaceHealthIndicator}.
34+
*
35+
* @author Mattias Severson
36+
*/
37+
@RunWith(MockitoJUnitRunner.class)
38+
public class DiskSpaceHealthIndicatorTests {
39+
40+
static final long THRESHOLD_BYTES = 1024;
41+
42+
@Rule
43+
public ExpectedException exception = ExpectedException.none();
44+
45+
@Mock
46+
File fileMock;
47+
48+
HealthIndicator healthIndicator;
49+
50+
@Before
51+
public void setUp() throws Exception {
52+
when(this.fileMock.exists()).thenReturn(true);
53+
when(this.fileMock.canRead()).thenReturn(true);
54+
this.healthIndicator = new DiskSpaceHealthIndicator(createProperties(
55+
this.fileMock, THRESHOLD_BYTES));
56+
}
57+
58+
@Test
59+
public void diskSpaceIsUp() throws Exception {
60+
when(this.fileMock.getFreeSpace()).thenReturn(THRESHOLD_BYTES + 10);
61+
62+
Health health = this.healthIndicator.health();
63+
assertEquals(Status.UP, health.getStatus());
64+
assertEquals(THRESHOLD_BYTES, health.getDetails().get("threshold"));
65+
assertEquals(THRESHOLD_BYTES + 10, health.getDetails().get("free"));
66+
}
67+
68+
@Test
69+
public void diskSpaceIsDown() throws Exception {
70+
when(this.fileMock.getFreeSpace()).thenReturn(THRESHOLD_BYTES - 10);
71+
72+
Health health = this.healthIndicator.health();
73+
assertEquals(Status.DOWN, health.getStatus());
74+
assertEquals(THRESHOLD_BYTES, health.getDetails().get("threshold"));
75+
assertEquals(THRESHOLD_BYTES - 10, health.getDetails().get("free"));
76+
}
77+
78+
private DiskSpaceHealthIndicatorProperties createProperties(File path, long threshold) {
79+
DiskSpaceHealthIndicatorProperties properties = new DiskSpaceHealthIndicatorProperties();
80+
properties.setPath(path);
81+
properties.setThreshold(threshold);
82+
return properties;
83+
}
84+
}

spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,10 @@ content into your application; rather pick only the properties that you need.
387387
endpoints.trace.sensitive=true
388388
endpoints.trace.enabled=true
389389
390+
# HEALTH INDICATORS
391+
health.diskspace.path=.
392+
health.diskspace.threshold=10485760
393+
390394
# MVC ONLY ENDPOINTS
391395
endpoints.jolokia.path=jolokia
392396
endpoints.jolokia.sensitive=true

spring-boot-docs/src/main/asciidoc/production-ready-features.adoc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,10 @@ To provide custom health information you can register a Spring bean that impleme
165165
Spring Boot provides a
166166
{sc-spring-boot-actuator}/health/DataSourceHealthIndicator.{sc-ext}[`DataSourceHealthIndicator`]
167167
implementation that attempts a simple database test (reusing the validation query set on the data
168-
source, if any) as well as implementations for Redis, MongoDB and RabbitMQ.
169-
170-
Spring Boot adds the `HealthIndicator` instances automatically if beans of type `DataSource`,
171-
`MongoTemplate`, `RedisConnectionFactory`, `RabbitTemplate` are present in the `ApplicationContext`.
168+
source, if any) as well as implementations for Redis, MongoDB and RabbitMQ. Spring Boot adds the
169+
`HealthIndicator` instances automatically if beans of type `DataSource`, `MongoTemplate`,
170+
`RedisConnectionFactory`, and `RabbitTemplate` respectively are present in the
171+
`ApplicationContext`. A health indicator that checks free disk space is also provided.
172172

173173
Besides implementing custom a `HealthIndicator` type and using out-of-box {sc-spring-boot-actuator}/health/Status.{sc-ext}[`Status`]
174174
types, it is also possible to introduce custom `Status` types for different or more complex system

0 commit comments

Comments
 (0)