Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 41 additions & 4 deletions src/standardLanguageClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import * as net from 'net';
import * as path from 'path';
import { CancellationToken, CodeActionKind, commands, ConfigurationTarget, DocumentSelector, EventEmitter, ExtensionContext, extensions, languages, Location, ProgressLocation, TextEditor, Uri, ViewColumn, window, workspace } from "vscode";
import { ConfigurationParams, ConfigurationRequest, LanguageClientOptions, Location as LSLocation, MessageType, Position as LSPosition, TextDocumentPositionParams, WorkspaceEdit, StaticFeature, ClientCapabilities, FeatureState } from "vscode-languageclient";
import { CancellationToken, CodeActionKind, commands, ConfigurationTarget, DocumentSelector, EventEmitter, ExtensionContext, extensions, languages, Location, ProgressLocation, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceConfiguration } from "vscode";
import { ConfigurationParams, ConfigurationRequest, LanguageClientOptions, Location as LSLocation, MessageType, Position as LSPosition, TextDocumentPositionParams, WorkspaceEdit, StaticFeature, ClientCapabilities, FeatureState, TelemetryEventNotification } from "vscode-languageclient";
import { LanguageClient, StreamInfo } from "vscode-languageclient/node";
import { apiManager } from "./apiManager";
import * as buildPath from './buildpath';
Expand Down Expand Up @@ -336,10 +336,45 @@ export class StandardLanguageClient {
return result;
});

function getJavaSettingsForTelemetry(config: WorkspaceConfiguration) {
// settings whose values we can record
const SETTINGS_BASIC = [
"java.quickfix.showAt", "java.symbols.includeSourceMethodDeclarations",
"java.completion.collapseCompletionItems", "java.completion.guessMethodArguments",
"java.cleanup.actionsOnSave", "java.completion.postfix.enabled",
"java.sharedIndexes.enabled", "java.inlayHints.parameterNames.enabled",
"java.server.launchMode", "java.autobuild.enabled"
];
// settings where we only record their existence
const SETTINGS_CUSTOM = [
"java.settings.url", "java.format.settings.url"
];

let value: any;
const properties = {};

for (const key of SETTINGS_CUSTOM) {
if (config.get(key)) {
properties[key] = true;
}
}
for (const key of SETTINGS_BASIC) {
value = config.get(key);
if (value !== undefined) {
properties[key] = value;
}
}

return properties;
}

this.languageClient.onTelemetry(async (e: TelemetryEvent) => {
apiManager.fireTraceEvent(e);
if (e.name === Telemetry.SERVER_INITIALIZED_EVT) {
return Telemetry.sendTelemetry(Telemetry.STARTUP_EVT, e.properties);
const javaSettings = getJavaSettingsForTelemetry(workspace.getConfiguration());

const properties= { ...e.properties, ...javaSettings };
await Telemetry.sendTelemetry(Telemetry.STARTUP_EVT, );
} else if (e.name === Telemetry.LS_ERROR) {
const tags = [];
const exception: string = e?.properties.exception;
Expand All @@ -357,8 +392,10 @@ export class StandardLanguageClient {

if (tags.length > 0) {
e.properties['tags'] = tags;
return Telemetry.sendTelemetry(Telemetry.LS_ERROR, e.properties);
await Telemetry.sendTelemetry(Telemetry.LS_ERROR, e.properties);
}
} else if (e.name === Telemetry.IMPORT_PROJECT) {
await Telemetry.sendTelemetry(Telemetry.IMPORT_PROJECT, e.properties);
}
});

Expand Down
57 changes: 14 additions & 43 deletions src/telemetry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { TelemetryService, getRedHatService } from "@redhat-developer/vscode-redhat-telemetry";
import { ExtensionContext, workspace, WorkspaceConfiguration } from "vscode";
import { cyrb53 } from "./utils";

/**
* Wrap vscode-redhat-telemetry to suit vscode-java
Expand All @@ -10,7 +11,10 @@ export namespace Telemetry {
export const COMPLETION_EVENT = "textCompletion";
export const SERVER_INITIALIZED_EVT = "java.workspace.initialized";
export const LS_ERROR = "java.ls.error";
export const IMPORT_PROJECT = "java.workspace.importProject";

let telemetryManager: TelemetryService = null;
let workspaceHash;

/**
* Starts the telemetry service
Expand All @@ -22,6 +26,10 @@ export namespace Telemetry {
if (!!telemetryManager) {
throw new Error("The telemetry service for vscode-java has already been started");
}
workspaceHash = cyrb53(workspace.workspaceFolders.map(f => f.uri.toString()).join('|'));
workspace.onDidChangeWorkspaceFolders(() => {
workspaceHash = cyrb53(workspace.workspaceFolders.map(f => f.uri.toString()).join('|'));
});
const redhatService = await getRedHatService(context);
const telemService = await redhatService.getTelemetryService();
telemetryManager = telemService;
Expand All @@ -35,54 +43,17 @@ export namespace Telemetry {
* @param data the telemetry data
* @throws Error if the telemetry service has not been started yet
*/
export async function sendTelemetry(eventName: string, data?: any): Promise<void> {
export async function sendTelemetry(eventName: string, data?: object): Promise<void> {
console.log(`Sending telemetry event: ${eventName} with data: ${JSON.stringify(data)}`);
if (!telemetryManager) {
throw new Error("The telemetry service for vscode-java has not been started yet");
}
const javaSettings = getJavaSettingsForTelemetry(workspace.getConfiguration());

let properties: any;
if (eventName === STARTUP_EVT) {
properties= { ...data, ...javaSettings };
} else {
properties= { ...data};
}

return telemetryManager.send({
const event = {
name: eventName,
properties
});
}

function getJavaSettingsForTelemetry(config: WorkspaceConfiguration) {
// settings whose values we can record
const SETTINGS_BASIC = [
"java.quickfix.showAt", "java.symbols.includeSourceMethodDeclarations",
"java.completion.collapseCompletionItems", "java.completion.guessMethodArguments",
"java.cleanup.actionsOnSave", "java.completion.postfix.enabled",
"java.sharedIndexes.enabled", "java.inlayHints.parameterNames.enabled",
"java.server.launchMode", "java.autobuild.enabled"
];
// settings where we only record their existence
const SETTINGS_CUSTOM = [
"java.settings.url", "java.format.settings.url"
];

let value: any;
const properties = {};

for (const key of SETTINGS_CUSTOM) {
if (config.get(key)) {
properties[key] = true;
}
}
for (const key of SETTINGS_BASIC) {
value = config.get(key);
if (value !== undefined) {
properties[key] = value;
}
}
properties: { workspaceHash, ...data}
};

return properties;
return telemetryManager.send(event);
}
}
20 changes: 20 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,3 +362,23 @@ export function getVSCodeVariablesMap(): any {
keys.forEach(key => res[key] = vscodeVariables(`\${${key}}`));
return res;
}

/*
* cyrb53 (c) 2018 bryc (github.com/bryc)
* Public domain (or MIT if needed). Attribution appreciated.
* A fast and simple 53-bit string hash function with decent collision resistance.
* Largely inspired by MurmurHash2/3, but with a focus on speed/simplicity.
*/
export function cyrb53 (str, seed = 0) {
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i);
h1 = Math.imul(h1 ^ ch, 2654435761);
h2 = Math.imul(h2 ^ ch, 1597334677);
}
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507);
h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909);
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507);
h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909);
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
};