@theia/plugin-ext 1.76.0-next.34 → 1.76.0-next.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/common/plugin-api-rpc.d.ts +14 -0
- package/lib/common/plugin-api-rpc.d.ts.map +1 -1
- package/lib/common/plugin-api-rpc.js +1 -1
- package/lib/common/plugin-api-rpc.js.map +1 -1
- package/lib/hosted/browser/hosted-plugin.d.ts +2 -0
- package/lib/hosted/browser/hosted-plugin.d.ts.map +1 -1
- package/lib/hosted/browser/hosted-plugin.js +8 -2
- package/lib/hosted/browser/hosted-plugin.js.map +1 -1
- package/lib/hosted/browser/worker/worker-main.js +3 -1
- package/lib/hosted/browser/worker/worker-main.js.map +1 -1
- package/lib/hosted/browser/worker/worker-plugin-module.d.ts.map +1 -1
- package/lib/hosted/browser/worker/worker-plugin-module.js +2 -0
- package/lib/hosted/browser/worker/worker-plugin-module.js.map +1 -1
- package/lib/hosted/node/plugin-host-module.d.ts.map +1 -1
- package/lib/hosted/node/plugin-host-module.js +2 -0
- package/lib/hosted/node/plugin-host-module.js.map +1 -1
- package/lib/hosted/node/plugin-host-rpc.d.ts +3 -0
- package/lib/hosted/node/plugin-host-rpc.d.ts.map +1 -1
- package/lib/hosted/node/plugin-host-rpc.js +9 -3
- package/lib/hosted/node/plugin-host-rpc.js.map +1 -1
- package/lib/main/browser/main-context.d.ts.map +1 -1
- package/lib/main/browser/main-context.js +3 -0
- package/lib/main/browser/main-context.js.map +1 -1
- package/lib/main/browser/telemetry-main.d.ts +20 -0
- package/lib/main/browser/telemetry-main.d.ts.map +1 -0
- package/lib/main/browser/telemetry-main.js +43 -0
- package/lib/main/browser/telemetry-main.js.map +1 -0
- package/lib/main/browser/telemetry-main.spec.d.ts +2 -0
- package/lib/main/browser/telemetry-main.spec.d.ts.map +1 -0
- package/lib/main/browser/telemetry-main.spec.js +66 -0
- package/lib/main/browser/telemetry-main.spec.js.map +1 -0
- package/lib/plugin/plugin-context.d.ts +2 -1
- package/lib/plugin/plugin-context.d.ts.map +1 -1
- package/lib/plugin/plugin-context.js +2 -3
- package/lib/plugin/plugin-context.js.map +1 -1
- package/lib/plugin/plugin-manager.d.ts +2 -0
- package/lib/plugin/plugin-manager.d.ts.map +1 -1
- package/lib/plugin/plugin-manager.js +7 -0
- package/lib/plugin/plugin-manager.js.map +1 -1
- package/lib/plugin/telemetry-ext.d.ts +23 -7
- package/lib/plugin/telemetry-ext.d.ts.map +1 -1
- package/lib/plugin/telemetry-ext.js +60 -33
- package/lib/plugin/telemetry-ext.js.map +1 -1
- package/lib/plugin/telemetry-ext.spec.js +121 -16
- package/lib/plugin/telemetry-ext.spec.js.map +1 -1
- package/package.json +32 -31
- package/src/common/plugin-api-rpc.ts +15 -1
- package/src/hosted/browser/hosted-plugin.ts +7 -2
- package/src/hosted/browser/worker/worker-main.ts +4 -1
- package/src/hosted/browser/worker/worker-plugin-module.ts +2 -0
- package/src/hosted/node/plugin-host-module.ts +2 -0
- package/src/hosted/node/plugin-host-rpc.ts +10 -4
- package/src/main/browser/main-context.ts +4 -0
- package/src/main/browser/telemetry-main.spec.ts +77 -0
- package/src/main/browser/telemetry-main.ts +46 -0
- package/src/plugin/plugin-context.ts +3 -2
- package/src/plugin/plugin-manager.ts +6 -0
- package/src/plugin/telemetry-ext.spec.ts +158 -17
- package/src/plugin/telemetry-ext.ts +63 -33
|
@@ -325,7 +325,8 @@ export function createAPIFactory(
|
|
|
325
325
|
messageRegistryExt: MessageRegistryExt,
|
|
326
326
|
clipboard: ClipboardExt,
|
|
327
327
|
webviewExt: WebviewsExtImpl,
|
|
328
|
-
localizationExt: LocalizationExtImpl
|
|
328
|
+
localizationExt: LocalizationExtImpl,
|
|
329
|
+
telemetryExt: TelemetryExtImpl
|
|
329
330
|
): PluginAPIFactory {
|
|
330
331
|
|
|
331
332
|
const authenticationExt = rpc.set(MAIN_RPC_CONTEXT.AUTHENTICATION_EXT, new AuthenticationExtImpl(rpc));
|
|
@@ -359,12 +360,12 @@ export function createAPIFactory(
|
|
|
359
360
|
const tabsExt = rpc.set(MAIN_RPC_CONTEXT.TABS_EXT, new TabsExtImpl(rpc));
|
|
360
361
|
const customEditorExt = rpc.set(MAIN_RPC_CONTEXT.CUSTOM_EDITORS_EXT, new CustomEditorsExtImpl(rpc, documents, webviewExt));
|
|
361
362
|
const webviewViewsExt = rpc.set(MAIN_RPC_CONTEXT.WEBVIEW_VIEWS_EXT, new WebviewViewsExtImpl(rpc, webviewExt));
|
|
362
|
-
const telemetryExt = rpc.set(MAIN_RPC_CONTEXT.TELEMETRY_EXT, new TelemetryExtImpl());
|
|
363
363
|
const testingExt = rpc.set(MAIN_RPC_CONTEXT.TESTING_EXT, new TestingExtImpl(rpc, commandRegistry));
|
|
364
364
|
const uriExt = rpc.set(MAIN_RPC_CONTEXT.URI_EXT, new UriExtImpl(rpc));
|
|
365
365
|
const lmExt = rpc.set(MAIN_RPC_CONTEXT.MCP_SERVER_DEFINITION_REGISTRY_EXT, new LmExtImpl(rpc));
|
|
366
366
|
const lmToolExt = rpc.set(MAIN_RPC_CONTEXT.LM_TOOLS_EXT, new LanguageModelToolsExtImpl(rpc));
|
|
367
367
|
rpc.set(MAIN_RPC_CONTEXT.DEBUG_EXT, debugExt);
|
|
368
|
+
rpc.set(MAIN_RPC_CONTEXT.TELEMETRY_EXT, telemetryExt);
|
|
368
369
|
|
|
369
370
|
const commandLogger = new PluginLogger(rpc, 'commands-plugin');
|
|
370
371
|
|
|
@@ -37,6 +37,7 @@ import * as theia from '@theia/plugin';
|
|
|
37
37
|
import * as types from './types-impl';
|
|
38
38
|
import { join } from './path';
|
|
39
39
|
import { EnvExtImpl } from './env';
|
|
40
|
+
import { TelemetryExtImpl } from './telemetry-ext';
|
|
40
41
|
import { PreferenceRegistryExtImpl } from './preference-registry';
|
|
41
42
|
import { InternalStorageExt, Memento, GlobalState } from './plugin-storage';
|
|
42
43
|
import { ExtPluginApi } from '../common/plugin-ext-api-contribution';
|
|
@@ -474,6 +475,9 @@ export class PluginManagerExtImpl extends AbstractPluginManagerExtImpl<PluginMan
|
|
|
474
475
|
@inject(WebviewsExtImpl)
|
|
475
476
|
protected readonly webview: WebviewsExtImpl;
|
|
476
477
|
|
|
478
|
+
@inject(TelemetryExtImpl)
|
|
479
|
+
protected readonly telemetryExt: TelemetryExtImpl;
|
|
480
|
+
|
|
477
481
|
private supportedActivationEvents: Set<string>;
|
|
478
482
|
|
|
479
483
|
async $init(params: PluginManagerInitializeParams): Promise<void> {
|
|
@@ -489,6 +493,8 @@ export class PluginManagerExtImpl extends AbstractPluginManagerExtImpl<PluginMan
|
|
|
489
493
|
this.envExt.setAppUriScheme(params.env.appUriScheme);
|
|
490
494
|
|
|
491
495
|
this.preferencesManager.init(params.preferences);
|
|
496
|
+
// must be in place before activation: plugins create their telemetry loggers during `activate()`
|
|
497
|
+
this.telemetryExt.setLevel(params.telemetryLevel ?? 'off');
|
|
492
498
|
|
|
493
499
|
if (params.extApi) {
|
|
494
500
|
this.host.initExtApi(params.extApi);
|
|
@@ -15,47 +15,188 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import * as chai from 'chai';
|
|
18
|
+
import { TelemetryLevel } from '@theia/telemetry/lib/common/telemetry-types';
|
|
18
19
|
import { TelemetryExtImpl } from './telemetry-ext';
|
|
19
20
|
|
|
20
21
|
const expect = chai.expect;
|
|
21
22
|
|
|
22
|
-
describe('
|
|
23
|
+
describe('TelemetryExtImpl', () => {
|
|
23
24
|
const sender = {
|
|
24
25
|
sendEventData: () => { },
|
|
25
26
|
sendErrorData: () => { }
|
|
26
27
|
};
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
interface Expectation {
|
|
30
|
+
isTelemetryEnabled: boolean;
|
|
31
|
+
isUsageEnabled: boolean;
|
|
32
|
+
isErrorsEnabled: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const expectations: Record<TelemetryLevel, Expectation> = {
|
|
36
|
+
off: { isTelemetryEnabled: false, isUsageEnabled: false, isErrorsEnabled: false },
|
|
37
|
+
crash: { isTelemetryEnabled: false, isUsageEnabled: false, isErrorsEnabled: false },
|
|
38
|
+
error: { isTelemetryEnabled: false, isUsageEnabled: false, isErrorsEnabled: true },
|
|
39
|
+
all: { isTelemetryEnabled: true, isUsageEnabled: true, isErrorsEnabled: true }
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
for (const level of ['off', 'crash', 'error', 'all'] as const) {
|
|
43
|
+
const expected = expectations[level];
|
|
44
|
+
|
|
45
|
+
it(`derives the enablement states from telemetry level '${level}'`, () => {
|
|
46
|
+
const telemetry = new TelemetryExtImpl();
|
|
47
|
+
telemetry.$onDidChangeTelemetryLevel(level);
|
|
48
|
+
const logger = telemetry.createTelemetryLogger(sender);
|
|
49
|
+
|
|
50
|
+
expect(telemetry.level).to.equal(level);
|
|
51
|
+
expect(telemetry.isTelemetryEnabled).to.equal(expected.isTelemetryEnabled);
|
|
52
|
+
expect(logger.isUsageEnabled).to.equal(expected.isUsageEnabled);
|
|
53
|
+
expect(logger.isErrorsEnabled).to.equal(expected.isErrorsEnabled);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it(`applies telemetry level '${level}' to loggers created before the level arrived`, () => {
|
|
57
|
+
const telemetry = new TelemetryExtImpl();
|
|
58
|
+
const logger = telemetry.createTelemetryLogger(sender);
|
|
59
|
+
telemetry.$onDidChangeTelemetryLevel(level);
|
|
60
|
+
|
|
61
|
+
expect(logger.isUsageEnabled).to.equal(expected.isUsageEnabled);
|
|
62
|
+
expect(logger.isErrorsEnabled).to.equal(expected.isErrorsEnabled);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
it('only fires onDidChangeTelemetryEnabled when the boolean it reports changes', () => {
|
|
67
|
+
const telemetry = new TelemetryExtImpl();
|
|
68
|
+
const fired: boolean[] = [];
|
|
69
|
+
telemetry.onDidChangeTelemetryEnabled(enabled => fired.push(enabled));
|
|
70
|
+
|
|
71
|
+
telemetry.$onDidChangeTelemetryLevel('crash');
|
|
72
|
+
telemetry.$onDidChangeTelemetryLevel('error');
|
|
73
|
+
telemetry.$onDidChangeTelemetryLevel('all');
|
|
74
|
+
telemetry.$onDidChangeTelemetryLevel('off');
|
|
75
|
+
|
|
76
|
+
expect(fired).to.deep.equal([true, false]);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('fires onDidChangeEnableStates once per transition that changes an enablement state', () => {
|
|
29
80
|
const telemetry = new TelemetryExtImpl();
|
|
30
81
|
const logger = telemetry.createTelemetryLogger(sender);
|
|
82
|
+
let changes = 0;
|
|
83
|
+
logger.onDidChangeEnableStates(() => changes++);
|
|
31
84
|
|
|
32
|
-
|
|
33
|
-
expect(
|
|
34
|
-
expect(logger.isErrorsEnabled).to.equal(false);
|
|
85
|
+
telemetry.$onDidChangeTelemetryLevel('crash'); // off -> crash: both stay false
|
|
86
|
+
expect(changes).to.equal(0);
|
|
35
87
|
|
|
36
|
-
telemetry
|
|
88
|
+
telemetry.$onDidChangeTelemetryLevel('error'); // errors become enabled
|
|
89
|
+
expect(changes).to.equal(1);
|
|
37
90
|
|
|
38
|
-
|
|
39
|
-
expect(
|
|
40
|
-
expect(logger.isErrorsEnabled).to.equal(true);
|
|
91
|
+
telemetry.$onDidChangeTelemetryLevel('all'); // usage becomes enabled
|
|
92
|
+
expect(changes).to.equal(2);
|
|
41
93
|
|
|
42
|
-
telemetry
|
|
94
|
+
telemetry.$onDidChangeTelemetryLevel('off');
|
|
95
|
+
expect(changes).to.equal(3);
|
|
96
|
+
});
|
|
43
97
|
|
|
44
|
-
|
|
98
|
+
it('stops following the level once the logger is disposed', () => {
|
|
99
|
+
const telemetry = new TelemetryExtImpl();
|
|
100
|
+
const logger = telemetry.createTelemetryLogger(sender);
|
|
101
|
+
let changes = 0;
|
|
102
|
+
logger.onDidChangeEnableStates(() => changes++);
|
|
103
|
+
|
|
104
|
+
logger.dispose();
|
|
105
|
+
telemetry.$onDidChangeTelemetryLevel('all');
|
|
45
106
|
expect(logger.isUsageEnabled).to.equal(false);
|
|
46
|
-
|
|
107
|
+
|
|
108
|
+
logger.isUsageEnabled = true;
|
|
109
|
+
expect(changes).to.equal(0);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('logs rather than propagates a sender that fails to flush on disposal', async () => {
|
|
113
|
+
const telemetry = new TelemetryExtImpl();
|
|
114
|
+
const logged: unknown[] = [];
|
|
115
|
+
const consoleError = console.error;
|
|
116
|
+
console.error = (...args: unknown[]) => { logged.push(args); };
|
|
117
|
+
try {
|
|
118
|
+
telemetry.createTelemetryLogger({ ...sender, flush: () => { throw new Error('boom'); } }).dispose();
|
|
119
|
+
telemetry.createTelemetryLogger({ ...sender, flush: () => Promise.reject(new Error('boom')) }).dispose();
|
|
120
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
121
|
+
} finally {
|
|
122
|
+
console.error = consoleError;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
expect(logged).to.have.lengthOf(2);
|
|
47
126
|
});
|
|
48
127
|
|
|
49
|
-
it('
|
|
128
|
+
it('ignores a repeated telemetry level', () => {
|
|
50
129
|
const telemetry = new TelemetryExtImpl();
|
|
51
130
|
const logger = telemetry.createTelemetryLogger(sender);
|
|
52
131
|
let changes = 0;
|
|
53
|
-
|
|
54
132
|
logger.onDidChangeEnableStates(() => changes++);
|
|
55
133
|
|
|
56
|
-
telemetry
|
|
57
|
-
telemetry
|
|
134
|
+
telemetry.$onDidChangeTelemetryLevel('all');
|
|
135
|
+
telemetry.$onDidChangeTelemetryLevel('all');
|
|
58
136
|
|
|
59
|
-
expect(changes).to.equal(
|
|
137
|
+
expect(changes).to.equal(1);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('TelemetryLogger', () => {
|
|
142
|
+
|
|
143
|
+
interface RecordingSender {
|
|
144
|
+
events: string[];
|
|
145
|
+
errors: Error[];
|
|
146
|
+
sendEventData(eventName: string): void;
|
|
147
|
+
sendErrorData(error: Error): void;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function createSender(): RecordingSender {
|
|
151
|
+
const events: string[] = [];
|
|
152
|
+
const errors: Error[] = [];
|
|
153
|
+
return {
|
|
154
|
+
events,
|
|
155
|
+
errors,
|
|
156
|
+
sendEventData: (eventName: string) => events.push(eventName),
|
|
157
|
+
sendErrorData: (error: Error) => errors.push(error)
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
it('delivers errors but suppresses usage at telemetry level \'error\'', () => {
|
|
162
|
+
const telemetry = new TelemetryExtImpl();
|
|
163
|
+
telemetry.$onDidChangeTelemetryLevel('error');
|
|
164
|
+
const sender = createSender();
|
|
165
|
+
const logger = telemetry.createTelemetryLogger(sender);
|
|
166
|
+
|
|
167
|
+
logger.logUsage('usage-event');
|
|
168
|
+
logger.logError('error-event');
|
|
169
|
+
logger.logError(new Error('boom'));
|
|
170
|
+
|
|
171
|
+
expect(sender.events).to.deep.equal(['error-event']);
|
|
172
|
+
expect(sender.errors).to.have.lengthOf(1);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('suppresses usage that a plugin re-enables while the telemetry level forbids it', () => {
|
|
176
|
+
const telemetry = new TelemetryExtImpl();
|
|
177
|
+
telemetry.$onDidChangeTelemetryLevel('off');
|
|
178
|
+
const sender = createSender();
|
|
179
|
+
const logger = telemetry.createTelemetryLogger(sender);
|
|
180
|
+
|
|
181
|
+
logger.isUsageEnabled = true;
|
|
182
|
+
logger.isErrorsEnabled = true;
|
|
183
|
+
logger.logUsage('usage-event');
|
|
184
|
+
logger.logError('error-event');
|
|
185
|
+
|
|
186
|
+
expect(sender.events).to.be.empty;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('refuses to let a plugin assign the telemetry level of its logger', () => {
|
|
190
|
+
const telemetry = new TelemetryExtImpl();
|
|
191
|
+
telemetry.$onDidChangeTelemetryLevel('off');
|
|
192
|
+
const sender = createSender();
|
|
193
|
+
const logger = telemetry.createTelemetryLogger(sender);
|
|
194
|
+
|
|
195
|
+
expect(Reflect.set(logger, 'level', 'all')).to.be.false;
|
|
196
|
+
logger.logUsage('usage-event');
|
|
197
|
+
|
|
198
|
+
expect(logger.level).to.equal('off');
|
|
199
|
+
expect(logger.isUsageEnabled).to.be.false;
|
|
200
|
+
expect(sender.events).to.be.empty;
|
|
60
201
|
});
|
|
61
202
|
});
|
|
@@ -14,33 +14,54 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
|
|
16
16
|
import { Event, Emitter } from '@theia/core/lib/common/event';
|
|
17
|
+
import { Disposable } from '@theia/core/lib/common/disposable';
|
|
17
18
|
import { cloneAndChange } from '@theia/core';
|
|
19
|
+
import { injectable } from '@theia/core/shared/inversify';
|
|
20
|
+
import { TelemetryLevel, isKindAllowedByLevel } from '@theia/telemetry/lib/common/telemetry-types';
|
|
21
|
+
import { TelemetryExt } from '../common/plugin-api-rpc';
|
|
18
22
|
import { mixin } from '../common/types';
|
|
19
23
|
import { TelemetryTrustedValue, TelemetryLoggerOptions } from './types-impl';
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Holds the telemetry level the user consented to and hands it to the loggers plugins create.
|
|
27
|
+
*
|
|
28
|
+
* @experimental
|
|
29
|
+
*/
|
|
30
|
+
@injectable()
|
|
31
|
+
export class TelemetryExtImpl implements TelemetryExt {
|
|
22
32
|
|
|
23
|
-
|
|
33
|
+
protected currentLevel: TelemetryLevel = 'off';
|
|
24
34
|
private readonly onDidChangeTelemetryEnabledEmitter = new Emitter<boolean>();
|
|
25
35
|
readonly onDidChangeTelemetryEnabled: Event<boolean> = this.onDidChangeTelemetryEnabledEmitter.event;
|
|
36
|
+
private readonly onDidChangeTelemetryLevelEmitter = new Emitter<TelemetryLevel>();
|
|
37
|
+
protected readonly onDidChangeTelemetryLevel: Event<TelemetryLevel> = this.onDidChangeTelemetryLevelEmitter.event;
|
|
26
38
|
|
|
27
|
-
get
|
|
28
|
-
return this.
|
|
39
|
+
get level(): TelemetryLevel {
|
|
40
|
+
return this.currentLevel;
|
|
29
41
|
}
|
|
30
42
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
$onDidChangeTelemetryLevel(level: TelemetryLevel): void {
|
|
44
|
+
this.setLevel(level);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
setLevel(level: TelemetryLevel): void {
|
|
48
|
+
if (this.currentLevel === level) {
|
|
49
|
+
return;
|
|
35
50
|
}
|
|
51
|
+
const wasTelemetryEnabled = this.isTelemetryEnabled;
|
|
52
|
+
this.currentLevel = level;
|
|
53
|
+
this.onDidChangeTelemetryLevelEmitter.fire(level);
|
|
54
|
+
if (this.isTelemetryEnabled !== wasTelemetryEnabled) {
|
|
55
|
+
this.onDidChangeTelemetryEnabledEmitter.fire(this.isTelemetryEnabled);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get isTelemetryEnabled(): boolean {
|
|
60
|
+
return isKindAllowedByLevel(this.currentLevel, 'usage');
|
|
36
61
|
}
|
|
37
62
|
|
|
38
63
|
createTelemetryLogger(sender: TelemetrySender, options?: TelemetryLoggerOptions | undefined): TelemetryLogger {
|
|
39
|
-
|
|
40
|
-
this.onDidChangeTelemetryEnabled(isEnabled => {
|
|
41
|
-
logger.telemetryEnabled = isEnabled;
|
|
42
|
-
});
|
|
43
|
-
return logger;
|
|
64
|
+
return new TelemetryLogger(sender, this.currentLevel, this.onDidChangeTelemetryLevel, options);
|
|
44
65
|
}
|
|
45
66
|
}
|
|
46
67
|
|
|
@@ -49,30 +70,36 @@ export class TelemetryLogger {
|
|
|
49
70
|
readonly options: TelemetryLoggerOptions | undefined;
|
|
50
71
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
72
|
readonly commonProperties: Record<string, any>;
|
|
52
|
-
private
|
|
73
|
+
private _level: TelemetryLevel;
|
|
53
74
|
|
|
54
75
|
private readonly onDidChangeEnableStatesEmitter: Emitter<TelemetryLogger> = new Emitter();
|
|
55
76
|
readonly onDidChangeEnableStates: Event<TelemetryLogger> = this.onDidChangeEnableStatesEmitter.event;
|
|
56
77
|
private _isUsageEnabled: boolean;
|
|
57
78
|
private _isErrorsEnabled: boolean;
|
|
79
|
+
private readonly levelSubscription: Disposable;
|
|
58
80
|
|
|
59
|
-
constructor(sender: TelemetrySender,
|
|
81
|
+
constructor(sender: TelemetrySender, level: TelemetryLevel, onDidChangeTelemetryLevel: Event<TelemetryLevel>, options?: TelemetryLoggerOptions) {
|
|
60
82
|
this.sender = sender;
|
|
61
83
|
this.options = options;
|
|
62
84
|
this.commonProperties = this.getCommonProperties();
|
|
63
|
-
this.
|
|
64
|
-
this._isErrorsEnabled =
|
|
65
|
-
this._isUsageEnabled =
|
|
85
|
+
this._level = level;
|
|
86
|
+
this._isErrorsEnabled = isKindAllowedByLevel(level, 'error');
|
|
87
|
+
this._isUsageEnabled = isKindAllowedByLevel(level, 'usage');
|
|
88
|
+
this.levelSubscription = onDidChangeTelemetryLevel(next => this.applyLevel(next));
|
|
66
89
|
}
|
|
67
90
|
|
|
68
|
-
|
|
69
|
-
|
|
91
|
+
/**
|
|
92
|
+
* The telemetry level the user consented to. Must stay read-only: the object handed to a plugin is proxied with a
|
|
93
|
+
* `get` trap only, so a setter here would let the plugin raise its own gate.
|
|
94
|
+
*/
|
|
95
|
+
get level(): TelemetryLevel {
|
|
96
|
+
return this._level;
|
|
70
97
|
}
|
|
71
98
|
|
|
72
|
-
|
|
73
|
-
if (this.
|
|
74
|
-
this.
|
|
75
|
-
this.updateEnableStates(
|
|
99
|
+
private applyLevel(level: TelemetryLevel): void {
|
|
100
|
+
if (this._level !== level) {
|
|
101
|
+
this._level = level;
|
|
102
|
+
this.updateEnableStates(isKindAllowedByLevel(level, 'usage'), isKindAllowedByLevel(level, 'error'));
|
|
76
103
|
}
|
|
77
104
|
}
|
|
78
105
|
|
|
@@ -108,7 +135,7 @@ export class TelemetryLogger {
|
|
|
108
135
|
|
|
109
136
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
110
137
|
logUsage(eventName: string, data?: Record<string, any | TelemetryTrustedValue<any>>): void {
|
|
111
|
-
if (!this.
|
|
138
|
+
if (!isKindAllowedByLevel(this._level, 'usage') || !this.isUsageEnabled) {
|
|
112
139
|
return;
|
|
113
140
|
}
|
|
114
141
|
this.logEvent(eventName, data);
|
|
@@ -116,7 +143,7 @@ export class TelemetryLogger {
|
|
|
116
143
|
|
|
117
144
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
118
145
|
logError(eventNameOrException: string | Error, data?: Record<string, any | TelemetryTrustedValue<any>>): void {
|
|
119
|
-
if (!this.
|
|
146
|
+
if (!isKindAllowedByLevel(this._level, 'error') || !this.isErrorsEnabled || !this.sender) {
|
|
120
147
|
// no sender available or error shall not be sent
|
|
121
148
|
return;
|
|
122
149
|
}
|
|
@@ -128,14 +155,17 @@ export class TelemetryLogger {
|
|
|
128
155
|
}
|
|
129
156
|
|
|
130
157
|
dispose(): void {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
158
|
+
this.levelSubscription.dispose();
|
|
159
|
+
this.onDidChangeEnableStatesEmitter.dispose();
|
|
160
|
+
const sender = this.sender;
|
|
161
|
+
this.sender = undefined;
|
|
162
|
+
const reportFlushFailure = (error: unknown): void => console.error('Failed to flush the telemetry sender.', error);
|
|
163
|
+
try {
|
|
164
|
+
Promise.resolve(sender?.flush?.()).catch(reportFlushFailure);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
reportFlushFailure(error);
|
|
137
167
|
}
|
|
138
|
-
}
|
|
168
|
+
}
|
|
139
169
|
|
|
140
170
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
141
171
|
private logEvent(eventName: string, data?: Record<string, any>): void {
|