Skip to content

Commit

Permalink
Merge pull request #342 from Achal1607/telemetry
Browse files Browse the repository at this point in the history
Initial structure of telemetry feature in the extension
  • Loading branch information
sid-srini authored Dec 16, 2024
2 parents 52b6a53 + 254a59f commit c86ce81
Show file tree
Hide file tree
Showing 42 changed files with 1,754 additions and 14 deletions.
1 change: 1 addition & 0 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
patches/l10n-licence.diff
patches/no-security-manager-allow.diff
patches/dev-dependency-licenses.diff
patches/nb-telemetry.diff
</string>
<filterchain>
<tokenfilter delimoutput=" ">
Expand Down
421 changes: 421 additions & 0 deletions patches/nb-telemetry.diff

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions vscode/.vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@
"env": {
"nbcode_userdir": "global"
}
},{
"name": "Debug Telemetry",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}",
"env": {
"nbcode_userdir": "global",
"oracle.oracle-java.enable.debug-logs": "true"
}
},
{
"name": "Extension Tests",
Expand Down
5 changes: 3 additions & 2 deletions vscode/l10n/bundle.l10n.en.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,6 @@
"jdk.extension.debugger.error_msg.debugAdapterNotInitialized":"Oracle Java SE Debug Server Adapter not yet initialized. Please wait for a while and try again.",
"jdk.workspace.new.prompt": "Input the directory path where the new file will be generated",
"jdk.extension.utils.error_message.failedHttpsRequest": "Failed to get {url} ({statusCode})",
"jdk.extension.error_msg.notEnabled": "{SERVER_NAME} not enabled"
}
"jdk.extension.error_msg.notEnabled": "{SERVER_NAME} not enabled",
"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."
}
5 changes: 3 additions & 2 deletions vscode/l10n/bundle.l10n.ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,6 @@
"jdk.extension.debugger.error_msg.debugAdapterNotInitialized":"Oracle Java SEのデバッグ・サーバー・アダプタが、まだ初期化されていません。しばらく待ってから再試行してください。",
"jdk.workspace.new.prompt": "新しいファイルを生成するディレクトリのパスを入力してください",
"jdk.extension.utils.error_message.failedHttpsRequest": "{url}の取得に失敗しました({statusCode})",
"jdk.extension.error_msg.notEnabled": "{SERVER_NAME}が有効化されていません"
}
"jdk.extension.error_msg.notEnabled": "{SERVER_NAME}が有効化されていません",
"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."
}
5 changes: 3 additions & 2 deletions vscode/l10n/bundle.l10n.zh-cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,6 @@
"jdk.extension.debugger.error_msg.debugAdapterNotInitialized":"Oracle Java SE 调试服务器适配器尚未初始化。请稍候,然后重试。",
"jdk.workspace.new.prompt": "输入生成新文件的目录路径",
"jdk.extension.utils.error_message.failedHttpsRequest": "无法获取 {url} ({statusCode})",
"jdk.extension.error_msg.notEnabled": "{SERVER_NAME} 未启用"
}
"jdk.extension.error_msg.notEnabled": "{SERVER_NAME} 未启用",
"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."
}
5 changes: 5 additions & 0 deletions vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@
"type": "boolean",
"default": false,
"description": "%jdk.configuration.disableProjectSearchLimit.description%"
},
"jdk.telemetry.enabled": {
"type": "boolean",
"description": "%jdk.configuration.telemetry.enabled.description%",
"default": false
}
}
},
Expand Down
3 changes: 2 additions & 1 deletion vscode/package.nls.ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"jdk.configuration.runConfig.cwd.description": "作業ディレクトリ",
"jdk.configuration.disableNbJavac.description": "拡張オプション: nb-javacライブラリを無効化すると、選択したJDKからのjavacが使用されます。選択したJDKは少なくともJDK 23である必要があります。",
"jdk.configuration.disableProjectSearchLimit.description": "拡張オプション: プロジェクト情報が含まれているフォルダの検索に対する制限を無効化します。",
"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/",
"jdk.debugger.configuration.mainClass.description": "プログラムのメイン・クラスへの絶対パス。",
"jdk.debugger.configuration.classPaths.description": "JVMの起動のためのクラスパス。",
"jdk.debugger.configuration.console.description": "プログラムを起動する指定されたコンソール。",
Expand All @@ -64,4 +65,4 @@
"jdk.configurationSnippets.name": "Javaアプリケーションの起動",
"jdk.configurationSnippets.label": "Java+: Javaアプリケーションの起動",
"jdk.configurationSnippets.description": "デバッグ・モードでのJavaアプリケーションの起動"
}
}
1 change: 1 addition & 0 deletions vscode/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"jdk.configuration.runConfig.cwd.description": "Working directory",
"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.",
"jdk.configuration.disableProjectSearchLimit.description": "Advanced option: disable limits on searching in containing folders for project information.",
"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/",
"jdk.debugger.configuration.mainClass.description": "Absolute path to the program main class.",
"jdk.debugger.configuration.classPaths.description": "The classpaths for launching the JVM.",
"jdk.debugger.configuration.console.description": "The specified console to launch the program.",
Expand Down
3 changes: 2 additions & 1 deletion vscode/package.nls.zh-cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"jdk.configuration.runConfig.cwd.description": "工作目录",
"jdk.configuration.disableNbJavac.description": "高级选项:禁用 nb-javac 库,将使用来自所选 JDK 的 javac。所选 JDK 必须至少为 JDK 23。",
"jdk.configuration.disableProjectSearchLimit.description": "高级选项:禁用在包含项目信息的文件夹中搜索的限制。",
"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/",
"jdk.debugger.configuration.mainClass.description": "程序主类的绝对路径。",
"jdk.debugger.configuration.classPaths.description": "用于启动 JVM 的类路径。",
"jdk.debugger.configuration.console.description": "用于启动程序的指定控制台。",
Expand All @@ -64,4 +65,4 @@
"jdk.configurationSnippets.name": "启动 Java 应用程序",
"jdk.configurationSnippets.label": "Java+:启动 Java 应用程序",
"jdk.configurationSnippets.description": "以调试模式启动 Java 应用程序"
}
}
3 changes: 2 additions & 1 deletion vscode/src/configurations/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export const configKeys = {
runConfigEnv: 'runConfig.env',
verbose: 'verbose',
userdir: 'userdir',
revealInActivteProj: "revealActiveInProjects"
revealInActivteProj: "revealActiveInProjects",
telemetryEnabled: 'telemetry.enabled',
};

