Skip to content

Commit e9355fd

Browse files
authored
Throttle LSP error telemetry reporting (#599)
* Throttle LSP error telemetry reporting Signed-off-by: Yevhen Vydolob <yvydolob@redhat.com> * Reduce timeout Signed-off-by: Yevhen Vydolob <yvydolob@redhat.com> * Fix error messages for telemetry Signed-off-by: Yevhen Vydolob <yvydolob@redhat.com>
1 parent af9cd09 commit e9355fd

File tree

2 files changed

+50
-5
lines changed

2 files changed

+50
-5
lines changed

src/telemetry.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ export class TelemetryErrorHandler implements ErrorHandler {
4646
const errorMassagesToSkip = [{ text: 'Warning: Setting the NODE_TLS_REJECT_UNAUTHORIZED', contains: true }];
4747

4848
export class TelemetryOutputChannel implements vscode.OutputChannel {
49+
private errors: string[] | undefined;
50+
private throttleTimeout: NodeJS.Timeout | undefined;
4951
constructor(private readonly delegate: vscode.OutputChannel, private readonly telemetry: TelemetryService) {}
5052

5153
get name(): string {
@@ -65,7 +67,17 @@ export class TelemetryOutputChannel implements vscode.OutputChannel {
6567
if (this.isNeedToSkip(value)) {
6668
return;
6769
}
68-
this.telemetry.send({ name: 'yaml.server.error', properties: { error: this.createErrorMessage(value) } });
70+
if (!this.errors) {
71+
this.errors = [];
72+
}
73+
if (this.throttleTimeout) {
74+
clearTimeout(this.throttleTimeout);
75+
}
76+
this.errors.push(value);
77+
this.throttleTimeout = setTimeout(() => {
78+
this.telemetry.send({ name: 'yaml.server.error', properties: { error: this.createErrorMessage() } });
79+
this.errors = undefined;
80+
}, 50);
6981
}
7082
}
7183

@@ -86,12 +98,17 @@ export class TelemetryOutputChannel implements vscode.OutputChannel {
8698
return false;
8799
}
88100

89-
private createErrorMessage(value: string): string {
90-
if (value.startsWith('[Error')) {
91-
value = value.substr(value.indexOf(']') + 1, value.length).trim();
101+
private createErrorMessage(): string {
102+
const result = [];
103+
for (const value of this.errors) {
104+
if (value.startsWith('[Error')) {
105+
result.push(value.substr(value.indexOf(']') + 1, value.length).trim());
106+
} else {
107+
result.push(value);
108+
}
92109
}
93110

94-
return value;
111+
return result.join('\n');
95112
}
96113

97114
clear(): void {

test/telemetry.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,20 @@ describe('Telemetry Test', () => {
3939
let telemetryChannel: TelemetryOutputChannel;
4040
let outputChannel: sinon.SinonStubbedInstance<vscode.OutputChannel>;
4141
let telemetry: sinon.SinonStubbedInstance<TelemetryService>;
42+
let clock: sinon.SinonFakeTimers;
43+
4244
beforeEach(() => {
4345
outputChannel = sandbox.stub(testOutputChannel);
4446
telemetry = sandbox.stub(new TelemetryStub());
4547
telemetryChannel = new TelemetryOutputChannel(
4648
(outputChannel as unknown) as vscode.OutputChannel,
4749
(telemetry as unknown) as TelemetryService
4850
);
51+
clock = sinon.useFakeTimers();
52+
});
53+
54+
afterEach(() => {
55+
clock.restore();
4956
});
5057

5158
it('should delegate "append" method', () => {
@@ -80,20 +87,41 @@ describe('Telemetry Test', () => {
8087

8188
it('should send telemetry if log error in "append"', () => {
8289
telemetryChannel.append('[Error] Some');
90+
clock.tick(51);
8391
expect(telemetry.send).calledOnceWith({ name: 'yaml.server.error', properties: { error: 'Some' } });
8492
});
8593

8694
it('should send telemetry if log error on "appendLine"', () => {
8795
telemetryChannel.appendLine('[Error] Some error');
96+
clock.tick(51);
8897
expect(telemetry.send).calledOnceWith({ name: 'yaml.server.error', properties: { error: 'Some error' } });
8998
});
9099

91100
it("shouldn't send telemetry if error should be skipped", () => {
92101
telemetryChannel.append(
93102
"[Error - 15:10:33] (node:25052) Warning: Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to '0' makes TLS connections and HTTPS requests insecure by disabling certificate verification."
94103
);
104+
clock.tick(51);
95105
expect(telemetry.send).not.called;
96106
});
107+
108+
it('should throttle send telemetry if "append" called multiple times', () => {
109+
telemetryChannel.append('[Error] Some');
110+
telemetryChannel.append('[Error] Second Error');
111+
clock.tick(51);
112+
expect(telemetry.send).calledOnceWith({ name: 'yaml.server.error', properties: { error: 'Some\nSecond Error' } });
113+
});
114+
115+
it('should throttle send telemetry if "appendLine" called multiple times', () => {
116+
telemetryChannel.appendLine('[Error] Some');
117+
telemetryChannel.appendLine('[Error] Second Error');
118+
telemetryChannel.appendLine('[Error] Third Error');
119+
clock.tick(51);
120+
expect(telemetry.send).calledOnceWith({
121+
name: 'yaml.server.error',
122+
properties: { error: 'Some\nSecond Error\nThird Error' },
123+
});
124+
});
97125
});
98126

99127
describe('TelemetryErrorHandler', () => {

0 commit comments

Comments
 (0)