Skip to content

Commit 65b4780

Browse files
authored
Merge pull request #51 from faststats-dev/fix/submission
Fixed metrics submission pre-1.20
2 parents bbca95c + e56701c commit 65b4780

File tree

5 files changed

+65
-49
lines changed

5 files changed

+65
-49
lines changed

bukkit/src/main/java/dev/faststats/bukkit/BukkitMetricsImpl.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ private BukkitMetricsImpl(SimpleMetrics.Factory<?> factory, Plugin plugin, Path
3333
}
3434

3535
private boolean checkOnlineMode() {
36-
return tryOrEmpty(server.getServerConfig()::isProxyOnlineMode)
36+
return tryOrEmpty(() -> server.getServerConfig().isProxyOnlineMode())
3737
.or(() -> tryOrEmpty(this::isProxyOnlineMode))
3838
.orElseGet(server::getOnlineMode);
3939
}
@@ -52,12 +52,14 @@ private boolean isProxyOnlineMode() {
5252
}
5353

5454
@Override
55-
@SuppressWarnings("deprecation")
55+
@SuppressWarnings({"deprecation", "Convert2MethodRef"})
5656
protected void appendDefaultData(JsonObject charts) {
5757
var pluginVersion = tryOrEmpty(() -> plugin.getPluginMeta().getVersion())
5858
.orElseGet(() -> plugin.getDescription().getVersion());
59-
var minecraftVersion = tryOrEmpty(server::getMinecraftVersion)
60-
.orElseGet(() -> server.getBukkitVersion().split("-", 2)[0]);
59+
60+
var minecraftVersion = tryOrEmpty(() -> server.getMinecraftVersion())
61+
.or(() -> tryOrEmpty(() -> server.getBukkitVersion().split("-", 2)[0]))
62+
.orElseGet(() -> server.getVersion().split("\\(MC: |\\)", 3)[1]);
6163

6264
charts.addProperty("minecraft_version", minecraftVersion);
6365
charts.addProperty("online_mode", checkOnlineMode());

core/src/main/java/dev/faststats/core/SimpleMetrics.java

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.Properties;
2727
import java.util.Set;
2828
import java.util.UUID;
29+
import java.util.concurrent.CompletableFuture;
2930
import java.util.concurrent.Executors;
3031
import java.util.concurrent.ScheduledExecutorService;
3132
import java.util.concurrent.TimeUnit;
@@ -110,7 +111,7 @@ private void startSubmitting(long initialDelay, long period, TimeUnit unit) {
110111
}
111112

112113
var enabled = Boolean.parseBoolean(System.getProperty("faststats.enabled", "true"));
113-
114+
114115
if (!config.enabled() || !enabled) {
115116
warn("Metrics disabled, not starting submission");
116117
return;
@@ -128,21 +129,34 @@ private void startSubmitting(long initialDelay, long period, TimeUnit unit) {
128129
});
129130

130131
info("Starting metrics submission");
131-
executor.scheduleAtFixedRate(this::submitData, initialDelay, period, unit);
132+
executor.scheduleAtFixedRate(() -> {
133+
try {
134+
submitAsync();
135+
} catch (Throwable t) {
136+
error("Failed to submit metrics", t);
137+
}
138+
}, initialDelay, period, unit);
132139
}
133140

134141
protected boolean isSubmitting() {
135142
return executor != null && !executor.isShutdown();
136143
}
137144

