Skip to content

Commit 08f4575

Browse files
committed
Reintroduce Bugsnag and refactor analytics
1 parent c121b04 commit 08f4575

File tree

10 files changed

+254
-59
lines changed

10 files changed

+254
-59
lines changed

pom.xml

+9
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@
109109
<pattern>okio</pattern>
110110
<shadedPattern>${project.groupId}.${project.artifactId}.libraries.okio</shadedPattern>
111111
</relocation>
112+
<relocation>
113+
<pattern>com.bugsnag</pattern>
114+
<shadedPattern>${project.groupId}.${project.artifactId}.libraries.com.bugsnag</shadedPattern>
115+
</relocation>
112116
</relocations>
113117
<filters>
114118
<filter>
@@ -204,6 +208,11 @@
204208
<artifactId>adventure-platform-bukkit</artifactId>
205209
<version>4.3.4</version>
206210
</dependency>
211+
<dependency>
212+
<groupId>com.bugsnag</groupId>
213+
<version>3.7.2</version>
214+
<artifactId>bugsnag</artifactId>
215+
</dependency>
207216

208217
<dependency>
209218
<groupId>org.spigotmc</groupId>

src/main/java/net/clementraynaud/skoice/Skoice.java

+8-56
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package net.clementraynaud.skoice;
2121

22+
import net.clementraynaud.skoice.analytics.AnalyticManager;
2223
import net.clementraynaud.skoice.api.SkoiceAPI;
2324
import net.clementraynaud.skoice.bot.Bot;
2425
import net.clementraynaud.skoice.commands.skoice.SkoiceCommand;
@@ -33,20 +34,15 @@
3334
import net.clementraynaud.skoice.storage.config.OutdatedConfig;
3435
import net.clementraynaud.skoice.system.ListenerManager;
3536
import net.clementraynaud.skoice.tasks.InterruptSystemTask;
36-
import net.clementraynaud.skoice.util.ChartUtil;
3737
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
38-
import org.bstats.bukkit.Metrics;
39-
import org.bstats.charts.SimplePie;
4038
import org.bukkit.GameMode;
4139
import org.bukkit.plugin.java.JavaPlugin;
4240

4341
import java.time.Duration;
44-
import java.util.EnumSet;
4542

