@theia/core 1.73.0-next.3 → 1.73.0-next.39
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/README.md +19 -9
- package/lib/browser/authentication-service.d.ts +2 -0
- package/lib/browser/authentication-service.d.ts.map +1 -1
- package/lib/browser/authentication-service.js +8 -2
- package/lib/browser/authentication-service.js.map +1 -1
- package/lib/browser/catalog.json +222 -66
- package/lib/browser/frontend-application.d.ts +2 -0
- package/lib/browser/frontend-application.d.ts.map +1 -1
- package/lib/browser/frontend-application.js +15 -9
- package/lib/browser/frontend-application.js.map +1 -1
- package/lib/browser/json-schema-store.d.ts +2 -0
- package/lib/browser/json-schema-store.d.ts.map +1 -1
- package/lib/browser/json-schema-store.js +8 -2
- package/lib/browser/json-schema-store.js.map +1 -1
- package/lib/browser/keybinding.js +2 -1
- package/lib/browser/keybinding.js.map +1 -1
- package/lib/browser/markdown-rendering/markdown.d.ts +1 -1
- package/lib/browser/markdown-rendering/markdown.d.ts.map +1 -1
- package/lib/browser/markdown-rendering/markdown.js +1 -1
- package/lib/browser/markdown-rendering/markdown.js.map +1 -1
- package/lib/browser/menu/composite-menu-node.js +4 -4
- package/lib/browser/menu/composite-menu-node.js.map +1 -1
- package/lib/browser/preferences/frontend-config-preference-contributions.d.ts +2 -0
- package/lib/browser/preferences/frontend-config-preference-contributions.d.ts.map +1 -1
- package/lib/browser/preferences/frontend-config-preference-contributions.js +7 -1
- package/lib/browser/preferences/frontend-config-preference-contributions.js.map +1 -1
- package/lib/browser/preferences/preference-proxy.spec.js +7 -0
- package/lib/browser/preferences/preference-proxy.spec.js.map +1 -1
- package/lib/browser/preferences/preference-schema-provider.spec.js +3 -0
- package/lib/browser/preferences/preference-schema-provider.spec.js.map +1 -1
- package/lib/browser/preferences/preference-validation-service.d.ts +2 -0
- package/lib/browser/preferences/preference-validation-service.d.ts.map +1 -1
- package/lib/browser/preferences/preference-validation-service.js +11 -5
- package/lib/browser/preferences/preference-validation-service.js.map +1 -1
- package/lib/browser/preferences/preference-validation-service.spec.js +2 -0
- package/lib/browser/preferences/preference-validation-service.spec.js.map +1 -1
- package/lib/browser/quick-input/quick-view-service.d.ts +1 -0
- package/lib/browser/quick-input/quick-view-service.d.ts.map +1 -1
- package/lib/browser/quick-input/quick-view-service.js +6 -1
- package/lib/browser/quick-input/quick-view-service.js.map +1 -1
- package/lib/browser/quick-input/quick-view-service.spec.d.ts +2 -0
- package/lib/browser/quick-input/quick-view-service.spec.d.ts.map +1 -0
- package/lib/browser/quick-input/quick-view-service.spec.js +41 -0
- package/lib/browser/quick-input/quick-view-service.spec.js.map +1 -0
- package/lib/browser/secondary-window-handler.d.ts +2 -0
- package/lib/browser/secondary-window-handler.d.ts.map +1 -1
- package/lib/browser/secondary-window-handler.js +12 -6
- package/lib/browser/secondary-window-handler.js.map +1 -1
- package/lib/browser/shell/application-shell.d.ts +2 -0
- package/lib/browser/shell/application-shell.d.ts.map +1 -1
- package/lib/browser/shell/application-shell.js +9 -3
- package/lib/browser/shell/application-shell.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js +4 -4
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js +2 -2
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.js +131 -0
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.js.map +1 -1
- package/lib/browser/status-bar/status-bar.d.ts +2 -2
- package/lib/browser/status-bar/status-bar.d.ts.map +1 -1
- package/lib/browser/status-bar/status-bar.js.map +1 -1
- package/lib/browser/test/jsdom.d.ts +4 -0
- package/lib/browser/test/jsdom.d.ts.map +1 -1
- package/lib/browser/test/jsdom.js +18 -0
- package/lib/browser/test/jsdom.js.map +1 -1
- package/lib/browser/tree/tree-container.spec.js +4 -0
- package/lib/browser/tree/tree-container.spec.js.map +1 -1
- package/lib/browser/tree/tree-widget.js +2 -2
- package/lib/browser/tree/tree-widget.js.map +1 -1
- package/lib/browser/tree/tree.d.ts +2 -0
- package/lib/browser/tree/tree.d.ts.map +1 -1
- package/lib/browser/tree/tree.js +7 -1
- package/lib/browser/tree/tree.js.map +1 -1
- package/lib/browser/window/default-window-service.d.ts +2 -1
- package/lib/browser/window/default-window-service.d.ts.map +1 -1
- package/lib/browser/window/default-window-service.js +10 -5
- package/lib/browser/window/default-window-service.js.map +1 -1
- package/lib/browser/window/default-window-service.spec.js +2 -0
- package/lib/browser/window/default-window-service.spec.js.map +1 -1
- package/lib/browser-only/messaging/frontend-only-service-connection-provider.d.ts +2 -0
- package/lib/browser-only/messaging/frontend-only-service-connection-provider.d.ts.map +1 -1
- package/lib/browser-only/messaging/frontend-only-service-connection-provider.js +8 -2
- package/lib/browser-only/messaging/frontend-only-service-connection-provider.js.map +1 -1
- package/lib/common/command.d.ts +2 -0
- package/lib/common/command.d.ts.map +1 -1
- package/lib/common/command.js +10 -4
- package/lib/common/command.js.map +1 -1
- package/lib/common/preferences/injectable-preference-proxy.d.ts +3 -3
- package/lib/common/preferences/injectable-preference-proxy.d.ts.map +1 -1
- package/lib/common/preferences/injectable-preference-proxy.js +6 -1
- package/lib/common/preferences/injectable-preference-proxy.js.map +1 -1
- package/lib/common/preferences/preference-proxy.d.ts.map +1 -1
- package/lib/common/preferences/preference-proxy.js +6 -1
- package/lib/common/preferences/preference-proxy.js.map +1 -1
- package/lib/electron-main/electron-main-application.d.ts.map +1 -1
- package/lib/electron-main/electron-main-application.js +4 -2
- package/lib/electron-main/electron-main-application.js.map +1 -1
- package/lib/electron-node/request/electron-backend-request-service.d.ts +2 -0
- package/lib/electron-node/request/electron-backend-request-service.d.ts.map +1 -1
- package/lib/electron-node/request/electron-backend-request-service.js +7 -1
- package/lib/electron-node/request/electron-backend-request-service.js.map +1 -1
- package/lib/electron-node/token/electron-token-backend-contribution.d.ts +2 -0
- package/lib/electron-node/token/electron-token-backend-contribution.d.ts.map +1 -1
- package/lib/electron-node/token/electron-token-backend-contribution.js +7 -1
- package/lib/electron-node/token/electron-token-backend-contribution.js.map +1 -1
- package/lib/electron-node/token/electron-token-validator.d.ts +2 -0
- package/lib/electron-node/token/electron-token-validator.d.ts.map +1 -1
- package/lib/electron-node/token/electron-token-validator.js +7 -1
- package/lib/electron-node/token/electron-token-validator.js.map +1 -1
- package/lib/node/backend-application.d.ts +2 -0
- package/lib/node/backend-application.d.ts.map +1 -1
- package/lib/node/backend-application.js +17 -11
- package/lib/node/backend-application.js.map +1 -1
- package/lib/node/backend-application.spec.js +3 -2
- package/lib/node/backend-application.spec.js.map +1 -1
- package/lib/node/logger-cli-contribution.d.ts +6 -0
- package/lib/node/logger-cli-contribution.d.ts.map +1 -1
- package/lib/node/logger-cli-contribution.js +28 -5
- package/lib/node/logger-cli-contribution.js.map +1 -1
- package/lib/node/logger-cli-contribution.spec.js +54 -0
- package/lib/node/logger-cli-contribution.spec.js.map +1 -1
- package/lib/node/messaging/default-messaging-service.d.ts +2 -0
- package/lib/node/messaging/default-messaging-service.d.ts.map +1 -1
- package/lib/node/messaging/default-messaging-service.js +8 -2
- package/lib/node/messaging/default-messaging-service.js.map +1 -1
- package/lib/node/messaging/test/default-messaging-service.spec.js +2 -0
- package/lib/node/messaging/test/default-messaging-service.spec.js.map +1 -1
- package/lib/node/messaging/websocket-endpoint.d.ts +2 -0
- package/lib/node/messaging/websocket-endpoint.d.ts.map +1 -1
- package/lib/node/messaging/websocket-endpoint.js +7 -1
- package/lib/node/messaging/websocket-endpoint.js.map +1 -1
- package/lib/node/process-utils.d.ts +2 -0
- package/lib/node/process-utils.d.ts.map +1 -1
- package/lib/node/process-utils.js +8 -2
- package/lib/node/process-utils.js.map +1 -1
- package/lib/node/process-utils.spec.js +11 -9
- package/lib/node/process-utils.spec.js.map +1 -1
- package/package.json +26 -16
- package/src/browser/authentication-service.ts +6 -3
- package/src/browser/frontend-application.ts +13 -9
- package/src/browser/json-schema-store.ts +6 -2
- package/src/browser/keybinding.ts +2 -2
- package/src/browser/markdown-rendering/markdown.tsx +2 -2
- package/src/browser/menu/composite-menu-node.ts +4 -4
- package/src/browser/preferences/frontend-config-preference-contributions.ts +7 -2
- package/src/browser/preferences/preference-proxy.spec.ts +8 -0
- package/src/browser/preferences/preference-schema-provider.spec.ts +5 -0
- package/src/browser/preferences/preference-validation-service.spec.ts +3 -1
- package/src/browser/preferences/preference-validation-service.ts +9 -6
- package/src/browser/quick-input/quick-view-service.spec.ts +50 -0
- package/src/browser/quick-input/quick-view-service.ts +5 -0
- package/src/browser/secondary-window-handler.ts +11 -7
- package/src/browser/shell/application-shell.ts +8 -4
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.tsx +4 -4
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.ts +2 -2
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.ts +159 -1
- package/src/browser/status-bar/status-bar.tsx +3 -3
- package/src/browser/test/jsdom.ts +18 -0
- package/src/browser/tree/tree-container.spec.ts +6 -0
- package/src/browser/tree/tree-widget.tsx +2 -2
- package/src/browser/tree/tree.ts +6 -2
- package/src/browser/window/default-window-service.spec.ts +3 -1
- package/src/browser/window/default-window-service.ts +9 -6
- package/src/browser-only/messaging/frontend-only-service-connection-provider.ts +8 -3
- package/src/common/command.ts +8 -4
- package/src/common/preferences/injectable-preference-proxy.ts +10 -4
- package/src/common/preferences/preference-proxy.ts +10 -4
- package/src/electron-main/electron-main-application.ts +4 -2
- package/src/electron-node/request/electron-backend-request-service.ts +6 -2
- package/src/electron-node/token/electron-token-backend-contribution.ts +6 -2
- package/src/electron-node/token/electron-token-validator.ts +6 -2
- package/src/node/backend-application.spec.ts +3 -3
- package/src/node/backend-application.ts +15 -11
- package/src/node/logger-cli-contribution.spec.ts +65 -0
- package/src/node/logger-cli-contribution.ts +32 -5
- package/src/node/messaging/default-messaging-service.ts +6 -2
- package/src/node/messaging/test/default-messaging-service.spec.ts +3 -1
- package/src/node/messaging/websocket-endpoint.ts +6 -2
- package/src/node/process-utils.spec.ts +12 -9
- package/src/node/process-utils.ts +7 -3
|
@@ -14,15 +14,19 @@
|
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
16
|
|
|
17
|
-
import { decorate, injectable } from 'inversify';
|
|
17
|
+
import { decorate, injectable, inject, named } from 'inversify';
|
|
18
18
|
import { NodeRequestOptions, NodeRequestService } from '@theia/request/lib/node-request-service';
|
|
19
19
|
import { ElectronSecurityToken } from '../../electron-common/electron-token';
|
|
20
|
+
import { ILogger } from '../../common';
|
|
20
21
|
|
|
21
22
|
decorate(injectable(), NodeRequestService);
|
|
22
23
|
|
|
23
24
|
@injectable()
|
|
24
25
|
export class ElectronBackendRequestService extends NodeRequestService {
|
|
25
26
|
|
|
27
|
+
@inject(ILogger) @named('core:ElectronBackendRequestService')
|
|
28
|
+
protected readonly logger: ILogger;
|
|
29
|
+
|
|
26
30
|
override async getProxyUrl(url: string): Promise<string | undefined> {
|
|
27
31
|
if (this.proxyUrl) {
|
|
28
32
|
return this.proxyUrl;
|
|
@@ -34,7 +38,7 @@ export class ElectronBackendRequestService extends NodeRequestService {
|
|
|
34
38
|
return this.buildProxyUrl(url, proxyHost);
|
|
35
39
|
}
|
|
36
40
|
} catch (e) {
|
|
37
|
-
|
|
41
|
+
this.logger.error('Could not resolve electron proxy.', e);
|
|
38
42
|
}
|
|
39
43
|
return super.getProxyUrl(url);
|
|
40
44
|
}
|
|
@@ -15,9 +15,10 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import express = require('express');
|
|
18
|
-
import { injectable, inject } from 'inversify';
|
|
18
|
+
import { injectable, inject, named } from 'inversify';
|
|
19
19
|
import { BackendApplicationContribution } from '../../node';
|
|
20
20
|
import { ElectronTokenValidator } from './electron-token-validator';
|
|
21
|
+
import { ILogger } from '../../common/logger';
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* This component contributes an Express middleware that will refuse all
|
|
@@ -26,6 +27,9 @@ import { ElectronTokenValidator } from './electron-token-validator';
|
|
|
26
27
|
@injectable()
|
|
27
28
|
export class ElectronTokenBackendContribution implements BackendApplicationContribution {
|
|
28
29
|
|
|
30
|
+
@inject(ILogger) @named('core:ElectronTokenBackendContribution')
|
|
31
|
+
protected readonly logger: ILogger;
|
|
32
|
+
|
|
29
33
|
@inject(ElectronTokenValidator)
|
|
30
34
|
protected readonly tokenValidator: ElectronTokenValidator;
|
|
31
35
|
|
|
@@ -40,7 +44,7 @@ export class ElectronTokenBackendContribution implements BackendApplicationContr
|
|
|
40
44
|
if (this.tokenValidator.allowRequest(req)) {
|
|
41
45
|
next();
|
|
42
46
|
} else {
|
|
43
|
-
|
|
47
|
+
this.logger.error(`refused an http request: ${req.connection.remoteAddress}`);
|
|
44
48
|
res.sendStatus(403);
|
|
45
49
|
}
|
|
46
50
|
}
|
|
@@ -17,10 +17,11 @@
|
|
|
17
17
|
import * as http from 'http';
|
|
18
18
|
import * as cookie from 'cookie';
|
|
19
19
|
import * as crypto from 'crypto';
|
|
20
|
-
import { injectable, postConstruct } from 'inversify';
|
|
20
|
+
import { injectable, postConstruct, inject, named } from 'inversify';
|
|
21
21
|
import { isObject, isString, MaybePromise } from '../../common';
|
|
22
22
|
import { ElectronSecurityToken } from '../../electron-common/electron-token';
|
|
23
23
|
import { WsRequestValidatorContribution } from '../../node/ws-request-validators';
|
|
24
|
+
import { ILogger } from '../../common/logger';
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* On Electron, we want to make sure that only Electron's browser-windows access the backend services.
|
|
@@ -28,6 +29,9 @@ import { WsRequestValidatorContribution } from '../../node/ws-request-validators
|
|
|
28
29
|
@injectable()
|
|
29
30
|
export class ElectronTokenValidator implements WsRequestValidatorContribution {
|
|
30
31
|
|
|
32
|
+
@inject(ILogger) @named('core:ElectronTokenValidator')
|
|
33
|
+
protected readonly logger: ILogger;
|
|
34
|
+
|
|
31
35
|
protected electronSecurityToken?: ElectronSecurityToken;
|
|
32
36
|
|
|
33
37
|
@postConstruct()
|
|
@@ -70,7 +74,7 @@ export class ElectronTokenValidator implements WsRequestValidatorContribution {
|
|
|
70
74
|
const expected = Buffer.from(this.electronSecurityToken!.value, 'utf8');
|
|
71
75
|
return received.byteLength === expected.byteLength && crypto.timingSafeEqual(received, expected);
|
|
72
76
|
} catch (error) {
|
|
73
|
-
|
|
77
|
+
this.logger.error(error);
|
|
74
78
|
}
|
|
75
79
|
}
|
|
76
80
|
return false;
|
|
@@ -19,7 +19,6 @@ import * as sinon from 'sinon';
|
|
|
19
19
|
import { Container, ContainerModule, injectable, preDestroy } from 'inversify';
|
|
20
20
|
import { bindContributionProvider, ILogger, Stopwatch } from '../common';
|
|
21
21
|
import { Deferred } from '../common/promise-util';
|
|
22
|
-
import { MockLogger } from '../common/test/mock-logger';
|
|
23
22
|
import { NodeStopwatch } from './performance/node-stopwatch';
|
|
24
23
|
import { ProcessUtils } from './process-utils';
|
|
25
24
|
import {
|
|
@@ -29,6 +28,7 @@ import {
|
|
|
29
28
|
RootContainer
|
|
30
29
|
} from './backend-application';
|
|
31
30
|
import { CliContribution } from './cli';
|
|
31
|
+
import { MockLogger } from '../common/test/mock-logger';
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Test subclass that exposes the protected `gracefulShutdown` for direct testing.
|
|
@@ -82,7 +82,6 @@ describe('BackendApplication', () => {
|
|
|
82
82
|
const container = new Container();
|
|
83
83
|
|
|
84
84
|
container.bind(RootContainer).toConstantValue(container);
|
|
85
|
-
|
|
86
85
|
container.bind(ILogger).to(MockLogger).inSingletonScope();
|
|
87
86
|
container.bind(Stopwatch).to(NodeStopwatch).inSingletonScope();
|
|
88
87
|
container.bind(ProcessUtils).toSelf().inSingletonScope();
|
|
@@ -242,7 +241,8 @@ describe('BackendApplication', () => {
|
|
|
242
241
|
container.bind(BackendApplicationContribution).toConstantValue({
|
|
243
242
|
onStop: () => { secondRan = true; }
|
|
244
243
|
});
|
|
245
|
-
const
|
|
244
|
+
const mockLogger = container.get(ILogger) as ILogger;
|
|
245
|
+
const errorStub = sandbox.stub(mockLogger, 'error');
|
|
246
246
|
|
|
247
247
|
const app = container.get(TestBackendApplication);
|
|
248
248
|
await app.invokeGracefulShutdown();
|
|
@@ -28,6 +28,7 @@ import { Deferred, timeoutReject } from '../common/promise-util';
|
|
|
28
28
|
import { environment } from '../common/index';
|
|
29
29
|
import { AddressInfo } from 'net';
|
|
30
30
|
import { ProcessUtils } from './process-utils';
|
|
31
|
+
import { ILogger } from '../common/logger';
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* The path to the application project directory. This is the directory where the application code is located.
|
|
@@ -180,6 +181,9 @@ export class BackendApplication {
|
|
|
180
181
|
@inject(Stopwatch)
|
|
181
182
|
protected readonly stopwatch: Stopwatch;
|
|
182
183
|
|
|
184
|
+
@inject(ILogger) @named('core:BackendApplication')
|
|
185
|
+
protected readonly logger: ILogger;
|
|
186
|
+
|
|
183
187
|
@inject(RootContainer)
|
|
184
188
|
protected readonly rootContainer: interfaces.Container;
|
|
185
189
|
|
|
@@ -201,7 +205,7 @@ export class BackendApplication {
|
|
|
201
205
|
// Workaround for Electron not installing a handler to ignore SIGPIPE error
|
|
202
206
|
// (https://github.com/electron/electron/issues/13254)
|
|
203
207
|
process.on('SIGPIPE', () => {
|
|
204
|
-
|
|
208
|
+
this.logger.error(new Error('Unexpected SIGPIPE'));
|
|
205
209
|
});
|
|
206
210
|
|
|
207
211
|
// Handles normal process termination.
|
|
@@ -221,7 +225,7 @@ export class BackendApplication {
|
|
|
221
225
|
await this.measureContribution(contribution, 'initialize',
|
|
222
226
|
() => contribution.initialize!());
|
|
223
227
|
} catch (error) {
|
|
224
|
-
|
|
228
|
+
this.logger.error('Could not initialize contribution', error);
|
|
225
229
|
}
|
|
226
230
|
}
|
|
227
231
|
}));
|
|
@@ -258,11 +262,11 @@ export class BackendApplication {
|
|
|
258
262
|
await this.measureContribution(contribution, 'configure',
|
|
259
263
|
() => contribution.configure!(this.app));
|
|
260
264
|
} catch (error) {
|
|
261
|
-
|
|
265
|
+
this.logger.error('Could not configure contribution', error);
|
|
262
266
|
}
|
|
263
267
|
}
|
|
264
268
|
}));
|
|
265
|
-
|
|
269
|
+
this.logger.info('configured all backend app contributions');
|
|
266
270
|
}
|
|
267
271
|
|
|
268
272
|
use(...handlers: express.Handler[]): void {
|
|
@@ -297,14 +301,14 @@ export class BackendApplication {
|
|
|
297
301
|
try {
|
|
298
302
|
key = await fs.readFile(this.cliParams.certkey as string);
|
|
299
303
|
} catch (err) {
|
|
300
|
-
|
|
304
|
+
this.logger.error("Can't read certificate key");
|
|
301
305
|
throw err;
|
|
302
306
|
}
|
|
303
307
|
|
|
304
308
|
try {
|
|
305
309
|
cert = await fs.readFile(this.cliParams.cert as string);
|
|
306
310
|
} catch (err) {
|
|
307
|
-
|
|
311
|
+
this.logger.error("Can't read certificate");
|
|
308
312
|
throw err;
|
|
309
313
|
}
|
|
310
314
|
server = https.createServer({ key, cert }, this.app);
|
|
@@ -323,7 +327,7 @@ export class BackendApplication {
|
|
|
323
327
|
// address should be defined at this point
|
|
324
328
|
const address = server.address()!;
|
|
325
329
|
const url = typeof address === 'string' ? address : this.getHttpUrl(address, this.cliParams.ssl);
|
|
326
|
-
|
|
330
|
+
this.logger.info(`Theia app listening on ${url}.`);
|
|
327
331
|
deferred.resolve(server);
|
|
328
332
|
});
|
|
329
333
|
|
|
@@ -336,7 +340,7 @@ export class BackendApplication {
|
|
|
336
340
|
await this.measureContribution(contribution, 'onStart',
|
|
337
341
|
() => contribution.onStart!(server));
|
|
338
342
|
} catch (error) {
|
|
339
|
-
|
|
343
|
+
this.logger.error('Could not start contribution', error);
|
|
340
344
|
}
|
|
341
345
|
}
|
|
342
346
|
}
|
|
@@ -415,7 +419,7 @@ export class BackendApplication {
|
|
|
415
419
|
try {
|
|
416
420
|
await contrib.onStop(this.app);
|
|
417
421
|
} catch (error) {
|
|
418
|
-
|
|
422
|
+
this.logger.error('Could not stop contribution', error);
|
|
419
423
|
}
|
|
420
424
|
}
|
|
421
425
|
}));
|
|
@@ -466,9 +470,9 @@ export class BackendApplication {
|
|
|
466
470
|
|
|
467
471
|
protected handleUncaughtError(error: Error): void {
|
|
468
472
|
if (error) {
|
|
469
|
-
|
|
473
|
+
this.logger.error('Uncaught Exception: ', error.toString());
|
|
470
474
|
if (error.stack) {
|
|
471
|
-
|
|
475
|
+
this.logger.error(error.stack);
|
|
472
476
|
}
|
|
473
477
|
}
|
|
474
478
|
}
|
|
@@ -257,4 +257,69 @@ describe('log-level-cli-contribution', () => {
|
|
|
257
257
|
world: LogLevel.FATAL,
|
|
258
258
|
});
|
|
259
259
|
});
|
|
260
|
+
|
|
261
|
+
describe('Wildcard Matching', () => {
|
|
262
|
+
|
|
263
|
+
async function setupLogLevels(levels: { [key: string]: string }): Promise<void> {
|
|
264
|
+
const file = track.openSync();
|
|
265
|
+
fs.writeFileSync(file.fd, JSON.stringify({
|
|
266
|
+
defaultLevel: 'info',
|
|
267
|
+
levels
|
|
268
|
+
}));
|
|
269
|
+
fs.fsyncSync(file.fd);
|
|
270
|
+
fs.closeSync(file.fd);
|
|
271
|
+
|
|
272
|
+
const args: yargs.Arguments = await yargs.parse(['--log-config', file.path]);
|
|
273
|
+
await cli.setArguments(args);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
it('should respect exact matches without wildcards', async () => {
|
|
277
|
+
await setupLogLevels({
|
|
278
|
+
'unrelated:Service': 'debug'
|
|
279
|
+
});
|
|
280
|
+
expect(cli.logLevelFor('unrelated:Service')).to.equal(LogLevel.DEBUG);
|
|
281
|
+
expect(cli.logLevelFor('something-else')).to.equal(LogLevel.INFO);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('should match prefix wildcards', async () => {
|
|
285
|
+
await setupLogLevels({
|
|
286
|
+
'ai-core*': 'error'
|
|
287
|
+
});
|
|
288
|
+
expect(cli.logLevelFor('ai-core:SomeOtherService')).to.equal(LogLevel.ERROR);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('should match suffix wildcards', async () => {
|
|
292
|
+
await setupLogLevels({
|
|
293
|
+
'*TokenUsageFrontendServiceImpl': 'warn'
|
|
294
|
+
});
|
|
295
|
+
expect(cli.logLevelFor('my-package:MyTokenUsageFrontendServiceImpl')).to.equal(LogLevel.WARN);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('should match middle wildcards', async () => {
|
|
299
|
+
await setupLogLevels({
|
|
300
|
+
'*ai*:*': 'warn'
|
|
301
|
+
});
|
|
302
|
+
expect(cli.logLevelFor('foo-ai-bar:SomeService')).to.equal(LogLevel.WARN);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('should enforce perfect match first, then last wildcard wins', async () => {
|
|
306
|
+
await setupLogLevels({
|
|
307
|
+
'ai-core*': 'error',
|
|
308
|
+
'*ai*:*': 'warn',
|
|
309
|
+
'ai-core:SpecificService': 'debug'
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
expect(cli.logLevelFor('ai-core:SpecificService')).to.equal(LogLevel.DEBUG);
|
|
313
|
+
|
|
314
|
+
expect(cli.logLevelFor('ai-core:OtherService')).to.equal(LogLevel.WARN);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('should properly escape regex specifics like periods', async () => {
|
|
318
|
+
await setupLogLevels({
|
|
319
|
+
'.*': 'error'
|
|
320
|
+
});
|
|
321
|
+
expect(cli.logLevelFor('anything-else')).to.equal(LogLevel.INFO);
|
|
322
|
+
expect(cli.logLevelFor('.*')).to.equal(LogLevel.ERROR);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
260
325
|
});
|
|
@@ -23,6 +23,7 @@ import { AsyncSubscription, subscribe } from '@parcel/watcher';
|
|
|
23
23
|
import { Event, Emitter } from '../common/event';
|
|
24
24
|
import * as path from 'path';
|
|
25
25
|
import { Disposable, DisposableCollection } from '../common';
|
|
26
|
+
import { escapeRegExpCharacters } from '../common/strings';
|
|
26
27
|
|
|
27
28
|
/** Maps logger names to log levels. */
|
|
28
29
|
export interface LogLevels {
|
|
@@ -38,6 +39,7 @@ export interface LogLevels {
|
|
|
38
39
|
export class LogLevelCliContribution implements CliContribution, Disposable {
|
|
39
40
|
|
|
40
41
|
protected _logLevels: LogLevels = {};
|
|
42
|
+
protected wildcardRegexCache = new Map<string, RegExp>();
|
|
41
43
|
protected asyncSubscriptions: AsyncSubscription[] = [];
|
|
42
44
|
protected toDispose = new DisposableCollection();
|
|
43
45
|
|
|
@@ -190,6 +192,7 @@ export class LogLevelCliContribution implements CliContribution, Disposable {
|
|
|
190
192
|
|
|
191
193
|
this._defaultLogLevel = newDefaultLogLevel;
|
|
192
194
|
this._logLevels = newLogLevels;
|
|
195
|
+
this.wildcardRegexCache.clear();
|
|
193
196
|
|
|
194
197
|
console.log(`Successfully read new log config from ${filename}.`);
|
|
195
198
|
} catch (e) {
|
|
@@ -202,13 +205,23 @@ export class LogLevelCliContribution implements CliContribution, Disposable {
|
|
|
202
205
|
}
|
|
203
206
|
|
|
204
207
|
logLevelFor(loggerName: string): LogLevel {
|
|
205
|
-
|
|
208
|
+
if (loggerName in this._logLevels) {
|
|
209
|
+
return this._logLevels[loggerName];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const keys = Object.keys(this._logLevels);
|
|
213
|
+
for (let i = keys.length - 1; i >= 0; i--) {
|
|
214
|
+
const pattern = keys[i];
|
|
206
215
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
216
|
+
if (pattern.includes('*')) {
|
|
217
|
+
const regex = this.getWildcardRegex(pattern);
|
|
218
|
+
if (regex.test(loggerName)) {
|
|
219
|
+
return this._logLevels[pattern];
|
|
220
|
+
}
|
|
221
|
+
}
|
|
211
222
|
}
|
|
223
|
+
|
|
224
|
+
return this.defaultLogLevel;
|
|
212
225
|
}
|
|
213
226
|
|
|
214
227
|
/**
|
|
@@ -223,4 +236,18 @@ export class LogLevelCliContribution implements CliContribution, Disposable {
|
|
|
223
236
|
|
|
224
237
|
return level;
|
|
225
238
|
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Converts a wildcard string into a strict regular expression and caches it.
|
|
242
|
+
* Example: "ai-core*" -> /^ai-core.*$/
|
|
243
|
+
*/
|
|
244
|
+
protected getWildcardRegex(pattern: string): RegExp {
|
|
245
|
+
let regex = this.wildcardRegexCache.get(pattern);
|
|
246
|
+
if (!regex) {
|
|
247
|
+
const escapedPattern = pattern.split('*').map(escapeRegExpCharacters).join('.*');
|
|
248
|
+
regex = new RegExp(`^${escapedPattern}$`);
|
|
249
|
+
this.wildcardRegexCache.set(pattern, regex);
|
|
250
|
+
}
|
|
251
|
+
return regex;
|
|
252
|
+
}
|
|
226
253
|
}
|
|
@@ -22,6 +22,7 @@ import Route = require('route-parser');
|
|
|
22
22
|
import { Channel, ChannelMultiplexer } from '../../common/message-rpc/channel';
|
|
23
23
|
import { FrontendConnectionService } from './frontend-connection-service';
|
|
24
24
|
import { BackendApplicationContribution } from '../backend-application';
|
|
25
|
+
import { ILogger } from '../../common/logger';
|
|
25
26
|
|
|
26
27
|
export const MessagingContainer = Symbol('MessagingContainer');
|
|
27
28
|
export const MainChannel = Symbol('MainChannel');
|
|
@@ -37,6 +38,9 @@ export class DefaultMessagingService implements MessagingService, BackendApplica
|
|
|
37
38
|
@inject(ContributionProvider) @named(ConnectionContainerModule)
|
|
38
39
|
protected readonly connectionModules: ContributionProvider<interfaces.ContainerModule>;
|
|
39
40
|
|
|
41
|
+
@inject(ILogger) @named('core:DefaultMessagingService')
|
|
42
|
+
protected readonly logger: ILogger;
|
|
43
|
+
|
|
40
44
|
@inject(ContributionProvider) @named(MessagingService.Contribution)
|
|
41
45
|
protected readonly contributions: ContributionProvider<MessagingService.Contribution>;
|
|
42
46
|
|
|
@@ -62,8 +66,8 @@ export class DefaultMessagingService implements MessagingService, BackendApplica
|
|
|
62
66
|
const channelHandlers = this.getConnectionChannelHandlers(channel);
|
|
63
67
|
multiplexer.onDidOpenChannel(event => {
|
|
64
68
|
if (channelHandlers.route(event.id, event.channel)) {
|
|
65
|
-
|
|
66
|
-
event.channel.onClose(() =>
|
|
69
|
+
this.logger.debug(`Opening channel for service path '${event.id}'.`);
|
|
70
|
+
event.channel.onClose(() => this.logger.info(`Closing channel on service path '${event.id}'.`));
|
|
67
71
|
}
|
|
68
72
|
});
|
|
69
73
|
}
|
|
@@ -16,13 +16,14 @@
|
|
|
16
16
|
|
|
17
17
|
import { expect } from 'chai';
|
|
18
18
|
import { Container, injectable, preDestroy } from 'inversify';
|
|
19
|
-
import { ConnectionHandler, bindContributionProvider, servicesPath } from '../../../common';
|
|
19
|
+
import { ConnectionHandler, bindContributionProvider, servicesPath, ILogger } from '../../../common';
|
|
20
20
|
import { BasicChannel, Channel } from '../../../common/message-rpc/channel';
|
|
21
21
|
import { Uint8ArrayWriteBuffer } from '../../../common/message-rpc/uint8-array-message-buffer';
|
|
22
22
|
import { ConnectionContainerModule } from '../connection-container-module';
|
|
23
23
|
import { DefaultMessagingService, MessagingContainer } from '../default-messaging-service';
|
|
24
24
|
import { FrontendConnectionService } from '../frontend-connection-service';
|
|
25
25
|
import { MessagingService } from '../messaging-service';
|
|
26
|
+
import { MockLogger } from '../../../common/test/mock-logger';
|
|
26
27
|
|
|
27
28
|
describe('DefaultMessagingService', () => {
|
|
28
29
|
|
|
@@ -63,6 +64,7 @@ describe('DefaultMessagingService', () => {
|
|
|
63
64
|
}
|
|
64
65
|
};
|
|
65
66
|
container.bind(FrontendConnectionService).toConstantValue(frontendConnectionService);
|
|
67
|
+
container.bind(ILogger).to(MockLogger).inSingletonScope();
|
|
66
68
|
|
|
67
69
|
const messagingService = container.get(DefaultMessagingService);
|
|
68
70
|
messagingService.initialize();
|
|
@@ -16,12 +16,13 @@
|
|
|
16
16
|
import { MessagingService } from './messaging-service';
|
|
17
17
|
import * as http from 'http';
|
|
18
18
|
import * as https from 'https';
|
|
19
|
-
import { inject, injectable } from 'inversify';
|
|
19
|
+
import { inject, injectable, named } from 'inversify';
|
|
20
20
|
import { Server, Socket } from 'socket.io';
|
|
21
21
|
import { WsRequestValidator } from '../ws-request-validators';
|
|
22
22
|
import { MessagingListener } from './messaging-listeners';
|
|
23
23
|
import { ConnectionHandlers } from './default-messaging-service';
|
|
24
24
|
import { BackendApplicationContribution } from '../backend-application';
|
|
25
|
+
import { ILogger } from '../../common/logger';
|
|
25
26
|
|
|
26
27
|
@injectable()
|
|
27
28
|
export class WebsocketEndpoint implements BackendApplicationContribution {
|
|
@@ -31,6 +32,9 @@ export class WebsocketEndpoint implements BackendApplicationContribution {
|
|
|
31
32
|
@inject(MessagingListener)
|
|
32
33
|
protected readonly messagingListener: MessagingListener;
|
|
33
34
|
|
|
35
|
+
@inject(ILogger) @named('core:WebsocketEndpoint')
|
|
36
|
+
protected readonly logger: ILogger;
|
|
37
|
+
|
|
34
38
|
protected checkAliveTimeout = 30000; // 30 seconds
|
|
35
39
|
protected maxHttpBufferSize = 1e8; // 100 MB
|
|
36
40
|
|
|
@@ -72,7 +76,7 @@ export class WebsocketEndpoint implements BackendApplicationContribution {
|
|
|
72
76
|
protected async handleConnection(socket: Socket): Promise<void> {
|
|
73
77
|
const pathname = socket.nsp.name;
|
|
74
78
|
if (pathname && !this.wsHandlers.route(pathname, socket)) {
|
|
75
|
-
|
|
79
|
+
this.logger.error('Cannot find a ws handler for the path: ' + pathname);
|
|
76
80
|
}
|
|
77
81
|
}
|
|
78
82
|
}
|
|
@@ -15,8 +15,11 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import { expect } from 'chai';
|
|
18
|
+
import * as sinon from 'sinon';
|
|
18
19
|
import { Container } from 'inversify';
|
|
19
20
|
import { ProcessUtils } from './process-utils';
|
|
21
|
+
import { ILogger } from '../common';
|
|
22
|
+
import { MockLogger } from '../common/test/mock-logger';
|
|
20
23
|
|
|
21
24
|
/** PPID, PID */
|
|
22
25
|
const mockPsOutput = `\
|
|
@@ -36,6 +39,8 @@ describe('ProcessUtils', () => {
|
|
|
36
39
|
beforeEach(() => {
|
|
37
40
|
const container = new Container();
|
|
38
41
|
container.bind(ProcessUtils).toSelf().inSingletonScope();
|
|
42
|
+
container.bind(ILogger).to(MockLogger).inSingletonScope();
|
|
43
|
+
|
|
39
44
|
coreProcessManager = container.get(ProcessUtils);
|
|
40
45
|
});
|
|
41
46
|
|
|
@@ -48,8 +53,7 @@ describe('ProcessUtils', () => {
|
|
|
48
53
|
|
|
49
54
|
describe('#unixTerminateProcessTree', () => {
|
|
50
55
|
let originalKill: typeof process.kill;
|
|
51
|
-
let
|
|
52
|
-
let loggedErrors: unknown[];
|
|
56
|
+
let errorStub: sinon.SinonStub;
|
|
53
57
|
|
|
54
58
|
function throwingKill(code: string): typeof process.kill {
|
|
55
59
|
return (() => {
|
|
@@ -61,9 +65,8 @@ describe('ProcessUtils', () => {
|
|
|
61
65
|
|
|
62
66
|
beforeEach(() => {
|
|
63
67
|
originalKill = process.kill;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
console.error = (...args: unknown[]) => { loggedErrors.push(args); };
|
|
68
|
+
const mockLogger = (coreProcessManager as unknown as { logger: ILogger }).logger;
|
|
69
|
+
errorStub = sinon.stub(mockLogger, 'error');
|
|
67
70
|
// One child plus the parent; report the parent as its own group leader so the `kill(-ppid)` branch runs too.
|
|
68
71
|
coreProcessManager['unixGetChildrenRecursive'] = () => new Set([424242]);
|
|
69
72
|
coreProcessManager['unixGetPGID'] = (pid: number) => pid;
|
|
@@ -71,26 +74,26 @@ describe('ProcessUtils', () => {
|
|
|
71
74
|
|
|
72
75
|
afterEach(() => {
|
|
73
76
|
process.kill = originalKill;
|
|
74
|
-
|
|
77
|
+
sinon.restore();
|
|
75
78
|
});
|
|
76
79
|
|
|
77
80
|
it('does not throw or log when processes in the tree are already gone (ESRCH)', () => {
|
|
78
81
|
process.kill = throwingKill('ESRCH');
|
|
79
82
|
expect(() => coreProcessManager['unixTerminateProcessTree'](424243)).to.not.throw();
|
|
80
|
-
expect(
|
|
83
|
+
expect(errorStub.called).to.be.false;
|
|
81
84
|
});
|
|
82
85
|
|
|
83
86
|
it('logs unexpected kill errors (e.g. EPERM) without throwing', () => {
|
|
84
87
|
process.kill = throwingKill('EPERM');
|
|
85
88
|
expect(() => coreProcessManager['unixTerminateProcessTree'](424243)).to.not.throw();
|
|
86
|
-
expect(
|
|
89
|
+
expect(errorStub.called).to.be.true;
|
|
87
90
|
});
|
|
88
91
|
|
|
89
92
|
it('does not throw when a kill rejects with a value that has no code (e.g. undefined)', () => {
|
|
90
93
|
const thrown: unknown = undefined;
|
|
91
94
|
process.kill = (() => { throw thrown; }) as typeof process.kill;
|
|
92
95
|
expect(() => coreProcessManager['unixTerminateProcessTree'](424243)).to.not.throw();
|
|
93
|
-
expect(
|
|
96
|
+
expect(errorStub.called).to.be.true;
|
|
94
97
|
});
|
|
95
98
|
});
|
|
96
99
|
});
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import * as cp from 'child_process';
|
|
18
|
-
import { injectable } from 'inversify';
|
|
18
|
+
import { injectable, inject, named } from 'inversify';
|
|
19
|
+
import { ILogger } from '../common/logger';
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* `@theia/core` service with some process-related utilities.
|
|
@@ -23,6 +24,9 @@ import { injectable } from 'inversify';
|
|
|
23
24
|
@injectable()
|
|
24
25
|
export class ProcessUtils {
|
|
25
26
|
|
|
27
|
+
@inject(ILogger) @named('core:ProcessUtils')
|
|
28
|
+
protected readonly logger: ILogger;
|
|
29
|
+
|
|
26
30
|
terminateProcessTree(ppid: number): void {
|
|
27
31
|
if (process.platform === 'win32') {
|
|
28
32
|
this.winTerminateProcessTree(ppid);
|
|
@@ -39,7 +43,7 @@ export class ProcessUtils {
|
|
|
39
43
|
// taskkill may exit with a non-zero code when some child processes have already exited.
|
|
40
44
|
// This is expected during shutdown — log but don't throw.
|
|
41
45
|
if (result.status !== 0) {
|
|
42
|
-
|
|
46
|
+
this.logger.warn(`taskkill.exe exited with ${result.status} for PID ${ppid}. Output:\n${JSON.stringify(result.output)}`);
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
|
|
@@ -66,7 +70,7 @@ export class ProcessUtils {
|
|
|
66
70
|
// ESRCH means the process is already gone, which is the goal here. Log
|
|
67
71
|
// anything else but keep going so the rest of the tree is still killed.
|
|
68
72
|
if ((error as NodeJS.ErrnoException | undefined)?.code !== 'ESRCH') {
|
|
69
|
-
|
|
73
|
+
this.logger.error(`[${pid}] failed to kill`, error);
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
}
|