Skip to content

Commit 912b2f7

Browse files
committed
Add docker stats support
Add docker stats support for 1.5+
1 parent 9dea5ed commit 912b2f7

12 files changed

Lines changed: 392 additions & 1 deletion

File tree

src/main/java/com/github/dockerjava/api/DockerClient.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ public CopyFileFromContainerCmd copyFileFromContainerCmd(
114114

115115
public EventsCmd eventsCmd(EventCallback eventCallback);
116116

117+
public StatsCmd statsCmd(StatsCallback statsCallback);
118+
117119
@Override
118120
public void close() throws IOException;
119121

src/main/java/com/github/dockerjava/api/command/DockerCmdExecFactory.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ public interface DockerCmdExecFactory extends Closeable {
7878
public UnpauseContainerCmd.Exec createUnpauseContainerCmdExec();
7979

8080
public EventsCmd.Exec createEventsCmdExec();
81+
82+
public StatsCmd.Exec createStatsCmdExec();
83+
8184

8285
@Override
8386
public void close() throws IOException;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.github.dockerjava.api.command;
2+
3+
import com.github.dockerjava.api.model.Statistics;
4+
5+
/**
6+
* Stats callback
7+
*/
8+
public interface StatsCallback {
9+
public void onStats(Statistics stats);
10+
public void onException(Throwable throwable);
11+
public void onCompletion(int numStats);
12+
public boolean isReceiving();
13+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.github.dockerjava.api.command;
2+
3+
import java.util.concurrent.ExecutorService;
4+
5+
6+
/**
7+
* Get stats
8+
*
9+
*/
10+
public interface StatsCmd extends DockerCmd<ExecutorService> {
11+
public StatsCmd withContainerId(String containerId);
12+
13+
public String getContainerId();
14+
15+
public StatsCmd withStatsCallback(StatsCallback statsCallback);
16+
17+
public StatsCallback getStatsCallback();
18+
19+
public static interface Exec extends DockerCmdExec<StatsCmd, ExecutorService> {
20+
}
21+
22+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.github.dockerjava.api.model;
2+
3+
import java.util.Map;
4+
5+
import org.apache.commons.lang.builder.ToStringBuilder;
6+
7+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
8+
import com.fasterxml.jackson.annotation.JsonProperty;
9+
10+
/**
11+
* Representation of a Docker statistics.
12+
*/
13+
@JsonIgnoreProperties(ignoreUnknown = true)
14+
public class Statistics {
15+
16+
@JsonProperty("read")
17+
private String read;
18+
19+
@JsonProperty("network")
20+
private Map<String,Object> networkStats;
21+
22+
@JsonProperty("memory_stats")
23+
private Map<String,Object> memoryStats;
24+
25+
@JsonProperty("blkio_stats")
26+
private Map<String,Object> blkioStats;
27+
28+
@JsonProperty("cpu_stats")
29+
private Map<String,Object> cpuStats;
30+
31+
public Map<String,Object> getNetworkStats() {
32+
return networkStats;
33+
}
34+
35+
public Map<String,Object> getCpuStats() {
36+
return cpuStats;
37+
}
38+
39+
public Map<String,Object> getMemoryStats() {
40+
return memoryStats;
41+
}
42+
43+
public Map<String,Object> getBlkioStats() {
44+
return blkioStats;
45+
}
46+
47+
@Override
48+
public String toString() {
49+
return ToStringBuilder.reflectionToString(this);
50+
}
51+
}

src/main/java/com/github/dockerjava/core/DockerClientImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,12 @@ public EventsCmd eventsCmd(EventCallback eventCallback) {
336336
return new EventsCmdImpl(getDockerCmdExecFactory()
337337
.createEventsCmdExec(), eventCallback);
338338
}
339+
340+
@Override
341+
public StatsCmd statsCmd(StatsCallback statsCallback) {
342+
return new StatsCmdImpl(getDockerCmdExecFactory()
343+
.createStatsCmdExec(), statsCallback);
344+
}
339345

340346
@Override
341347
public void close() throws IOException {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.github.dockerjava.core.command;
2+
3+
import static com.google.common.base.Preconditions.checkNotNull;
4+
5+
import java.util.concurrent.ExecutorService;
6+
7+
import com.github.dockerjava.api.command.EventCallback;
8+
import com.github.dockerjava.api.command.EventsCmd;
9+
import com.github.dockerjava.api.command.StatsCallback;
10+
import com.github.dockerjava.api.command.StatsCmd;
11+
import com.github.dockerjava.api.command.TopContainerCmd;
12+
13+
/**
14+
* Stream docker stats
15+
*/
16+
public class StatsCmdImpl extends AbstrDockerCmd<StatsCmd, ExecutorService> implements StatsCmd {
17+
18+
private String containerId;
19+
private StatsCallback statsCallback;
20+
21+
public StatsCmdImpl(StatsCmd.Exec exec, StatsCallback statsCallback) {
22+
super(exec);
23+
withStatsCallback(statsCallback);
24+
}
25+
26+
@Override
27+
public StatsCmd withContainerId(String containerId) {
28+
checkNotNull(containerId, "containerId was not specified");
29+
this.containerId = containerId;
30+
return this;
31+
}
32+
33+
@Override
34+
public String getContainerId() {
35+
return containerId;
36+
}
37+
38+
@Override
39+
public StatsCmd withStatsCallback(StatsCallback statsCallback) {
40+
this.statsCallback = statsCallback;
41+
return this;
42+
}
43+
44+
45+
@Override
46+
public StatsCallback getStatsCallback() {
47+
return statsCallback;
48+
}
49+
50+
@Override
51+
public ExecutorService exec() {
52+
return super.exec();
53+
}
54+
55+
@Override
56+
public String toString() {
57+
return new StringBuilder("stats")
58+
.append(containerId != null ? " --id=" + containerId : "")
59+
.toString();
60+
}
61+
}

src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,11 @@ public UnpauseContainerCmd.Exec createUnpauseContainerCmdExec() {
312312
public EventsCmd.Exec createEventsCmdExec() {
313313
return new EventsCmdExec(getBaseResource());
314314
}
315+
316+
@Override
317+
public StatsCmd.Exec createStatsCmdExec() {
318+
return new StatsCmdExec(getBaseResource());
319+
}
315320

316321
@Override
317322
public void close() throws IOException {
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.github.dockerjava.jaxrs;
2+
3+
import static com.google.common.base.Preconditions.checkNotNull;
4+
5+
import java.io.InputStream;
6+
import java.util.concurrent.Callable;
7+
import java.util.concurrent.ExecutorService;
8+
import java.util.concurrent.Executors;
9+
10+
import javax.ws.rs.client.WebTarget;
11+
import javax.ws.rs.core.Response;
12+
13+
import org.slf4j.Logger;
14+
import org.slf4j.LoggerFactory;
15+
16+
import com.fasterxml.jackson.core.JsonFactory;
17+
import com.fasterxml.jackson.core.JsonParser;
18+
import com.fasterxml.jackson.core.JsonToken;
19+
import com.fasterxml.jackson.databind.ObjectMapper;
20+
import com.github.dockerjava.api.command.StatsCallback;
21+
import com.github.dockerjava.api.command.StatsCmd;
22+
import com.github.dockerjava.api.model.Statistics;
23+
import com.github.dockerjava.jaxrs.util.WrappedResponseInputStream;
24+
25+
public class StatsCmdExec extends AbstrDockerCmdExec<StatsCmd, ExecutorService> implements StatsCmd.Exec {
26+
private static final Logger LOGGER = LoggerFactory.getLogger(StatsCmdExec.class);
27+
28+
public StatsCmdExec(WebTarget baseResource) {
29+
super(baseResource);
30+
}
31+
32+
@Override
33+
protected ExecutorService execute(StatsCmd command) {
34+
ExecutorService executorService = Executors.newSingleThreadExecutor();
35+
36+
WebTarget webResource = getBaseResource().path("/containers/{id}/stats")
37+
.resolveTemplate("id", command.getContainerId());
38+
39+
LOGGER.trace("GET: {}", webResource);
40+
StatsNotifier eventNotifier = StatsNotifier.create(command.getStatsCallback(), webResource);
41+
executorService.submit(eventNotifier);
42+
return executorService;
43+
}
44+
45+
private static class StatsNotifier implements Callable<Void> {
46+
private static final JsonFactory JSON_FACTORY = new JsonFactory();
47+
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
48+
49+
private final StatsCallback statsCallback;
50+
private final WebTarget webTarget;
51+
52+
private StatsNotifier(StatsCallback statsCallback, WebTarget webTarget) {
53+
this.statsCallback = statsCallback;
54+
this.webTarget = webTarget;
55+
}
56+
57+
public static StatsNotifier create(StatsCallback statsCallback, WebTarget webTarget) {
58+
checkNotNull(statsCallback, "An StatsCallback must be provided");
59+
checkNotNull(webTarget, "An WebTarget must be provided");
60+
return new StatsNotifier(statsCallback, webTarget);
61+
}
62+
63+
@Override
64+
public Void call() throws Exception {
65+
int numStats=0;
66+
Response response = null;
67+
try {
68+
response = webTarget.request().get(Response.class);
69+
InputStream inputStream = new WrappedResponseInputStream(response);
70+
JsonParser jp = JSON_FACTORY.createParser(inputStream);
71+
while (jp.nextToken() != JsonToken.END_OBJECT && !jp.isClosed() && statsCallback.isReceiving()) {
72+
statsCallback.onStats(OBJECT_MAPPER.readValue(jp, Statistics.class));
73+
numStats++;
74+
}
75+
statsCallback.onCompletion(numStats);
76+
LOGGER.info("Finished collecting stats");
77+
return null ;
78+
}
79+
catch(Throwable t) {
80+
statsCallback.onException(t);
81+
}
82+
finally {
83+
if (response != null) {
84+
response.close();
85+
}
86+
}
87+
return null ;
88+
}
89+
}
90+
}

src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ private DockerClientConfig config() {
6060

6161
protected DockerClientConfig config(String password) {
6262
DockerClientConfig.DockerClientConfigBuilder builder = DockerClientConfig.createDefaultConfigBuilder()
63-
.withServerAddress("https://index.docker.io/v1/");
63+
.withServerAddress("https://index.docker.io/v1/").withMaxTotalConnections(5).withMaxPerRouteConnections(5);
6464
if (password!=null) {
6565
builder = builder.withPassword(password);
6666
}

0 commit comments

Comments
 (0)