diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusDeploymentSupport.java b/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusDeploymentSupport.java index e07646b34..e1d3f6f9a 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusDeploymentSupport.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusDeploymentSupport.java @@ -20,7 +20,6 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbService; -import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.impl.OrderEntryUtil; @@ -35,6 +34,8 @@ import com.redhat.devtools.intellij.lsp4mp4ij.classpath.ClasspathResourceChangedManager; import com.redhat.devtools.intellij.quarkus.buildtool.BuildToolDelegate; import com.redhat.devtools.intellij.quarkus.search.QuarkusModuleComponent; +import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryEventName; +import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -110,22 +111,20 @@ public static void updateClasspathWithQuarkusDeployment(Module module, ProgressI Library library = table.getLibraryByName(QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME); while (library != null) { table.removeLibrary(library); - try { - TelemetryService.instance().action(TelemetryService.MODEL_PREFIX + "removeLibrary"); - } catch (Exception e) { - } + // Send "model-removeLibrary" telemetry event + TelemetryManager.instance().send(TelemetryEventName.MODEL_REMOVE_LIBRARY); + library = table.getLibraryByName(QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME); } progressIndicator.checkCanceled(); progressIndicator.setText("Adding in ''" + module.getName() + "'' Quarkus deployment dependencies to classpath..."); List[] files = toolDelegate.getDeploymentFiles(module, progressIndicator); LOGGER.info("Adding library to " + module.getName() + " previousHash=" + previousHash + " newHash=" + actualHash); - try { - TelemetryService.instance().action(TelemetryService.MODEL_PREFIX + "addLibrary").send(); - } catch (Exception e) { - } + // Send "model-addLibrary" telemetry event + TelemetryManager.instance().send(TelemetryEventName.MODEL_ADD_LIBRARY); + addLibrary(model, files); }); component.setHash(actualHash); diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/TelemetryService.java b/src/main/java/com/redhat/devtools/intellij/quarkus/TelemetryService.java deleted file mode 100644 index 411e83baa..000000000 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/TelemetryService.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2021 Red Hat, Inc. - * Distributed under license by Red Hat, Inc. All rights reserved. - * This program is made available under the terms of the - * Eclipse Public License v2.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v20.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - ******************************************************************************/ -package com.redhat.devtools.intellij.quarkus; - -import com.intellij.ide.plugins.PluginManager; -import com.redhat.devtools.intellij.telemetry.core.service.TelemetryMessageBuilder; -import com.redhat.devtools.intellij.telemetry.core.util.Lazy; - -public class TelemetryService { - public static final String LSP_PREFIX = "lsp-"; - - public static final String UI_PREFIX = "ui-"; - - public static final String MODEL_PREFIX = "model-"; - - public static final String RUN_PREFIX = "run-"; - - private static final TelemetryService INSTANCE = new TelemetryService(); - - private final Lazy builder = new Lazy<>(() -> - new TelemetryMessageBuilder(PluginManager.getPluginByClass(this.getClass())) - ); - - public static TelemetryMessageBuilder instance() { - return INSTANCE.builder.get(); - } -} diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/maven/MavenToolDelegate.java b/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/maven/MavenToolDelegate.java index c45db09b8..b6b61d15d 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/maven/MavenToolDelegate.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/maven/MavenToolDelegate.java @@ -203,7 +203,7 @@ private Set resolveDeploymentArtifacts(Module module, MavenProjec } } } - } catch (MavenProcessCanceledException | RuntimeException e) { + } catch (Exception e) { LOGGER.warn(e.getLocalizedMessage(), e); } return deploymentArtifacts; diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusServer.java b/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusServer.java index b71269a5d..d15e28242 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusServer.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusServer.java @@ -15,14 +15,14 @@ import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryEventName; +import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryManager; import com.redhat.devtools.lsp4ij.server.JavaProcessCommandBuilder; import com.redhat.devtools.lsp4ij.server.ProcessStreamConnectionProvider; import com.redhat.devtools.intellij.lsp4mp4ij.settings.UserDefinedMicroProfileSettings; -import com.redhat.devtools.intellij.quarkus.TelemetryService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.URI; import java.nio.file.Path; import java.util.Arrays; import java.util.HashMap; @@ -55,11 +55,8 @@ public QuarkusServer(Project project) { commands.add("-DrunAsync=true"); super.setCommands(commands); - try { - TelemetryService.instance().action(TelemetryService.LSP_PREFIX + "start").send(); - } catch (Exception e) { - LOGGER.error("Error while consuming telemetry service", e); - } + // Send "ls-start" telemetry event + TelemetryManager.instance().send(TelemetryEventName.LSP_START_MICROPROFILE_SERVER); } @Override diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/projectWizard/QuarkusModuleBuilder.java b/src/main/java/com/redhat/devtools/intellij/quarkus/projectWizard/QuarkusModuleBuilder.java index ee3d955ce..e0d9094f9 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/projectWizard/QuarkusModuleBuilder.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/projectWizard/QuarkusModuleBuilder.java @@ -23,7 +23,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.RefreshQueue; import com.redhat.devtools.intellij.quarkus.QuarkusConstants; -import com.redhat.devtools.intellij.quarkus.TelemetryService; +import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryEventName; +import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryManager; import com.redhat.devtools.intellij.telemetry.core.service.TelemetryMessageBuilder; import org.jdom.JDOMException; import org.jetbrains.annotations.NotNull; @@ -86,15 +87,16 @@ public ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep) { @NotNull @Override public Module createModule(@NotNull ModifiableModuleModel moduleModel) throws InvalidDataException, IOException, ModuleWithNameAlreadyExists, JDOMException, ConfigurationException { - TelemetryMessageBuilder.ActionMessage telemetry = TelemetryService.instance().action(TelemetryService.UI_PREFIX + "wizard"); try { processDownload(); Module module = super.createModule(moduleModel); wizardContext.getUserData(QuarkusConstants.WIZARD_TOOL_KEY).processImport(module); - telemetry.send(); + // Send "ui-wizard" telemetry event with no error + TelemetryManager.instance().send(TelemetryEventName.UI_WIZARD); return module; } catch (IOException | InvalidDataException | ModuleWithNameAlreadyExists | JDOMException | ConfigurationException e) { - telemetry.error(e).send(); + // Send "ui-wizard" telemetry event with error + TelemetryManager.instance().send(TelemetryEventName.UI_WIZARD, e); throw e; } } diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfiguration.java b/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfiguration.java index 32164f4f5..fdadf6c1f 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfiguration.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfiguration.java @@ -33,9 +33,9 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil; -import com.redhat.devtools.intellij.quarkus.TelemetryService; import com.redhat.devtools.intellij.quarkus.buildtool.BuildToolDelegate; -import com.redhat.devtools.intellij.telemetry.core.service.TelemetryMessageBuilder; +import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryEventName; +import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -47,6 +47,7 @@ import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.Collection; +import java.util.HashMap; import java.util.Map; import static com.intellij.execution.runners.ExecutionUtil.createEnvironment; @@ -121,24 +122,29 @@ private void allocateLocalPort() { @Nullable @Override public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment environment) throws ExecutionException { - TelemetryMessageBuilder.ActionMessage telemetry = TelemetryService.instance().action(TelemetryService.RUN_PREFIX + "run"); - telemetry.property("kind", executor.getId()); - BuildToolDelegate toolDelegate = BuildToolDelegate.getDelegate(getModule()); + Module module = getModule(); + + Map telemetryData = new HashMap<>(); + telemetryData.put("kind", executor.getId()); + + BuildToolDelegate toolDelegate = BuildToolDelegate.getDelegate(module); allocateLocalPort(); RunProfileState state = null; if (toolDelegate != null) { - telemetry.property("tool", toolDelegate.getDisplay()); + telemetryData.put("tool", toolDelegate.getDisplay()); // Create a Gradle or Maven run configuration in memory - RunnerAndConfigurationSettings settings = toolDelegate.getConfigurationDelegate(getModule(), this); + RunnerAndConfigurationSettings settings = toolDelegate.getConfigurationDelegate(module, this); if (settings != null) { long groupId = ExecutionEnvironment.getNextUnusedExecutionId(); state = doRunConfiguration(settings, executor, DefaultExecutionTarget.INSTANCE, groupId, null); } } else { - telemetry.property("tool", "not found"); + telemetryData.put("tool", "not found"); } - telemetry.send(); - if (executor.getId() == DefaultDebugExecutor.EXECUTOR_ID) { + // Send "run-run" telemetry event + TelemetryManager.instance().send(TelemetryEventName.RUN_RUN, telemetryData); + + if (executor.getId().equals(DefaultDebugExecutor.EXECUTOR_ID)) { ProgressManager.getInstance().run(new Task.Backgroundable(getProject(), QUARKUS_CONFIGURATION, false) { @Override public void run(@NotNull ProgressIndicator indicator) { diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/run/dashboard/QuarkusRunDashboardCustomizer.java b/src/main/java/com/redhat/devtools/intellij/quarkus/run/dashboard/QuarkusRunDashboardCustomizer.java index 0042db922..4b201890f 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/run/dashboard/QuarkusRunDashboardCustomizer.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/run/dashboard/QuarkusRunDashboardCustomizer.java @@ -17,13 +17,15 @@ import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.ide.projectView.PresentationData; import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.project.PsiMicroProfileProject; import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.project.PsiMicroProfileProjectManager; import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil; -import com.redhat.devtools.intellij.quarkus.TelemetryService; import com.redhat.devtools.intellij.quarkus.run.QuarkusRunConfiguration; +import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryEventName; +import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -81,8 +83,8 @@ public boolean updatePresentation(@NotNull PresentationData presentation, @NotNu public void run() { // Open Quarkus application in a Web Browser super.run(); - // Send event with telemetry - TelemetryService.instance().action(TelemetryService.UI_PREFIX + "openApplication").send(); + // Send "ui-openApplication" telemetry event + TelemetryManager.instance().send(TelemetryEventName.UI_OPEN_APPLICATION); } }); links.put(devUILabel, new SimpleColoredComponent.BrowserLauncherTag(devUIUrl) { @@ -90,8 +92,8 @@ public void run() { public void run() { // Open DevUI in a Web Browser super.run(); - // Send event with telemetry - TelemetryService.instance().action(TelemetryService.UI_PREFIX + "openDevUI").send(); + // Send "ui-openDevUI" telemetry event + TelemetryManager.instance().send(TelemetryEventName.UI_OPEN_DEV_UI); } }); node.putUserData(RunDashboardCustomizer.NODE_LINKS, links); diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/telemetry/TelemetryEventName.java b/src/main/java/com/redhat/devtools/intellij/quarkus/telemetry/TelemetryEventName.java new file mode 100644 index 000000000..e5b1a453d --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/telemetry/TelemetryEventName.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2024 Red Hat Inc. and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package com.redhat.devtools.intellij.quarkus.telemetry; + +/** + * Quarkus telemetry event name. + */ +public enum TelemetryEventName { + + // LSP event names + LSP_START_MICROPROFILE_SERVER(Constants.LSP_PREFIX + "start"), + LSP_START_QUTE_SERVER(Constants.LSP_PREFIX + "startQute"), + + // Model event names + MODEL_REMOVE_LIBRARY(Constants.MODEL_PREFIX + "removeLibrary"), + MODEL_ADD_LIBRARY(Constants.MODEL_PREFIX + "addLibrary"), + + // UI event names + UI_WIZARD(Constants.UI_PREFIX + "wizard"), + UI_OPEN_APPLICATION(Constants.UI_PREFIX + "openApplication"), + UI_OPEN_DEV_UI(Constants.UI_PREFIX + "openDevUI"), + + // Run event names + RUN_RUN(Constants.RUN_PREFIX + "run"); + + private static class Constants { + public static final String LSP_PREFIX = "lsp-"; + public static final String UI_PREFIX = "ui-"; + public static final String MODEL_PREFIX = "model-"; + public static final String RUN_PREFIX = "run-"; + } + + private final String eventName; + + TelemetryEventName(String eventName) { + this.eventName = eventName; + } + + + public String getEventName() { + return eventName; + } + +} \ No newline at end of file diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/telemetry/TelemetryManager.java b/src/main/java/com/redhat/devtools/intellij/quarkus/telemetry/TelemetryManager.java new file mode 100644 index 000000000..7195f9bb8 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/telemetry/TelemetryManager.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2023 Red Hat Inc. and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package com.redhat.devtools.intellij.quarkus.telemetry; + +import com.intellij.ide.plugins.PluginManager; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; +import com.redhat.devtools.intellij.telemetry.core.service.TelemetryMessageBuilder; +import com.redhat.devtools.intellij.telemetry.core.util.Lazy; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +/** + * Helper to initialize Telemetry. A Telemetry service based on intellij-redhat-telemetry, + * will be instantiated if an API compatible plugin is installed, + */ +public class TelemetryManager implements Disposable { + + private static final Logger LOGGER = LoggerFactory.getLogger(TelemetryManager.class); + + private final Lazy builder = new Lazy<>(() -> new TelemetryMessageBuilder(PluginManager.getPluginByClass(this.getClass()))); + + private boolean hasError; + + public static TelemetryManager instance() { + return ApplicationManager.getApplication().getService(TelemetryManager.class); + } + + /** + * Sends a tracking event without additional properties. + * @param eventName the name of the event + */ + public void send(@NotNull TelemetryEventName eventName) { + send(eventName, null, null); + } + + /** + * Sends a tracking event with additional properties. + * @param eventName the name of the event + * @param error the error + */ + public void send(@NotNull TelemetryEventName eventName, + @NotNull Exception error) { + send(eventName, null, error); + } + + /** + * Sends a tracking event with additional properties. + * @param eventName the name of the event + * @param properties the properties of the event + */ + public void send(@NotNull TelemetryEventName eventName, + @NotNull Map properties) { + send(eventName, properties, null); + } + + /** + * Sends a tracking event with additional properties. + * @param eventName the name of the event + * @param properties the properties of the event and null otherwise + * @param error the error of the event and null otherwise + */ + public void send(@NotNull TelemetryEventName eventName, + @Nullable Map properties, + @Nullable Exception error) { + TelemetryMessageBuilder.ActionMessage action = action(eventName, properties, error); + if (action == null) { + return; + } + asyncSend(action); + } + + @Nullable + private TelemetryMessageBuilder.ActionMessage action(@NotNull TelemetryEventName eventName, + @Nullable Map properties, + @Nullable Exception error) { + TelemetryMessageBuilder builder = getMessageBuilder(); + if (builder == null) { + return null; + } + try { + TelemetryMessageBuilder.ActionMessage action = error != null ? + builder.action(eventName.getEventName()).error(error) : + builder.action(eventName.getEventName()); + if (properties != null) { + properties.forEach((k, v) -> action.property(k, v)); + } + return action; + } + catch(Exception e) { + LOGGER.warn("Error while creating telemetry message.", e); + return null; + } + } + + @Nullable + private TelemetryMessageBuilder getMessageBuilder() { + if (hasError) { + return null; + } + try { + return builder.get(); + } + catch(Exception e) { + LOGGER.warn("Error while creating TelemetryMessageBuilder instance.", e); + hasError = true; + return null; + } + } + + private void asyncSend(@NotNull TelemetryMessageBuilder.ActionMessage message) { + ApplicationManager.getApplication().executeOnPooledThread(() -> { + try{ + message.send(); + } catch (Exception e) { + LOGGER.warn("Failed to send Telemetry data : {}", e.getMessage()); + } + }); + } + + @Override + public void dispose() { + } +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteServer.java b/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteServer.java index eea161650..274809e88 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteServer.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteServer.java @@ -15,14 +15,14 @@ import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryEventName; +import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryManager; import com.redhat.devtools.lsp4ij.server.JavaProcessCommandBuilder; import com.redhat.devtools.lsp4ij.server.ProcessStreamConnectionProvider; -import com.redhat.devtools.intellij.quarkus.TelemetryService; import com.redhat.devtools.intellij.qute.settings.UserDefinedQuteSettings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.URI; import java.nio.file.Path; import java.util.Arrays; import java.util.HashMap; @@ -52,12 +52,8 @@ public QuteServer(Project project) { commands.add("-DrunAsync=true"); super.setCommands(commands); - try { - TelemetryService.instance().action(TelemetryService.LSP_PREFIX + "startQute").send(); - } - catch(Exception e) { - LOGGER.error("Error while consuming telemetry service", e); - } + // Send "ls-startQute" telemetry event + TelemetryManager.instance().send(TelemetryEventName.LSP_START_QUTE_SERVER); } @Override diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index df9026641..825c697de 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -353,7 +353,10 @@ - + + +