From 5a3df459f90d4476d6ba1b671f89734715738052 Mon Sep 17 00:00:00 2001 From: Nathan McRae Date: Mon, 20 Jan 2025 22:38:01 -0800 Subject: [PATCH] Add logging --- .../numbersstation/CustomFormatter.java | 34 ++++++++++++ .../name/nathanmcrae/numbersstation/Main.java | 53 +++++++++++++++++++ .../numbersstation/MainController.java | 15 ++++-- .../numbersstation/MainSettings.java | 6 ++- 4 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 src/main/java/name/nathanmcrae/numbersstation/CustomFormatter.java diff --git a/src/main/java/name/nathanmcrae/numbersstation/CustomFormatter.java b/src/main/java/name/nathanmcrae/numbersstation/CustomFormatter.java new file mode 100644 index 0000000..134b054 --- /dev/null +++ b/src/main/java/name/nathanmcrae/numbersstation/CustomFormatter.java @@ -0,0 +1,34 @@ +package name.nathanmcrae.numbersstation; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.Formatter; +import java.util.logging.LogRecord; + +public class CustomFormatter extends Formatter { + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + + @Override + public String format(LogRecord record) { + String timestamp = dateFormat.format(new Date(record.getMillis())); + String logLevel = record.getLevel().getName(); + String className = record.getSourceClassName(); + String methodName = record.getSourceMethodName(); + String message = formatMessage(record); + + StringBuilder logMessage = new StringBuilder(); + logMessage.append(String.format("%s\t%s\t%s\t%s\t%s", timestamp, logLevel, className, methodName, message)); + + if (record.getThrown() != null) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + record.getThrown().printStackTrace(pw); + logMessage.append("\n\t").append(sw.toString()); + } + + logMessage.append(System.lineSeparator()); + return logMessage.toString(); + } +} diff --git a/src/main/java/name/nathanmcrae/numbersstation/Main.java b/src/main/java/name/nathanmcrae/numbersstation/Main.java index a25b329..8030e99 100644 --- a/src/main/java/name/nathanmcrae/numbersstation/Main.java +++ b/src/main/java/name/nathanmcrae/numbersstation/Main.java @@ -1,21 +1,74 @@ package name.nathanmcrae.numbersstation; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.logging.FileHandler; +import java.util.logging.Logger; +import java.util.logging.Level; import javafx.application.Application; +import javafx.application.Platform; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; public class Main extends Application { + private static final Logger logger = Logger.getLogger(Main.class.getName()); + + private static Path statePath = null; + + public Path getStatePath() { + if (statePath == null) { + String stateHome = System.getenv("XDG_STATE_HOME"); + if (stateHome == null || stateHome.isEmpty() || !Paths.get(stateHome).isAbsolute()) { + String userHome = System.getProperty("user.home"); + statePath = Paths.get(userHome, ".local", "state", "numbers-station"); + } else { + statePath = Paths.get(stateHome, "numbers-station"); + } + } + + return statePath; + } + @Override public void start(Stage primaryStage) throws Exception { + setupLogger(); Parent root = FXMLLoader.load(getClass().getResource("MainView.fxml")); primaryStage.setTitle("Numbers Station"); primaryStage.setScene(new Scene(root)); primaryStage.show(); + logger.info("Application started"); + } + + private void setupLogger() { + try { + Path logFile = getStatePath().resolve("main.log"); + + if (!Files.exists(logFile.getParent())) { + Files.createDirectories(logFile.getParent()); + } + + FileHandler fileHandler = new FileHandler(logFile.toString(), true); + fileHandler.setFormatter(new CustomFormatter()); + logger.addHandler(fileHandler); + } catch (IOException e) { + System.out.println("Failed to set up logger: " + e.getMessage()); + } } public static void main(String[] args) { + Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> { + logger.log(Level.SEVERE, "Unhandled exception caught", throwable); + }); + + Platform.setImplicitExit(false); + Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> { + logger.log(Level.SEVERE, "Unhandled exception in JavaFX application thread", throwable); + }); + launch(args); } } diff --git a/src/main/java/name/nathanmcrae/numbersstation/MainController.java b/src/main/java/name/nathanmcrae/numbersstation/MainController.java index 988a5ef..1656506 100644 --- a/src/main/java/name/nathanmcrae/numbersstation/MainController.java +++ b/src/main/java/name/nathanmcrae/numbersstation/MainController.java @@ -10,6 +10,8 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.Random; import java.util.ResourceBundle; import javafx.beans.property.SimpleStringProperty; @@ -29,6 +31,8 @@ import javafx.stage.Modality; import javafx.stage.Stage; public class MainController implements Initializable { + private static final Logger logger = Logger.getLogger(Main.class.getName()); + private Stage settingsStage; private Stage selectStationStage; private MainSettings settings; @@ -75,7 +79,7 @@ public class MainController implements Initializable { updateStationSettings(selectedStation); }); } catch (Exception e) { - e.printStackTrace(); + logger.log(Level.SEVERE, "Exception while opening settings", e); } } else { settingsStage.toFront(); @@ -83,7 +87,7 @@ public class MainController implements Initializable { } @FXML - private void handleSelectStationButtonPress() { + private void handleSelectStationButtonPress() throws Exception { if (selectStationStage == null || !selectStationStage.isShowing()) { try { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("StationSelectionView.fxml")); @@ -107,7 +111,7 @@ public class MainController implements Initializable { updateStationSettings(newSelectedStation); }); } catch (Exception e) { - e.printStackTrace(); + logger.log(Level.SEVERE, "Exception while selecting station", e); } } else { selectStationStage.toFront(); @@ -139,9 +143,8 @@ public class MainController implements Initializable { } } } catch (IOException e) { - // Print the contents of filePath + logger.log(Level.SEVERE, "Failed to load settings from " + filePath.toString(), e); System.out.println("File contents: " + Files.readString(filePath)); - e.printStackTrace(); } } @@ -216,6 +219,8 @@ public class MainController implements Initializable { } private void updateStationSettings(StationSettings newStationSettings) { + logger.info("Updating station settings: " + newStationSettings.getName()); + if (newStationSettings == null) { return; } diff --git a/src/main/java/name/nathanmcrae/numbersstation/MainSettings.java b/src/main/java/name/nathanmcrae/numbersstation/MainSettings.java index f8aac36..8f704c5 100644 --- a/src/main/java/name/nathanmcrae/numbersstation/MainSettings.java +++ b/src/main/java/name/nathanmcrae/numbersstation/MainSettings.java @@ -11,8 +11,11 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.logging.Logger; public class MainSettings { + private static final Logger logger = Logger.getLogger(Main.class.getName()); + private int digitsPerGroup; private String username; private int refreshInterval; @@ -30,7 +33,7 @@ public class MainSettings { Path directoryPath; Path filePath; - if (configHome != null && !configHome.isEmpty()) { + if (configHome != null && !configHome.isEmpty() && Paths.get(configHome).isAbsolute()) { directoryPath = Paths.get(configHome, "numbers-station"); } else { String userHome = System.getProperty("user.home"); @@ -81,6 +84,7 @@ public class MainSettings { } xmlMapper.writeValue(new File(filePath.toString()), this); + logger.info("Settings saved to " + filePath.toString()); } catch (IOException e) { e.printStackTrace(); }