From e2565097cde8c3912ed76105bd7bafd7cf3ee438 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 29 Apr 2021 16:31:39 +0200 Subject: [PATCH] add function to export a report of health checks --- .../ui/health/CheckController.java | 9 +- .../ui/health/HealthReportWriteTask.java | 91 +++++++++++++++++++ .../src/main/resources/fxml/health_check.fxml | 1 + 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 main/ui/src/main/java/org/cryptomator/ui/health/HealthReportWriteTask.java diff --git a/main/ui/src/main/java/org/cryptomator/ui/health/CheckController.java b/main/ui/src/main/java/org/cryptomator/ui/health/CheckController.java index 571a447b5..2af708589 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/health/CheckController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/health/CheckController.java @@ -24,6 +24,7 @@ import java.util.concurrent.ExecutorService; public class CheckController implements FxController { private final HealthCheckSupervisor supervisor; + private final HealthReportWriteTask reportWriter; private final ExecutorService executorService; private final ObjectProperty selectedTask; private final Binding> selectedResults; @@ -40,8 +41,9 @@ public class CheckController implements FxController { @Inject - public CheckController(HealthCheckSupervisor supervisor, ExecutorService executorService) { + public CheckController(HealthCheckSupervisor supervisor, HealthReportWriteTask reportWriteTask, ExecutorService executorService) { this.supervisor = supervisor; + this.reportWriter = reportWriteTask; this.executorService = executorService; this.selectedTask = new SimpleObjectProperty<>(); this.selectedResults = EasyBind.wrapNullable(selectedTask).map(HealthCheckTask::results).orElse(FXCollections.emptyObservableList()); @@ -71,6 +73,11 @@ public class CheckController implements FxController { } + @FXML + public void exportResults() { + executorService.execute(reportWriter); + } + /* Getter&Setter */ public boolean isRunning() { diff --git a/main/ui/src/main/java/org/cryptomator/ui/health/HealthReportWriteTask.java b/main/ui/src/main/java/org/cryptomator/ui/health/HealthReportWriteTask.java new file mode 100644 index 000000000..efaead6e0 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/health/HealthReportWriteTask.java @@ -0,0 +1,91 @@ +package org.cryptomator.ui.health; + +import dagger.Lazy; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.cryptomator.common.Environment; +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.cryptofs.VaultConfig; + +import javax.inject.Inject; +import javafx.concurrent.Task; +import javafx.concurrent.Worker; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ByteChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Collection; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +@HealthCheckScoped +public class HealthReportWriteTask extends Task { + + private static final String REPORT_HEADER = """ + ************************************** + * Cryptomator Vault Health Report * + ************************************** + Analyzed vault: %s (Current name \"%s\") + Vault storage path: %s + + """; + private static final String REPORT_CHECK_SUCCESS = "\tCheck %s successful. Results:\n"; + private static final String REPORT_CHECK_RESULT = "\t\t %s - %s\n"; + private static final String REPORT_CHECK_CANCELED = "\tCheck %s canceled.\n"; + private static final String REPORT_CHECK_FAILED = "\tCheck %s failed.\n"; + + private final Vault vault; + private final VaultConfig vaultConfig; + private final Lazy> tasks; + private final Environment env; + + @Inject + public HealthReportWriteTask(@HealthCheckWindow Vault vault, AtomicReference vaultConfigRef, Lazy> tasks, Environment env) { + this.vault = vault; + this.vaultConfig = Objects.requireNonNull(vaultConfigRef.get()); + this.tasks = tasks; + this.env = env; + } + + @Override + protected Void call() throws IOException { + var path = env.getLogDir().orElse(Path.of(System.getProperty("user.home"))).resolve("healthReport_" + vault.getDisplayName() + "(" + vaultConfig.getId() + ")" + ".log"); + final var tasks = this.tasks.get(); + //use file channel, since results can be pretty big + try (var channel = Files.newByteChannel(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) { + internalWrite(channel, String.format(REPORT_HEADER, vaultConfig.getId(), vault.getDisplayName(), vault.getPath())); + for (var task : tasks) { + final var state = task.getEndState(); + if (state == Worker.State.SUCCEEDED) { + internalWrite(channel, REPORT_CHECK_SUCCESS, task.getCheck().identifier()); + for (var result : task.results()) { + internalWrite(channel, REPORT_CHECK_RESULT, result.getServerity(), result); + } + } else if (state == Worker.State.CANCELLED) { + internalWrite(channel, REPORT_CHECK_CANCELED, task.getCheck().identifier()); + } else if (state == Worker.State.FAILED) { + internalWrite(channel, REPORT_CHECK_FAILED, task.getCheck().identifier()); + internalWrite(channel, prepareFailureMsg(task)); + } else { + throw new IllegalStateException("Cannot export unfinished task"); + } + } + } + return null; + } + + private void internalWrite(ByteChannel channel, String s, Object... formatArguments) throws IOException { + channel.write(ByteBuffer.wrap(s.formatted(formatArguments).getBytes(StandardCharsets.UTF_8))); + } + + private String prepareFailureMsg(HealthCheckTask task) { + return task.getExceptionOnDone() // + .map(t -> ExceptionUtils.getStackTrace(t)).orElse("Unknown reason of failure.") // + .lines().map(line -> "\t\t" + line + "\n") // + .collect(Collectors.joining()); + } + +} diff --git a/main/ui/src/main/resources/fxml/health_check.fxml b/main/ui/src/main/resources/fxml/health_check.fxml index 131d025ab..7ccc88d73 100644 --- a/main/ui/src/main/resources/fxml/health_check.fxml +++ b/main/ui/src/main/resources/fxml/health_check.fxml @@ -24,6 +24,7 @@