From 8caaf05de4882ac1d60d55f08ebcc6da130ee04c Mon Sep 17 00:00:00 2001 From: Brett Saviano Date: Wed, 9 Jul 2025 16:08:44 -0400 Subject: [PATCH] Better telemetry --- package-lock.json | 272 +++++++++-------- package.json | 4 +- src/commands/serverActions.ts | 2 + src/commands/unitTest.ts | 3 +- src/commands/webSocketTerminal.ts | 3 +- src/debug/debugSession.ts | 4 +- src/extension.ts | 401 +++++++++++++++++++------ src/providers/LowCodeEditorProvider.ts | 3 +- src/utils/documentIndex.ts | 2 + 9 files changed, 462 insertions(+), 232 deletions(-) diff --git a/package-lock.json b/package-lock.json index fbf93747..ede094c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,18 @@ { "name": "vscode-objectscript", - "version": "3.0.0-SNAPSHOT", + "version": "3.0.5-SNAPSHOT", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vscode-objectscript", - "version": "3.0.0-SNAPSHOT", + "version": "3.0.5-SNAPSHOT", "hasInstallScript": true, "license": "MIT", "dependencies": { "@vscode/debugadapter": "^1.68.0", "@vscode/debugprotocol": "^1.68.0", + "@vscode/extension-telemetry": "^1.0.0", "@xmldom/xmldom": "^0.9.8", "axios": "^1.8.4", "core-js": "^3.41.0", @@ -20,7 +21,6 @@ "minimatch": "^10.0.1", "node-cmd": "^5.0.0", "vscode-cache": "^0.3.0", - "vscode-extension-telemetry": "^0.1.6", "ws": "^8.18.1" }, "devDependencies": { @@ -424,6 +424,130 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@microsoft/1ds-core-js": { + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/@microsoft/1ds-core-js/-/1ds-core-js-4.3.9.tgz", + "integrity": "sha512-T8s5qROH7caBNiFrUpN8vgC6wg7QysVPryZKprgl3kLQQPpoMFM6ffIYvUWD74KM9fWWLU7vzFFNBWDBsrTyWg==", + "license": "MIT", + "dependencies": { + "@microsoft/applicationinsights-core-js": "3.3.9", + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.4 < 2.x", + "@nevware21/ts-utils": ">= 0.11.8 < 2.x" + } + }, + "node_modules/@microsoft/1ds-post-js": { + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/@microsoft/1ds-post-js/-/1ds-post-js-4.3.9.tgz", + "integrity": "sha512-BvxI4CW8Ws+gfXKy+Y/9pmEXp88iU1GYVjkUfqXP7La59VHARTumlG5iIgMVvaifOrvSW7G6knvQM++0tEfMBQ==", + "license": "MIT", + "dependencies": { + "@microsoft/1ds-core-js": "4.3.9", + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.4 < 2.x", + "@nevware21/ts-utils": ">= 0.11.8 < 2.x" + } + }, + "node_modules/@microsoft/applicationinsights-channel-js": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-3.3.9.tgz", + "integrity": "sha512-/yEgSe6vT2ycQJkXu6VF04TB5XBurk46ECV7uo6KkNhWyDEctAk1VDWB7EqXYdwLhKMbNOYX1pvz7fj43fGNqg==", + "license": "MIT", + "dependencies": { + "@microsoft/applicationinsights-common": "3.3.9", + "@microsoft/applicationinsights-core-js": "3.3.9", + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.4 < 2.x", + "@nevware21/ts-utils": ">= 0.11.8 < 2.x" + }, + "peerDependencies": { + "tslib": ">= 1.0.0" + } + }, + "node_modules/@microsoft/applicationinsights-common": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-common/-/applicationinsights-common-3.3.9.tgz", + "integrity": "sha512-IgruOuDBxmBK9jYo7SqLJG7Z9OwmAmlvHET49srpN6pqQlEjRpjD1nfA3Ps4RSEbF89a/ad2phQaBp8jvm122g==", + "license": "MIT", + "dependencies": { + "@microsoft/applicationinsights-core-js": "3.3.9", + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-utils": ">= 0.11.8 < 2.x" + }, + "peerDependencies": { + "tslib": ">= 1.0.0" + } + }, + "node_modules/@microsoft/applicationinsights-core-js": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-3.3.9.tgz", + "integrity": "sha512-xliiE9H09xCycndlua4QjajN8q5k/ET6VCv+e0Jjodxr9+cmoOP/6QY9dun9ptokuwR8TK0qOaIJ8z4fgslVSA==", + "license": "MIT", + "dependencies": { + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.4 < 2.x", + "@nevware21/ts-utils": ">= 0.11.8 < 2.x" + }, + "peerDependencies": { + "tslib": ">= 1.0.0" + } + }, + "node_modules/@microsoft/applicationinsights-shims": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-shims/-/applicationinsights-shims-3.0.1.tgz", + "integrity": "sha512-DKwboF47H1nb33rSUfjqI6ryX29v+2QWcTrRvcQDA32AZr5Ilkr7whOOSsD1aBzwqX0RJEIP1Z81jfE3NBm/Lg==", + "license": "MIT", + "dependencies": { + "@nevware21/ts-utils": ">= 0.9.4 < 2.x" + } + }, + "node_modules/@microsoft/applicationinsights-web-basic": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-web-basic/-/applicationinsights-web-basic-3.3.9.tgz", + "integrity": "sha512-8tLaAgsCpWjoaxit546RqeuECnHQPBLnOZhzTYG76oPG1ku7dNXaRNieuZLbO+XmAtg/oxntKLAVoPND8NRgcA==", + "license": "MIT", + "dependencies": { + "@microsoft/applicationinsights-channel-js": "3.3.9", + "@microsoft/applicationinsights-common": "3.3.9", + "@microsoft/applicationinsights-core-js": "3.3.9", + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.4 < 2.x", + "@nevware21/ts-utils": ">= 0.11.8 < 2.x" + }, + "peerDependencies": { + "tslib": ">= 1.0.0" + } + }, + "node_modules/@microsoft/dynamicproto-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@microsoft/dynamicproto-js/-/dynamicproto-js-2.0.3.tgz", + "integrity": "sha512-JTWTU80rMy3mdxOjjpaiDQsTLZ6YSGGqsjURsY6AUQtIj0udlF/jYmhdLZu8693ZIC0T1IwYnFa0+QeiMnziBA==", + "license": "MIT", + "dependencies": { + "@nevware21/ts-utils": ">= 0.10.4 < 2.x" + } + }, + "node_modules/@nevware21/ts-async": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@nevware21/ts-async/-/ts-async-0.5.4.tgz", + "integrity": "sha512-IBTyj29GwGlxfzXw2NPnzty+w0Adx61Eze1/lknH/XIVdxtF9UnOpk76tnrHXWa6j84a1RR9hsOcHQPFv9qJjA==", + "license": "MIT", + "dependencies": { + "@nevware21/ts-utils": ">= 0.11.6 < 2.x" + } + }, + "node_modules/@nevware21/ts-utils": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.12.5.tgz", + "integrity": "sha512-JPQZWPKQJjj7kAftdEZL0XDFfbMgXCGiUAZe0d7EhLC3QlXTlZdSckGqqRIQ2QNl0VTEZyZUvRBw6Ednw089Fw==", + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -852,6 +976,20 @@ "dts": "index.js" } }, + "node_modules/@vscode/extension-telemetry": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@vscode/extension-telemetry/-/extension-telemetry-1.0.0.tgz", + "integrity": "sha512-vaTZE65zigWwSWYB6yaZUAyVC/Ux+6U82hnzy/ejuS/KpFifO+0oORNd5yAoPeIRnYjvllM6ES3YlX4K5tUuww==", + "license": "MIT", + "dependencies": { + "@microsoft/1ds-core-js": "^4.3.4", + "@microsoft/1ds-post-js": "^4.3.4", + "@microsoft/applicationinsights-web-basic": "^3.3.4" + }, + "engines": { + "vscode": "^1.75.0" + } + }, "node_modules/@vscode/test-electron": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.1.tgz", @@ -1213,17 +1351,6 @@ "node": ">= 8" } }, - "node_modules/applicationinsights": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-1.7.4.tgz", - "integrity": "sha512-XFLsNlcanpjFhHNvVWEfcm6hr7lu9znnb6Le1Lk5RE03YUV9X2B2n2MfM4kJZRrUdV+C0hdHxvWyv+vWoLfY7A==", - "dependencies": { - "cls-hooked": "^4.2.2", - "continuation-local-storage": "^3.2.1", - "diagnostic-channel": "0.2.0", - "diagnostic-channel-publishers": "^0.3.3" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1359,37 +1486,6 @@ "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", "dev": true }, - "node_modules/async-hook-jl": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/async-hook-jl/-/async-hook-jl-1.7.6.tgz", - "integrity": "sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==", - "dependencies": { - "stack-chain": "^1.3.7" - }, - "engines": { - "node": "^4.7 || >=6.9 || >=7.3" - } - }, - "node_modules/async-listener": { - "version": "0.6.10", - "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", - "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", - "dependencies": { - "semver": "^5.3.0", - "shimmer": "^1.1.0" - }, - "engines": { - "node": "<=0.11.8 || >0.11.10" - } - }, - "node_modules/async-listener/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1767,27 +1863,6 @@ "node": ">=6" } }, - "node_modules/cls-hooked": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", - "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", - "dependencies": { - "async-hook-jl": "^1.7.6", - "emitter-listener": "^1.0.1", - "semver": "^5.4.1" - }, - "engines": { - "node": "^4.7 || >=6.9 || >=7.3 || >=8.2.1" - } - }, - "node_modules/cls-hooked/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1835,15 +1910,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "node_modules/continuation-local-storage": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", - "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", - "dependencies": { - "async-listener": "^0.6.0", - "emitter-listener": "^1.1.1" - } - }, "node_modules/core-js": { "version": "3.41.0", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.41.0.tgz", @@ -2009,30 +2075,6 @@ "node": ">=0.4.0" } }, - "node_modules/diagnostic-channel": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz", - "integrity": "sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc=", - "dependencies": { - "semver": "^5.3.0" - } - }, - "node_modules/diagnostic-channel-publishers": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.3.5.tgz", - "integrity": "sha512-AOIjw4T7Nxl0G2BoBPhkQ6i7T4bUd9+xvdYizwvG7vVAM1dvr+SDrcUudlmzwH0kbEwdR2V1EcnKT0wAeYLQNQ==", - "peerDependencies": { - "diagnostic-channel": "*" - } - }, - "node_modules/diagnostic-channel/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", @@ -2055,14 +2097,6 @@ "integrity": "sha512-ddeXKuY9BHo/mw145axlyWjlJ1UBt4WK3AlvkT7W2AbqfRQoacVoRUCF6wL3uIx/8wT9oLKXzI+rFqHHscByaA==", "dev": true }, - "node_modules/emitter-listener": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", - "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", - "dependencies": { - "shimmer": "^1.2.0" - } - }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -5244,11 +5278,6 @@ "node": ">=8" } }, - "node_modules/shimmer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", - "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" - }, "node_modules/side-channel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", @@ -5298,11 +5327,6 @@ "source-map": "^0.6.0" } }, - "node_modules/stack-chain": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz", - "integrity": "sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU=" - }, "node_modules/stdin-discarder": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", @@ -5664,8 +5688,7 @@ "node_modules/tslib": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", - "dev": true + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==" }, "node_modules/type-check": { "version": "0.4.0", @@ -5836,17 +5859,6 @@ "resolved": "https://registry.npmjs.org/vscode-cache/-/vscode-cache-0.3.0.tgz", "integrity": "sha1-fMOWZOvZnTcDAwaLibxMlWFGZ8A=" }, - "node_modules/vscode-extension-telemetry": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.7.tgz", - "integrity": "sha512-pZuZTHO9OpsrwlerOKotWBRLRYJ53DobYb7aWiRAXjlqkuqE+YJJaP+2WEy8GrLIF1EnitXTDMaTAKsmLQ5ORQ==", - "dependencies": { - "applicationinsights": "1.7.4" - }, - "engines": { - "vscode": "^1.5.0" - } - }, "node_modules/watchpack": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", diff --git a/package.json b/package.json index 00ba58f1..361200db 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "InterSystems ObjectScript language support for Visual Studio Code", "version": "3.0.5-SNAPSHOT", "icon": "images/logo.png", - "aiKey": "9cd75d51-697c-406c-a929-2bcf46e97c64", + "aiKey": "InstrumentationKey=9cd75d51-697c-406c-a929-2bcf46e97c64;IngestionEndpoint=https://eastus2-4.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus2.livediagnostics.monitor.azure.com/;ApplicationId=a431c56f-8ccc-4b99-b5e9-fce3763215b1", "categories": [ "Programming Languages", "Other", @@ -1821,6 +1821,7 @@ "dependencies": { "@vscode/debugadapter": "^1.68.0", "@vscode/debugprotocol": "^1.68.0", + "@vscode/extension-telemetry": "^1.0.0", "@xmldom/xmldom": "^0.9.8", "axios": "^1.8.4", "core-js": "^3.41.0", @@ -1829,7 +1830,6 @@ "minimatch": "^10.0.1", "node-cmd": "^5.0.0", "vscode-cache": "^0.3.0", - "vscode-extension-telemetry": "^0.1.6", "ws": "^8.18.1" }, "extensionDependencies": [ diff --git a/src/commands/serverActions.ts b/src/commands/serverActions.ts index e4589209..295ec47c 100644 --- a/src/commands/serverActions.ts +++ b/src/commands/serverActions.ts @@ -6,6 +6,7 @@ import { explorerProvider, filesystemSchemas, FILESYSTEM_SCHEMA, + sendStudioAddinTelemetryEvent, } from "../extension"; import { connectionTarget, @@ -246,6 +247,7 @@ export async function serverActions(): Promise { title: `Pick a Studio Add-In to open for server: ${connInfo}`, }); if (addin) { + sendStudioAddinTelemetryEvent(addin.label); const token = await getCSPToken(api, addin.id); let params = `Namespace=${nsEncoded}`; params += `&User=${encodeURIComponent(username)}`; diff --git a/src/commands/unitTest.ts b/src/commands/unitTest.ts index c5643467..3a0bbd32 100644 --- a/src/commands/unitTest.ts +++ b/src/commands/unitTest.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; import * as Atelier from "../api/atelier"; -import { clsLangId, extensionId, filesystemSchemas, lsExtensionId } from "../extension"; +import { clsLangId, extensionId, filesystemSchemas, lsExtensionId, sendUnitTestTelemetryEvent } from "../extension"; import { getFileText, handleError, @@ -416,6 +416,7 @@ async function runHandler( // Need a root to continue return; } + sendUnitTestTelemetryEvent(root.uri, debug); // Add the initial items to the queue to process const queue: vscode.TestItem[] = []; diff --git a/src/commands/webSocketTerminal.ts b/src/commands/webSocketTerminal.ts index 6888ae9b..aa5d69f0 100644 --- a/src/commands/webSocketTerminal.ts +++ b/src/commands/webSocketTerminal.ts @@ -3,7 +3,7 @@ import WebSocket = require("ws"); import { AtelierAPI } from "../api"; import { connectionTarget, currentFile, getWsServerConnection, handleError, notIsfs, outputChannel } from "../utils"; -import { config, iscIcon, resolveConnectionSpec } from "../extension"; +import { config, iscIcon, resolveConnectionSpec, sendLiteTerminalTelemetryEvent } from "../extension"; const NO_ELIGIBLE_CONNECTIONS = "Lite Terminal requires an active server connection to InterSystems IRIS version 2023.2 or above."; @@ -745,6 +745,7 @@ function terminalConfigForUri( return; } + sendLiteTerminalTelemetryEvent(throwErrors ? "profile" : "command"); return { name: api.config.serverName && api.config.serverName != "" ? api.config.serverName : "iris", location: diff --git a/src/debug/debugSession.ts b/src/debug/debugSession.ts index 977f3502..525401cd 100644 --- a/src/debug/debugSession.ts +++ b/src/debug/debugSession.ts @@ -17,7 +17,7 @@ import { DebugProtocol } from "@vscode/debugprotocol"; import WebSocket = require("ws"); import { AtelierAPI } from "../api"; import * as xdebug from "./xdebugConnection"; -import { lsExtensionId, schemas } from "../extension"; +import { lsExtensionId, schemas, sendDebuggerTelemetryEvent } from "../extension"; import { DocumentContentProvider } from "../providers/DocumentContentProvider"; import { formatPropertyValue } from "./utils"; import { isfsConfig } from "../utils/FileProviderUtil"; @@ -263,6 +263,7 @@ export class ObjectScriptDebugSession extends LoggingDebugSession { this._isLaunch = true; const debugTarget = `${this._namespace}:${args.program}`; await this._connection.sendFeatureSetCommand("debug_target", debugTarget, true); + sendDebuggerTelemetryEvent("launch"); } catch (error) { this.sendErrorResponse(response, error); return; @@ -300,6 +301,7 @@ export class ObjectScriptDebugSession extends LoggingDebugSession { stopped = await this._isStopped(); } } + sendDebuggerTelemetryEvent(this._isCsp ? "rest" : this._isUnitTest ? "unittest" : "attach"); } catch (error) { this.sendErrorResponse(response, error); return; diff --git a/src/extension.ts b/src/extension.ts index 7e0eca9f..40f6889b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -5,6 +5,7 @@ export const smExtensionId = "intersystems-community.servermanager"; import vscode = require("vscode"); import * as semver from "semver"; import * as serverManager from "@intersystems-community/intersystems-servermanager"; +import { TelemetryReporter } from "@vscode/extension-telemetry"; import { AtelierJob, Content, Response, ServerInfo } from "./api/atelier"; export const OBJECTSCRIPT_FILE_SCHEMA = "objectscript"; @@ -127,7 +128,6 @@ export const terminals: vscode.Terminal[] = []; export let xmlContentProvider: XmlContentProvider; export let iscIcon: vscode.Uri; -import TelemetryReporter from "vscode-extension-telemetry"; import { CodeActionProvider } from "./providers/CodeActionProvider"; import { addWorkspaceFolderForProject, @@ -212,7 +212,7 @@ export const config = (setting?: string, workspaceFolderName?: string): vscode.W return setting && setting.length ? result.get(setting) : result; }; -let reporter: TelemetryReporter = null; +let reporter: TelemetryReporter; export let checkingConnection = false; @@ -440,12 +440,6 @@ export async function checkConnection( `Connected${api.config.pathPrefix ? ` to \`${api.config.pathPrefix}\`` : ""} as \`${username}\`` ); } - const hasHS = info.result.content.features.find((el) => el.name === "HEALTHSHARE" && el.enabled) !== undefined; - reporter && - reporter.sendTelemetryEvent("connected", { - serverVersion: info.result.content.version, - healthshare: hasHS ? "yes" : "no", - }); if (!api.externalServer) { await setConnectionState(configName, true); } @@ -779,6 +773,67 @@ async function updateWebAndAbstractDocsCaches(wsFolders: readonly vscode.Workspa ); } +/** Send a telemetry event that `commandId` was executed */ +function sendCommandTelemetryEvent(commandId: string): void { + reporter?.sendTelemetryEvent("commandExecuted", { commandId }); +} + +/** Send a telemetry event that Studio Add-In `addIn` was opened */ +export function sendStudioAddinTelemetryEvent(addInName: string): void { + reporter?.sendTelemetryEvent("studioAddInOpened", { addInName }); +} + +/** Send a telemetry event with details of each folder in `wsFolders` */ +function sendWsFolderTelemetryEvent(wsFolders: readonly vscode.WorkspaceFolder[], added = false): void { + if (!reporter || !wsFolders?.length) return; + wsFolders.forEach((wsFolder) => { + const api = new AtelierAPI(wsFolder.uri); + const { csp, project, ns } = isfsConfig(wsFolder.uri); + const serverSide = filesystemSchemas.includes(wsFolder.uri.scheme); + const conf = vscode.workspace.getConfiguration("objectscript", wsFolder); + reporter.sendTelemetryEvent("workspaceFolder", { + scheme: wsFolder.uri.scheme, + added: String(added), + isWeb: serverSide ? String(csp) : undefined, + isProject: serverSide ? String(project.length) : undefined, + hasNs: serverSide ? String(typeof ns == "string") : undefined, + serverVersion: api.active ? api.config.serverVersion : undefined, + "config.syncLocalChanges": !serverSide ? conf.get("syncLocalChanges") : undefined, + dockerCompose: !serverSide ? String(typeof conf.get("conn.docker-compose") == "object") : undefined, + }); + }); +} + +/** Send a telemetry event that a unit test run was started */ +export function sendUnitTestTelemetryEvent(root: vscode.Uri, debug: boolean): void { + reporter?.sendTelemetryEvent("unitTestRun", { scheme: root.scheme, debug: String(debug) }); +} + +/** Send a telemetry event that a non-class or routine client-side file was saved */ +export function sendClientSideSyncTelemetryEvent(fileExt: string): void { + reporter?.sendTelemetryEvent("clientSideFileSynced", { fileExt }); +} + +/** Send a telemetry event that a low-code editor was opened */ +export function sendLowCodeTelemetryEvent(editorType: string, scheme: string): void { + reporter?.sendTelemetryEvent("lowCodeEditorOpened", { editorType, scheme }); +} + +/** Send a telemetry event that the debugger was started */ +export function sendDebuggerTelemetryEvent(debugType: string): void { + reporter?.sendTelemetryEvent("debuggerStarted", { debugType }); +} + +/** Send a telemetry event that a Lite Terminal was started */ +export function sendLiteTerminalTelemetryEvent(terminalOrigin: string): void { + reporter?.sendTelemetryEvent("liteTerminalStarted", { + terminalOrigin, + "config.webSocketTerminal.syntaxColoring": String( + vscode.workspace.getConfiguration("objectscript.webSocketTerminal").get("syntaxColoring") + ), + }); +} + /** The URIs of all classes that have been opened. Used when `objectscript.openClassContracted` is true */ let openedClasses: string[]; @@ -788,11 +843,13 @@ let incLangConf: vscode.Disposable; let intLangConf: vscode.Disposable; export async function activate(context: vscode.ExtensionContext): Promise { - if (!packageJson.version.includes("SNAPSHOT")) { + if (!packageJson.version.includes("-") || packageJson.version.includes("-beta.")) { + // Don't send telemetry for development builds try { - reporter = new TelemetryReporter(extensionId, extensionVersion, aiKey); - } catch (_error) { - reporter = null; + reporter = new TelemetryReporter(aiKey); + } catch { + // Run without telemetry + reporter = undefined; } } @@ -1020,7 +1077,6 @@ export async function activate(context: vscode.ExtensionContext): Promise { } context.subscriptions.push( - reporter, panel, posPanel, vscode.extensions.onDidChange(async () => { @@ -1061,12 +1117,28 @@ export async function activate(context: vscode.ExtensionContext): Promise { } } }), - vscode.commands.registerCommand("vscode-objectscript.compile", () => importAndCompile(false)), - vscode.commands.registerCommand("vscode-objectscript.touchBar.compile", () => importAndCompile(false)), - vscode.commands.registerCommand("vscode-objectscript.compileWithFlags", () => importAndCompile(true)), - vscode.commands.registerCommand("vscode-objectscript.compileAll", () => namespaceCompile(false)), - vscode.commands.registerCommand("vscode-objectscript.compileAllWithFlags", () => namespaceCompile(true)), + vscode.commands.registerCommand("vscode-objectscript.compile", () => { + sendCommandTelemetryEvent("compile"); + importAndCompile(false); + }), + vscode.commands.registerCommand("vscode-objectscript.touchBar.compile", () => { + sendCommandTelemetryEvent("touchBar.compile"); + importAndCompile(false); + }), + vscode.commands.registerCommand("vscode-objectscript.compileWithFlags", () => { + sendCommandTelemetryEvent("compileWithFlags"); + importAndCompile(true); + }), + vscode.commands.registerCommand("vscode-objectscript.compileAll", () => { + sendCommandTelemetryEvent("compileAll"); + namespaceCompile(false); + }), + vscode.commands.registerCommand("vscode-objectscript.compileAllWithFlags", () => { + sendCommandTelemetryEvent("compileAllWithFlags"); + namespaceCompile(true); + }), vscode.commands.registerCommand("vscode-objectscript.refreshLocalFile", async () => { + sendCommandTelemetryEvent("refreshLocalFile"); const file = currentFile(); if (!file) return; try { @@ -1078,17 +1150,24 @@ export async function activate(context: vscode.ExtensionContext): Promise { ); } }), - vscode.commands.registerCommand("vscode-objectscript.compileFolder", (_file, files) => - Promise.all(files.map((file) => importFileOrFolder(file, false))) - ), - vscode.commands.registerCommand("vscode-objectscript.importFolder", (_file, files) => - Promise.all(files.map((file) => importFileOrFolder(file, true))) - ), - vscode.commands.registerCommand("vscode-objectscript.export", exportAll), + vscode.commands.registerCommand("vscode-objectscript.compileFolder", (_file, files) => { + sendCommandTelemetryEvent("compileFolder"); + Promise.all(files.map((file) => importFileOrFolder(file, false))); + }), + vscode.commands.registerCommand("vscode-objectscript.importFolder", (_file, files) => { + sendCommandTelemetryEvent("importFolder"); + Promise.all(files.map((file) => importFileOrFolder(file, true))); + }), + vscode.commands.registerCommand("vscode-objectscript.export", () => { + sendCommandTelemetryEvent("export"); + exportAll(); + }), vscode.commands.registerCommand("vscode-objectscript.copyToClipboard", (command: string) => { + sendCommandTelemetryEvent("copyToClipboard"); vscode.env.clipboard.writeText(command); }), vscode.commands.registerCommand("vscode-objectscript.debug", (program: string, askArgs: boolean) => { + sendCommandTelemetryEvent("debug"); const startDebugging = (args) => { const programWithArgs = program + (program.includes("##class") || args.length ? `(${args})` : ""); vscode.debug.startDebugging(undefined, { @@ -1113,6 +1192,7 @@ export async function activate(context: vscode.ExtensionContext): Promise { }); }), vscode.commands.registerCommand("vscode-objectscript.pickProcess", async (config) => { + sendCommandTelemetryEvent("pickProcess"); const system = config.system; let connectionUri = vscode.window.activeTextEditor?.document.uri; if (connectionUri) { @@ -1186,51 +1266,90 @@ export async function activate(context: vscode.ExtensionContext): Promise { } }); }), - vscode.commands.registerCommand("vscode-objectscript.jumpToTagAndOffset", jumpToTagAndOffset), - vscode.commands.registerCommand("vscode-objectscript.viewOthers", () => viewOthers(false)), - vscode.commands.registerCommand("vscode-objectscript.serverCommands.sourceControl", mainSourceControlMenu), - vscode.commands.registerCommand( - "vscode-objectscript.serverCommands.contextSourceControl", - contextSourceControlMenu - ), - vscode.commands.registerCommand("vscode-objectscript.serverCommands.other", mainCommandMenu), - vscode.commands.registerCommand("vscode-objectscript.serverCommands.contextOther", contextCommandMenu), - vscode.commands.registerCommand("vscode-objectscript.subclass", subclass), - vscode.commands.registerCommand("vscode-objectscript.superclass", superclass), - vscode.commands.registerCommand("vscode-objectscript.serverActions", serverActions), - vscode.commands.registerCommand("vscode-objectscript.touchBar.viewOthers", () => viewOthers(false)), - vscode.commands.registerCommand("vscode-objectscript.explorer.refresh", () => explorerProvider.refresh()), - vscode.commands.registerCommand("vscode-objectscript.explorer.project.refresh", () => - projectsExplorerProvider.refresh() - ), + vscode.commands.registerCommand("vscode-objectscript.jumpToTagAndOffset", () => { + sendCommandTelemetryEvent("jumpToTagAndOffset"); + jumpToTagAndOffset(); + }), + vscode.commands.registerCommand("vscode-objectscript.viewOthers", () => { + sendCommandTelemetryEvent("viewOthers"); + viewOthers(false); + }), + vscode.commands.registerCommand("vscode-objectscript.serverCommands.sourceControl", (uri?: vscode.Uri) => { + sendCommandTelemetryEvent("serverCommands.sourceControl"); + mainSourceControlMenu(uri); + }), + vscode.commands.registerCommand("vscode-objectscript.serverCommands.contextSourceControl", (uri?: vscode.Uri) => { + sendCommandTelemetryEvent("serverCommands.contextSourceControl"); + contextSourceControlMenu(uri); + }), + vscode.commands.registerCommand("vscode-objectscript.serverCommands.other", (uri?: vscode.Uri) => { + sendCommandTelemetryEvent("serverCommands.other"); + mainCommandMenu(uri); + }), + vscode.commands.registerCommand("vscode-objectscript.serverCommands.contextOther", (uri?: vscode.Uri) => { + sendCommandTelemetryEvent("serverCommands.contextOther"); + contextCommandMenu(uri); + }), + vscode.commands.registerCommand("vscode-objectscript.subclass", () => { + sendCommandTelemetryEvent("subclass"); + subclass(); + }), + vscode.commands.registerCommand("vscode-objectscript.superclass", () => { + sendCommandTelemetryEvent("superclass"); + superclass(); + }), + vscode.commands.registerCommand("vscode-objectscript.serverActions", () => { + sendCommandTelemetryEvent("serverActions"); // TODO remove? + serverActions(); + }), + vscode.commands.registerCommand("vscode-objectscript.touchBar.viewOthers", () => { + sendCommandTelemetryEvent("touchBar.viewOthers"); + viewOthers(false); + }), + vscode.commands.registerCommand("vscode-objectscript.explorer.refresh", () => { + sendCommandTelemetryEvent("explorer.refresh"); + explorerProvider.refresh(); + }), + vscode.commands.registerCommand("vscode-objectscript.explorer.project.refresh", () => { + sendCommandTelemetryEvent("explorer.project.refresh"); + projectsExplorerProvider.refresh(); + }), // Register the vscode-objectscript.explorer.open command elsewhere registerExplorerOpen(), - vscode.commands.registerCommand("vscode-objectscript.explorer.export", (item, items) => - exportExplorerItems(items && items.length ? items : [item]) - ), - vscode.commands.registerCommand("vscode-objectscript.explorer.delete", (item, items) => - deleteExplorerItems(items && items.length ? items : [item]) - ), - vscode.commands.registerCommand("vscode-objectscript.explorer.compile", (item, items) => - compileExplorerItems(items && items.length ? items : [item]) - ), + vscode.commands.registerCommand("vscode-objectscript.explorer.export", (item, items) => { + sendCommandTelemetryEvent("explorer.export"); + exportExplorerItems(items && items.length ? items : [item]); + }), + vscode.commands.registerCommand("vscode-objectscript.explorer.delete", (item, items) => { + sendCommandTelemetryEvent("explorer.delete"); + deleteExplorerItems(items && items.length ? items : [item]); + }), + vscode.commands.registerCommand("vscode-objectscript.explorer.compile", (item, items) => { + sendCommandTelemetryEvent("explorer.compile"); + compileExplorerItems(items && items.length ? items : [item]); + }), vscode.commands.registerCommand("vscode-objectscript.explorer.showGenerated", (workspaceNode: WorkspaceNode) => { + sendCommandTelemetryEvent("explorer.showGenerated"); workspaceState.update(`ExplorerGenerated:${workspaceNode.uniqueId}`, true); return explorerProvider.refresh(); }), vscode.commands.registerCommand("vscode-objectscript.explorer.showSystem", (workspaceNode: WorkspaceNode) => { + sendCommandTelemetryEvent("explorer.showSystem"); workspaceState.update(`ExplorerSystem:${workspaceNode.uniqueId}`, true); return explorerProvider.refresh(); }), vscode.commands.registerCommand("vscode-objectscript.explorer.hideGenerated", (workspaceNode: WorkspaceNode) => { + sendCommandTelemetryEvent("explorer.hideGenerated"); workspaceState.update(`ExplorerGenerated:${workspaceNode.uniqueId}`, false); return explorerProvider.refresh(); }), vscode.commands.registerCommand("vscode-objectscript.explorer.hideSystem", (workspaceNode: WorkspaceNode) => { + sendCommandTelemetryEvent("explorer.hideSystem"); workspaceState.update(`ExplorerSystem:${workspaceNode.uniqueId}`, false); return explorerProvider.refresh(); }), vscode.commands.registerCommand("vscode-objectscript.explorer.otherNamespace", (workspaceNode: WorkspaceNode) => { + sendCommandTelemetryEvent("explorer.otherNamespace"); return explorerProvider.selectNamespace(workspaceNode.label); }), vscode.commands.registerCommand( @@ -1239,13 +1358,16 @@ export async function activate(context: vscode.ExtensionContext): Promise { return explorerProvider.closeExtra4Workspace(workspaceNode.label, workspaceNode.namespace); } ), - vscode.commands.registerCommand("vscode-objectscript.previewXml", () => - previewXMLAsUDL(vscode.window.activeTextEditor) - ), + vscode.commands.registerCommand("vscode-objectscript.previewXml", () => { + sendCommandTelemetryEvent("previewXml"); + previewXMLAsUDL(vscode.window.activeTextEditor); + }), vscode.commands.registerCommand("vscode-objectscript.addServerNamespaceToWorkspace", (resource?: vscode.Uri) => { + sendCommandTelemetryEvent("addServerNamespaceToWorkspace"); addServerNamespaceToWorkspace(resource); }), vscode.commands.registerCommand("vscode-objectscript.connectFolderToServerNamespace", () => { + sendCommandTelemetryEvent("connectFolderToServerNamespace"); connectFolderToServerNamespace(); }), vscode.workspace.registerTextDocumentContentProvider(OBJECTSCRIPT_FILE_SCHEMA, documentContentProvider), @@ -1267,17 +1389,31 @@ export async function activate(context: vscode.ExtensionContext): Promise { documentSelector(clsLangId, macLangId, intLangId), new ObjectScriptCodeLensProvider() ), - vscode.commands.registerCommand("vscode-objectscript.compileOnly", () => compileOnly(false)), - vscode.commands.registerCommand("vscode-objectscript.compileOnlyWithFlags", () => compileOnly(true)), + vscode.commands.registerCommand("vscode-objectscript.compileOnly", () => { + sendCommandTelemetryEvent("compileOnly"); + compileOnly(false); + }), + vscode.commands.registerCommand("vscode-objectscript.compileOnlyWithFlags", () => { + sendCommandTelemetryEvent("compileOnlyWithFlags"); + compileOnly(true); + }), vscode.languages.registerDocumentLinkProvider({ language: outputLangId }, new DocumentLinkProvider()), - vscode.commands.registerCommand("vscode-objectscript.editOthers", () => viewOthers(true)), - vscode.commands.registerCommand("vscode-objectscript.showClassDocumentationPreview", () => - DocumaticPreviewPanel.create() - ), - vscode.commands.registerCommand("vscode-objectscript.showRESTDebugWebview", () => - RESTDebugPanel.create(context.extensionUri) - ), - vscode.commands.registerCommand("vscode-objectscript.exportCurrentFile", exportCurrentFile), + vscode.commands.registerCommand("vscode-objectscript.editOthers", () => { + sendCommandTelemetryEvent("editOthers"); + viewOthers(true); + }), + vscode.commands.registerCommand("vscode-objectscript.showClassDocumentationPreview", () => { + sendCommandTelemetryEvent("showClassDocumentationPreview"); + DocumaticPreviewPanel.create(); + }), + vscode.commands.registerCommand("vscode-objectscript.showRESTDebugWebview", () => { + sendCommandTelemetryEvent("showRESTDebugWebview"); + RESTDebugPanel.create(context.extensionUri); + }), + vscode.commands.registerCommand("vscode-objectscript.exportCurrentFile", () => { + sendCommandTelemetryEvent("exportCurrentFile"); + exportCurrentFile(); + }), vscode.workspace.onDidCreateFiles((e: vscode.FileCreateEvent) => { return Promise.all( e.files @@ -1358,26 +1494,39 @@ export async function activate(context: vscode.ExtensionContext): Promise { } }), vscode.commands.registerCommand("vscode-objectscript.addItemsToProject", (item) => { + sendCommandTelemetryEvent("addItemsToProject"); return modifyProject(item instanceof NodeBase || item instanceof vscode.Uri ? item : undefined, "add"); }), vscode.commands.registerCommand("vscode-objectscript.removeFromProject", (item) => { + sendCommandTelemetryEvent("removeFromProject"); return modifyProject(item instanceof NodeBase || item instanceof vscode.Uri ? item : undefined, "remove"); }), vscode.commands.registerCommand("vscode-objectscript.removeItemsFromProject", (item) => { + sendCommandTelemetryEvent("removeItemsFromProject"); return modifyProject(item instanceof NodeBase || item instanceof vscode.Uri ? item : undefined, "remove"); }), vscode.commands.registerCommand("vscode-objectscript.modifyProjectMetadata", (item) => { + sendCommandTelemetryEvent("modifyProjectMetadata"); return modifyProjectMetadata(item instanceof NodeBase || item instanceof vscode.Uri ? item : undefined); }), - vscode.commands.registerCommand("vscode-objectscript.createProject", (node) => createProject(node)), - vscode.commands.registerCommand("vscode-objectscript.deleteProject", (node) => deleteProject(node)), - vscode.commands.registerCommand("vscode-objectscript.explorer.project.exportProjectContents", (node) => - exportProjectContents(node) - ), - vscode.commands.registerCommand("vscode-objectscript.explorer.project.compileProjectContents", (node) => - compileProjectContents(node) - ), + vscode.commands.registerCommand("vscode-objectscript.createProject", (node) => { + sendCommandTelemetryEvent("createProject"); + createProject(node); + }), + vscode.commands.registerCommand("vscode-objectscript.deleteProject", (node) => { + sendCommandTelemetryEvent("deleteProject"); + deleteProject(node); + }), + vscode.commands.registerCommand("vscode-objectscript.explorer.project.exportProjectContents", (node) => { + sendCommandTelemetryEvent("explorer.project.exportProjectContents"); + exportProjectContents(node); + }), + vscode.commands.registerCommand("vscode-objectscript.explorer.project.compileProjectContents", (node) => { + sendCommandTelemetryEvent("explorer.project.compileProjectContents"); + compileProjectContents(node); + }), vscode.commands.registerCommand("vscode-objectscript.explorer.project.openOtherServerNs", () => { + sendCommandTelemetryEvent("explorer.project.openOtherServerNs"); pickServerAndNamespace().then((pick) => { if (pick != undefined) { projectsExplorerProvider.openExtraServerNs(pick); @@ -1387,9 +1536,10 @@ export async function activate(context: vscode.ExtensionContext): Promise { vscode.commands.registerCommand("vscode-objectscript.explorer.project.closeOtherServerNs", (node) => projectsExplorerProvider.closeExtraServerNs(node) ), - vscode.commands.registerCommand("vscode-objectscript.explorer.project.addWorkspaceFolderForProject", (node) => - addWorkspaceFolderForProject(node) - ), + vscode.commands.registerCommand("vscode-objectscript.explorer.project.addWorkspaceFolderForProject", (node) => { + sendCommandTelemetryEvent("explorer.project.addWorkspaceFolderForProject"); + addWorkspaceFolderForProject(node); + }), vscode.window.registerCustomEditorProvider(lowCodeEditorViewType, new LowCodeEditorProvider(), { webviewOptions: { retainContextWhenHidden: true, @@ -1496,23 +1646,42 @@ export async function activate(context: vscode.ExtensionContext): Promise { posPanel.text = ""; } }), - vscode.commands.registerCommand("vscode-objectscript.loadStudioSnippets", loadStudioSnippets), + vscode.commands.registerCommand("vscode-objectscript.loadStudioSnippets", () => { + sendCommandTelemetryEvent("loadStudioSnippets"); + loadStudioSnippets(); + }), vscode.commands.registerCommand("vscode-objectscript.loadStudioColors", () => { + sendCommandTelemetryEvent("loadStudioColors"); loadStudioColors(languageServerExt); }), - vscode.commands.registerCommand("vscode-objectscript.newFile.businessOperation", () => - newFile(NewFileType.BusinessOperation) - ), - vscode.commands.registerCommand("vscode-objectscript.newFile.bpl", () => newFile(NewFileType.BPL)), - vscode.commands.registerCommand("vscode-objectscript.newFile.rule", () => newFile(NewFileType.Rule)), - vscode.commands.registerCommand("vscode-objectscript.newFile.businessService", () => - newFile(NewFileType.BusinessService) - ), - vscode.commands.registerCommand("vscode-objectscript.newFile.dtl", () => newFile(NewFileType.DTL)), - vscode.commands.registerCommand("vscode-objectscript.newFile.kpi", () => newFile(NewFileType.KPI)), + vscode.commands.registerCommand("vscode-objectscript.newFile.businessOperation", () => { + sendCommandTelemetryEvent("newFile.businessOperation"); + newFile(NewFileType.BusinessOperation); + }), + vscode.commands.registerCommand("vscode-objectscript.newFile.bpl", () => { + sendCommandTelemetryEvent("newFile.bpl"); + newFile(NewFileType.BPL); + }), + vscode.commands.registerCommand("vscode-objectscript.newFile.rule", () => { + sendCommandTelemetryEvent("newFile.rule"); + newFile(NewFileType.Rule); + }), + vscode.commands.registerCommand("vscode-objectscript.newFile.businessService", () => { + sendCommandTelemetryEvent("newFile.businessService"); + newFile(NewFileType.BusinessService); + }), + vscode.commands.registerCommand("vscode-objectscript.newFile.dtl", () => { + sendCommandTelemetryEvent("newFile.dtl"); + newFile(NewFileType.DTL); + }), + vscode.commands.registerCommand("vscode-objectscript.newFile.kpi", () => { + sendCommandTelemetryEvent("newFile.kpi"); + newFile(NewFileType.KPI); + }), vscode.window.registerFileDecorationProvider(fileDecorationProvider), vscode.workspace.onDidOpenTextDocument((doc) => !doc.isUntitled && fileDecorationProvider.emitter.fire(doc.uri)), vscode.commands.registerCommand("vscode-objectscript.importLocalFilesServerSide", (wsFolderUri) => { + sendCommandTelemetryEvent("importLocalFilesServerSide"); if ( wsFolderUri instanceof vscode.Uri && wsFolderUri.scheme == FILESYSTEM_SCHEMA && @@ -1524,12 +1693,21 @@ export async function activate(context: vscode.ExtensionContext): Promise { return importLocalFilesToServerSideFolder(wsFolderUri); } }), - vscode.commands.registerCommand("vscode-objectscript.modifyWsFolder", modifyWsFolder), - vscode.commands.registerCommand("vscode-objectscript.openErrorLocation", openErrorLocation), - vscode.commands.registerCommand("vscode-objectscript.launchWebSocketTerminal", () => launchWebSocketTerminal()), + vscode.commands.registerCommand("vscode-objectscript.modifyWsFolder", (wsFolderUri?: vscode.Uri) => { + sendCommandTelemetryEvent("modifyWsFolder"); + modifyWsFolder(wsFolderUri); + }), + vscode.commands.registerCommand("vscode-objectscript.openErrorLocation", () => { + sendCommandTelemetryEvent("openErrorLocation"); + openErrorLocation(); + }), + vscode.commands.registerCommand("vscode-objectscript.launchWebSocketTerminal", () => { + launchWebSocketTerminal(); + }), vscode.commands.registerCommand( "vscode-objectscript.intersystems-servermanager.webterminal", (namespaceTreeItem) => { + sendCommandTelemetryEvent("intersystems-servermanager.webterminal"); const idArray = namespaceTreeItem.id.split(":"); const serverId = idArray[1]; const namespace = idArray[3]; @@ -1538,6 +1716,7 @@ export async function activate(context: vscode.ExtensionContext): Promise { } ), vscode.commands.registerCommand("vscode-objectscript.ObjectScriptExplorer.webterminal", (node: NodeBase) => { + sendCommandTelemetryEvent("ObjectScriptExplorer.webterminal"); const targetUri = DocumentContentProvider.getUri( node.fullName, node.workspaceFolder, @@ -1580,13 +1759,25 @@ export async function activate(context: vscode.ExtensionContext): Promise { setExplorerContextKeys(); // Fire OpenedDocument UserAction for added folders showing the contents of a server-side project fireOpenProjectUserAction(e.added); + // Send telemetry events for all added folders + sendWsFolderTelemetryEvent(e.added, true); + }), + vscode.commands.registerCommand("vscode-objectscript.importXMLFiles", () => { + sendCommandTelemetryEvent("importXMLFiles"); + importXMLFiles(); + }), + vscode.commands.registerCommand("vscode-objectscript.exportToXMLFile", () => { + sendCommandTelemetryEvent("exportToXMLFile"); + exportDocumentsToXMLFile(); + }), + vscode.commands.registerCommand("vscode-objectscript.extractXMLFileContents", (xmlUri?: vscode.Uri) => { + sendCommandTelemetryEvent("extractXMLFileContents"); + extractXMLFileContents(xmlUri); }), - vscode.commands.registerCommand("vscode-objectscript.importXMLFiles", importXMLFiles), - vscode.commands.registerCommand("vscode-objectscript.exportToXMLFile", exportDocumentsToXMLFile), - vscode.commands.registerCommand("vscode-objectscript.extractXMLFileContents", extractXMLFileContents), vscode.commands.registerCommand( "vscode-objectscript.openPathInBrowser", async (path: string, docUri: vscode.Uri) => { + sendCommandTelemetryEvent("openPathInBrowser"); if (typeof path == "string" && docUri instanceof vscode.Uri) { const api = new AtelierAPI(docUri); // Get the default web application for this namespace. @@ -1608,8 +1799,12 @@ export async function activate(context: vscode.ExtensionContext): Promise { } } ), - vscode.commands.registerCommand("vscode-objectscript.compileIsfs", (uri) => fileSystemProvider.compile(uri)), + vscode.commands.registerCommand("vscode-objectscript.compileIsfs", (uri) => { + sendCommandTelemetryEvent("compileIsfs"); + fileSystemProvider.compile(uri); + }), vscode.commands.registerCommand("vscode-objectscript.openISCDocument", async () => { + sendCommandTelemetryEvent("openISCDocument"); const wsFolder = await getWsFolder( "Pick the workspace folder where you want to open a document", false, @@ -1663,6 +1858,7 @@ export async function activate(context: vscode.ExtensionContext): Promise { } }), vscode.commands.registerCommand("vscode-objectscript.showPlanWebview", (args) => { + sendCommandTelemetryEvent("showPlanWebview"); if (typeof args != "object") return; showPlanWebview(args); }), @@ -1702,7 +1898,21 @@ export async function activate(context: vscode.ExtensionContext): Promise { /* Anything we use from the VS Code proposed API */ ...proposed ); - reporter && reporter.sendTelemetryEvent("extensionActivated"); + + // Send the activation and workspace folders telemetry events + reporter?.sendTelemetryEvent("extensionActivated", { + languageServerVersion: languageServerExt?.packageJSON.version, + serverManagerVersion: smExt?.packageJSON.version, + "config.explorer.alwaysShowServerCopy": String(conf.get("explorer.alwaysShowServerCopy")), + "config.autoAdjustName": String(conf.get("autoAdjustName")), + "config.autoShowTerminal": String(conf.get("autoShowTerminal")), + "config.suppressCompileMessages": String(conf.get("suppressCompileMessages")), + "config.suppressCompileErrorMessages": String(conf.get("suppressCompileErrorMessages")), + "config.autoPreviewXML": String(conf.get("autoPreviewXML")), + "config.showGeneratedFileDecorations": String(conf.get("showGeneratedFileDecorations")), + "config.showProposedApiPrompt": String(conf.get("showProposedApiPrompt")), + }); + sendWsFolderTelemetryEvent(vscode.workspace.workspaceFolders); // The API we export const extensionApi = { @@ -1810,8 +2020,7 @@ export async function deactivate(): Promise { if (workspaceState) { workspaceState.update("openedClasses", openedClasses); } - // This will ensure all pending events get flushed - reporter && reporter.dispose(); + reporter?.dispose(); if (terminals) { terminals.forEach((t) => t.dispose()); } diff --git a/src/providers/LowCodeEditorProvider.ts b/src/providers/LowCodeEditorProvider.ts index 7d52b968..5d274cf3 100644 --- a/src/providers/LowCodeEditorProvider.ts +++ b/src/providers/LowCodeEditorProvider.ts @@ -3,7 +3,7 @@ import { lt } from "semver"; import { AtelierAPI } from "../api"; import { loadChanges } from "../commands/compile"; import { StudioActions } from "../commands/studio"; -import { clsLangId } from "../extension"; +import { clsLangId, sendLowCodeTelemetryEvent } from "../extension"; import { currentFile, notIsfs, openLowCodeEditors, outputChannel } from "../utils"; export class LowCodeEditorProvider implements vscode.CustomTextEditorProvider { @@ -79,6 +79,7 @@ export class LowCodeEditorProvider implements vscode.CustomTextEditorProvider { // Class exists but is not a rule or DTL class return this._errorMessage(`${className} is neither a rule definition class nor a DTL transformation class.`); } + sendLowCodeTelemetryEvent(webApp == this._rule ? "rule" : "dtl", document.uri.scheme); // Add this document to the Set of open low-code editors const documentUriString = document.uri.toString(); diff --git a/src/utils/documentIndex.ts b/src/utils/documentIndex.ts index 9cf36d76..737717c3 100644 --- a/src/utils/documentIndex.ts +++ b/src/utils/documentIndex.ts @@ -15,6 +15,7 @@ import { import { isText } from "istextorbinary"; import { AtelierAPI } from "../api"; import { compile, importFile } from "../commands/compile"; +import { sendClientSideSyncTelemetryEvent } from "../extension"; interface WSFolderIndex { /** The `FileSystemWatcher` for this workspace folder */ @@ -227,6 +228,7 @@ export async function indexWorkspaceFolder(wsFolder: vscode.WorkspaceFolder): Pr change = await updateIndexForDocument(uri, documents, uris); } else if (sync && isImportableLocalFile(uri)) { change.addedOrChanged = await getCurrentFile(uri); + sendClientSideSyncTelemetryEvent(change.addedOrChanged.fileName.split(".").pop().toLowerCase()); } if (!sync || (!change.addedOrChanged && !change.removed)) return; if (change.addedOrChanged) {