Skip to content

Commit 181172a

Browse files
authored
Merge pull request #358 from Achal1607/telemetry
Improvements in telemetry client
2 parents 82149ad + 61e389e commit 181172a

File tree

10 files changed

+187
-82
lines changed

10 files changed

+187
-82
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ build/
66
/nbcode/l10n/locale_zh_CN/release/
77
/nbcode/l10n/locale_ja/nbproject/private/
88
/nbcode/l10n/locale_zh_CN/nbproject/private/
9+
telemetryConfig.json

vscode/.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"preLaunchTask": "${defaultBuildTask}",
3535
"env": {
3636
"nbcode_userdir": "global",
37-
"oracle.oracle-java.enable.debug-logs": "true"
37+
"oracle_oracleJava_enable_debugLogs": "true"
3838
}
3939
},
4040
{

vscode/esbuild.js

Lines changed: 80 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ const scriptConfig = {
1515
};
1616

1717
const watchConfig = {
18-
watch: {
19-
onRebuild(error, result) {
20-
console.log("[watch] build started");
21-
if (error) {
22-
error.errors.forEach(error =>
23-
console.error(`> ${error.location.file}:${error.location.line}:${error.location.column}: error: ${error.text}`)
24-
);
25-
} else {
26-
console.log("[watch] build finished");
27-
}
28-
},
18+
watch: {
19+
onRebuild(error, result) {
20+
console.log("[watch] build started");
21+
if (error) {
22+
error.errors.forEach(error =>
23+
console.error(`> ${error.location.file}:${error.location.line}:${error.location.column}: error: ${error.text}`)
24+
);
25+
} else {
26+
console.log("[watch] build finished");
27+
}
2928
},
30-
};
29+
},
30+
};
3131

3232
const NON_NPM_ARTIFACTORY = new RegExp(
3333
String.raw`"resolved"\s*:\s*"http[s]*://(?!registry.npmjs.org)[^"]+"`,
@@ -43,26 +43,74 @@ const checkAritfactoryUrl = () => {
4343
}
4444
}
4545

46-
(async () => {
47-
const args = process.argv.slice(2);
48-
try {
49-
if (args.includes("--watch")) {
50-
// Build and watch source code
51-
console.log("[watch] build started");
52-
await build({
53-
...scriptConfig,
54-
...watchConfig,
46+
const createTelemetryConfig = () => {
47+
const defaultConfig = {
48+
telemetryRetryConfig: {
49+
maxRetries: 6,
50+
baseCapacity: 256,
51+
baseTimer: 5000,
52+
maxDelayMs: 100000,
53+
backoffFactor: 2,
54+
jitterFactor: 0.25
55+
},
56+
telemetryApi: {
57+
baseUrl: null,
58+
baseEndpoint: "/vscode/java/sendTelemetry",
59+
version: "/v1"
60+
}
61+
}
62+
63+
const envConfig = Object.freeze({
64+
telemetryRetryConfig: {
65+
maxRetries: process.env.TELEMETRY_MAX_RETRIES,
66+
baseCapacity: process.env.TELEMETRY_BASE_CAPACITY,
67+
baseTimer: process.env.TELEMETRY_BASE_TIMER,
68+
maxDelayMs: process.env.TELEMETRY_MAX_DELAY,
69+
backoffFactor: process.env.TELEMETRY_BACKOFF_FACTOR,
70+
jitterFactor: process.env.TELEMETRY_JITTER_FACTOR
71+
},
72+
telemetryApi: {
73+
baseUrl: process.env.TELEMETRY_API_BASE_URL,
74+
baseEndpoint: process.env.TELEMETRY_API_ENDPOINT,
75+
version: process.env.TELEMETRY_API_VERSION
76+
}
77+
});
78+
79+
Object.entries(defaultConfig).forEach(([parent, configs]) => {
80+
if (parent in envConfig) {
81+
Object.entries(configs).forEach(([key, _]) => {
82+
if (envConfig[parent]?.[key]) {
83+
defaultConfig[parent][key] = envConfig[parent][key];
84+
}
5585
});
56-
console.log("[watch] build finished");
57-
} else if(args.includes("--artifactory-check")){
58-
checkAritfactoryUrl();
59-
} else {
60-
// Build source code
61-
await build(scriptConfig);
62-
console.log("build complete");
6386
}
64-
} catch (err) {
65-
process.stderr.write(err.message);
66-
process.exit(1);
87+
});
88+
89+
fs.writeFileSync("telemetryConfig.json", JSON.stringify(defaultConfig, null, 4));
90+
console.log("Telemetry config generated successfully.");
91+
}
92+
93+
(async () => {
94+
const args = process.argv.slice(2);
95+
try {
96+
if (args.includes("--watch")) {
97+
// Build and watch source code
98+
console.log("[watch] build started");
99+
await build({
100+
...scriptConfig,
101+
...watchConfig,
102+
});
103+
console.log("[watch] build finished");
104+
} else if (args.includes("--artifactory-check")) {
105+
checkAritfactoryUrl();
106+
} else {
107+
// Build source code
108+
createTelemetryConfig();
109+
await build(scriptConfig);
110+
console.log("build complete");
67111
}
68-
})();
112+
} catch (err) {
113+
process.stderr.write(err.message);
114+
process.exit(1);
115+
}
116+
})();

vscode/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,4 +804,4 @@
804804
"jsonc-parser": "3.3.1",
805805
"vscode-languageclient": "^9.0.1"
806806
}
807-
}
807+
}

vscode/src/logger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class ExtensionLogger {
2929

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

3535
public log(message: string): void {

vscode/src/lsp/nbLanguageClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export class NbLanguageClient extends LanguageClient {
6262
'showHtmlPageSupport': true,
6363
'wantsJavaSupport': true,
6464
'wantsGroovySupport': false,
65-
'wantsTelemetryEnabled': Telemetry.isTelemetryFeatureAvailable,
65+
'wantsTelemetryEnabled': Telemetry.getIsTelemetryFeatureAvailable(),
6666
'commandPrefix': extConstants.COMMAND_PREFIX,
6767
'configurationPrefix': `${extConstants.COMMAND_PREFIX}.`,
6868
'altConfigurationPrefix': `${extConstants.COMMAND_PREFIX}.`

vscode/src/telemetry/config.ts

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
you may not use this file except in compliance with the License.
66
You may obtain a copy of the License at
77
8-
https://www.apache.org/licenses/LICENSE-2.0
8+
https://www.apache.org/licenses/LICENSE-2.0
99
1010
Unless required by applicable law or agreed to in writing, software
1111
distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,18 +14,58 @@
1414
limitations under the License.
1515
*/
1616
import { RetryConfig, TelemetryApi } from "./types";
17+
import * as path from 'path';
18+
import * as fs from 'fs';
19+
import { LOGGER } from "../logger";
1720

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-
});
21+
export class TelemetryConfiguration {
22+
private static CONFIG_FILE_PATH = path.resolve(__dirname, "..", "..", "telemetryConfig.json");
23+
24+
private static instance: TelemetryConfiguration;
25+
private retryConfig!: RetryConfig;
26+
private apiConfig!: TelemetryApi;
27+
28+
public constructor() {
29+
this.initialize();
30+
}
31+
32+
public static getInstance(): TelemetryConfiguration {
33+
if (!TelemetryConfiguration.instance) {
34+
TelemetryConfiguration.instance = new TelemetryConfiguration();
35+
}
36+
return TelemetryConfiguration.instance;
37+
}
38+
39+
private initialize(): void {
40+
try {
41+
const config = JSON.parse(fs.readFileSync(TelemetryConfiguration.CONFIG_FILE_PATH).toString());
42+
43+
this.retryConfig = Object.freeze({
44+
maxRetries: config.telemetryRetryConfig.maxRetries,
45+
baseCapacity: config.telemetryRetryConfig.baseCapacity,
46+
baseTimer: config.telemetryRetryConfig.baseTimer,
47+
maxDelayMs: config.telemetryRetryConfig.maxDelayMs,
48+
backoffFactor: config.telemetryRetryConfig.backoffFactor,
49+
jitterFactor: config.telemetryRetryConfig.jitterFactor
50+
});
51+
52+
this.apiConfig = Object.freeze({
53+
baseUrl: config.telemetryApi.baseUrl,
54+
baseEndpoint: config.telemetryApi.baseEndpoint,
55+
version: config.telemetryApi.version
56+
});
57+
} catch (error: any) {
58+
LOGGER.error("Error occurred while setting up telemetry config");
59+
LOGGER.error(error.message);
60+
}
61+
}
62+
63+
public getRetryConfig(): Readonly<RetryConfig> {
64+
return this.retryConfig;
65+
}
66+
67+
public getApiConfig(): Readonly<TelemetryApi> {
68+
return this.apiConfig;
69+
}
70+
71+
}

vscode/src/telemetry/impl/postTelemetry.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
16+
import { integer } from "vscode-languageclient";
1617
import { LOGGER } from "../../logger";
17-
import { TELEMETRY_API } from "../config";
18+
import { TelemetryConfiguration } from "../config";
1819
import { BaseEvent } from "../events/baseEvent";
1920

2021
interface TelemetryEventResponse {
@@ -28,9 +29,11 @@ export interface TelemetryPostResponse {
2829
};
2930

3031
export class PostTelemetry {
32+
private TELEMETRY_API = TelemetryConfiguration.getInstance().getApiConfig();
33+
3134
public post = async (events: BaseEvent<any>[]): Promise<TelemetryPostResponse> => {
3235
try {
33-
if (TELEMETRY_API.baseUrl == null) {
36+
if (this.TELEMETRY_API.baseUrl == null) {
3437
return {
3538
success: [],
3639
failures: []
@@ -47,7 +50,7 @@ export class PostTelemetry {
4750
};
4851

4952
private addBaseEndpoint = (endpoint: string) => {
50-
return `${TELEMETRY_API.baseUrl}${TELEMETRY_API.baseEndpoint}${TELEMETRY_API.version}${endpoint}`;
53+
return `${this.TELEMETRY_API.baseUrl}${this.TELEMETRY_API.baseEndpoint}${this.TELEMETRY_API.version}${endpoint}`;
5154
}
5255

5356
private postEvent = (event: BaseEvent<any>): Promise<Response> => {
@@ -57,25 +60,34 @@ export class PostTelemetry {
5760

5861
return fetch(serverEndpoint, {
5962
method: "POST",
60-
body: JSON.stringify(payload)
63+
body: JSON.stringify(payload),
64+
redirect: "follow",
65+
headers: {
66+
"Content-Type": "application/json",
67+
"Accept": "application/json"
68+
}
6169
});
6270
}
6371

6472
private parseTelemetryResponse = (events: BaseEvent<any>[], eventResponses: PromiseSettledResult<Response>[]): TelemetryPostResponse => {
6573
let success: TelemetryEventResponse[] = [], failures: TelemetryEventResponse[] = [];
6674
eventResponses.forEach((eventResponse, index) => {
6775
const event = events[index];
76+
let list: TelemetryEventResponse[] = success;
77+
let statusCode: integer = 0;
6878
if (eventResponse.status === "rejected") {
69-
failures.push({
70-
event,
71-
statusCode: -1
72-
});
79+
list = failures;
80+
statusCode = -1;
7381
} else {
74-
success.push({
75-
statusCode: eventResponse.value.status,
76-
event
77-
});
82+
statusCode = eventResponse.value.status;
83+
if (statusCode <= 0 || statusCode >= 400) {
84+
list = failures;
85+
}
7886
}
87+
list.push({
88+
event,
89+
statusCode
90+
});
7991
});
8092

8193
return {

vscode/src/telemetry/impl/telemetryRetry.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,16 @@
1515
*/
1616

1717
import { LOGGER } from "../../logger";
18-
import { TELEMETRY_RETRY_CONFIG } from "../config";
18+
import { TelemetryConfiguration } from "../config";
1919
import { BaseEvent } from "../events/baseEvent";
2020
import { TelemetryPostResponse } from "./postTelemetry";
2121

2222
export class TelemetryRetry {
23-
private timePeriod: number = TELEMETRY_RETRY_CONFIG.baseTimer;
23+
private TELEMETRY_RETRY_CONFIG = TelemetryConfiguration.getInstance().getRetryConfig();
24+
private timePeriod: number = this.TELEMETRY_RETRY_CONFIG?.baseTimer;
2425
private timeout?: NodeJS.Timeout | null;
2526
private numOfAttemptsWhenTimerHits: number = 1;
26-
private queueCapacity: number = TELEMETRY_RETRY_CONFIG.baseCapacity;
27+
private queueCapacity: number = this.TELEMETRY_RETRY_CONFIG?.baseCapacity;
2728
private numOfAttemptsWhenQueueIsFull: number = 1;
2829
private triggeredDueToQueueOverflow: boolean = false;
2930
private callbackHandler?: () => {};
@@ -45,12 +46,12 @@ export class TelemetryRetry {
4546

4647
private resetTimerParameters = () => {
4748
this.numOfAttemptsWhenTimerHits = 1;
48-
this.timePeriod = TELEMETRY_RETRY_CONFIG.baseTimer;
49+
this.timePeriod = this.TELEMETRY_RETRY_CONFIG.baseTimer;
4950
this.clearTimer();
5051
}
5152

5253
private increaseTimePeriod = (): void => {
53-
if (this.numOfAttemptsWhenTimerHits <= TELEMETRY_RETRY_CONFIG.maxRetries) {
54+
if (this.numOfAttemptsWhenTimerHits <= this.TELEMETRY_RETRY_CONFIG.maxRetries) {
5455
this.timePeriod = this.calculateDelay();
5556
this.numOfAttemptsWhenTimerHits++;
5657
return;
@@ -66,26 +67,26 @@ export class TelemetryRetry {
6667
}
6768

6869
private calculateDelay = (): number => {
69-
const baseDelay = TELEMETRY_RETRY_CONFIG.baseTimer *
70-
Math.pow(TELEMETRY_RETRY_CONFIG.backoffFactor, this.numOfAttemptsWhenTimerHits);
70+
const baseDelay = this.TELEMETRY_RETRY_CONFIG.baseTimer *
71+
Math.pow(this.TELEMETRY_RETRY_CONFIG.backoffFactor, this.numOfAttemptsWhenTimerHits);
7172

72-
const cappedDelay = Math.min(baseDelay, TELEMETRY_RETRY_CONFIG.maxDelayMs);
73+
const cappedDelay = Math.min(baseDelay, this.TELEMETRY_RETRY_CONFIG.maxDelayMs);
7374

74-
const jitterMultiplier = 1 + (Math.random() * 2 - 1) * TELEMETRY_RETRY_CONFIG.jitterFactor;
75+
const jitterMultiplier = 1 + (Math.random() * 2 - 1) * this.TELEMETRY_RETRY_CONFIG.jitterFactor;
7576

7677
return Math.floor(cappedDelay * jitterMultiplier);
7778
};
7879

7980
private increaseQueueCapacity = (): void => {
80-
if (this.numOfAttemptsWhenQueueIsFull < TELEMETRY_RETRY_CONFIG.maxRetries) {
81-
this.queueCapacity = TELEMETRY_RETRY_CONFIG.baseCapacity *
82-
Math.pow(TELEMETRY_RETRY_CONFIG.backoffFactor, this.numOfAttemptsWhenQueueIsFull);
81+
if (this.numOfAttemptsWhenQueueIsFull < this.TELEMETRY_RETRY_CONFIG.maxRetries) {
82+
this.queueCapacity = this.TELEMETRY_RETRY_CONFIG.baseCapacity *
83+
Math.pow(this.TELEMETRY_RETRY_CONFIG.backoffFactor, this.numOfAttemptsWhenQueueIsFull);
8384
}
8485
throw new Error("Number of retries exceeded");
8586
}
8687

8788
private resetQueueCapacity = (): void => {
88-
this.queueCapacity = TELEMETRY_RETRY_CONFIG.baseCapacity;
89+
this.queueCapacity = this.TELEMETRY_RETRY_CONFIG.baseCapacity;
8990
this.numOfAttemptsWhenQueueIsFull = 1;
9091
this.triggeredDueToQueueOverflow = false;
9192
}

0 commit comments

Comments
 (0)