@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.
Files changed (59) hide show
  1. package/lib/common/plugin-api-rpc.d.ts +14 -0
  2. package/lib/common/plugin-api-rpc.d.ts.map +1 -1
  3. package/lib/common/plugin-api-rpc.js +1 -1
  4. package/lib/common/plugin-api-rpc.js.map +1 -1
  5. package/lib/hosted/browser/hosted-plugin.d.ts +2 -0
  6. package/lib/hosted/browser/hosted-plugin.d.ts.map +1 -1
  7. package/lib/hosted/browser/hosted-plugin.js +8 -2
  8. package/lib/hosted/browser/hosted-plugin.js.map +1 -1
  9. package/lib/hosted/browser/worker/worker-main.js +3 -1
  10. package/lib/hosted/browser/worker/worker-main.js.map +1 -1
  11. package/lib/hosted/browser/worker/worker-plugin-module.d.ts.map +1 -1
  12. package/lib/hosted/browser/worker/worker-plugin-module.js +2 -0
  13. package/lib/hosted/browser/worker/worker-plugin-module.js.map +1 -1
  14. package/lib/hosted/node/plugin-host-module.d.ts.map +1 -1
  15. package/lib/hosted/node/plugin-host-module.js +2 -0
  16. package/lib/hosted/node/plugin-host-module.js.map +1 -1
  17. package/lib/hosted/node/plugin-host-rpc.d.ts +3 -0
  18. package/lib/hosted/node/plugin-host-rpc.d.ts.map +1 -1
  19. package/lib/hosted/node/plugin-host-rpc.js +9 -3
  20. package/lib/hosted/node/plugin-host-rpc.js.map +1 -1
  21. package/lib/main/browser/main-context.d.ts.map +1 -1
  22. package/lib/main/browser/main-context.js +3 -0
  23. package/lib/main/browser/main-context.js.map +1 -1
  24. package/lib/main/browser/telemetry-main.d.ts +20 -0
  25. package/lib/main/browser/telemetry-main.d.ts.map +1 -0
  26. package/lib/main/browser/telemetry-main.js +43 -0
  27. package/lib/main/browser/telemetry-main.js.map +1 -0
  28. package/lib/main/browser/telemetry-main.spec.d.ts +2 -0
  29. package/lib/main/browser/telemetry-main.spec.d.ts.map +1 -0
  30. package/lib/main/browser/telemetry-main.spec.js +66 -0
  31. package/lib/main/browser/telemetry-main.spec.js.map +1 -0
  32. package/lib/plugin/plugin-context.d.ts +2 -1
  33. package/lib/plugin/plugin-context.d.ts.map +1 -1
  34. package/lib/plugin/plugin-context.js +2 -3
  35. package/lib/plugin/plugin-context.js.map +1 -1
  36. package/lib/plugin/plugin-manager.d.ts +2 -0
  37. package/lib/plugin/plugin-manager.d.ts.map +1 -1
  38. package/lib/plugin/plugin-manager.js +7 -0
  39. package/lib/plugin/plugin-manager.js.map +1 -1
  40. package/lib/plugin/telemetry-ext.d.ts +23 -7
  41. package/lib/plugin/telemetry-ext.d.ts.map +1 -1
  42. package/lib/plugin/telemetry-ext.js +60 -33
  43. package/lib/plugin/telemetry-ext.js.map +1 -1
  44. package/lib/plugin/telemetry-ext.spec.js +121 -16
  45. package/lib/plugin/telemetry-ext.spec.js.map +1 -1
  46. package/package.json +32 -31
  47. package/src/common/plugin-api-rpc.ts +15 -1
  48. package/src/hosted/browser/hosted-plugin.ts +7 -2
  49. package/src/hosted/browser/worker/worker-main.ts +4 -1
  50. package/src/hosted/browser/worker/worker-plugin-module.ts +2 -0
  51. package/src/hosted/node/plugin-host-module.ts +2 -0
  52. package/src/hosted/node/plugin-host-rpc.ts +10 -4
  53. package/src/main/browser/main-context.ts +4 -0
  54. package/src/main/browser/telemetry-main.spec.ts +77 -0
  55. package/src/main/browser/telemetry-main.ts +46 -0
  56. package/src/plugin/plugin-context.ts +3 -2
  57. package/src/plugin/plugin-manager.ts +6 -0
  58. package/src/plugin/telemetry-ext.spec.ts +158 -17
  59. 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('TelemetryLogger', () => {
23
+ describe('TelemetryExtImpl', () => {
23
24
  const sender = {
24
25
  sendEventData: () => { },
25
26
  sendErrorData: () => { }
26
27
  };
27
28
 
28
- it('reflects the current telemetry enabled state', () => {
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
- expect(logger.telemetryEnabled).to.equal(false);
33
- expect(logger.isUsageEnabled).to.equal(false);
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.isTelemetryEnabled = true;
88
+ telemetry.$onDidChangeTelemetryLevel('error'); // errors become enabled
89
+ expect(changes).to.equal(1);
37
90
 
38
- expect(logger.telemetryEnabled).to.equal(true);
39
- expect(logger.isUsageEnabled).to.equal(true);
40
- expect(logger.isErrorsEnabled).to.equal(true);
91
+ telemetry.$onDidChangeTelemetryLevel('all'); // usage becomes enabled
92
+ expect(changes).to.equal(2);
41
93
 
42
- telemetry.isTelemetryEnabled = false;
94
+ telemetry.$onDidChangeTelemetryLevel('off');
95
+ expect(changes).to.equal(3);
96
+ });
43
97
 
44
- expect(logger.telemetryEnabled).to.equal(false);
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
- expect(logger.isErrorsEnabled).to.equal(false);
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('emits enable-state changes when telemetry is toggled', () => {
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.isTelemetryEnabled = true;
57
- telemetry.isTelemetryEnabled = false;
134
+ telemetry.$onDidChangeTelemetryLevel('all');
135
+ telemetry.$onDidChangeTelemetryLevel('all');
58
136
 
59
- expect(changes).to.equal(2);
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
- export class TelemetryExtImpl {
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
- _isTelemetryEnabled: boolean = false; // telemetry not activated by default
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 isTelemetryEnabled(): boolean {
28
- return this._isTelemetryEnabled;
39
+ get level(): TelemetryLevel {
40
+ return this.currentLevel;
29
41
  }
30
42
 
31
- set isTelemetryEnabled(isTelemetryEnabled: boolean) {
32
- if (this._isTelemetryEnabled !== isTelemetryEnabled) {
33
- this._isTelemetryEnabled = isTelemetryEnabled;
34
- this.onDidChangeTelemetryEnabledEmitter.fire(this._isTelemetryEnabled);
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
- const logger = new TelemetryLogger(sender, this._isTelemetryEnabled, options);
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 _telemetryEnabled: boolean;
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, telemetryEnabled: boolean, options?: TelemetryLoggerOptions) {
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._telemetryEnabled = telemetryEnabled;
64
- this._isErrorsEnabled = telemetryEnabled;
65
- this._isUsageEnabled = telemetryEnabled;
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
- get telemetryEnabled(): boolean {
69
- return this._telemetryEnabled;
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
- set telemetryEnabled(telemetryEnabled: boolean) {
73
- if (this._telemetryEnabled !== telemetryEnabled) {
74
- this._telemetryEnabled = telemetryEnabled;
75
- this.updateEnableStates(telemetryEnabled, telemetryEnabled);
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.telemetryEnabled || !this.isUsageEnabled) {
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.telemetryEnabled || !this.isErrorsEnabled || !this.sender) {
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
- if (this.sender?.flush) {
132
- let tempSender: TelemetrySender | undefined = this.sender;
133
- this.sender = undefined;
134
- Promise.resolve(tempSender.flush!()).then(tempSender = undefined);
135
- } else {
136
- this.sender = undefined;
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 {