Skip to content

Commit c86ce81

Browse files
authored
Merge pull request #342 from Achal1607/telemetry
Initial structure of telemetry feature in the extension
2 parents 52b6a53 + 254a59f commit c86ce81

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1754
-14
lines changed

build.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
patches/l10n-licence.diff
7171
patches/no-security-manager-allow.diff
7272
patches/dev-dependency-licenses.diff
73+
patches/nb-telemetry.diff
7374
</string>
7475
<filterchain>
7576
<tokenfilter delimoutput=" ">

patches/nb-telemetry.diff

Lines changed: 421 additions & 0 deletions
Large diffs are not rendered by default.

vscode/.vscode/launch.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,22 @@
2020
"env": {
2121
"nbcode_userdir": "global"
2222
}
23+
},{
24+
"name": "Debug Telemetry",
25+
"type": "extensionHost",
26+
"request": "launch",
27+
"runtimeExecutable": "${execPath}",
28+
"args": [
29+
"--extensionDevelopmentPath=${workspaceFolder}"
30+
],
31+
"outFiles": [
32+
"${workspaceFolder}/out/**/*.js"
33+
],
34+
"preLaunchTask": "${defaultBuildTask}",
35+
"env": {
36+
"nbcode_userdir": "global",
37+
"oracle.oracle-java.enable.debug-logs": "true"
38+
}
2339
},
2440
{
2541
"name": "Extension Tests",

vscode/l10n/bundle.l10n.en.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,6 @@
9393
"jdk.extension.debugger.error_msg.debugAdapterNotInitialized":"Oracle Java SE Debug Server Adapter not yet initialized. Please wait for a while and try again.",
9494
"jdk.workspace.new.prompt": "Input the directory path where the new file will be generated",
9595
"jdk.extension.utils.error_message.failedHttpsRequest": "Failed to get {url} ({statusCode})",
96-
"jdk.extension.error_msg.notEnabled": "{SERVER_NAME} not enabled"
97-
}
96+
"jdk.extension.error_msg.notEnabled": "{SERVER_NAME} not enabled",
97+
"jdk.telemetry.consent": "Do you want to enable telemetry for {extensionName} extension? You may opt-out or in at any time from the Settings for jdk.telemetry.enabled."
98+
}

vscode/l10n/bundle.l10n.ja.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,6 @@
9393
"jdk.extension.debugger.error_msg.debugAdapterNotInitialized":"Oracle Java SEのデバッグ・サーバー・アダプタが、まだ初期化されていません。しばらく待ってから再試行してください。",
9494
"jdk.workspace.new.prompt": "新しいファイルを生成するディレクトリのパスを入力してください",
9595
"jdk.extension.utils.error_message.failedHttpsRequest": "{url}の取得に失敗しました({statusCode})",
96-
"jdk.extension.error_msg.notEnabled": "{SERVER_NAME}が有効化されていません"
97-
}
96+
"jdk.extension.error_msg.notEnabled": "{SERVER_NAME}が有効化されていません",
97+
"jdk.telemetry.consent": "Do you want to enable telemetry for {extensionName} extension? You may opt-out or in at any time from the Settings for jdk.telemetry.enabled."
98+
}

vscode/l10n/bundle.l10n.zh-cn.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,6 @@
9393
"jdk.extension.debugger.error_msg.debugAdapterNotInitialized":"Oracle Java SE 调试服务器适配器尚未初始化。请稍候,然后重试。",
9494
"jdk.workspace.new.prompt": "输入生成新文件的目录路径",
9595
"jdk.extension.utils.error_message.failedHttpsRequest": "无法获取 {url} ({statusCode})",
96-
"jdk.extension.error_msg.notEnabled": "{SERVER_NAME} 未启用"
97-
}
96+
"jdk.extension.error_msg.notEnabled": "{SERVER_NAME} 未启用",
97+
"jdk.telemetry.consent": "Do you want to enable telemetry for {extensionName} extension? You may opt-out or in at any time from the Settings for jdk.telemetry.enabled."
98+
}

vscode/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@
236236
"type": "boolean",
237237
"default": false,
238238
"description": "%jdk.configuration.disableProjectSearchLimit.description%"
239+
},
240+
"jdk.telemetry.enabled": {
241+
"type": "boolean",
242+
"description": "%jdk.configuration.telemetry.enabled.description%",
243+
"default": false
239244
}
240245
}
241246
},

