blob: e53792389a888b73445fe8bd638e73f677c841c5 [file] [log] [blame]
/*******************************************************************************
* 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();
}
}