diff --git a/.gitignore b/.gitignore
index b4dc8d0..a65e01e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
TO-DO.md
dist
target/
+app.log
.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
diff --git a/HowToRun.md b/HowToRun.md
new file mode 100644
index 0000000..856f92a
--- /dev/null
+++ b/HowToRun.md
@@ -0,0 +1,40 @@
+## 🖥️ Installation (2 clicks — for recruiters)
+
+The application is distributed as a **standalone EXE** built with `jpackage`.
+
+### âś” Requirements
+Nothing except:
+- Windows 10/11 (Currently on win 10 System Logs are not working - TODO)
+- Local user profile
+- Windows PowerShell (built-in on Windows 10/11)
+
+> **Java is bundled inside the EXE**.
+> You do NOT need to install Java.
+
+### âś” Running the app
+1. Download `SystemLogAnalyzer.rar`
+2. unpack it with winrar anywhere.
+3. Double-click on SystemLogAnalyzer.exe
+4. (Optional) If Security logs are selected → confirm Windows UAC popup
+
+That's all.
+
+## 📦 How it works
+
+### 1. Choose:
+- directory for storing exported CSVs
+- directory for saving reports
+- log types (Application / System / Security)
+
+### 2. The app:
+- runs PowerShell → exports CSV
+- parses records
+- loads them into a JavaFX table
+
+### 3. You can:
+- filter
+- search
+- inspect details
+- refresh logs anytime
+
+All without touching Event Viewer manually.
\ No newline at end of file
diff --git a/HowToRun_PL.md b/HowToRun_PL.md
new file mode 100644
index 0000000..45c5d5b
--- /dev/null
+++ b/HowToRun_PL.md
@@ -0,0 +1,40 @@
+## 🖥️ Instalacja (2 kliknięcia — dla rekruterów)
+
+Aplikacja jest dystrybuowana jako **samodzielny plik EXE** zbudowany przy uĹĽyciu `jpackage`.
+
+### âś” Wymagania
+Nic poza:
+- Windows 10/11
+- Lokalnym profilem uĹĽytkownika
+- Windows PowerShell (built-in on Windows 10/11)
+
+> **Java jest dołączona do pliku EXE**.
+> NIE musisz instalować Javy.
+
+### âś” Uruchamianie aplikacji
+1. Pobierz `SystemLogAnalyzer.exe`
+2. Wypakuj program w dowolne miejsce
+3. Kliknij go dwukrotnie na SystemLogAnalyzer.exe
+4. (Opcjonalnie) Jeśli wybrano dzienniki zabezpieczeń → potwierdź wyskakujące okienko UAC systemu Windows
+
+To wszystko.
+
+## 📦 Jak to działa
+
+### 1. Wybierz:
+- katalog do przechowywania wyeksportowanych plikĂłw CSV
+- katalog do zapisywania raportĂłw
+- typy logĂłw (Aplikacja/System/Zabezpieczenia)
+
+### 2. Aplikacja:
+- uruchamia program PowerShell → eksportuje plik CSV
+- analizuje rekordy
+- ładuje je do tabeli JavaFX
+
+### 3. MoĹĽesz:
+- filtrować
+- wyszukiwać
+- sprawdzać szczegóły
+- odświeżać logi w dowolnym momencie
+
+Wszystko to bez ręcznego uruchamiania Podglądu zdarzeń.
\ No newline at end of file
diff --git a/README.md b/README.md
index 72888d8..ac1a073 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# System Log Analyzer (Work in progress — v0.1 MVP)
+# System Log Analyzer (Work in progress — v0.2)
**System Log Analyzer** A standalone Windows desktop application for IT professionals to export,
parse and analyze Windows Event Logs with a fast, clean and modern UI.
diff --git a/pom.xml b/pom.xml
index 04fd624..842a6f4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,7 +18,7 @@
-
+
org.springframework
spring-context
@@ -46,12 +46,19 @@
25-ea+1
+
+
+ net.java.dev.jna
+ jna
+ 5.13.0
+
+
-
+
org.apache.maven.plugins
maven-compiler-plugin
@@ -71,7 +78,7 @@
-
+
org.apache.maven.plugins
maven-surefire-plugin
diff --git a/src/main/java/com/project/system_log_analyzer/SystemLogAnalyzerApp.java b/src/main/java/com/project/system_log_analyzer/SystemLogAnalyzerApp.java
index 47c9a4a..f5869ec 100644
--- a/src/main/java/com/project/system_log_analyzer/SystemLogAnalyzerApp.java
+++ b/src/main/java/com/project/system_log_analyzer/SystemLogAnalyzerApp.java
@@ -8,13 +8,35 @@
import javafx.stage.Stage;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+
public class SystemLogAnalyzerApp extends Application {
+ private boolean app_Log = false;
+
private AnnotationConfigApplicationContext springContext;
+ private static Boolean elevatedFlag = false; // Admin permissions
+
@Override
public void init() {
springContext = new AnnotationConfigApplicationContext(SpringConfig.class);
+
+ if (app_Log) { // debug app.log in main directory
+ PrintStream out = null;
+ try {
+ out = new PrintStream(new FileOutputStream("app.log", true), true);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ System.setOut(out);
+ System.setErr(out);
+ }
+
+
+
}
@Override
@@ -22,8 +44,25 @@ public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/WelcomeView.fxml"));
loader.setControllerFactory(springContext::getBean);
- Parent root = loader.load();
+ boolean elevated = getParameters().getRaw().contains("--elevated");
+ elevatedFlag = elevated; // Admin profile checker
+ System.out.println("ARGS = " + getParameters().getRaw()); // Admin permission check to debug file
+
+ com.project.system_log_analyzer.config.appConfig cfg = springContext.getBean(com.project.system_log_analyzer.config.appConfig.class);
+
+ if (elevated) {
+ cfg.setCsvSecurity(true);
+ }
+
+ try {
+ cfg.setCsvSecurity(elevated);
+ IO.println("Elevated mode: " + elevated);
+ } catch (Exception e) {
+ System.err.println("Could not set elevated flag in appConfig: " + e.getMessage());
+ }
+
+ Parent root = loader.load();
SpringConfig.APP_READY = true;
Scene scene = new Scene(root);
@@ -37,6 +76,10 @@ public void stop() {
springContext.close();
}
+ public static boolean isElevated() {
+ return Boolean.TRUE.equals(elevatedFlag);
+ }
+
public static void main(String[] args) {
launch(args);
}
diff --git a/src/main/java/com/project/system_log_analyzer/config/SpringConfig.java b/src/main/java/com/project/system_log_analyzer/config/SpringConfig.java
index 8aecbdc..a9185d5 100644
--- a/src/main/java/com/project/system_log_analyzer/config/SpringConfig.java
+++ b/src/main/java/com/project/system_log_analyzer/config/SpringConfig.java
@@ -1,6 +1,8 @@
package com.project.system_log_analyzer.config;
+import com.project.system_log_analyzer.SystemLogAnalyzerApp;
+import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
diff --git a/src/main/java/com/project/system_log_analyzer/config/appConfig.java b/src/main/java/com/project/system_log_analyzer/config/appConfig.java
index 4629dab..09bd5f4 100644
--- a/src/main/java/com/project/system_log_analyzer/config/appConfig.java
+++ b/src/main/java/com/project/system_log_analyzer/config/appConfig.java
@@ -9,6 +9,33 @@ public class appConfig {
private boolean csvApplication;
private boolean csvSystem;
private boolean csvSecurity;
+ private boolean noLogs;
+ private boolean saveInExeDir;
+ private boolean relaunch;
+
+ public boolean isRelaunch() {
+ return relaunch;
+ }
+
+ public void setRelaunch(boolean relaunch) {
+ this.relaunch = relaunch;
+ }
+
+ public boolean isNoLogs() {
+ return noLogs;
+ }
+
+ public void setNoLogs(boolean noLogs) {
+ this.noLogs = noLogs;
+ }
+
+ public boolean isSaveInExeDir() {
+ return saveInExeDir;
+ }
+
+ public void setSaveInExeDir(boolean saveInExeDir) {
+ this.saveInExeDir = saveInExeDir;
+ }
public boolean isCsvSecurity() {
return csvSecurity;
diff --git a/src/main/java/com/project/system_log_analyzer/controller/MainWindowFXController.java b/src/main/java/com/project/system_log_analyzer/controller/MainWindowFXController.java
index 3d38742..1f2807b 100644
--- a/src/main/java/com/project/system_log_analyzer/controller/MainWindowFXController.java
+++ b/src/main/java/com/project/system_log_analyzer/controller/MainWindowFXController.java
@@ -175,6 +175,9 @@ public void onRefreshClick() {
refreshButton.setDisable(true);
logTable.setDisable(true);
loadingLabel.setText("Refreshing logs… Please wait. (Time of loading depends on number of logs)");
+ logTable.getSelectionModel().clearSelection();
+ logTable.getFocusModel().focus(-1); // Details unexpected pop-up || Fixed
+ onClearFilters(); // Clear all filters
Task> task = new Task>() {
@Override
@@ -222,6 +225,8 @@ protected List call() throws Exception {
}
@FXML
public void onSearchChanged() {
+ logTable.getSelectionModel().clearSelection();
+ logTable.getFocusModel().focus(-1); // Details unexpected pop-up || Fixed
applyFilters();
}
@@ -244,6 +249,9 @@ public void onFilterChanged() {
private void applyFilters() {
if (logs == null) return;
+ logTable.getSelectionModel().clearSelection();
+ logTable.getFocusModel().focus(-1);
+
String input = searchField.getText().toLowerCase().trim();
// input correctness check
diff --git a/src/main/java/com/project/system_log_analyzer/controller/WelcomeViewFXController.java b/src/main/java/com/project/system_log_analyzer/controller/WelcomeViewFXController.java
index 61982cb..fbb1112 100644
--- a/src/main/java/com/project/system_log_analyzer/controller/WelcomeViewFXController.java
+++ b/src/main/java/com/project/system_log_analyzer/controller/WelcomeViewFXController.java
@@ -1,7 +1,10 @@
package com.project.system_log_analyzer.controller;
+import com.project.system_log_analyzer.SystemLogAnalyzerApp;
import com.project.system_log_analyzer.config.ApplicationContextProvider;
import com.project.system_log_analyzer.config.appConfig;
+import com.project.system_log_analyzer.system.WindowsElevationManager;
+import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
@@ -28,12 +31,23 @@ public class WelcomeViewFXController {
@FXML private CheckBox systemButton;
@FXML private CheckBox securityButton;
@FXML private Label securityLabel;
+ @FXML private Button logFilesDirButton;
+ @FXML private Button reportDirButton;
+
+ @FXML private CheckBox noLogsBox;
+ @FXML private CheckBox saveInAppDirectoryBox;
+
@Autowired public appConfig appConfig;
@FXML
public void initialize() {
System.out.println("Controller initialized, appConfig = " + appConfig);
+
+ if (appConfig.isCsvSecurity()) {
+ securityButton.setSelected(true);
+ securityLabel.setText("Admin permission granted!");
+ }
}
@@ -42,9 +56,11 @@ private void scan(ActionEvent event) throws IOException {
String logDir = logFilesDirField.getText();
String reportDir = reportDirField.getText();
- if (logDir.isEmpty() || reportDir.isEmpty()) {
- informationLabel.setText("Please select both directories.");
- return;
+ if (!noLogsBox.isSelected()) {
+ if (logDir.isEmpty() || reportDir.isEmpty()) {
+ informationLabel.setText("Please select both directories.");
+ return;
+ }
}
if (!appButton.isSelected() && !systemButton.isSelected() && !securityButton.isSelected()) {
@@ -57,7 +73,7 @@ private void scan(ActionEvent event) throws IOException {
ApplicationContext springContext = ApplicationContextProvider.getApplicationContext();
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/LoadingScreen.fxml"));
- loader.setControllerFactory(springContext::getBean); // Spring Boot starter by JavaFX !!IMPORTANT!!
+ loader.setControllerFactory(springContext::getBean); // Spring starter by JavaFX !!IMPORTANT!!
Parent root = loader.load();
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
@@ -103,19 +119,36 @@ private void systemButtonON(ActionEvent event) throws IOException {
@FXML
private void securityButtonON(ActionEvent event) throws IOException {
+
+ if (SystemLogAnalyzerApp.isElevated()) { // Admin ckeck for Security Logs
+ securityLabel.setText("Admin permission granted!");
+ appConfig.setCsvSecurity(securityButton.isSelected());
+ return;
+ }
+
if (securityButton.isSelected()) {
boolean proceed = askForSecurityPermission();
if (!proceed) {
securityButton.setSelected(false);
- securityLabel.setText("Admin permission required!");
appConfig.setCsvSecurity(false);
+ securityLabel.setText("Admin permission required!");
return;
+ }
+
+ boolean relaunchStarted = WindowsElevationManager.relaunchAsAdmin("--elevated");
+
+ if (relaunchStarted) {
+ appConfig.setRelaunch(true);
+ Platform.exit();
} else {
- securityLabel.setText("Admin permission granted!");
- appConfig.setCsvSecurity(true);
+ appConfig.setCsvSecurity(false);
+ securityButton.setSelected(false);
+ securityLabel.setText("(Requires Admin Permission)");
}
+
} else {
appConfig.setCsvSecurity(false);
+ securityButton.setSelected(false);
securityLabel.setText("(Requires Admin Permission)");
}
}
@@ -129,4 +162,76 @@ private boolean askForSecurityPermission() {
return alert.showAndWait().filter(btn -> btn == ButtonType.OK).isPresent();
}
+ @FXML
+ private void noLogsBoxOn(ActionEvent event) throws IOException {
+ if (noLogsBox.isSelected()) {
+ appConfig.setNoLogs(true);
+
+ appConfig.setSaveInExeDir(false);
+ saveInAppDirectoryBox.setSelected(false);
+ saveInAppDirectoryBox.setDisable(true);
+
+ logFilesDirButton.setDisable(true);
+ reportDirButton.setDisable(true);
+
+ logFilesDirField.clear();
+ reportDirField.clear();
+
+ appConfig.setLogsDir(null);
+ appConfig.setReportDir(null);
+
+ } else {
+ appConfig.setNoLogs(false);
+ saveInAppDirectoryBox.setDisable(false);
+
+ if (appConfig.isSaveInExeDir()) {
+ String baseDir = System.getProperty("user.dir");
+ String logs = baseDir + "/logs";
+ String reports = baseDir + "/reports";
+
+ appConfig.setSaveInExeDir(true);
+ appConfig.setLogsDir(logs);
+ appConfig.setReportDir(reports);
+
+ logFilesDirField.setText(logs);
+ reportDirField.setText(reports);
+
+ logFilesDirButton.setDisable(true);
+ reportDirButton.setDisable(true);
+
+ } else {
+ logFilesDirButton.setDisable(false);
+ reportDirButton.setDisable(false);
+ }
+ }
+ }
+ @FXML
+ private void saveInAppDirectoryBoxOn(ActionEvent event) throws IOException {
+ if (saveInAppDirectoryBox.isSelected()) {
+ appConfig.setSaveInExeDir(true);
+
+ String baseDir = System.getProperty("user.dir");
+ String logs = baseDir + "/logs";
+ String reports = baseDir + "/reports";
+
+ logFilesDirField.setText(logs);
+ reportDirField.setText(reports);
+
+ logFilesDirButton.setDisable(true);
+ reportDirButton.setDisable(true);
+
+ //new File(logs).mkdirs();
+ //new File(reports).mkdirs();
+
+ appConfig.setLogsDir(logs);
+ appConfig.setReportDir(reports);
+
+ } else {
+ appConfig.setSaveInExeDir(false);
+
+ logFilesDirButton.setDisable(false);
+ reportDirButton.setDisable(false);
+
+ }
+ }
}
diff --git a/src/main/java/com/project/system_log_analyzer/core/FileLoggerService.java b/src/main/java/com/project/system_log_analyzer/core/FileLoggerService.java
index 778712a..bb5c76d 100644
--- a/src/main/java/com/project/system_log_analyzer/core/FileLoggerService.java
+++ b/src/main/java/com/project/system_log_analyzer/core/FileLoggerService.java
@@ -57,13 +57,23 @@ private void ensureLogFile() {
if (logsDir == null) {
String path = config.getLogsDir();
- if (path == null) {
- System.out.println("FileLoggerService: logsDir not set yet — skipping log.");
- return; //
+
+ if (path == null || path.isBlank()) {
+
+ String baseDir = System.getProperty("user.dir");
+ path = baseDir + "/temp_";
+
+ new File(path).mkdirs();
+
+ config.setLogsDir(path);
+ config.setReportDir(path);
+
+ System.out.println("FileLoggerService: Using TEMP directory for logs: " + path);
}
logsDir = new File(path);
if (!logsDir.exists()) logsDir.mkdirs();
+
logFile = new File(logsDir, "log_" + nOfLogPart + ".log");
createLogFileIfMissing();
}
diff --git a/src/main/java/com/project/system_log_analyzer/io/WindowsEventExporter.java b/src/main/java/com/project/system_log_analyzer/io/WindowsEventExporter.java
index eda0b19..5938ef6 100644
--- a/src/main/java/com/project/system_log_analyzer/io/WindowsEventExporter.java
+++ b/src/main/java/com/project/system_log_analyzer/io/WindowsEventExporter.java
@@ -21,7 +21,7 @@ public class WindowsEventExporter {
public enum LogType {
APPLICATION("Application"),
SYSTEM("System"),
- SECURITY("Security"); // TODO - Test in real environment (.exe/.jar)
+ SECURITY("Security");
private final String logName;
LogType(String logName) {
@@ -42,14 +42,18 @@ public WindowsEventExporter(appConfig config) {
public Path exportToCsv(LogType type) { // Method responsible for exporting logs from windows
try {
- String baseDir = config.getLogsDir() != null && !config.getLogsDir().isEmpty()
- ? config.getLogsDir() : "logs/exported";
+ String baseDir;
+ if (config.getLogsDir() == null || config.getLogsDir().isBlank()) {
+ baseDir = System.getProperty("user.dir") + "/temp_";
+ } else {
+ baseDir = config.getLogsDir();
+ }
- File dir = new File(baseDir, "exported");
- if (!dir.exists()) dir.mkdirs();
+ File exportedDir = new File(baseDir, "exported");
+ if (!exportedDir.exists()) exportedDir.mkdirs();
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
- Path outputFile = Path.of(dir.getAbsolutePath(), type.getLogName() + "_" + timestamp + ".csv");
+ Path outputFile = Path.of(exportedDir.getAbsolutePath(), type.getLogName() + "_" + timestamp + ".csv");
// Powershell command
String command = String.format(
@@ -78,26 +82,45 @@ public Path exportToCsv(LogType type) { // Method responsible for exporting logs
}
}
- public Path exportSecurityLogsAsAdmin() { // Method responsible for exporting Security logs with admin permissions
+ public Path exportSecurityLogsAsAdmin() {
try {
- String baseDir = config.getLogsDir() != null && !config.getLogsDir().isEmpty()
- ? config.getLogsDir() : "logs/exported";
+ String baseDir;
+ if (config.getLogsDir() == null || config.getLogsDir().isBlank()) {
+ baseDir = System.getProperty("user.dir") + "/temp_";
+ } else {
+ baseDir = config.getLogsDir();
+ }
- File dir = new File(baseDir, "exported");
- if (!dir.exists()) dir.mkdirs();
+ File exportedDir = new File(baseDir, "exported");
+ if (!exportedDir.exists()) exportedDir.mkdirs();
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
- Path outputFile = Path.of(dir.getAbsolutePath(), "Security_" + timestamp + ".csv");
+ Path outputFile = Path.of(exportedDir.getAbsolutePath(), "Security_" + timestamp + ".csv");
- String powershellCommand =
- "Start-Process powershell -Verb RunAs -ArgumentList " +
- "\"Get-WinEvent -LogName Security | " +
+ String ps =
+ "Get-WinEvent -LogName Security -MaxEvents 15000 | " +
"Select-Object TimeCreated, Id, LevelDisplayName, ProviderName, Message | " +
- "Export-Csv -Path '" + outputFile.toAbsolutePath() + "' -NoTypeInformation -Encoding UTF8\"";
+ "Export-Csv -Path '" + outputFile.toAbsolutePath() +
+ "' -NoTypeInformation -Encoding UTF8";
+
- ProcessBuilder pb = new ProcessBuilder("Powershell.exe", "-Command", powershellCommand);
+
+ List cmd = new ArrayList<>();
+ cmd.add("powershell.exe");
+ cmd.add("-NoProfile");
+ cmd.add("-ExecutionPolicy");
+ cmd.add("Bypass");
+ cmd.add("-Command");
+ cmd.add(ps);
+
+ ProcessBuilder pb = new ProcessBuilder(cmd);
+ pb.redirectErrorStream(true);
Process process = pb.start();
+ try (BufferedReader out = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+ out.lines().forEach(System.out::println);
+ }
+
int exit = process.waitFor();
if (exit == 0) {
@@ -114,6 +137,7 @@ public Path exportSecurityLogsAsAdmin() { // Method responsible for exporting S
return null;
}
+
public List exportSelected() {
List paths = new ArrayList<>();
diff --git a/src/main/java/com/project/system_log_analyzer/system/AppShutdownHandler.java b/src/main/java/com/project/system_log_analyzer/system/AppShutdownHandler.java
index 8a5cba4..198a3ab 100644
--- a/src/main/java/com/project/system_log_analyzer/system/AppShutdownHandler.java
+++ b/src/main/java/com/project/system_log_analyzer/system/AppShutdownHandler.java
@@ -1,6 +1,7 @@
package com.project.system_log_analyzer.system;
import com.project.system_log_analyzer.config.SpringConfig;
+import com.project.system_log_analyzer.config.appConfig;
import com.project.system_log_analyzer.core.FileLoggerService;
import com.project.system_log_analyzer.core.FileReportExporter;
import org.springframework.beans.factory.annotation.Autowired;
@@ -8,16 +9,25 @@
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Comparator;
+
@Component
public class AppShutdownHandler {
private FileLoggerService fileLoggerService;
private FileReportExporter reportExporter;
+ private appConfig appConfig;
+ private Boolean elevatedFlag;
@Autowired
- public AppShutdownHandler(FileLoggerService fileLoggerService, FileReportExporter reportExporter) {
+ public AppShutdownHandler(FileLoggerService fileLoggerService, FileReportExporter reportExporter, appConfig config) {
this.fileLoggerService = fileLoggerService;
this.reportExporter = reportExporter;
+ this.appConfig = config;
}
@EventListener(ContextClosedEvent.class)
@@ -27,14 +37,47 @@ public void onShutdown() {
return;
}
- try {
- System.out.println("AppShutdownHandler - Application is shutting down! Flushing logs and exporting report...");
- fileLoggerService.flushLogToMainFile();
- System.out.println("AppShutdownHandler - Shutdown tasks completed successfully.");
- } catch (Exception e) {
- System.err.println("AppShutdownHandler - Error during shutdown tasks: " + e.getMessage());
- e.printStackTrace();
+ if (appConfig.isNoLogs()) {
+ Path dir = Paths.get(appConfig.getLogsDir());
+
+ try {
+ if (Files.exists(dir)) {
+ deleteDirectoryRecursively(dir);
+ System.out.println("NoLogs = true → temporary directory removed.");
+ }
+ } catch (Exception e) {
+ System.err.println("Failed to delete temp directory: " + e.getMessage());
+ }
+ return;
+ }
+
+ if (appConfig.isRelaunch() || appConfig.getLogsDir() == null || appConfig.getLogsDir().isBlank()) {
+ System.out.println("Skipping flush — elevated admin relaunch or before Spring Injection");
+ return;
+ } else {
+ try {
+ System.out.println("AppShutdownHandler - Application is shutting down! Flushing logs and exporting report...");
+ fileLoggerService.flushLogToMainFile();
+ System.out.println("AppShutdownHandler - Shutdown tasks completed successfully.");
+ } catch (Exception e) {
+ System.err.println("AppShutdownHandler - Error during shutdown tasks: " + e.getMessage());
+ e.printStackTrace();
+ }
}
+
+
+ }
+ // Method for correct deletion of temp files when noLogs is selected
+ private void deleteDirectoryRecursively(Path path) throws IOException {
+ if (!Files.exists(path)) return;
+
+ Files.walk(path)
+ .sorted(Comparator.reverseOrder())
+ .forEach(p -> {
+ try {
+ Files.deleteIfExists(p);
+ } catch (IOException ignored) {}
+ });
}
}
diff --git a/src/main/java/com/project/system_log_analyzer/system/WindowsElevationManager.java b/src/main/java/com/project/system_log_analyzer/system/WindowsElevationManager.java
new file mode 100644
index 0000000..fee16ff
--- /dev/null
+++ b/src/main/java/com/project/system_log_analyzer/system/WindowsElevationManager.java
@@ -0,0 +1,56 @@
+package com.project.system_log_analyzer.system;
+
+import com.sun.jna.Native;
+import com.sun.jna.Pointer;
+import com.sun.jna.WString;
+import com.sun.jna.win32.W32APIOptions;
+
+import java.io.File;
+
+public class WindowsElevationManager {
+
+ public interface Shell32 extends com.sun.jna.Library {
+ Shell32 INSTANCE = Native.load("shell32", Shell32.class, W32APIOptions.DEFAULT_OPTIONS);
+
+ Pointer ShellExecuteW(
+ Pointer hwnd,
+ WString lpOperation,
+ WString lpFile,
+ WString lpParameters,
+ WString lpDirectory,
+ int nShowCmd
+ );
+ }
+
+ public static boolean relaunchAsAdmin(String params) {
+ try {
+ String exePath = new File(System.getProperty("user.dir"),
+ "System_Log_Analyzer.exe").getAbsolutePath();
+
+ Pointer p = Shell32.INSTANCE.ShellExecuteW(
+ null,
+ new WString("runas"),
+ new WString(exePath),
+ params == null ? null : new WString(params),
+ null,
+ 1
+ );
+
+ long result = Pointer.nativeValue(p);
+ return result > 32;
+
+ } catch (Throwable t) {
+ t.printStackTrace();
+ return false;
+ }
+ }
+
+ public static boolean isCurrentUserAdmin() {
+ try {
+ new java.io.File("C:\\Windows\\System32\\config\\systemprofile").list();
+ return true;
+ } catch (Throwable e) {
+ return false;
+ }
+ }
+}
diff --git a/src/main/resources/view/WelcomeView.fxml b/src/main/resources/view/WelcomeView.fxml
index 04c532f..966ade8 100644
--- a/src/main/resources/view/WelcomeView.fxml
+++ b/src/main/resources/view/WelcomeView.fxml
@@ -38,6 +38,15 @@
+
+
+