vscode/package.nls.ja.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"jdk.configuration.runConfig.cwd.description": "作業ディレクトリ",
4747
"jdk.configuration.disableNbJavac.description": "拡張オプション: nb-javacライブラリを無効化すると、選択したJDKからのjavacが使用されます。選択したJDKは少なくともJDK 23である必要があります。",
4848
"jdk.configuration.disableProjectSearchLimit.description": "拡張オプション: プロジェクト情報が含まれているフォルダの検索に対する制限を無効化します。",
49+
"jdk.configuration.telemetry.enabled.description": "Allow the Oracle Java Visual Studio Code extension to collect and send usage data to Oracle servers to help improve the Java platform support. No personal information nor source code is collected. You may refer to our general privacy policy at https://www.oracle.com/legal/privacy/services-privacy-policy/",
4950
"jdk.debugger.configuration.mainClass.description": "プログラムのメイン・クラスへの絶対パス。",
5051
"jdk.debugger.configuration.classPaths.description": "JVMの起動のためのクラスパス。",
5152
"jdk.debugger.configuration.console.description": "プログラムを起動する指定されたコンソール。",
@@ -64,4 +65,4 @@
6465
"jdk.configurationSnippets.name": "Javaアプリケーションの起動",
6566
"jdk.configurationSnippets.label": "Java+: Javaアプリケーションの起動",
6667
"jdk.configurationSnippets.description": "デバッグ・モードでのJavaアプリケーションの起動"
67-
}
68+
}

vscode/package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"jdk.configuration.runConfig.cwd.description": "Working directory",
4747
"jdk.configuration.disableNbJavac.description": "Advanced option: disable nb-javac library, javac from the selected JDK will be used. The selected JDK must be at least JDK 23.",
4848
"jdk.configuration.disableProjectSearchLimit.description": "Advanced option: disable limits on searching in containing folders for project information.",
49+
"jdk.configuration.telemetry.enabled.description": "Allow the Oracle Java Visual Studio Code extension to collect and send usage data to Oracle servers to help improve the Java platform support. No personal information nor source code is collected. You may refer to our general privacy policy at https://www.oracle.com/legal/privacy/services-privacy-policy/",
4950
"jdk.debugger.configuration.mainClass.description": "Absolute path to the program main class.",
5051
"jdk.debugger.configuration.classPaths.description": "The classpaths for launching the JVM.",
5152
"jdk.debugger.configuration.console.description": "The specified console to launch the program.",

vscode/package.nls.zh-cn.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"jdk.configuration.runConfig.cwd.description": "工作目录",
4747
"jdk.configuration.disableNbJavac.description": "高级选项:禁用 nb-javac 库,将使用来自所选 JDK 的 javac。所选 JDK 必须至少为 JDK 23。",
4848
"jdk.configuration.disableProjectSearchLimit.description": "高级选项:禁用在包含项目信息的文件夹中搜索的限制。",
49+
"jdk.configuration.telemetry.enabled.description": "Allow the Oracle Java Visual Studio Code extension to collect and send usage data to Oracle servers to help improve the Java platform support. No personal information nor source code is collected. You may refer to our general privacy policy at https://www.oracle.com/legal/privacy/services-privacy-policy/",
4950
"jdk.debugger.configuration.mainClass.description": "程序主类的绝对路径。",
5051
"jdk.debugger.configuration.classPaths.description": "用于启动 JVM 的类路径。",
5152
"jdk.debugger.configuration.console.description": "用于启动程序的指定控制台。",
@@ -64,4 +65,4 @@
6465
"jdk.configurationSnippets.name": "启动 Java 应用程序",
6566
"jdk.configurationSnippets.label": "Java+:启动 Java 应用程序",
6667
"jdk.configurationSnippets.description": "以调试模式启动 Java 应用程序"
67-
}
68+
}

vscode/src/configurations/configuration.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ export const configKeys = {
3030
runConfigEnv: 'runConfig.env',
3131
verbose: 'verbose',
3232
userdir: 'userdir',
33-
revealInActivteProj: "revealActiveInProjects"
33+
revealInActivteProj: "revealActiveInProjects",
34+
telemetryEnabled: 'telemetry.enabled',
3435
};
3536

