Skip to content

Commit

Permalink
Bugsnag
Browse files Browse the repository at this point in the history
Fixes #939
Fixes #632
  • Loading branch information
1-alex98 authored and Alexander von Trostorff committed Feb 11, 2019
1 parent 6f0e2c5 commit 17fd0fc
Show file tree
Hide file tree
Showing 17 changed files with 421 additions and 44 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ jacoco {
}

dependencies {
compile ("com.bugsnag:bugsnag:3.1.6")
compile("org.springframework.boot:spring-boot-starter")
compile("org.springframework.boot:spring-boot-starter-cache")
compile("org.springframework.boot:spring-boot-starter-logging")
Expand Down
17 changes: 15 additions & 2 deletions src/main/java/com/faforever/client/config/AsyncConfig.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.faforever.client.config;

import com.faforever.client.reporting.ReportingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
Expand All @@ -13,23 +14,35 @@
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

import javax.annotation.PreDestroy;
import javax.inject.Inject;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
@EnableAsync
@EnableScheduling
@Configuration
public class AsyncConfig implements AsyncConfigurer, SchedulingConfigurer {

private final ReportingService reportingService;

@Inject
public AsyncConfig(ReportingService reportingService) {
this.reportingService = reportingService;
}

@Override
public Executor getAsyncExecutor() {
return taskExecutor();
}

@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
return (ex, method, params) -> {
reportingService.silentlyReport(ex, false);
log.error("Uncaught exception in async", ex);
};
}

@Override
Expand Down
24 changes: 21 additions & 3 deletions src/main/java/com/faforever/client/config/BaseConfig.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.faforever.client.config;

import com.bugsnag.Bugsnag;
import com.faforever.client.reporting.ReportingService;
import com.faforever.client.update.Version;
import com.google.common.eventbus.DeadEvent;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
Expand All @@ -26,13 +29,28 @@ ReloadableResourceBundleMessageSource messageSource() {
}

@Bean
EventBus eventBus() {
EventBus bus = new EventBus((exception, context) -> log.warn("Exception in '{}#{}' while handling event: {}",
context.getSubscriber().getClass(), context.getSubscriberMethod().getName(), context.getEvent(), exception));
EventBus eventBus(ReportingService reportingService) {
EventBus bus = new EventBus((exception, context) -> {
log.warn("Exception in '{}#{}' while handling event: {}",
context.getSubscriber().getClass(), context.getSubscriberMethod().getName(), context.getEvent(), exception);
reportingService.silentlyReport(exception, false);
});
bus.register(new DeadEventHandler());
return bus;
}

@Bean
public Bugsnag bugsnag(ClientProperties clientProperties) {
String token = clientProperties.getBugsnagConfig().getToken();
if (token == null) {
log.warn("No token for bugsnag specified, bugsnag wont report errors correctly");
}
Bugsnag bugsnag = new Bugsnag(token == null ? "" : token, false);
bugsnag.setReleaseStage(Version.class.getPackage().getImplementationVersion() == null ? "development" : "production");
bugsnag.setAppVersion(Version.VERSION);
return bugsnag;
}

private static class DeadEventHandler {
@Subscribe
public void onDeadEvent(DeadEvent deadEvent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class ClientProperties {
private UnitDatabase unitDatabase = new UnitDatabase();
private Website website = new Website();
private String translationProjectUrl;
private BugsnagConfig bugsnagConfig = new BugsnagConfig();
private String clientConfigUrl;
private boolean useRemotePreferences;
private Duration clientConfigConnectTimeout = Duration.ofSeconds(30);
Expand All @@ -34,6 +35,12 @@ public static class News {
private String feedUrl;
}

@Data
public static class BugsnagConfig {
private String token;
private int logLinesSent;
}

@Data
public static class ForgedAlliance {
/**
Expand Down
23 changes: 22 additions & 1 deletion src/main/java/com/faforever/client/main/MainController.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import com.faforever.client.preferences.ui.SettingsController;
import com.faforever.client.rankedmatch.MatchmakerMessage;
import com.faforever.client.remote.domain.RatingRange;
import com.faforever.client.reporting.ReportingDialogController;
import com.faforever.client.reporting.ReportingService;
import com.faforever.client.theme.UiService;
import com.faforever.client.ui.StageHolder;
import com.faforever.client.ui.tray.event.UpdateApplicationBadgeEvent;
Expand Down Expand Up @@ -107,6 +109,7 @@ public class MainController implements Controller<Node> {
private final int ratingBeta;
private final GamePathHandler gamePathHandler;
private final PlatformService platformService;
private final ReportingService reportingService;
public Pane mainHeaderPane;
public Labeled notificationsBadge;
public Pane contentPane;
Expand All @@ -131,7 +134,7 @@ public class MainController implements Controller<Node> {
public MainController(PreferencesService preferencesService, I18n i18n, NotificationService notificationService,
PlayerService playerService, GameService gameService, ClientUpdateService clientUpdateService,
UiService uiService, EventBus eventBus, ClientProperties clientProperties, GamePathHandler gamePathHandler,
PlatformService platformService) {
PlatformService platformService, ReportingService reportingService) {
this.preferencesService = preferencesService;
this.i18n = i18n;
this.notificationService = notificationService;
Expand All @@ -145,6 +148,7 @@ public MainController(PreferencesService preferencesService, I18n i18n, Notifica
this.ratingBeta = clientProperties.getTrueSkill().getBeta();
this.gamePathHandler = gamePathHandler;
this.platformService = platformService;
this.reportingService = reportingService;
this.viewCache = CacheBuilder.newBuilder().build();
}

Expand Down Expand Up @@ -178,6 +182,7 @@ public void initialize() {
notificationService.addImmediateNotificationListener(notification -> runLater(() -> displayImmediateNotification(notification)));
notificationService.addTransientNotificationListener(notification -> runLater(() -> transientNotificationsController.addNotification(notification)));
gameService.addOnRankedMatchNotificationListener(this::onMatchmakerMessage);
reportingService.setReportDialogListener(this::displayReportingWindow);
// Always load chat immediately so messages or joined channels don't need to be cached until we display them.
getView(NavigationItem.CHAT);
}
Expand Down Expand Up @@ -539,6 +544,22 @@ private void displayImmediateNotification(ImmediateNotification notification) {
dialog.show();
}

private void displayReportingWindow(int defaultLogLines, Throwable exception) {
JFXAlert<?> dialog = new JFXAlert<>((Stage) windowController.getWindowRoot().getScene().getWindow());

ReportingDialogController controller = ((ReportingDialogController) uiService.loadFxml("theme/reporting_dialog.fxml"))
.setThrowable(exception)
.setDefaultLogLines(defaultLogLines)
.setCloseListener(dialog::close);
dialog.setContent(controller.getRoot());
dialog.setAnimation(JFXAlertAnimation.TOP_ANIMATION);
dialog.show();
}

public void onSupport() {
reportingService.supportRequest();
}

public class ToastDisplayer implements InvalidationListener {
private final TransientNotificationsController transientNotificationsController;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,6 @@ private Button createButton(Action action) {
break;
}

// Until implemented
if (action instanceof ReportAction) {
button.setDisable(true);
}

return button;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
public class ReportAction extends Action {

public ReportAction(I18n i18n, ReportingService reportingService, Throwable throwable) {
super(i18n.get("report"), event -> reportingService.reportError(throwable));
super(i18n.get("report"), event -> reportingService.report(throwable));
}
}
10 changes: 9 additions & 1 deletion src/main/java/com/faforever/client/player/PlayerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.faforever.client.chat.ChatChannelUser;
import com.faforever.client.chat.ChatUserCreatedEvent;
import com.bugsnag.Bugsnag;
import com.faforever.client.chat.avatar.AvatarBean;
import com.faforever.client.chat.avatar.event.AvatarChangedEvent;
import com.faforever.client.chat.event.ChatMessageEvent;
Expand Down Expand Up @@ -55,12 +56,14 @@ public class PlayerService {
private final List<Integer> foeList;
private final List<Integer> friendList;
private final ObjectProperty<Player> currentPlayer;
private final Bugsnag bugsnag;

private final FafService fafService;
private final UserService userService;
private final EventBus eventBus;

public PlayerService(FafService fafService, UserService userService, EventBus eventBus) {
public PlayerService(Bugsnag bugsnag, FafService fafService, UserService userService, EventBus eventBus) {
this.bugsnag = bugsnag;
this.fafService = fafService;
this.userService = userService;
this.eventBus = eventBus;
Expand Down Expand Up @@ -111,6 +114,11 @@ public void onLoginSuccess(LoginSuccessEvent event) {
player.setId(event.getUserId());
currentPlayer.set(player);
player.setIdleSince(Instant.now());

bugsnag.addCallback(report -> {
report.setUserName(event.getUsername());
report.setUserId(String.valueOf(event.getUserId()));
});
}

@Subscribe
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.faforever.client.reporting;

import com.bugsnag.Severity;
import com.faforever.client.fx.Controller;
import com.jfoenix.controls.JFXCheckBox;
import com.jfoenix.controls.JFXComboBox;
import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.NumberValidator;
import javafx.collections.FXCollections;
import javafx.scene.Node;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.util.StringConverter;
import org.springframework.stereotype.Component;

import javax.inject.Inject;

@Component
public class ReportingDialogController implements Controller<Node> {
private final ReportingService reportingService;
public JFXTextField logLinesTextField;
public VBox root;
public JFXCheckBox contactMeCheckBox;
public TextArea feedbackText;
public JFXComboBox<Severity> severityChoiceBox;
private Runnable closeListener;
private Throwable throwable;

@Inject
public ReportingDialogController(ReportingService reportingService) {
this.reportingService = reportingService;
}

@Override
public Node getRoot() {
return root;
}

@Override
public void initialize() {
logLinesTextField.setValidators(new NumberValidator());
severityChoiceBox.setConverter(new StringConverter<Severity>() {
@Override
public String toString(Severity object) {
return object.name();
}

@Override
public Severity fromString(String string) {
return Severity.valueOf(string);
}
});
severityChoiceBox.setItems(FXCollections.observableArrayList(Severity.values()));
severityChoiceBox.getSelectionModel().select(Severity.ERROR);
}

public void cancel() {
closeListener.run();
}

public void submit() {
reportingService.userFilledOutReportForm(
Integer.parseInt(logLinesTextField.getText()),
contactMeCheckBox.isSelected(),
feedbackText.getText(),
severityChoiceBox.getSelectionModel().getSelectedItem(),
throwable);
closeListener.run();
}

public ReportingDialogController setCloseListener(Runnable close) {
closeListener = close;
return this;
}

public ReportingDialogController setDefaultLogLines(int defaultLogLines) {
logLinesTextField.setText(String.valueOf(defaultLogLines));
return this;
}

public ReportingDialogController setThrowable(Throwable throwable) {
this.throwable = throwable;
return this;
}
}

0 comments on commit 17fd0fc

Please sign in to comment.