4643
public class Skoice extends JavaPlugin {
4744

4845
private static final String OUTDATED_MINECRAFT_SERVER_ERROR_MESSAGE = "Skoice only supports Minecraft 1.8 or later. Please update your Minecraft server to use the proximity voice chat.";
49-
private static final int BSTATS_SERVICE_ID = 11380;
5046
private static SkoiceAPI api;
5147
private MinecraftLang lang;
5248
private ConfigYamlFile configYamlFile;
@@ -57,6 +53,7 @@ public class Skoice extends JavaPlugin {
5753
private Bot bot;
5854
private BukkitAudiences adventure;
5955
private HookManager hookManager;
56+
private AnalyticManager analyticManager;
6057

6158
public static SkoiceAPI api() {
6259
return Skoice.api;
@@ -93,7 +90,8 @@ public void onEnable() {
9390
new SkoiceCommand(this).init();
9491
this.hookManager = new HookManager(this);
9592
this.hookManager.initialize();
96-
this.addCustomCharts();
93+
this.analyticManager = new AnalyticManager(this);
94+
this.analyticManager.initialize();
9795
Updater updater = new Updater(this, this.getFile().getAbsolutePath());
9896
updater.runUpdaterTaskTimer();
9997
}
@@ -134,56 +132,6 @@ private boolean isMinecraftServerCompatible() {
134132
return true;
135133
}
136134

137-
private void addCustomCharts() {
138-
Metrics metrics = new Metrics(this, Skoice.BSTATS_SERVICE_ID);
139-
140-
this.getSharedConfigFields().forEach(field ->
141-
metrics.addCustomChart(new SimplePie(field.toCamelCase(), () ->
142-
this.configYamlFile.getString(field.toString())
143-
))
144-
);
145-
146-
this.getSharedIntConfigFields().forEach(field ->
147-
metrics.addCustomChart(ChartUtil.createDrilldownPie(field.toCamelCase(),
148-
this.configYamlFile.getInt(field.toString()), 0, 10, 11)
149-
)
150-
);
151-
152-
int linkedUsers = this.linksYamlFile.getLinks().size();
153-
metrics.addCustomChart(ChartUtil.createDrilldownPie("linkedUsers", linkedUsers, 0, 10, 11));
154-
155-
metrics.addCustomChart(new SimplePie("botStatus", () -> this.bot.getStatus().toString()));
156-
}
157-
158-
private EnumSet<ConfigField> getSharedConfigFields() {
159-
return EnumSet.of(
160-
ConfigField.LANG,
161-
ConfigField.LOGIN_NOTIFICATION,
162-
ConfigField.CONNECTING_ALERT,
163-
ConfigField.DISCONNECTING_ALERT,
164-
ConfigField.TOOLTIPS,
165-
ConfigField.PLAYERS_ON_DEATH_SCREEN_INCLUDED,
166-
ConfigField.SPECTATORS_INCLUDED,
167-
ConfigField.SEPARATED_TEAMS,
168-
ConfigField.TEXT_CHAT,
169-
ConfigField.CHANNEL_VISIBILITY,
170-
ConfigField.DISCORDSRV_SYNCHRONIZATION,
171-
ConfigField.ESSENTIALSX_SYNCHRONIZATION,
172-
ConfigField.RELEASE_CHANNEL
173-
);
174-
}
175-
176-
private EnumSet<ConfigField> getSharedIntConfigFields() {
177-
EnumSet<ConfigField> fields = EnumSet.noneOf(ConfigField.class);
178-
if (this.configYamlFile.contains(ConfigField.HORIZONTAL_RADIUS.toString())) {
179-
fields.add(ConfigField.HORIZONTAL_RADIUS);
180-
}
181-
if (this.configYamlFile.contains(ConfigField.VERTICAL_RADIUS.toString())) {
182-
fields.add(ConfigField.VERTICAL_RADIUS);
183-
}
184-
return fields;
185-
}
186-
187135
public MinecraftLang getLang() {
188136
return this.lang;
189137
}
@@ -215,4 +163,8 @@ public Bot getBot() {
215163
public HookManager getHookManager() {
216164
return this.hookManager;
217165
}
166+
167+
public AnalyticManager getAnalyticManager() {
168+
return this.analyticManager;
169+
}
218170
}

src/main/java/net/clementraynaud/skoice/Updater.java

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package net.clementraynaud.skoice;
2121

22+
import com.bugsnag.Severity;
2223
import net.clementraynaud.skoice.storage.config.ConfigField;
2324

2425
import java.io.File;
@@ -154,6 +155,7 @@ private synchronized void update(String version, String expectedHash) {
154155
Files.delete(tempUpdateFile.toPath());
155156
} catch (IOException ignored) {
156157
}
158+
this.plugin.getAnalyticManager().getBugsnag().notify(exception, Severity.WARNING);
157159
} finally {
158160
if (connection != null) {
159161
connection.disconnect();
@@ -196,6 +198,7 @@ private boolean verifyFileIntegrity(File file, String expectedHash) throws NoSuc
196198
for (byte b : fileHashBytes) {
197199
fileHash.append(String.format("%02x", b));
198200
}
201+
this.plugin.getAnalyticManager().getBugsnag().notify(new IOException("File integrity check failed: expected " + expectedHash + ", got " + fileHash), Severity.WARNING);
199202
return fileHash.toString().equals(expectedHash);
200203
}
201204
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2020, 2021, 2022, 2023, 2024 Clément "carlodrift" Raynaud, Lucas "Lucas_Cdry" Cadiry and contributors
3+
*
4+
* This file is part of Skoice.
5+
*
6+
* Skoice is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Skoice is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with Skoice. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
package net.clementraynaud.skoice.analytics;
21+
22+
import net.clementraynaud.skoice.Skoice;
23+
import net.clementraynaud.skoice.storage.config.ConfigField;
24+
25+
import java.util.EnumSet;
26+
27+
public class AnalyticManager {
28+
29+
private final Skoice plugin;
30+
private BugsnagAnalytics bugsnagAnalytics;
31+
32+
public AnalyticManager(Skoice plugin) {
33+
this.plugin = plugin;
34+
}
35+
36+
public void initialize() {
37+
new BStatsAnalytics(this.plugin, this).addCustomCharts();
38+
this.bugsnagAnalytics = new BugsnagAnalytics(this.plugin, this);
39+
this.bugsnagAnalytics.initialize();
40+
}
41+
42+
public EnumSet<ConfigField> getSharedConfigFields() {
43+
return EnumSet.of(
44+
ConfigField.LANG,
45+
ConfigField.LOGIN_NOTIFICATION,
46+
ConfigField.CONNECTING_ALERT,
47+
ConfigField.DISCONNECTING_ALERT,
48+
ConfigField.TOOLTIPS,
49+
ConfigField.PLAYERS_ON_DEATH_SCREEN_INCLUDED,
50+
ConfigField.SPECTATORS_INCLUDED,
51+
ConfigField.SEPARATED_TEAMS,
52+
ConfigField.TEXT_CHAT,
53+
ConfigField.CHANNEL_VISIBILITY,
54+
ConfigField.DISCORDSRV_SYNCHRONIZATION,
55+
ConfigField.ESSENTIALSX_SYNCHRONIZATION,
56+
ConfigField.RELEASE_CHANNEL
57+
);
58+
}
59+
60+
public EnumSet<ConfigField> getSharedIntConfigFields() {
61+
EnumSet<ConfigField> fields = EnumSet.noneOf(ConfigField.class);
62+
if (this.plugin.getConfigYamlFile().contains(ConfigField.HORIZONTAL_RADIUS.toString())) {
63+
fields.add(ConfigField.HORIZONTAL_RADIUS);
64+
}
65+
if (this.plugin.getConfigYamlFile().contains(ConfigField.VERTICAL_RADIUS.toString())) {
66+
fields.add(ConfigField.VERTICAL_RADIUS);
67+
}
68+
return fields;
69+
}
70+
71+
public BugsnagAnalytics getBugsnag() {
72+
return this.bugsnagAnalytics;
73+
}
74+
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright 2020, 2021, 2022, 2023, 2024 Clément "carlodrift" Raynaud, Lucas "Lucas_Cdry" Cadiry and contributors
3+
*
4+
* This file is part of Skoice.
5+
*
6+
* Skoice is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Skoice is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with Skoice. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
package net.clementraynaud.skoice.analytics;
21+
22+
import net.clementraynaud.skoice.Skoice;
23+
import net.clementraynaud.skoice.util.ChartUtil;
24+
import org.bstats.bukkit.Metrics;
25+
import org.bstats.charts.SimplePie;
26+
27+
public class BStatsAnalytics {
28+
29+
private static final int BSTATS_SERVICE_ID = 11380;
30+
private final Skoice plugin;
31+
private final AnalyticManager analyticManager;
32+
33+
public BStatsAnalytics(Skoice plugin, AnalyticManager analyticManager) {
34+
this.plugin = plugin;
35+
this.analyticManager = analyticManager;
36+
}
37+
38+
public void addCustomCharts() {
39+
Metrics metrics = new Metrics(this.plugin, BStatsAnalytics.BSTATS_SERVICE_ID);
40+
41+
this.analyticManager.getSharedConfigFields().forEach(field ->
42+
metrics.addCustomChart(new SimplePie(field.toCamelCase(), () ->
43+
this.plugin.getConfigYamlFile().getString(field.toString())
44+
))
45+
);
46+
47+
this.analyticManager.getSharedIntConfigFields().forEach(field ->
48+
metrics.addCustomChart(ChartUtil.createDrilldownPie(field.toCamelCase(),
49+
this.plugin.getConfigYamlFile().getInt(field.toString()), 0, 10, 11)
50+
)
51+
);
52+
53+
int linkedUsers = this.plugin.getLinksYamlFile().getLinks().size();
54+
metrics.addCustomChart(ChartUtil.createDrilldownPie("linkedUsers", linkedUsers, 0, 10, 11));
55+
56+
metrics.addCustomChart(new SimplePie("botStatus", () -> this.plugin.getBot().getStatus().toString()));
57+
}
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2020, 2021, 2022, 2023, 2024 Clément "carlodrift" Raynaud, Lucas "Lucas_Cdry" Cadiry and contributors
3+
*
4+
* This file is part of Skoice.
5+
*
6+
* Skoice is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Skoice is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with Skoice. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
package net.clementraynaud.skoice.analytics;
21+
22+
import com.bugsnag.Bugsnag;
23+
import com.bugsnag.Severity;
24+
import net.clementraynaud.skoice.Skoice;
25+
import net.clementraynaud.skoice.lang.LangInfo;
26+
import net.clementraynaud.skoice.storage.config.ConfigField;
27+
28+
public class BugsnagAnalytics {
29+
30+
private static final String BUGSNAG_SERVICE_ID = "";
31+
private final Skoice plugin;
32+
private final AnalyticManager analyticManager;
33+
private Bugsnag bugsnag;
34+
35+
public BugsnagAnalytics(Skoice plugin, AnalyticManager analyticManager) {
36+
this.plugin = plugin;
37+
this.analyticManager = analyticManager;
38+
}
39+
40+
public void notify(Throwable throwable, Severity severity) {
41+
if (this.bugsnag == null) {
42+
return;
43+
}
44+
this.plugin.getServer().getScheduler().runTaskAsynchronously(this.plugin, () -> {
45+
try {
46+
this.bugsnag.notify(throwable, severity);
47+
} catch (Throwable ignored) {
48+
}
49+
});
50+
}
51+
52+
public void initialize() {
53+
if (BugsnagAnalytics.BUGSNAG_SERVICE_ID.isEmpty()) {
54+
return;
55+
}
56+
this.bugsnag = new Bugsnag(BugsnagAnalytics.BUGSNAG_SERVICE_ID);
57+
this.bugsnag.setAppVersion(this.plugin.getDescription().getVersion());
58+
59+
this.bugsnag.addCallback(report -> {
60+
StackTraceElement[] trace = report.getException().getStackTrace();
61+
boolean reportError = false;
62+
for (StackTraceElement element : trace) {
63+
if (element.getClassName().startsWith("net.clementraynaud.skoice")) {
64+
reportError = true;
65+
break;
66+
}
67+
}
68+
if (!reportError) {
69+
report.cancel();
70+
return;
71+
}
72+
73+
report.addToTab("server", "version", this.plugin.getServer().getVersion());
74+
report.addToTab("server", "bukkitVersion", this.plugin.getServer().getBukkitVersion());
75+
76+
this.analyticManager.getSharedConfigFields().forEach(field ->
77+
report.addToTab("app", field.toCamelCase(), this.plugin.getConfigYamlFile().getString(field.toString()))
78+
);
79+
80+
this.analyticManager.getSharedIntConfigFields().forEach(field ->
81+
report.addToTab("app", field.toCamelCase(), this.plugin.getConfigYamlFile().getInt(field.toString()))
82+
);
83+
84+
report.addToTab("app", ConfigField.LANG.toCamelCase(), LangInfo.valueOf(this.plugin.getConfigYamlFile().getString(ConfigField.LANG.toString())).getFullName());
85+
86+
int linkedUsers = this.plugin.getLinksYamlFile().getLinks().size();
87+
report.addToTab("app", "linkedUsers", linkedUsers);
88+
report.addToTab("app", "botStatus", this.plugin.getBot().getStatus().toString());
89+
});
90+
91+
this.bugsnag.setAutoCaptureSessions(false);
92+
if (!this.plugin.getConfigYamlFile().contains(ConfigField.SESSION_REPORTED.toString())) {
93+
this.bugsnag.startSession();
94+
this.plugin.getConfigYamlFile().set(ConfigField.SESSION_REPORTED.toString(), true);
95+
}
96+
}
97+
}

0 commit comments

Comments
 (0)