3637
export const builtInConfigKeys = {

vscode/src/configurations/handlers.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ export const getBuiltinConfigurationValue = <T>(key: string, defaultValue: T | u
4444
return defaultValue != undefined ? conf?.get(confKey, defaultValue) : conf?.get(confKey) as T;
4545
}
4646

47+
export const inspectConfiguration = (config: string) => {
48+
return workspace.getConfiguration().inspect(config);
49+
}
50+
4751
export const jdkHomeValueHandler = (): string | null => {
4852
return getConfigurationValue(configKeys.jdkHome) ||
4953
process.env.JDK_HOME ||

vscode/src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export namespace jdkDownloaderConstants {
3434

3535
export const OPEN_JDK_VERSION_DOWNLOAD_LINKS: { [key: string]: string } = {
3636
"23": "https://download.java.net/java/GA/jdk23.0.1/c28985cbf10d4e648e4004050f8781aa/11/GPL/openjdk-23.0.1"
37-
};
37+
};
3838
}
3939

4040
export const NODE_WINDOWS_LABEL = "Windows_NT";

vscode/src/extension.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@ import { registerFileProviders } from './lsp/listeners/textDocumentContentProvid
3333
import { ExtensionContextInfo } from './extensionContextInfo';
3434
import { ClientPromise } from './lsp/clientPromise';
3535
import { globalState } from './globalState';
36+
import { Telemetry } from './telemetry/telemetry';
3637

3738
export function activate(context: ExtensionContext): VSNetBeansAPI {
38-
globalState.initialize(new ExtensionContextInfo(context), new ClientPromise());
39+
const contextInfo = new ExtensionContextInfo(context);
40+
globalState.initialize(contextInfo, new ClientPromise());
3941
globalState.getClientPromise().initialize();
4042

43+
Telemetry.initializeTelemetry(contextInfo);
4144
registerConfigChangeListeners(context);
4245
clientInit();
4346

@@ -59,6 +62,7 @@ export function activate(context: ExtensionContext): VSNetBeansAPI {
5962

6063

6164
export function deactivate(): Thenable<void> {
65+
Telemetry.enqueueCloseEvent();
6266
const process = globalState.getNbProcessManager()?.getProcess();
6367
if (process != null) {
6468
process?.kill();

vscode/src/extensionContextInfo.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,7 @@ export class ExtensionContextInfo {
2323
getExtensionStorageUri = () => this.context.extensionUri;
2424
getExtensionContext = () => this.context;
2525
pushSubscription = (listener: Disposable) => this.context.subscriptions.push(listener);
26+
getExtensionId = () => this.context.extension.id;
27+
getPackageJson = () => this.context.extension.packageJSON;
28+
getVscGlobalState = () => this.context.globalState;
2629
}

vscode/src/logger.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@ enum LogLevel {
2020
INFO = 'INFO',
2121
WARN = 'WARN',
2222
ERROR = 'ERROR',
23+
DEBUG = 'DEBUG',
2324
}
2425

2526
export class ExtensionLogger {
2627
private outChannel: OutputChannel;
28+
private isDebugLogEnabled: boolean;
2729

2830
constructor(channelName: string) {
2931
this.outChannel = window.createOutputChannel(channelName);
32+
this.isDebugLogEnabled = process.env['oracle.oracle-java.enable.debug-logs'] === "true";
3033
}
3134

3235
public log(message: string): void {
@@ -44,6 +47,13 @@ export class ExtensionLogger {
4447
this.printLog(formattedMessage);
4548
}
4649

50+
public debug(message: string): void {
51+
if(this.isDebugLogEnabled){
52+
const formattedMessage = `[${LogLevel.DEBUG}]: ${message}`;
53+
this.printLog(formattedMessage);
54+
}
55+
}
56+
4757
public logNoNL(message: string): void {
4858
this.outChannel.append(message);
4959
}

vscode/src/lsp/initializer.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { registerNotificationListeners } from "./listeners/notifications/registe
2828
import { registerRequestListeners } from "./listeners/requests/register";
2929
import { createViews } from "../views/initializer";
3030
import { globalState } from "../globalState";
31+
import { Telemetry } from "../telemetry/telemetry";
3132

3233
const establishConnection = () => new Promise<StreamInfo>((resolve, reject) => {
3334
const nbProcessManager = globalState.getNbProcessManager();
@@ -108,8 +109,8 @@ export const clientInit = () => {
108109

109110
LOGGER.log('Language Client: Starting');
110111
client.start().then(() => {
111-
112-
112+
Telemetry.enqueueStartEvent();
113+
113114
registerListenersAfterClientInit();
114115
registerNotificationListeners(client);
115116
registerRequestListeners(client);

vscode/src/lsp/listeners/notifications/handlers.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import { configKeys } from "../../../configurations/configuration";
2323
import { builtInCommands } from "../../../commands/commands";
2424
import { LOGGER } from '../../../logger';
2525
import { globalState } from "../../../globalState";
26+
import { WorkspaceChangeData, WorkspaceChangeEvent } from "../../../telemetry/events/workspaceChange";
27+
import { Telemetry } from "../../../telemetry/telemetry";
2628

2729
const checkInstallNbJavac = (msg: string) => {
2830
const NO_JAVA_SUPPORT = "Cannot initialize Java support";
@@ -109,6 +111,18 @@ const textEditorDecorationDisposeHandler = (param: any) => {
109111

110112

111113
const telemetryEventHandler = (param: any) => {
114+
if(WorkspaceChangeEvent.NAME === param?.name){
115+
const {projectInfo, numProjects, lspInitTimeTaken, projInitTimeTaken} = param?.properties;
116+
const eventData: WorkspaceChangeData = {
117+
projectInfo,
118+
numProjects,
119+
lspInitTimeTaken,
120+
projInitTimeTaken
121+
};
122+
const workspaceChangeEvent: WorkspaceChangeEvent = new WorkspaceChangeEvent(eventData);
123+
Telemetry.sendTelemetry(workspaceChangeEvent);
124+
return;
125+
}
112126
const ls = globalState.getListener(param);
113127
if (ls) {
114128
for (const listener of ls) {

vscode/src/lsp/nbLanguageClient.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { userConfigsListenedByServer } from '../configurations/configuration';
2222
import { restartWithJDKLater } from './utils';
2323
import { ExtensionLogger } from '../logger';
2424
import { globalState } from '../globalState';
25+
import { Telemetry } from '../telemetry/telemetry';
2526

2627

2728
export class NbLanguageClient extends LanguageClient {
@@ -61,6 +62,7 @@ export class NbLanguageClient extends LanguageClient {
6162
'showHtmlPageSupport': true,
6263
'wantsJavaSupport': true,
6364
'wantsGroovySupport': false,
65+
'wantsTelemetryEnabled': Telemetry.isTelemetryFeatureAvailable,
6466
'commandPrefix': extConstants.COMMAND_PREFIX,
6567
'configurationPrefix': `${extConstants.COMMAND_PREFIX}.`,
6668
'altConfigurationPrefix': `${extConstants.COMMAND_PREFIX}.`

vscode/src/telemetry/config.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Copyright (c) 2024, Oracle and/or its affiliates.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
import { RetryConfig, TelemetryApi } from "./types";
17+
18+
export const TELEMETRY_RETRY_CONFIG: RetryConfig = Object.freeze({
19+
maxRetries: 6,
20+
baseCapacity: 256,
21+
baseTimer: 5 * 1000,
22+
maxDelayMs: 100 * 1000,
23+
backoffFactor: 2,
24+
jitterFactor: 0.25
25+
});
26+
27+
export const TELEMETRY_API: TelemetryApi = Object.freeze({
28+
baseUrl: null,
29+
baseEndpoint: "/vscode/java/sendTelemetry",
30+
version: "/v1"
31+
});
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
Copyright (c) 2024, Oracle and/or its affiliates.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
import { LOGGER } from "../../logger";
17+
import { AnonymousIdManager } from "../impl/AnonymousIdManager";
18+
import { cacheService } from "../impl/cacheServiceImpl";
19+
import { getHashCode } from "../utils";
20+
21+
export interface BaseEventPayload {
22+
vsCodeId: string;
23+
vscSessionId: string;
24+
}
25+
26+
export abstract class BaseEvent<T> {
27+
protected _payload: T & BaseEventPayload;
28+
protected _data: T
29+
30+
constructor(public readonly NAME: string,
31+
public readonly ENDPOINT: string,
32+
data: T
33+
) {
34+
this._data = data;
35+
this._payload = {
36+
vsCodeId: AnonymousIdManager.machineId,
37+
vscSessionId: AnonymousIdManager.sessionId,
38+
...data
39+
};
40+
}
41+
42+
get getPayload(): T & BaseEventPayload {
43+
return this._payload;
44+
}
45+
46+
get getData(): T {
47+
return this._data;
48+
}
49+
50+
public onSuccessPostEventCallback = async (): Promise<void> => {
51+
LOGGER.debug(`${this.NAME} sent successfully`);
52+
}
53+
54+
public onFailPostEventCallback = async (): Promise<void> => {
55+
LOGGER.debug(`${this.NAME} send failed`);
56+
}
57+
58+
protected addEventToCache = (): void => {
59+
const dataString = JSON.stringify(this.getData);
60+
const calculatedHashVal = getHashCode(dataString);
61+
const isAdded = cacheService.put(this.NAME, calculatedHashVal);
62+
63+
LOGGER.debug(`${this.NAME} added in cache ${isAdded ? "Successfully" : "Unsucessfully"}`);
64+
}
65+
}

0 commit comments

Comments
 (0)