diff --git a/src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java b/src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java index c9e3f2c..369602e 100644 --- a/src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java +++ b/src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java @@ -20,6 +20,9 @@ package ru.windcorp.progressia.client; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import ru.windcorp.progressia.ProgressiaLauncher; +import ru.windcorp.progressia.common.util.crash.CrashReportGenerator; +import ru.windcorp.progressia.common.util.crash.analyzers.OutOfMemoryAnalyzer; +import ru.windcorp.progressia.common.util.crash.providers.OSContextProvider; public class ProgressiaClientMain { @@ -28,6 +31,15 @@ public class ProgressiaClientMain { public static void main(String[] args) { logger.info("App started!"); + CrashReportGenerator.registerProvider(new OSContextProvider()); + CrashReportGenerator.registerAnalyzer(new OutOfMemoryAnalyzer()); + try { + long[] ssdss = new long[1 << 30]; + } catch (Throwable t) + { + CrashReportGenerator.makeCrashReport(t, ""); + } + ProgressiaLauncher.launch(args, new ClientProxy()); } diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/Analyzer.java b/src/main/java/ru/windcorp/progressia/common/util/crash/Analyzer.java new file mode 100644 index 0000000..47b9e76 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/Analyzer.java @@ -0,0 +1,5 @@ +package ru.windcorp.progressia.common.util.crash; + +public interface Analyzer { + String getPrompt(Throwable throwable, String messageFormat, Object... args); +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/ContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/ContextProvider.java new file mode 100644 index 0000000..ad0d5d3 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/ContextProvider.java @@ -0,0 +1,8 @@ +package ru.windcorp.progressia.common.util.crash; + +import java.util.Map; + +public interface ContextProvider { + + Map provideContext(); +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/CrashReportGenerator.java b/src/main/java/ru/windcorp/progressia/common/util/crash/CrashReportGenerator.java new file mode 100644 index 0000000..4c808dd --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/CrashReportGenerator.java @@ -0,0 +1,134 @@ +package ru.windcorp.progressia.common.util.crash; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.*; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Map; + +public class CrashReportGenerator { + + private CrashReportGenerator() { + } + + final static File latestLogFile = new File("crash-reports/latest.log"); + + private static Collection providers = new ArrayList(); + private static Collection> providerResponse = new ArrayList>(); + + private static Collection analyzers = new ArrayList(); + private static Collection analyzerResponse = new ArrayList(); + + private static final Logger logger = LogManager.getLogger("crash"); + + static public void makeCrashReport(Throwable throwable, String messageFormat, Object... args) { + + StringBuilder output = new StringBuilder(); + + for (ContextProvider currentProvider : providers) { + if (currentProvider != null) { + providerResponse.add(currentProvider.provideContext()); + } + } + + if (throwable != null) { + for (Analyzer currentAnalyzer : analyzers) { + if (currentAnalyzer != null) { + analyzerResponse.add(currentAnalyzer.getPrompt(throwable, messageFormat, args)); + } + } + } + + for (Map currentProviderResponse : providerResponse) { + if (currentProviderResponse != null && !currentProviderResponse.isEmpty()) { + addSeparator(output); + for (Map.Entry entry : currentProviderResponse.entrySet()) { + output.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n"); + } + } + } + + for (String currentPrompt : analyzerResponse) { + if (currentPrompt != null && !currentPrompt.isEmpty()) { + addSeparator(output); + output.append(currentPrompt).append("\n"); + } + } + + // Formatting to a human-readable string + StringWriter sink = new StringWriter(); + if (throwable != null) { + try { + throwable.printStackTrace(new PrintWriter(sink)); + } catch (Exception e) { + // PLAK + } + } else { + sink.append("Null"); + } + + logger.info("\n" + output.toString()); + logger.fatal("Stacktrace: \n" + sink.toString()); + + addSeparator(output); + + output.append("Stacktrace: \n"); + output.append(sink.toString()).append("\n"); + + try { + System.err.println(output.toString()); + } catch (Exception e) { + // PLAK + } + + + createFileForCrashReport(output); + createFileForLatestCrashReport(output); + + + System.exit(0); + } + + public static void createFileForCrashReport(StringBuilder sb) { + Date date = new Date(); + + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss"); + + File logFile = new File("crash-reports/" + "crash-" + dateFormat.format(date) + ".log"); + + try (FileOutputStream fos = new FileOutputStream(logFile)) { + byte[] buffer = sb.toString().getBytes(); + + fos.write(buffer, 0, buffer.length); + } catch (IOException ex) { + // Crash Report not created + } + } + + public static void createFileForLatestCrashReport(StringBuilder sb) { + try (FileOutputStream fos = new FileOutputStream(latestLogFile)) { + byte[] buffer = sb.toString().getBytes(); + + fos.write(buffer, 0, buffer.length); + } catch (IOException ex) { + // Crash Report not created + } + } + + public static void registerProvider(ContextProvider provider) { + providers.add(provider); + } + + public static void registerAnalyzer(Analyzer analyzer) { + analyzers.add(analyzer); + } + + private static void addSeparator(StringBuilder sb) { + sb.append("-------------------------------------------------").append("\n"); + } +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/analyzers/OutOfMemoryAnalyzer.java b/src/main/java/ru/windcorp/progressia/common/util/crash/analyzers/OutOfMemoryAnalyzer.java new file mode 100644 index 0000000..e750cea --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/analyzers/OutOfMemoryAnalyzer.java @@ -0,0 +1,12 @@ +package ru.windcorp.progressia.common.util.crash.analyzers; + +import ru.windcorp.progressia.common.util.crash.Analyzer; + +public class OutOfMemoryAnalyzer implements Analyzer { + @Override + public String getPrompt(Throwable throwable, String messageFormat, Object... args) { + if (throwable instanceof OutOfMemoryError) + return "Try add memory for the JVM"; + return null; + } +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OSContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OSContextProvider.java new file mode 100644 index 0000000..712ee17 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OSContextProvider.java @@ -0,0 +1,18 @@ +package ru.windcorp.progressia.common.util.crash.providers; + +import ru.windcorp.progressia.common.util.crash.ContextProvider; + +import java.util.HashMap; +import java.util.Map; + +public class OSContextProvider implements ContextProvider { + + @Override + public Map provideContext() { + Map theThings = new HashMap<>(); + theThings.put("Name OS", System.getProperty("os.name")); + theThings.put("Version OS", System.getProperty("os.version")); + theThings.put("Architecture OS", System.getProperty("os.arch")); + return theThings; + } +} diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 29aaea2..c40552b 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -13,18 +13,14 @@ - - - -