138-
protected void submitData() {
145+
protected CompletableFuture<Boolean> submitAsync() throws IOException {
139146
var data = createData().toString();
140147
var bytes = data.getBytes(StandardCharsets.UTF_8);
148+
149+
info("Uncompressed data: " + data);
150+
141151
try (var byteOutput = new ByteArrayOutputStream();
142152
var output = new GZIPOutputStream(byteOutput)) {
153+
143154
output.write(bytes);
144155
output.finish();
156+
145157
var compressed = byteOutput.toByteArray();
158+
info("Compressed size: " + compressed.length + " bytes");
159+
146160
var request = HttpRequest.newBuilder()
147161
.POST(HttpRequest.BodyPublishers.ofByteArray(compressed))
148162
.header("Content-Encoding", "gzip")
@@ -154,31 +168,34 @@ protected void submitData() {
154168
.build();
155169

156170
info("Sending metrics to: " + url);
157-
info("Uncompressed data: " + data);
158-
info("Compressed size: " + compressed.length + " bytes");
159-
160-
var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
161-
var statusCode = response.statusCode();
162-
var body = response.body();
163-
164-
if (statusCode >= 200 && statusCode < 300) {
165-
info("Metrics submitted with status code: " + statusCode + " (" + body + ")");
166-
} else if (statusCode >= 300 && statusCode < 400) {
167-
warn("Received redirect response from metrics server: " + statusCode + " (" + body + ")");
168-
} else if (statusCode >= 400 && statusCode < 500) {
169-
error("Submitted invalid request to metrics server: " + statusCode + " (" + body + ")", null);
170-
} else if (statusCode >= 500 && statusCode < 600) {
171-
error("Received server error response from metrics server: " + statusCode + " (" + body + ")", null);
172-
} else {
173-
warn("Received unexpected response from metrics server: " + statusCode + " (" + body + ")");
174-
}
175-
176-
} catch (HttpConnectTimeoutException e) {
177-
error("Metrics submission timed out after 3 seconds: " + url, null);
178-
} catch (ConnectException e) {
179-
error("Failed to connect to metrics server: " + url, null);
180-
} catch (Exception e) {
181-
error("Failed to submit metrics", e);
171+
return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)).thenApply(response -> {
172+
var statusCode = response.statusCode();
173+
var body = response.body();
174+
175+
if (statusCode >= 200 && statusCode < 300) {
176+
info("Metrics submitted with status code: " + statusCode + " (" + body + ")");
177+
return true;
178+
} else if (statusCode >= 300 && statusCode < 400) {
179+
warn("Received redirect response from metrics server: " + statusCode + " (" + body + ")");
180+
} else if (statusCode >= 400 && statusCode < 500) {
181+
error("Submitted invalid request to metrics server: " + statusCode + " (" + body + ")", null);
182+
} else if (statusCode >= 500 && statusCode < 600) {
183+
error("Received server error response from metrics server: " + statusCode + " (" + body + ")", null);
184+
} else {
185+
warn("Received unexpected response from metrics server: " + statusCode + " (" + body + ")");
186+
}
187+
return false;
188+
}).exceptionally(throwable -> {
189+
var cause = throwable.getCause() != null ? throwable.getCause() : throwable;
190+
if (cause instanceof HttpConnectTimeoutException) {
191+
error("Metrics submission timed out after 3 seconds: " + url, null);
192+
} else if (cause instanceof ConnectException) {
193+
error("Failed to connect to metrics server: " + url, null);
194+
} else {
195+
error("Failed to submit metrics", throwable);
196+
}
197+
return false;
198+
});
182199
}
183200
}
184201

@@ -195,7 +212,7 @@ protected JsonObject createData() {
195212
this.charts.forEach(chart -> {
196213
try {
197214
chart.getData().ifPresent(chartData -> charts.add(chart.getId(), chartData));
198-
} catch (Exception e) {
215+
} catch (Throwable e) {
199216
error("Failed to build chart data: " + chart.getId(), e);
200217
}
201218
});

core/src/test/java/dev/faststats/BukkitMetricsTest.java

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,15 @@
22

33
import org.junit.jupiter.api.Test;
44

5-
import java.io.ByteArrayOutputStream;
65
import java.io.IOException;
7-
import java.nio.charset.StandardCharsets;
86
import java.util.UUID;
9-
import java.util.zip.GZIPOutputStream;
7+
8+
import static org.junit.jupiter.api.Assumptions.assumeTrue;
109

1110
public class BukkitMetricsTest {
1211
@Test
1312
public void testCreateData() throws IOException {
14-
var mock = new MockMetrics(UUID.randomUUID(), "bba4a14eac38779007a6fda4814381ab", true);
15-
var data = mock.createData();
16-
var bytes = data.toString().getBytes(StandardCharsets.UTF_8);
17-
try (var byteOutput = new ByteArrayOutputStream();
18-
var output = new GZIPOutputStream(byteOutput)) {
19-
output.write(bytes);
20-
output.finish();
21-
var compressed = byteOutput.toByteArray();
22-
mock.printInfo(new String(compressed, StandardCharsets.UTF_8) + " (" + compressed.length + " bytes)");
23-
mock.printInfo(new String(bytes, StandardCharsets.UTF_8) + " (" + bytes.length + " bytes)");
24-
}
13+
var mock = new MockMetrics(UUID.randomUUID(), "24f9fc423ed06194065a42d00995c600", true);
14+
assumeTrue(mock.submitAsync().join(), "For this test to run, the server must be running");
2515
}
2616
}

core/src/test/java/dev/faststats/MockMetrics.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@
66
import org.jspecify.annotations.NullMarked;
77
import org.jspecify.annotations.Nullable;
88

9+
import java.io.IOException;
910
import java.net.URI;
1011
import java.util.Set;
1112
import java.util.UUID;
13+
import java.util.concurrent.CompletableFuture;
1214

1315
@NullMarked
1416
public class MockMetrics extends SimpleMetrics {
1517
public MockMetrics(UUID serverId, @Token String token, boolean debug) {
16-
super(new SimpleMetrics.Config(serverId, true, debug), Set.of(), token, URI.create("http://localhost:5000"), debug);
18+
super(new SimpleMetrics.Config(serverId, true, debug), Set.of(), token, URI.create("http://localhost:5000/v1/collect"), debug);
1719
}
1820

1921
@Override
@@ -32,6 +34,11 @@ protected void printWarning(String message) {
3234
System.out.println(message);
3335
}
3436

37+
@Override
38+
public CompletableFuture<Boolean> submitAsync() throws IOException {
39+
return super.submitAsync();
40+
}
41+
3542
@Override
3643
public JsonObject createData() {
3744
return super.createData();

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
version=0.7.4
1+
version=0.7.5

0 commit comments

Comments
 (0)