Skip to content

Commit 4ed6db1

Browse files
feat: add plugin installed event [IDE-736] (#211)
* feat: add plugin installed event * feat: add plugin installed analytics event and base url setting * fix: improve startup * docs: updated changelog * fix: improve startup wizard * fix: tests * fix: tests * fix: check if test in token refresher * chore: add test for plugin sending * chore: add second test for plugin install sending * chore: optimize import * chore: revert log level to info
1 parent be26ddb commit 4ed6db1

19 files changed

Lines changed: 1010 additions & 649 deletions

File tree

.classpath

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<classpath>
3-
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
3+
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
44
<attributes>
55
<attribute name="module" value="true"/>
66
</attributes>

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
## [Unreleased]
44
### Changes
55
- process api URL from hasAuthenticated message
6+
- add release channel preference to select which CLI is downloaded
7+
- added plugin installed event and analytics sender
68

79
## [2.2.0] - v20241024.154007
810
### Changes

plugin/src/main/java/io/snyk/eclipse/plugin/SnykStartup.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@
3636
import io.snyk.languageserver.download.LsDownloader;
3737

3838
public class SnykStartup implements IStartup {
39-
private LsRuntimeEnvironment runtimeEnvironment;
39+
private static LsRuntimeEnvironment runtimeEnvironment;
4040
private SnykView snykView = null;
4141
private static boolean downloading = true;
42-
private ILog logger;
42+
private static ILog logger;
4343

4444
private static SnykStartup instance;
4545

@@ -69,7 +69,8 @@ protected IStatus run(IProgressMonitor monitor) {
6969
startLanguageServer();
7070

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

8586
private void startLanguageServer() {
86-
var definition = LanguageServersRegistry.getInstance().getDefinition(SnykLanguageServer.LANGUAGE_SERVER_ID);
8787
try {
88-
LanguageServiceAccessor.startLanguageServer(definition);
88+
SnykLanguageServer.startSnykLanguageServer();
8989
} catch (RuntimeException e) {
9090
logError(e);
9191
}
@@ -141,12 +141,12 @@ private boolean downloadLS() {
141141
return true;
142142
}
143143

144-
LsDownloader getLsDownloader() throws URISyntaxException {
144+
static LsDownloader getLsDownloader() throws URISyntaxException {
145145
return new LsDownloader(HttpClientFactory.getInstance(), runtimeEnvironment, logger);
146146
}
147147

148148
@SuppressWarnings("ResultOfMethodCallIgnored")
149-
IStatus download(IProgressMonitor monitor) {
149+
public static IStatus download(IProgressMonitor monitor) {
150150
final File lsFile = new File(Preferences.getInstance().getCliPath());
151151
try {
152152
LsDownloader lsDownloader = getLsDownloader();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package io.snyk.eclipse.plugin.analytics;
2+
3+
public interface AbstractAnalyticsEvent {
4+
5+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package io.snyk.eclipse.plugin.analytics;
2+
3+
import java.time.Instant;
4+
import java.util.ArrayList;
5+
import java.util.HashMap;
6+
import java.util.List;
7+
import java.util.Map;
8+
9+
import io.snyk.eclipse.plugin.properties.preferences.Preferences;
10+
11+
public class AnalyticsEvent implements AbstractAnalyticsEvent {
12+
private final String interactionType;
13+
private final List<String> category;
14+
private final String status;
15+
private final String targetId;
16+
private final long timestampMs;
17+
private final long durationMs;
18+
private final Map<String, Object> results;
19+
private final List<Object> errors;
20+
private final Map<String, Object> extension;
21+
22+
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) {
23+
this.interactionType = interactionType;
24+
this.category = category;
25+
this.status = status != null ? status : "success";
26+
this.targetId = targetId != null ? targetId : "pkg:filesystem/scrubbed";
27+
this.timestampMs = timestampMs != 0 ? timestampMs : Instant.now().toEpochMilli() ;
28+
this.durationMs = durationMs;
29+
this.results = results != null ? results : new HashMap<>();
30+
this.errors = errors != null ? errors : new ArrayList<>();
31+
this.extension = extension != null ? extension : new HashMap<>();
32+
this.extension.put("device_id", Preferences.getInstance().getPref(Preferences.DEVICE_ID));
33+
}
34+
35+
public AnalyticsEvent(String interactionType, List<String> category) {
36+
this(interactionType, category, null, null, 0, 0, null, null, null);
37+
}
38+
39+
public String getInteractionType() {
40+
return interactionType;
41+
}
42+
43+
public List<String> getCategory() {
44+
return category;
45+
}
46+
47+
public String getStatus() {
48+
return status;
49+
}
50+
51+
public String getTargetId() {
52+
return targetId;
53+
}
54+
55+
public long getTimestampMs() {
56+
return timestampMs;
57+
}
58+
59+
public long getDurationMs() {
60+
return durationMs;
61+
}
62+
63+
public Map<String, Object> getResults() {
64+
return results;
65+
}
66+
67+
public List<Object> getErrors() {
68+
return errors;
69+
}
70+
71+
public Map<String, Object> getExtension() {
72+
return extension;
73+
}
74+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package io.snyk.eclipse.plugin.analytics;
2+
3+
import java.util.LinkedList;
4+
import java.util.concurrent.CompletableFuture;
5+
import java.util.concurrent.ConcurrentLinkedQueue;
6+
import java.util.function.Consumer;
7+
8+
import org.apache.commons.lang3.tuple.Pair;
9+
10+
import io.snyk.eclipse.plugin.properties.preferences.Preferences;
11+
import io.snyk.eclipse.plugin.utils.SnykLogger;
12+
import io.snyk.languageserver.protocolextension.SnykExtendedLanguageClient;
13+
14+
public class AnalyticsSender {
15+
// left = event, right = callback function
16+
private final ConcurrentLinkedQueue<Pair<AbstractAnalyticsEvent, Consumer<Void>>> eventQueue = new ConcurrentLinkedQueue<>();
17+
18+
private AnalyticsSender() {
19+
CompletableFuture.runAsync(() -> { start(); });
20+
}
21+
22+
private static AnalyticsSender instance;
23+
24+
public static AnalyticsSender getInstance() {
25+
if (instance == null) {
26+
synchronized (AnalyticsSender.class) {
27+
if (instance == null) {
28+
instance = new AnalyticsSender();
29+
}
30+
}
31+
}
32+
return instance;
33+
}
34+
35+
private void start() {
36+
while (true) {
37+
String authToken = Preferences.getInstance().getAuthToken();
38+
var lc = SnykExtendedLanguageClient.getInstance();
39+
if (eventQueue.isEmpty() || authToken == null || authToken.isBlank() || lc == null ) {
40+
try {
41+
Thread.sleep(1000);
42+
} catch (InterruptedException e) {
43+
Thread.currentThread().interrupt();
44+
}
45+
continue;
46+
}
47+
LinkedList<Pair<AbstractAnalyticsEvent, Consumer<Void>>> copyForSending = new LinkedList<>(eventQueue);
48+
for (Pair<AbstractAnalyticsEvent, Consumer<Void>> event : copyForSending) {
49+
try {
50+
lc.reportAnalytics(event.getLeft());
51+
event.getRight().accept(null);
52+
} catch (Exception e) {
53+
SnykLogger.logError(e);
54+
} finally {
55+
eventQueue.remove(event);
56+
}
57+
}
58+
}
59+
}
60+
61+
public void logEvent(AbstractAnalyticsEvent event, Consumer<Void> callback) {
62+
var pair = Pair.of(event, callback);
63+
eventQueue.add(pair);
64+
}
65+
}

0 commit comments

Comments
 (0)