Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

usage logging #181

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion bundles/org.codechecker.eclipse.plugin/build.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ bin.includes = plugin.xml,\
.,\
icons/,\
contexts.xml,\
log4j.properties
log4j.properties,\
resources/

35 changes: 35 additions & 0 deletions bundles/org.codechecker.eclipse.plugin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.codechecker.eclipse</groupId>
<artifactId>org.codechecker.eclipse.bundles</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>

<artifactId>org.codechecker.eclipse.plugin</artifactId>
<version>0.0.6-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>

<properties>
<host.log>empty</host.log>
<port.log>0</port.log>
<plugin.version>${project.version}</plugin.version>
</properties>

<build>
<resources>
<resource>
<directory>resources</directory>
<targetPath>resources</targetPath>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
host=${host.log}
port=${port.log}
version=${plugin.version}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -36,6 +40,7 @@ public class CodeChecker implements ICodeChecker {
private Path location;
private ShellExecutorHelper she;
private Map<String, File> subMap;
private String version;

/**
*
Expand All @@ -52,7 +57,7 @@ public CodeChecker(Path path, ShellExecutorHelper she) throws InvalidCodeChecker
this.she = she;
subMap = new HashMap<String, File>();
subMap.put(LOCATION_KEY, path.toAbsolutePath().toFile());
getVersion();
version = getVersion();
}

@Override
Expand All @@ -70,7 +75,8 @@ public String getVersion() throws InvalidCodeCheckerException {
Optional<String> 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
Expand All @@ -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<String> ccOutput = she.progressableWaitReturnOutput(cmd, subMap, logToConsole, monitor, taskCount);

return ccOutput.or("");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 |
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
}

}
Original file line number Diff line number Diff line change
@@ -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
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Usage logging.
*/
package org.codechecker.eclipse.plugin.usage;
Original file line number Diff line number Diff line change
Expand Up @@ -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!");
}
Expand Down