export const builtInConfigKeys = {
Expand Down
4 changes: 4 additions & 0 deletions vscode/src/configurations/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export const getBuiltinConfigurationValue = <T>(key: string, defaultValue: T | u
return defaultValue != undefined ? conf?.get(confKey, defaultValue) : conf?.get(confKey) as T;
}

export const inspectConfiguration = (config: string) => {
return workspace.getConfiguration().inspect(config);
}

export const jdkHomeValueHandler = (): string | null => {
return getConfigurationValue(configKeys.jdkHome) ||
process.env.JDK_HOME ||
Expand Down
2 changes: 1 addition & 1 deletion vscode/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export namespace jdkDownloaderConstants {

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

export const NODE_WINDOWS_LABEL = "Windows_NT";
6 changes: 5 additions & 1 deletion vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,14 @@ import { registerFileProviders } from './lsp/listeners/textDocumentContentProvid
import { ExtensionContextInfo } from './extensionContextInfo';
import { ClientPromise } from './lsp/clientPromise';
import { globalState } from './globalState';
import { Telemetry } from './telemetry/telemetry';

export function activate(context: ExtensionContext): VSNetBeansAPI {
globalState.initialize(new ExtensionContextInfo(context), new ClientPromise());
const contextInfo = new ExtensionContextInfo(context);
globalState.initialize(contextInfo, new ClientPromise());
globalState.getClientPromise().initialize();

Telemetry.initializeTelemetry(contextInfo);
registerConfigChangeListeners(context);
clientInit();

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


export function deactivate(): Thenable<void> {
Telemetry.enqueueCloseEvent();
const process = globalState.getNbProcessManager()?.getProcess();
if (process != null) {
process?.kill();
Expand Down
3 changes: 3 additions & 0 deletions vscode/src/extensionContextInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ export class ExtensionContextInfo {
getExtensionStorageUri = () => this.context.extensionUri;
getExtensionContext = () => this.context;
pushSubscription = (listener: Disposable) => this.context.subscriptions.push(listener);
getExtensionId = () => this.context.extension.id;
getPackageJson = () => this.context.extension.packageJSON;
getVscGlobalState = () => this.context.globalState;
}
10 changes: 10 additions & 0 deletions vscode/src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ enum LogLevel {
INFO = 'INFO',
WARN = 'WARN',
ERROR = 'ERROR',
DEBUG = 'DEBUG',
}

export class ExtensionLogger {
private outChannel: OutputChannel;
private isDebugLogEnabled: boolean;

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

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

public debug(message: string): void {
if(this.isDebugLogEnabled){
const formattedMessage = `[${LogLevel.DEBUG}]: ${message}`;
this.printLog(formattedMessage);
}
}

public logNoNL(message: string): void {
this.outChannel.append(message);
}
Expand Down
5 changes: 3 additions & 2 deletions vscode/src/lsp/initializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { registerNotificationListeners } from "./listeners/notifications/registe
import { registerRequestListeners } from "./listeners/requests/register";
import { createViews } from "../views/initializer";
import { globalState } from "../globalState";
import { Telemetry } from "../telemetry/telemetry";

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

LOGGER.log('Language Client: Starting');
client.start().then(() => {


Telemetry.enqueueStartEvent();
registerListenersAfterClientInit();
registerNotificationListeners(client);
registerRequestListeners(client);
Expand Down
14 changes: 14 additions & 0 deletions vscode/src/lsp/listeners/notifications/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { configKeys } from "../../../configurations/configuration";
import { builtInCommands } from "../../../commands/commands";
import { LOGGER } from '../../../logger';
import { globalState } from "../../../globalState";
import { WorkspaceChangeData, WorkspaceChangeEvent } from "../../../telemetry/events/workspaceChange";
import { Telemetry } from "../../../telemetry/telemetry";

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


const telemetryEventHandler = (param: any) => {
if(WorkspaceChangeEvent.NAME === param?.name){
const {projectInfo, numProjects, lspInitTimeTaken, projInitTimeTaken} = param?.properties;
const eventData: WorkspaceChangeData = {
projectInfo,
numProjects,
lspInitTimeTaken,
projInitTimeTaken
};
const workspaceChangeEvent: WorkspaceChangeEvent = new WorkspaceChangeEvent(eventData);
Telemetry.sendTelemetry(workspaceChangeEvent);
return;
}
const ls = globalState.getListener(param);
if (ls) {
for (const listener of ls) {
Expand Down
2 changes: 2 additions & 0 deletions vscode/src/lsp/nbLanguageClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { userConfigsListenedByServer } from '../configurations/configuration';
import { restartWithJDKLater } from './utils';
import { ExtensionLogger } from '../logger';
import { globalState } from '../globalState';
import { Telemetry } from '../telemetry/telemetry';


export class NbLanguageClient extends LanguageClient {
Expand Down Expand Up @@ -61,6 +62,7 @@ export class NbLanguageClient extends LanguageClient {
'showHtmlPageSupport': true,
'wantsJavaSupport': true,
'wantsGroovySupport': false,
'wantsTelemetryEnabled': Telemetry.isTelemetryFeatureAvailable,
'commandPrefix': extConstants.COMMAND_PREFIX,
'configurationPrefix': `${extConstants.COMMAND_PREFIX}.`,
'altConfigurationPrefix': `${extConstants.COMMAND_PREFIX}.`
Expand Down
31 changes: 31 additions & 0 deletions vscode/src/telemetry/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Copyright (c) 2024, Oracle and/or its affiliates.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { RetryConfig, TelemetryApi } from "./types";

export const TELEMETRY_RETRY_CONFIG: RetryConfig = Object.freeze({
maxRetries: 6,
baseCapacity: 256,
baseTimer: 5 * 1000,
maxDelayMs: 100 * 1000,
backoffFactor: 2,
jitterFactor: 0.25
});

export const TELEMETRY_API: TelemetryApi = Object.freeze({
baseUrl: null,
baseEndpoint: "/vscode/java/sendTelemetry",
version: "/v1"
});
65 changes: 65 additions & 0 deletions vscode/src/telemetry/events/baseEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
Copyright (c) 2024, Oracle and/or its affiliates.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { LOGGER } from "../../logger";
import { AnonymousIdManager } from "../impl/AnonymousIdManager";
import { cacheService } from "../impl/cacheServiceImpl";
import { getHashCode } from "../utils";

export interface BaseEventPayload {
vsCodeId: string;
vscSessionId: string;
}

export abstract class BaseEvent<T> {
protected _payload: T & BaseEventPayload;
protected _data: T

constructor(public readonly NAME: string,
public readonly ENDPOINT: string,
data: T
) {
this._data = data;
this._payload = {
vsCodeId: AnonymousIdManager.machineId,
vscSessionId: AnonymousIdManager.sessionId,
...data
};
}

get getPayload(): T & BaseEventPayload {
return this._payload;
}

get getData(): T {
return this._data;
}

public onSuccessPostEventCallback = async (): Promise<void> => {
LOGGER.debug(`${this.NAME} sent successfully`);
}

public onFailPostEventCallback = async (): Promise<void> => {
LOGGER.debug(`${this.NAME} send failed`);
}

protected addEventToCache = (): void => {
const dataString = JSON.stringify(this.getData);
const calculatedHashVal = getHashCode(dataString);
const isAdded = cacheService.put(this.NAME, calculatedHashVal);

LOGGER.debug(`${this.NAME} added in cache ${isAdded ? "Successfully" : "Unsucessfully"}`);
}
}
Loading

0 comments on commit c86ce81

Please sign in to comment.