From 93e26ec35c86f00c08f63cfea8b0f70b8c601f4d Mon Sep 17 00:00:00 2001 From: Gerard Braad Date: Tue, 25 Apr 2023 20:16:56 +0800 Subject: [PATCH] Add telemetry using the extension API This adds telemetry to the extension, utilizing the functionality provided by Podman Desktop. --- .gitpod.yml | 11 +++++++++++ src/command.ts | 13 ++++++++++++- src/crc-start.ts | 8 ++++++-- src/crc-stop.ts | 4 +++- src/extension.ts | 29 +++++++++++++++++------------ src/preferences.ts | 24 ++++++++++++++++-------- 6 files changed, 65 insertions(+), 24 deletions(-) create mode 100644 .gitpod.yml diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000..525964b --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,11 @@ +# This configuration file was automatically generated by Gitpod. +# Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml) +# and commit this file to your remote git repository to share the goodness with others. + +# Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart + +tasks: + - init: yarn install && yarn run build + command: yarn run watch + + diff --git a/src/command.ts b/src/command.ts index 0ab7a95..e633023 100644 --- a/src/command.ts +++ b/src/command.ts @@ -30,6 +30,7 @@ export interface ProviderCommand extends extensionApi.MenuItem { export class CommandManager { private extensionContext: extensionApi.ExtensionContext; + private telemetryLogger: extensionApi.TelemetryLogger; private commands: ProviderCommand[] = []; private disposables = new Map(); constructor() { @@ -69,7 +70,13 @@ export class CommandManager { const disposable = extensionApi.tray.registerProviderMenuItem(providerId, command); this.disposables.set(command.id, disposable); this.commands.push(command); - this.extensionContext.subscriptions.push(extensionApi.commands.registerCommand(command.id, command.callback)); + + this.extensionContext.subscriptions.push( + extensionApi.commands.registerCommand(command.id, () => { + this.telemetryLogger.logUsage(command.id); + command.callback(); + }), + ); } setExtContext(extensionContext: extensionApi.ExtensionContext): void { @@ -77,6 +84,10 @@ export class CommandManager { extensionContext.subscriptions.push(extensionApi.Disposable.from(this)); } + setTelemetryLogger(telemetryLogger: extensionApi.TelemetryLogger): void { + this.telemetryLogger = telemetryLogger; + } + dispose(): void { // dispose all commands registered for (const disposable of this.disposables.values()) { diff --git a/src/crc-start.ts b/src/crc-start.ts index 465b0d5..28318a5 100644 --- a/src/crc-start.ts +++ b/src/crc-start.ts @@ -33,7 +33,11 @@ interface Auths { const missingPullSecret = 'Failed to ask for pull secret'; -export async function startCrc(logger: extensionApi.Logger): Promise { +export async function startCrc( + logger: extensionApi.Logger, + telemetryLogger: extensionApi.TelemetryLogger, +): Promise { + telemetryLogger.logUsage('crc.start'); try { // call crc setup to prepare bundle, before start if (isNeedSetup) { @@ -58,7 +62,7 @@ export async function startCrc(logger: extensionApi.Logger): Promise { // ask user to provide pull secret if (await askAndStorePullSecret(logger)) { // if pull secret provided try to start again - return startCrc(logger); + return startCrc(logger, telemetryLogger); } return; } else if (err.name === 'RequestError' && err.code === 'ECONNRESET') { diff --git a/src/crc-stop.ts b/src/crc-stop.ts index ab11aa2..d85e72a 100644 --- a/src/crc-stop.ts +++ b/src/crc-stop.ts @@ -16,10 +16,12 @@ * SPDX-License-Identifier: Apache-2.0 ***********************************************************************/ +import type * as extensionApi from '@podman-desktop/api'; import { commander } from './daemon-commander'; import { crcLogProvider } from './log-provider'; -export async function stopCrc(): Promise { +export async function stopCrc(telemetryLogger: extensionApi.TelemetryLogger): Promise { + telemetryLogger.logUsage('crc.stop'); console.log('extension:crc: receive the call stop'); try { await commander.stop(); diff --git a/src/extension.ts b/src/extension.ts index 0accd7d..209a2b2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -43,6 +43,7 @@ export async function activate(extensionContext: extensionApi.ExtensionContext): const crcInstaller = new CrcInstall(); extensionApi.configuration.getConfiguration(); const crcVersion = await getCrcVersion(); + const telemetryLogger = extensionApi.env.createTelemetryLogger(); const detectionChecks: extensionApi.ProviderDetectionCheck[] = []; let status: extensionApi.ProviderStatus = 'not-installed'; @@ -75,13 +76,14 @@ export async function activate(extensionContext: extensionApi.ExtensionContext): extensionContext.subscriptions.push(provider); const providerLifecycle: extensionApi.ProviderLifecycle = { - status: () => crcStatus.getProviderStatus(), - + status: () => { + return crcStatus.getProviderStatus(); + }, start: context => { - return startCrc(context.log); + return startCrc(context.log, telemetryLogger); }, stop: () => { - return stopCrc(); + return stopCrc(telemetryLogger); }, }; @@ -92,7 +94,7 @@ export async function activate(extensionContext: extensionApi.ExtensionContext): if (hasSetupFinished) { await needSetup(); connectToCrc(); - presetChanged(provider, extensionContext); + presetChanged(provider, extensionContext, telemetryLogger); } }, }), @@ -101,17 +103,18 @@ export async function activate(extensionContext: extensionApi.ExtensionContext): extensionContext.subscriptions.push(provider.registerLifecycle(providerLifecycle)); commandManager.setExtContext(extensionContext); + commandManager.setTelemetryLogger(telemetryLogger); registerOpenTerminalCommand(); registerOpenConsoleCommand(); registerLogInCommands(); registerDeleteCommand(); - syncPreferences(extensionContext); + syncPreferences(extensionContext, telemetryLogger); if (!isNeedSetup) { // initial preset check - presetChanged(provider, extensionContext); + presetChanged(provider, extensionContext, telemetryLogger); } if (crcInstaller.isAbleToInstall()) { @@ -125,7 +128,7 @@ export async function activate(extensionContext: extensionApi.ExtensionContext): return; } await connectToCrc(); - presetChanged(provider, extensionContext); + presetChanged(provider, extensionContext, telemetryLogger); }); }, }); @@ -170,6 +173,7 @@ async function registerOpenShiftLocalCluster( name, provider: extensionApi.Provider, extensionContext: extensionApi.ExtensionContext, + telemetryLogger: extensionApi.TelemetryLogger, ): Promise { const status = () => crcStatus.getConnectionStatus(); const apiURL = 'https://api.crc.testing:6443'; @@ -184,10 +188,10 @@ async function registerOpenShiftLocalCluster( return deleteCrc(); }, start: ctx => { - return startCrc(ctx.log); + return startCrc(ctx.log, telemetryLogger); }, stop: () => { - return stopCrc(); + return stopCrc(telemetryLogger); }, }, }; @@ -230,6 +234,7 @@ async function connectToCrc(): Promise { async function presetChanged( provider: extensionApi.Provider, extensionContext: extensionApi.ExtensionContext, + telemetryLogger: extensionApi.TelemetryLogger, ): Promise { // TODO: handle situation if some cluster/connection was registered already @@ -239,8 +244,8 @@ async function presetChanged( // podman connection registerPodmanConnection(provider, extensionContext); } else if (preset === 'OpenShift') { - registerOpenShiftLocalCluster('OpenShift Local', provider, extensionContext); + registerOpenShiftLocalCluster('OpenShift Local', provider, extensionContext, telemetryLogger); } else if (preset === 'MicroShift') { - registerOpenShiftLocalCluster('MicroShift', provider, extensionContext); + registerOpenShiftLocalCluster('MicroShift', provider, extensionContext, telemetryLogger); } } diff --git a/src/preferences.ts b/src/preferences.ts index 8dcab92..b07336c 100644 --- a/src/preferences.ts +++ b/src/preferences.ts @@ -49,7 +49,10 @@ interface ConfigEntry { let initialCrcConfig: Configuration; -export async function syncPreferences(context: extensionApi.ExtensionContext): Promise { +export async function syncPreferences( + context: extensionApi.ExtensionContext, + telemetryLogger: extensionApi.TelemetryLogger, +): Promise { try { initialCrcConfig = await commander.configGet(); @@ -62,7 +65,7 @@ export async function syncPreferences(context: extensionApi.ExtensionContext): P context.subscriptions.push( extensionApi.configuration.onDidChangeConfiguration(e => { - configChanged(e); + configChanged(e, telemetryLogger); }), ); @@ -120,7 +123,10 @@ async function handleProxyChange(proxy?: extensionApi.ProxySettings): Promise { +async function configChanged( + e: extensionApi.ConfigurationChangeEvent, + telemetryLogger: extensionApi.TelemetryLogger, +): Promise { const currentConfig = await commander.configGet(); const extConfig = extensionApi.configuration.getConfiguration(); @@ -167,7 +173,7 @@ async function configChanged(e: extensionApi.ConfigurationChangeEvent): Promise< if (!isEmpty(newConfig)) { await commander.configSet(newConfig); if (needRecreateCrc) { - await handleRecreate(); + await handleRecreate(telemetryLogger); } } } catch (err) { @@ -209,7 +215,7 @@ function validateRam(newVal: string | number): string | undefined { } } -async function handleRecreate(): Promise { +async function handleRecreate(telemetryLogger: extensionApi.TelemetryLogger): Promise { const needDelete = crcStatus.status.CrcStatus !== 'No Cluster'; const needStop = crcStatus.getProviderStatus() === 'started' || crcStatus.getProviderStatus() === 'starting'; @@ -228,13 +234,15 @@ async function handleRecreate(): Promise { ...buttons, ); + // we might wanna log what user clicked on. + // for now we infer from the logged events if (result === 'Stop and Delete') { - await stopCrc(); + await stopCrc(telemetryLogger); await deleteCrc(); } else if (result === 'Delete and Restart') { - await stopCrc(); + await stopCrc(telemetryLogger); await deleteCrc(); - await startCrc(defaultLogger); + await startCrc(defaultLogger, telemetryLogger); } else if (result === 'Delete') { await deleteCrc(); }