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

feat: add plugin installed event [IDE-736] #211

Merged
2 changes: 1 addition & 1 deletion .classpath
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
<attributes>
<attribute name="module" value="true"/>
</attributes>
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
## [Unreleased]
### Changes
- process api URL from hasAuthenticated message
- add release channel preference to select which CLI is downloaded
- added plugin installed event and analytics sender

## [2.2.0] - v20241024.154007
### Changes
Expand Down
14 changes: 7 additions & 7 deletions plugin/src/main/java/io/snyk/eclipse/plugin/SnykStartup.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@
import io.snyk.languageserver.download.LsDownloader;

public class SnykStartup implements IStartup {
private LsRuntimeEnvironment runtimeEnvironment;
private static LsRuntimeEnvironment runtimeEnvironment;
private SnykView snykView = null;
private static boolean downloading = true;
private ILog logger;
private static ILog logger;

private static SnykStartup instance;

Expand Down Expand Up @@ -69,7 +69,8 @@ protected IStatus run(IProgressMonitor monitor) {
startLanguageServer();

PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
if (Preferences.getInstance().getAuthToken().isBlank()) {
Preferences prefs = Preferences.getInstance();
if (prefs.getAuthToken().isBlank() && !prefs.isTest()) {
monitor.subTask("Starting Snyk Wizard to configure initial settings...");
SnykWizard wizard = new SnykWizard();
WizardDialog dialog = new WizardDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell(), wizard);
Expand All @@ -83,9 +84,8 @@ protected IStatus run(IProgressMonitor monitor) {
}

private void startLanguageServer() {
var definition = LanguageServersRegistry.getInstance().getDefinition(SnykLanguageServer.LANGUAGE_SERVER_ID);
try {
LanguageServiceAccessor.startLanguageServer(definition);
SnykLanguageServer.startSnykLanguageServer();
} catch (RuntimeException e) {
logError(e);
}
Expand Down Expand Up @@ -141,12 +141,12 @@ private boolean downloadLS() {
return true;
}

LsDownloader getLsDownloader() throws URISyntaxException {
static LsDownloader getLsDownloader() throws URISyntaxException {
return new LsDownloader(HttpClientFactory.getInstance(), runtimeEnvironment, logger);
}

@SuppressWarnings("ResultOfMethodCallIgnored")
IStatus download(IProgressMonitor monitor) {
public static IStatus download(IProgressMonitor monitor) {
final File lsFile = new File(Preferences.getInstance().getCliPath());
try {
LsDownloader lsDownloader = getLsDownloader();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.snyk.eclipse.plugin.analytics;

public interface AbstractAnalyticsEvent {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package io.snyk.eclipse.plugin.analytics;

import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.snyk.eclipse.plugin.properties.preferences.Preferences;

public class AnalyticsEvent implements AbstractAnalyticsEvent {
private final String interactionType;
private final List<String> category;
private final String status;
private final String targetId;
private final long timestampMs;
private final long durationMs;
private final Map<String, Object> results;
private final List<Object> errors;
private final Map<String, Object> extension;

public AnalyticsEvent(String interactionType, List<String> category, String status, String targetId, long timestampMs, long durationMs, Map<String, Object> results, List<Object> errors, Map<String, Object> extension) {
this.interactionType = interactionType;
this.category = category;
this.status = status != null ? status : "success";
this.targetId = targetId != null ? targetId : "pkg:filesystem/scrubbed";
this.timestampMs = timestampMs != 0 ? timestampMs : Instant.now().toEpochMilli() ;
this.durationMs = durationMs;
this.results = results != null ? results : new HashMap<>();
this.errors = errors != null ? errors : new ArrayList<>();
this.extension = extension != null ? extension : new HashMap<>();
this.extension.put("device_id", Preferences.getInstance().getPref(Preferences.DEVICE_ID));
}

public AnalyticsEvent(String interactionType, List<String> category) {
this(interactionType, category, null, null, 0, 0, null, null, null);
}

public String getInteractionType() {
return interactionType;
}

public List<String> getCategory() {
return category;
}

public String getStatus() {
return status;
}

public String getTargetId() {
return targetId;
}

public long getTimestampMs() {
return timestampMs;
}

public long getDurationMs() {
return durationMs;
}

public Map<String, Object> getResults() {
return results;
}

public List<Object> getErrors() {
return errors;
}

public Map<String, Object> getExtension() {
return extension;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package io.snyk.eclipse.plugin.analytics;

import java.util.LinkedList;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.Consumer;

import org.apache.commons.lang3.tuple.Pair;

import io.snyk.eclipse.plugin.properties.preferences.Preferences;
import io.snyk.eclipse.plugin.utils.SnykLogger;
import io.snyk.languageserver.protocolextension.SnykExtendedLanguageClient;

public class AnalyticsSender {
// left = event, right = callback function
private final ConcurrentLinkedQueue<Pair<AbstractAnalyticsEvent, Consumer<Void>>> eventQueue = new ConcurrentLinkedQueue<>();

private AnalyticsSender() {
CompletableFuture.runAsync(() -> { start(); });
}

private static AnalyticsSender instance;

public static AnalyticsSender getInstance() {
if (instance == null) {
synchronized (AnalyticsSender.class) {
if (instance == null) {
instance = new AnalyticsSender();
}
}
}
return instance;
}

private void start() {
while (true) {
String authToken = Preferences.getInstance().getAuthToken();
var lc = SnykExtendedLanguageClient.getInstance();
if (eventQueue.isEmpty() || authToken == null || authToken.isBlank() || lc == null ) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
continue;
}
LinkedList<Pair<AbstractAnalyticsEvent, Consumer<Void>>> copyForSending = new LinkedList<>(eventQueue);
for (Pair<AbstractAnalyticsEvent, Consumer<Void>> event : copyForSending) {
try {
lc.reportAnalytics(event.getLeft());
event.getRight().accept(null);
} catch (Exception e) {
SnykLogger.logError(e);
} finally {
eventQueue.remove(event);
}
}
}
}

public void logEvent(AbstractAnalyticsEvent event, Consumer<Void> callback) {
var pair = Pair.of(event, callback);
eventQueue.add(pair);
}
}
Loading
Loading