| /******************************************************************************* |
| * Copyright (c) 2012 EclipseSource Muenchen GmbH. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| ******************************************************************************/ |
| package org.eclipse.emf.emfstore.client.ui.errorreporting; |
| |
| import java.awt.AWTException; |
| import java.awt.HeadlessException; |
| import java.awt.Rectangle; |
| import java.awt.Robot; |
| import java.awt.Toolkit; |
| import java.awt.image.BufferedImage; |
| import java.io.BufferedWriter; |
| import java.io.File; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.lang.management.ManagementFactory; |
| import java.lang.management.RuntimeMXBean; |
| import java.text.MessageFormat; |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Date; |
| import java.util.List; |
| |
| import javax.imageio.ImageIO; |
| |
| import org.apache.commons.io.FileUtils; |
| import org.apache.commons.io.output.ByteArrayOutputStream; |
| import org.apache.commons.lang.StringUtils; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.emf.emfstore.client.model.Configuration; |
| import org.eclipse.emf.emfstore.client.model.util.WorkspaceUtil; |
| import org.eclipse.emf.emfstore.common.extensionpoint.ExtensionElement; |
| import org.eclipse.emf.emfstore.common.extensionpoint.ExtensionPoint; |
| import org.eclipse.swt.dnd.Clipboard; |
| import org.eclipse.swt.dnd.TextTransfer; |
| import org.eclipse.swt.dnd.Transfer; |
| import org.eclipse.ui.IEditorReference; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.statushandlers.StatusAdapter; |
| |
| /** |
| * Utility class for capturing system specific information for debugging purposes. |
| * |
| * @author emueller |
| */ |
| public final class ErrorReportingUtil { |
| |
| private static final String CUSTOMLOG_EXTENSION_POINT_ID = "org.eclipse.emf.emfstore.client.ui.errorreporting"; |
| private static final String SCREENSHOT_FOLDER_NAME = "screenshots"; |
| private static final String DEFAULT_SCREENSHOT_PREFIX = "emfstore-screenshot-"; |
| private static final String DEFAULT_SYSINFO_PREFIX = "emfstore-sysinfo-"; |
| private static final String SYSINFO_SUFFIX = "txt"; |
| |
| private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); |
| |
| /** |
| * Private constructor. |
| */ |
| private ErrorReportingUtil() { |
| |
| } |
| |
| private static String getLogText() { |
| |
| String filename = Platform.getLogFileLocation().toOSString(); |
| File log = new File(filename); |
| |
| try { |
| String version = Configuration.getClientVersion().getVersion(); |
| String logFileContent = FileUtils.readFileToString(log); |
| |
| StringBuffer result = new StringBuffer(16384); |
| result.append(MessageFormat.format("EMFStore client {0}. Log copied at {1}\n\n", version, SimpleDateFormat |
| .getDateTimeInstance().format(new Date()))); |
| result.append(logFileContent); |
| |
| return result.toString(); |
| } catch (IOException ex) { |
| WorkspaceUtil.logException("Exception while copying log to clipboard", ex); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Copies the content of the current log file to the clipboard. |
| * |
| * @param window |
| * the window that is used to determine which Display to copy to |
| */ |
| public static void copyLogToClipboard(IWorkbenchWindow window) { |
| String text = getLogText(); |
| Clipboard clipboard = null; |
| |
| if (text == null) { |
| return; |
| } |
| |
| try { |
| clipboard = new Clipboard(window.getShell().getDisplay()); |
| clipboard.setContents(new Object[] { text }, new Transfer[] { TextTransfer.getInstance() }); |
| } finally { |
| if (clipboard != null) { |
| clipboard.dispose(); |
| } |
| } |
| } |
| |
| /** |
| * Creates the error diagnosis file. |
| * |
| * @param date |
| * the date that will be written to the error diagnosis file in order to indicate when the |
| * file was created |
| * @param path |
| * the parent path under which the error diagnosis file will be put |
| * @param statusAdapter |
| * a status adapter that may contain the most recent stack trace, that will be copied |
| * into the error diagnosis file |
| * @return the absolute path to the created error diagnosis file |
| */ |
| public static String captureSysInfo(Date date, String path, StatusAdapter statusAdapter) { |
| |
| File temp = new File(path); |
| FileWriter fileWriter = null; |
| BufferedWriter bufferedWriter = null; |
| |
| temp.deleteOnExit(); |
| |
| try { |
| Runtime runtime = Runtime.getRuntime(); |
| RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); |
| fileWriter = new FileWriter(temp); |
| |
| bufferedWriter = new BufferedWriter(fileWriter); |
| bufferedWriter.write(MessageFormat.format("Log file created on {0}\n", new Date())); |
| bufferedWriter.write(MessageFormat.format("Client version: {0} {1}\n", Configuration.getClientVersion() |
| .getName(), Configuration.getClientVersion().getVersion())); |
| bufferedWriter.write("List of open editors:\n"); |
| |
| if (getOpenEditorIDs().size() == 0) { |
| bufferedWriter.write("\t<None>\n"); |
| } else { |
| for (String viewId : getOpenEditorIDs()) { |
| bufferedWriter.write(MessageFormat.format("\t{0}\n", viewId)); |
| } |
| } |
| |
| bufferedWriter.write(MessageFormat.format("Working directory: {0}", System.getProperty("user.dir"))); |
| bufferedWriter.write(MessageFormat.format("System user: {0}", System.getProperty("user.name"))); |
| bufferedWriter.write(MessageFormat.format("Memory usage: {0}/{1} MB", |
| toMb(runtime.totalMemory() - runtime.freeMemory()), toMb(runtime.maxMemory()))); |
| bufferedWriter.write(MessageFormat.format("Available processors (cores): {0}\n", |
| runtime.availableProcessors())); |
| bufferedWriter.write(MessageFormat.format("Java version: {0}", System.getProperty("java.version"))); |
| bufferedWriter.write(MessageFormat.format("OS version: {0}", System.getProperty("os.version"))); |
| bufferedWriter.write("VM Startup parameters:\n"); |
| |
| for (String vmArg : runtimeMXBean.getInputArguments()) { |
| bufferedWriter.write(MessageFormat.format("\t{0}\n", vmArg)); |
| } |
| |
| ExtensionPoint extPoint = new ExtensionPoint(CUSTOMLOG_EXTENSION_POINT_ID); |
| for (ExtensionElement el : extPoint.getExtensionElements()) { |
| ILoggable loggable = el.getClass("loggableClass", ILoggable.class); |
| |
| if (loggable == null) { |
| continue; |
| } |
| |
| bufferedWriter.write(loggable.getLoggable()); |
| } |
| |
| if (statusAdapter != null) { |
| bufferedWriter.write(MessageFormat.format("Stacktrace: {0}\n", getStatus(statusAdapter))); |
| } |
| |
| return temp.getAbsolutePath(); |
| } catch (IOException e) { |
| WorkspaceUtil.logException("Error while writing error diagnosis file: ", e); |
| } finally { |
| try { |
| if (bufferedWriter != null) { |
| bufferedWriter.close(); |
| } |
| |
| if (fileWriter != null) { |
| fileWriter.close(); |
| } |
| } catch (IOException e) { |
| WorkspaceUtil.logException("Error while closing error diagnosis stream.", e); |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Creates the error diagnosis file. |
| * |
| * @param date |
| * the date that will be written to the error diagnosis file in order to indicate when the |
| * file was created |
| * @param path |
| * the parent path under which the error diagnosis file will be put |
| * @return the absolute path to the created error diagnosis file |
| */ |
| public static String captureSysInfo(Date date, String path) { |
| return captureSysInfo(date, path, null); |
| } |
| |
| /** |
| * Returns a list of strings containing the IDs of all opened editors. |
| * |
| * @return a list of strings containing the IDs of all opened editors |
| */ |
| private static List<String> getOpenEditorIDs() { |
| |
| List<String> openedEditors = new ArrayList<String>(); |
| IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); |
| |
| for (IEditorReference editorRef : activePage.getEditorReferences()) { |
| openedEditors.add(editorRef.getId()); |
| } |
| |
| return openedEditors; |
| } |
| |
| private static String getStatus(StatusAdapter statusAdapter) { |
| StringBuilder sb = new StringBuilder(); |
| addException(sb, statusAdapter.getStatus()); |
| String logText = sb.toString(); |
| if (logText == null || logText.length() == 0) { |
| logText = "Could not find exception"; |
| } |
| return logText; |
| } |
| |
| private static void addException(StringBuilder collector, IStatus iStatus) { |
| if (iStatus instanceof MultiStatus) { |
| MultiStatus ms = (MultiStatus) iStatus; |
| IStatus[] children = ms.getChildren(); |
| for (IStatus childStatus : children) { |
| addException(collector, childStatus); |
| } |
| } else { |
| Throwable ex = iStatus.getException(); |
| if (ex != null) { |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| PrintWriter pw = new PrintWriter(baos); |
| ex.printStackTrace(pw); |
| pw.flush(); |
| collector.append(new String(baos.toByteArray())); |
| } |
| } |
| } |
| |
| private static int toMb(long value) { |
| return (int) (value / 1024 / 1024); |
| } |
| |
| /** |
| * Returns the path to the file that contains error diagnosis and system specific information. |
| * |
| * @param date |
| * the date to be used as a part of the constructed path |
| * @return the constructed path |
| */ |
| public static String getSysInfoPath(Date date) { |
| String errorDiagnosisFilename = DEFAULT_SYSINFO_PREFIX + formatDate(date) + "." + SYSINFO_SUFFIX; |
| return StringUtils.join(Arrays.asList(Configuration.getErrorLogDirectory(), errorDiagnosisFilename), |
| File.separatorChar); |
| } |
| |
| /** |
| * Formats the given date. |
| * |
| * @param date |
| * the date to be formatted |
| * @return the formatted date |
| */ |
| public static String formatDate(Date date) { |
| return format.format(date); |
| } |
| |
| /** |
| * Takes a screenshot. |
| * |
| * @param screenshotPath |
| * the path under which the screenshot will be put |
| * @param format |
| * the format of the screenshot being created |
| * @return the path to the taken screenshot |
| */ |
| public static String makeScreenshot(String screenshotPath, ScreenshotFormat format) { |
| |
| try { |
| BufferedImage bufferedImage = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit() |
| .getScreenSize())); |
| File temp = new File(screenshotPath); |
| temp.deleteOnExit(); |
| ImageIO.write(bufferedImage, format.getType(), temp); |
| return temp.getAbsolutePath(); |
| } catch (HeadlessException e) { |
| WorkspaceUtil.logException("Could not create screenshot.", e); |
| } catch (AWTException e) { |
| WorkspaceUtil.logException("Could not create screenshot.", e); |
| } catch (IOException e) { |
| WorkspaceUtil.logException("Could not create screenshot.", e); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the screenshot path. |
| * |
| * @param date |
| * the date that will be part of the screenshot name |
| * @param format |
| * the format of the screenshot |
| * @return the constructed path to the screenshot |
| */ |
| public static String getScreenshotPath(Date date, ScreenshotFormat format) { |
| String screenShotFilename = DEFAULT_SCREENSHOT_PREFIX + formatDate(date) + "." + format.getType(); |
| return StringUtils.join(Arrays.asList(getScreenshotFolder(), screenShotFilename), File.separatorChar); |
| } |
| |
| private static String getScreenshotFolder() { |
| File screenshotDir = new File(StringUtils.join( |
| Arrays.asList(Configuration.getErrorLogDirectory(), SCREENSHOT_FOLDER_NAME), File.separatorChar)); |
| |
| if (!screenshotDir.exists()) { |
| screenshotDir.mkdir(); |
| } |
| |
| return screenshotDir.getAbsolutePath(); |
| } |
| } |