diff --git a/bundles/org.codechecker.eclipse.plugin/build.properties b/bundles/org.codechecker.eclipse.plugin/build.properties
index 44ad5f18..0ef59e52 100644
--- a/bundles/org.codechecker.eclipse.plugin/build.properties
+++ b/bundles/org.codechecker.eclipse.plugin/build.properties
@@ -5,5 +5,6 @@ bin.includes = plugin.xml,\
.,\
icons/,\
contexts.xml,\
- log4j.properties
+ log4j.properties,\
+ resources/
diff --git a/bundles/org.codechecker.eclipse.plugin/pom.xml b/bundles/org.codechecker.eclipse.plugin/pom.xml
new file mode 100644
index 00000000..0bb96d5e
--- /dev/null
+++ b/bundles/org.codechecker.eclipse.plugin/pom.xml
@@ -0,0 +1,35 @@
+
+
+ 4.0.0
+
+ org.codechecker.eclipse
+ org.codechecker.eclipse.bundles
+ 1.0.0-SNAPSHOT
+
+
+ org.codechecker.eclipse.plugin
+ 0.0.6-SNAPSHOT
+ eclipse-plugin
+
+
+ empty
+ 0
+ ${project.version}
+
+
+
+
+
+ resources
+ resources
+ true
+
+ **/*.properties
+
+
+
+
+
+
diff --git a/bundles/org.codechecker.eclipse.plugin/resources/config.properties b/bundles/org.codechecker.eclipse.plugin/resources/config.properties
new file mode 100644
index 00000000..faca1a5b
--- /dev/null
+++ b/bundles/org.codechecker.eclipse.plugin/resources/config.properties
@@ -0,0 +1,3 @@
+host=${host.log}
+port=${port.log}
+version=${plugin.version}
diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/CodeChecker.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/CodeChecker.java
index f4f261d2..6b0caa73 100644
--- a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/CodeChecker.java
+++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/CodeChecker.java
@@ -3,6 +3,7 @@
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -12,6 +13,9 @@
import org.codechecker.eclipse.plugin.runtime.LogI;
import org.codechecker.eclipse.plugin.runtime.SLogger;
import org.codechecker.eclipse.plugin.runtime.ShellExecutorHelper;
+import org.codechecker.eclipse.plugin.usage.StatisticUploader;
+import org.codechecker.eclipse.plugin.usage.UsageInfo;
+import org.codechecker.eclipse.plugin.usage.UsageInfo.CommandType;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
@@ -36,6 +40,7 @@ public class CodeChecker implements ICodeChecker {
private Path location;
private ShellExecutorHelper she;
private Map subMap;
+ private String version;
/**
*
@@ -52,7 +57,7 @@ public CodeChecker(Path path, ShellExecutorHelper she) throws InvalidCodeChecker
this.she = she;
subMap = new HashMap();
subMap.put(LOCATION_KEY, path.toAbsolutePath().toFile());
- getVersion();
+ version = getVersion();
}
@Override
@@ -70,7 +75,8 @@ public String getVersion() throws InvalidCodeCheckerException {
Optional ccOutput = she.waitReturnOutput(cmd, subMap, false);
if (!ccOutput.isPresent() || ccOutput.get().isEmpty())
throw new InvalidCodeCheckerException("Couldn't run CodeChecker version!");
- return ccOutput.get();
+ return Arrays.stream(ccOutput.get().split("\n")).filter(line -> line.contains("Base package version"))
+ .findFirst().get().split("\\|")[1].trim();
}
@Override
@@ -87,6 +93,8 @@ public String analyze(Path logFile, boolean logToConsole, IProgressMonitor monit
String cmd = getSubstituteAnalyzeString(config);
SLogger.log(LogI.INFO, "Running analyze Command: " + cmd);
+ new Thread(new StatisticUploader(new UsageInfo(CommandType.analyze_started, version))).start();
+
Optional ccOutput = she.progressableWaitReturnOutput(cmd, subMap, logToConsole, monitor, taskCount);
return ccOutput.or("");
diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/init/StartupJob.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/init/StartupJob.java
index 0ccfa272..5f1f6d32 100644
--- a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/init/StartupJob.java
+++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/init/StartupJob.java
@@ -13,6 +13,9 @@
import org.codechecker.eclipse.plugin.report.job.JobDoneChangeListener;
import org.codechecker.eclipse.plugin.report.job.PlistParseJob;
import org.codechecker.eclipse.plugin.runtime.SLogger;
+import org.codechecker.eclipse.plugin.usage.StatisticUploader;
+import org.codechecker.eclipse.plugin.usage.UsageInfo;
+import org.codechecker.eclipse.plugin.usage.UsageInfo.CommandType;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
@@ -81,6 +84,8 @@ public IStatus runInUIThread(IProgressMonitor monitor) {
Logger.log(IStatus.INFO, Logger.getStackTrace(e));
}
+ new Thread(new StatisticUploader(new UsageInfo(CommandType.started, null))).start();
+
Logger.log(IStatus.INFO, "adding addResourceChangeListener ");
ResourcesPlugin.getWorkspace().addResourceChangeListener(new ResourceChangeListener(),
IResourceChangeEvent.POST_BUILD | IResourceChangeEvent.POST_CHANGE |
diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/usage/StatisticUploader.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/usage/StatisticUploader.java
new file mode 100644
index 00000000..1af083a9
--- /dev/null
+++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/usage/StatisticUploader.java
@@ -0,0 +1,75 @@
+package org.codechecker.eclipse.plugin.usage;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.Inet4Address;
+import java.util.Properties;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.osgi.framework.FrameworkUtil;
+
+import com.google.gson.Gson;
+
+/**
+ * Class for uploading the usage statistics.
+ */
+public class StatisticUploader implements Runnable {
+
+ private UsageInfo info;
+
+ /**
+ * Need to pass an {@link UsageInfo}.
+ *
+ * @param info
+ * This will be uploaded in JSON format.
+ */
+ public StatisticUploader(UsageInfo info) {
+ this.info = info;
+ }
+
+ /**
+ * This is the upload logic. The host and port is specified compile time in
+ * maven.
+ */
+ private void uploadStatistics() {
+ Integer port = null;
+ String host = null;
+
+ try (InputStream is = FileLocator.openStream(FrameworkUtil.getBundle(getClass()),
+ new Path("resources/config.properties"), false)) {
+ Properties prop = new Properties();
+ prop.load(is);
+ host = prop.getProperty("host");
+ try {
+ port = Integer.parseInt(prop.getProperty("port"));
+ } catch (Exception e) {
+ ;
+ }
+ } catch (IOException e1) {
+ ;
+ }
+
+ try (DatagramSocket socket = new DatagramSocket()) {
+ if (port != null && host != null) {
+ DatagramPacket packet = new DatagramPacket(new Gson().toJson(info).getBytes(),
+ new Gson().toJson(info).getBytes().length,
+ Inet4Address.getByName(host), port);
+ socket.send(packet);
+ }
+ } catch (IOException e) {
+ ;
+ }
+ }
+
+ /**
+ * Uploads usage statistics.
+ */
+ @Override
+ public void run() {
+ uploadStatistics();
+ }
+
+}
diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/usage/UsageInfo.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/usage/UsageInfo.java
new file mode 100644
index 00000000..86d720c1
--- /dev/null
+++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/usage/UsageInfo.java
@@ -0,0 +1,131 @@
+package org.codechecker.eclipse.plugin.usage;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Properties;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IContributor;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jdt.annotation.Nullable;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Class for Storing usage logging related info.
+ */
+public class UsageInfo {
+ private static final String UNKNOWN = "unknown";
+ private static final String UNKNOWN_VER = "unknown version";
+
+ @SuppressWarnings("unused")
+ private final String machine;
+ @SuppressWarnings("unused")
+ private final String hostname;
+ //@SuppressWarnings("unused")
+ //private String clangsa = UNKNOWN;
+ @SuppressWarnings("unused")
+ private final String version;
+ // TODO make this parameter dynamic, from build parameters.
+ @SuppressWarnings("unused")
+ private final String pluginVersion;
+ @SuppressWarnings("unused")
+ private final String user;
+ @SuppressWarnings("unused")
+ @SerializedName("command_type")
+ private final CommandType commandType;
+ //@SuppressWarnings("unused")
+ //private String clang_tidy = UNKNOWN;
+
+ /**
+ * Specify the event type and the CodeChecker version if in context.
+ *
+ * @param ct
+ * The command (event) type to be logged.
+ * @param ccVersion
+ * The CodeChecker version to be logged. Not every context has
+ * CodeChecker.
+ */
+ public UsageInfo(CommandType ct, @Nullable String ccVersion) {
+ StringBuilder tempos = new StringBuilder(System.getProperty("os.name"));
+ tempos.append(" ").append(System.getProperty("os.version"));
+ tempos.append(" / Eclipse ").append(getEclipseVersion());
+ machine = tempos.toString();
+ String tHostName = UNKNOWN;
+ try {
+ tHostName = InetAddress.getLocalHost().getHostName();
+ } catch (UnknownHostException ex) {
+ ;
+ }
+ hostname = tHostName;
+
+ if (ccVersion != null)
+ version = ccVersion;
+ else
+ version = UNKNOWN_VER;
+
+ pluginVersion = setPluginVersion();
+ user = System.getProperty("user.name");
+ commandType = ct;
+ }
+
+ /**
+ * Used for returning the eclipse version number. From:
+ * https://stackoverflow.com/a/28855362/8149485
+ *
+ * @return The eclipse version number in 1.2.3.v19700101-0000 format.
+ */
+ private String getEclipseVersion() {
+ String version = UNKNOWN_VER;
+ String product = System.getProperty("eclipse.product");
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint point = registry.getExtensionPoint("org.eclipse.core.runtime.products");
+ if (point != null) {
+ IExtension[] extensions = point.getExtensions();
+ for (IExtension ext : extensions)
+ if (product.equals(ext.getUniqueIdentifier())) {
+ IContributor contributor = ext.getContributor();
+ if (contributor != null) {
+ Bundle bundle = Platform.getBundle(contributor.getName());
+ if (bundle != null)
+ version = bundle.getVersion().toString();
+ }
+ }
+ }
+ return version;
+ }
+
+ /**
+ * Sets the plugin version from a properties file, which gets substituted during
+ * build.
+ *
+ * @return The plugin version read from the config file.
+ */
+ private String setPluginVersion() {
+ String ver = UNKNOWN_VER;
+ try (InputStream is = FileLocator.openStream(FrameworkUtil.getBundle(getClass()),
+ new Path("resources/config.properties"), false)) {
+ Properties prop = new Properties();
+ prop.load(is);
+ ver = prop.getProperty("version");
+ } catch (IOException e1) {
+ e1.printStackTrace();
+ }
+ return ver;
+ }
+
+ /**
+ * Command (Event) types.
+ */
+ public enum CommandType {
+ started, analyze_started
+ }
+}
diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/usage/package-info.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/usage/package-info.java
new file mode 100644
index 00000000..da382658
--- /dev/null
+++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/usage/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Usage logging.
+ */
+package org.codechecker.eclipse.plugin.usage;
\ No newline at end of file
diff --git a/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/CodeCheckerTest.java b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/CodeCheckerTest.java
index 67ad816a..bb4930f4 100644
--- a/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/CodeCheckerTest.java
+++ b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/CodeCheckerTest.java
@@ -78,7 +78,7 @@ public void testVersionReturned() {
try {
String version = codeChecker.getVersion();
- assertThat("Missing Version String", version.startsWith("CodeChecker analyzer version:"));
+ assertThat("Missing Version String", "1.2.3".equals(version));
} catch (InvalidCodeCheckerException e) {
fail("An exception was thrown after a successful initialization!");
}