@theia/core 1.58.3 → 1.59.0-next.72
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 +6 -6
- package/i18n/nls.json +1 -1
- package/lib/browser/catalog.json +26 -7
- package/lib/browser/logger-frontend-module.d.ts.map +1 -1
- package/lib/browser/logger-frontend-module.js +2 -3
- package/lib/browser/logger-frontend-module.js.map +1 -1
- package/lib/browser/menu/browser-menu-plugin.d.ts +7 -0
- package/lib/browser/menu/browser-menu-plugin.d.ts.map +1 -1
- package/lib/browser/menu/browser-menu-plugin.js +46 -3
- package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
- package/lib/browser/navigatable-types.d.ts.map +1 -1
- package/lib/browser/navigatable-types.js +1 -1
- package/lib/browser/navigatable-types.js.map +1 -1
- package/lib/browser/saveable-service.js +1 -1
- package/lib/browser/saveable-service.js.map +1 -1
- package/lib/browser/saveable.d.ts +2 -0
- package/lib/browser/saveable.d.ts.map +1 -1
- package/lib/browser/saveable.js.map +1 -1
- package/lib/common/array-utils.d.ts +2 -0
- package/lib/common/array-utils.d.ts.map +1 -1
- package/lib/common/array-utils.js +24 -0
- package/lib/common/array-utils.js.map +1 -1
- package/lib/common/content-replacer.d.ts +56 -0
- package/lib/common/content-replacer.d.ts.map +1 -0
- package/lib/common/content-replacer.js +139 -0
- package/lib/common/content-replacer.js.map +1 -0
- package/lib/common/content-replacer.spec.d.ts +2 -0
- package/lib/common/content-replacer.spec.d.ts.map +1 -0
- package/lib/common/content-replacer.spec.js +115 -0
- package/lib/common/content-replacer.spec.js.map +1 -0
- package/lib/common/logger-binding.d.ts +3 -0
- package/lib/common/logger-binding.d.ts.map +1 -0
- package/lib/common/logger-binding.js +36 -0
- package/lib/common/logger-binding.js.map +1 -0
- package/lib/common/logger-protocol.d.ts +1 -1
- package/lib/common/logger-protocol.d.ts.map +1 -1
- package/lib/common/logger-protocol.js +3 -1
- package/lib/common/logger-protocol.js.map +1 -1
- package/lib/common/logger.d.ts +1 -0
- package/lib/common/logger.d.ts.map +1 -1
- package/lib/common/logger.js +12 -1
- package/lib/common/logger.js.map +1 -1
- package/lib/common/menu/composite-menu-node.d.ts +2 -2
- package/lib/common/menu/composite-menu-node.d.ts.map +1 -1
- package/lib/common/menu/composite-menu-node.js +2 -0
- package/lib/common/menu/composite-menu-node.js.map +1 -1
- package/lib/common/menu/menu-model-registry.d.ts +22 -4
- package/lib/common/menu/menu-model-registry.d.ts.map +1 -1
- package/lib/common/menu/menu-model-registry.js +74 -17
- package/lib/common/menu/menu-model-registry.js.map +1 -1
- package/lib/common/menu/menu-types.d.ts +2 -1
- package/lib/common/menu/menu-types.d.ts.map +1 -1
- package/lib/common/menu/menu-types.js.map +1 -1
- package/lib/common/resource.d.ts +11 -2
- package/lib/common/resource.d.ts.map +1 -1
- package/lib/common/resource.js +11 -1
- package/lib/common/resource.js.map +1 -1
- package/lib/node/console-logger-server.d.ts +5 -1
- package/lib/node/console-logger-server.d.ts.map +1 -1
- package/lib/node/console-logger-server.js +18 -4
- package/lib/node/console-logger-server.js.map +1 -1
- package/lib/node/logger-backend-module.d.ts.map +1 -1
- package/lib/node/logger-backend-module.js +2 -3
- package/lib/node/logger-backend-module.js.map +1 -1
- package/lib/node/logger-cli-contribution.d.ts +2 -0
- package/lib/node/logger-cli-contribution.d.ts.map +1 -1
- package/lib/node/logger-cli-contribution.js +40 -7
- package/lib/node/logger-cli-contribution.js.map +1 -1
- package/package.json +6 -6
- package/src/browser/logger-frontend-module.ts +3 -4
- package/src/browser/menu/browser-menu-plugin.ts +55 -5
- package/src/browser/navigatable-types.ts +1 -1
- package/src/browser/saveable-service.ts +1 -1
- package/src/browser/saveable.ts +2 -0
- package/src/common/array-utils.ts +25 -0
- package/src/common/content-replacer.spec.ts +124 -0
- package/src/common/content-replacer.ts +151 -0
- package/src/common/logger-binding.ts +34 -0
- package/src/common/logger-protocol.ts +4 -2
- package/src/common/logger.ts +10 -1
- package/src/common/menu/composite-menu-node.ts +4 -2
- package/src/common/menu/menu-model-registry.ts +84 -19
- package/src/common/menu/menu-types.ts +2 -1
- package/src/common/resource.ts +17 -4
- package/src/node/console-logger-server.ts +22 -2
- package/src/node/logger-backend-module.ts +3 -4
- package/src/node/logger-cli-contribution.ts +43 -7
package/src/common/logger.ts
CHANGED
|
@@ -240,6 +240,8 @@ export class Logger implements ILogger {
|
|
|
240
240
|
@inject(LoggerFactory) protected readonly factory: LoggerFactory;
|
|
241
241
|
@inject(LoggerName) protected name: string;
|
|
242
242
|
|
|
243
|
+
protected cache = new Map<string, ILogger>();
|
|
244
|
+
|
|
243
245
|
@postConstruct()
|
|
244
246
|
protected init(): void {
|
|
245
247
|
if (this.name !== rootLoggerName) {
|
|
@@ -384,6 +386,13 @@ export class Logger implements ILogger {
|
|
|
384
386
|
}
|
|
385
387
|
|
|
386
388
|
child(name: string): ILogger {
|
|
387
|
-
|
|
389
|
+
const existing = this.cache.get(name);
|
|
390
|
+
if (existing) {
|
|
391
|
+
return existing;
|
|
392
|
+
} else {
|
|
393
|
+
const child = this.factory(name);
|
|
394
|
+
this.cache.set(name, child);
|
|
395
|
+
return child;
|
|
396
|
+
}
|
|
388
397
|
}
|
|
389
398
|
}
|
|
@@ -54,11 +54,13 @@ export class CompositeMenuNode implements MutableCompoundMenuNode {
|
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
removeNode(id: string):
|
|
57
|
+
removeNode(id: string): boolean {
|
|
58
58
|
const idx = this._children.findIndex(n => n.id === id);
|
|
59
59
|
if (idx >= 0) {
|
|
60
60
|
this._children.splice(idx, 1);
|
|
61
|
+
return true;
|
|
61
62
|
}
|
|
63
|
+
return false;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
updateOptions(options?: SubMenuOptions): void {
|
|
@@ -108,7 +110,7 @@ export class CompositeMenuNodeWrapper implements MutableCompoundMenuNode {
|
|
|
108
110
|
|
|
109
111
|
addNode(node: MenuNode): Disposable { return this.wrapped.addNode(node); }
|
|
110
112
|
|
|
111
|
-
removeNode(id: string):
|
|
113
|
+
removeNode(id: string): boolean { return this.wrapped.removeNode(id); }
|
|
112
114
|
|
|
113
115
|
updateOptions(options: SubMenuOptions): void { return this.wrapped.updateOptions(options); }
|
|
114
116
|
}
|
|
@@ -59,6 +59,29 @@ export interface MenuContribution {
|
|
|
59
59
|
registerMenus(menus: MenuModelRegistry): void;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
export enum ChangeKind {
|
|
63
|
+
ADDED,
|
|
64
|
+
REMOVED,
|
|
65
|
+
CHANGED,
|
|
66
|
+
LINKED
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface MenuChangedEvent {
|
|
70
|
+
kind: ChangeKind;
|
|
71
|
+
path: MenuPath
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface StructuralMenuChange extends MenuChangedEvent {
|
|
75
|
+
kind: ChangeKind.ADDED | ChangeKind.REMOVED | ChangeKind.LINKED;
|
|
76
|
+
affectedChildId: string
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export namespace StructuralMenuChange {
|
|
80
|
+
export function is(evt: MenuChangedEvent): evt is StructuralMenuChange {
|
|
81
|
+
return evt.kind !== ChangeKind.CHANGED;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
62
85
|
/**
|
|
63
86
|
* The MenuModelRegistry allows to register and unregister menus, submenus and actions
|
|
64
87
|
* via strings and {@link MenuAction}s without the need to access the underlying UI
|
|
@@ -69,9 +92,9 @@ export class MenuModelRegistry {
|
|
|
69
92
|
protected readonly root = new CompositeMenuNode('');
|
|
70
93
|
protected readonly independentSubmenus = new Map<string, MutableCompoundMenuNode>();
|
|
71
94
|
|
|
72
|
-
protected readonly onDidChangeEmitter = new Emitter<
|
|
95
|
+
protected readonly onDidChangeEmitter = new Emitter<MenuChangedEvent>();
|
|
73
96
|
|
|
74
|
-
get onDidChange(): Event<
|
|
97
|
+
get onDidChange(): Event<MenuChangedEvent> {
|
|
75
98
|
return this.onDidChangeEmitter.event;
|
|
76
99
|
}
|
|
77
100
|
|
|
@@ -108,8 +131,21 @@ export class MenuModelRegistry {
|
|
|
108
131
|
registerMenuNode(menuPath: MenuPath | string, menuNode: MenuNode, group?: string): Disposable {
|
|
109
132
|
const parent = this.getMenuNode(menuPath, group);
|
|
110
133
|
const disposable = parent.addNode(menuNode);
|
|
111
|
-
this.
|
|
112
|
-
|
|
134
|
+
const parentPath = this.getParentPath(menuPath, group);
|
|
135
|
+
this.fireChangeEvent({
|
|
136
|
+
kind: ChangeKind.ADDED,
|
|
137
|
+
path: parentPath,
|
|
138
|
+
affectedChildId: menuNode.id
|
|
139
|
+
});
|
|
140
|
+
return this.changeEventOnDispose(parentPath, menuNode.id, disposable);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
protected getParentPath(menuPath: MenuPath | string, group?: string): string[] {
|
|
144
|
+
if (typeof menuPath === 'string') {
|
|
145
|
+
return group ? [menuPath, group] : [menuPath];
|
|
146
|
+
} else {
|
|
147
|
+
return group ? menuPath.concat(group) : menuPath;
|
|
148
|
+
}
|
|
113
149
|
}
|
|
114
150
|
|
|
115
151
|
getMenuNode(menuPath: MenuPath | string, group?: string): MutableCompoundMenuNode {
|
|
@@ -152,11 +188,19 @@ export class MenuModelRegistry {
|
|
|
152
188
|
let disposable = Disposable.NULL;
|
|
153
189
|
if (!groupNode) {
|
|
154
190
|
groupNode = new CompositeMenuNode(menuId, label, options, parent);
|
|
155
|
-
disposable = this.changeEventOnDispose(parent.addNode(groupNode));
|
|
191
|
+
disposable = this.changeEventOnDispose(groupPath, menuId, parent.addNode(groupNode));
|
|
192
|
+
this.fireChangeEvent({
|
|
193
|
+
kind: ChangeKind.ADDED,
|
|
194
|
+
path: groupPath,
|
|
195
|
+
affectedChildId: menuId
|
|
196
|
+
});
|
|
156
197
|
} else {
|
|
198
|
+
this.fireChangeEvent({
|
|
199
|
+
kind: ChangeKind.CHANGED,
|
|
200
|
+
path: groupPath,
|
|
201
|
+
});
|
|
157
202
|
groupNode.updateOptions({ ...options, label });
|
|
158
203
|
}
|
|
159
|
-
this.fireChangeEvent();
|
|
160
204
|
return disposable;
|
|
161
205
|
}
|
|
162
206
|
|
|
@@ -165,12 +209,13 @@ export class MenuModelRegistry {
|
|
|
165
209
|
console.debug(`Independent submenu with path ${id} registered, but given ID already exists.`);
|
|
166
210
|
}
|
|
167
211
|
this.independentSubmenus.set(id, new CompositeMenuNode(id, label, options));
|
|
168
|
-
return this.changeEventOnDispose(Disposable.create(() => this.independentSubmenus.delete(id)));
|
|
212
|
+
return this.changeEventOnDispose([], id, Disposable.create(() => this.independentSubmenus.delete(id)));
|
|
169
213
|
}
|
|
170
214
|
|
|
171
215
|
linkSubmenu(parentPath: MenuPath | string, childId: string | MenuPath, options?: SubMenuOptions, group?: string): Disposable {
|
|
172
216
|
const child = this.getMenuNode(childId);
|
|
173
217
|
const parent = this.getMenuNode(parentPath, group);
|
|
218
|
+
const affectedPath = this.getParentPath(parentPath, group);
|
|
174
219
|
|
|
175
220
|
const isRecursive = (node: MenuNodeMetadata, childNode: MenuNodeMetadata): boolean => {
|
|
176
221
|
if (node.id === childNode.id) {
|
|
@@ -190,8 +235,13 @@ export class MenuModelRegistry {
|
|
|
190
235
|
|
|
191
236
|
const wrapper = new CompositeMenuNodeWrapper(child, parent, options);
|
|
192
237
|
const disposable = parent.addNode(wrapper);
|
|
193
|
-
this.fireChangeEvent(
|
|
194
|
-
|
|
238
|
+
this.fireChangeEvent({
|
|
239
|
+
kind: ChangeKind.LINKED,
|
|
240
|
+
path: affectedPath,
|
|
241
|
+
affectedChildId: child.id
|
|
242
|
+
|
|
243
|
+
});
|
|
244
|
+
return this.changeEventOnDispose(affectedPath, child.id, disposable);
|
|
195
245
|
}
|
|
196
246
|
|
|
197
247
|
/**
|
|
@@ -223,11 +273,14 @@ export class MenuModelRegistry {
|
|
|
223
273
|
if (menuPath) {
|
|
224
274
|
const parent = this.findGroup(menuPath);
|
|
225
275
|
parent.removeNode(id);
|
|
226
|
-
this.fireChangeEvent(
|
|
227
|
-
|
|
276
|
+
this.fireChangeEvent({
|
|
277
|
+
kind: ChangeKind.REMOVED,
|
|
278
|
+
path: menuPath,
|
|
279
|
+
affectedChildId: id
|
|
280
|
+
});
|
|
281
|
+
} else {
|
|
282
|
+
this.unregisterMenuNode(id);
|
|
228
283
|
}
|
|
229
|
-
|
|
230
|
-
this.unregisterMenuNode(id);
|
|
231
284
|
}
|
|
232
285
|
|
|
233
286
|
/**
|
|
@@ -236,16 +289,24 @@ export class MenuModelRegistry {
|
|
|
236
289
|
* @param id technical identifier of the `MenuNode`.
|
|
237
290
|
*/
|
|
238
291
|
unregisterMenuNode(id: string): void {
|
|
292
|
+
const parentPath: string[] = [];
|
|
239
293
|
const recurse = (root: MutableCompoundMenuNode) => {
|
|
240
294
|
root.children.forEach(node => {
|
|
241
295
|
if (CompoundMenuNode.isMutable(node)) {
|
|
242
|
-
node.removeNode(id)
|
|
296
|
+
if (node.removeNode(id)) {
|
|
297
|
+
this.fireChangeEvent({
|
|
298
|
+
kind: ChangeKind.REMOVED,
|
|
299
|
+
path: parentPath,
|
|
300
|
+
affectedChildId: id
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
parentPath.push(node.id);
|
|
243
304
|
recurse(node);
|
|
305
|
+
parentPath.pop();
|
|
244
306
|
}
|
|
245
307
|
});
|
|
246
308
|
};
|
|
247
309
|
recurse(this.root);
|
|
248
|
-
this.fireChangeEvent();
|
|
249
310
|
}
|
|
250
311
|
|
|
251
312
|
/**
|
|
@@ -339,16 +400,20 @@ export class MenuModelRegistry {
|
|
|
339
400
|
return true;
|
|
340
401
|
}
|
|
341
402
|
|
|
342
|
-
protected changeEventOnDispose(disposable: Disposable): Disposable {
|
|
403
|
+
protected changeEventOnDispose(path: MenuPath, id: string, disposable: Disposable): Disposable {
|
|
343
404
|
return Disposable.create(() => {
|
|
344
405
|
disposable.dispose();
|
|
345
|
-
this.fireChangeEvent(
|
|
406
|
+
this.fireChangeEvent({
|
|
407
|
+
path,
|
|
408
|
+
affectedChildId: id,
|
|
409
|
+
kind: ChangeKind.REMOVED
|
|
410
|
+
});
|
|
346
411
|
});
|
|
347
412
|
}
|
|
348
413
|
|
|
349
|
-
protected fireChangeEvent(): void {
|
|
414
|
+
protected fireChangeEvent<T extends MenuChangedEvent>(evt: T): void {
|
|
350
415
|
if (this.isReady) {
|
|
351
|
-
this.onDidChangeEmitter.fire();
|
|
416
|
+
this.onDidChangeEmitter.fire(evt);
|
|
352
417
|
}
|
|
353
418
|
}
|
|
354
419
|
|
|
@@ -139,8 +139,9 @@ export interface MutableCompoundMenuNode extends CompoundMenuNode {
|
|
|
139
139
|
* Removes the first node with the given id.
|
|
140
140
|
*
|
|
141
141
|
* @param id node id.
|
|
142
|
+
* @returns true if the id was present
|
|
142
143
|
*/
|
|
143
|
-
removeNode(id: string):
|
|
144
|
+
removeNode(id: string): boolean;
|
|
144
145
|
|
|
145
146
|
/**
|
|
146
147
|
* Fills any `undefined` fields with the values from the {@link options}.
|
package/src/common/resource.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import { injectable, inject, named } from 'inversify';
|
|
17
|
+
import { injectable, inject, named, postConstruct } from 'inversify';
|
|
18
18
|
import { TextDocumentContentChangeEvent } from 'vscode-languageserver-protocol';
|
|
19
19
|
import URI from '../common/uri';
|
|
20
20
|
import { ContributionProvider } from './contribution-provider';
|
|
@@ -62,6 +62,8 @@ export interface Resource extends Disposable {
|
|
|
62
62
|
readonly readOnly?: boolean | MarkdownString;
|
|
63
63
|
|
|
64
64
|
readonly initiallyDirty?: boolean;
|
|
65
|
+
/** If false, the application should not attempt to auto-save this resource. */
|
|
66
|
+
readonly autosaveable?: boolean;
|
|
65
67
|
/**
|
|
66
68
|
* Reads latest content of this resource.
|
|
67
69
|
*
|
|
@@ -178,6 +180,11 @@ export namespace ResourceError {
|
|
|
178
180
|
|
|
179
181
|
export const ResourceResolver = Symbol('ResourceResolver');
|
|
180
182
|
export interface ResourceResolver {
|
|
183
|
+
/**
|
|
184
|
+
* Resolvers will be ordered by descending priority.
|
|
185
|
+
* Default: 0
|
|
186
|
+
*/
|
|
187
|
+
priority?: number;
|
|
181
188
|
/**
|
|
182
189
|
* Reject if a resource cannot be provided.
|
|
183
190
|
*/
|
|
@@ -195,6 +202,11 @@ export class DefaultResourceProvider {
|
|
|
195
202
|
protected readonly resolversProvider: ContributionProvider<ResourceResolver>
|
|
196
203
|
) { }
|
|
197
204
|
|
|
205
|
+
@postConstruct()
|
|
206
|
+
init(): void {
|
|
207
|
+
this.resolversProvider.getContributions().sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
208
|
+
}
|
|
209
|
+
|
|
198
210
|
/**
|
|
199
211
|
* Reject if a resource cannot be provided.
|
|
200
212
|
*/
|
|
@@ -213,7 +225,7 @@ export class DefaultResourceProvider {
|
|
|
213
225
|
}
|
|
214
226
|
|
|
215
227
|
export class MutableResource implements Resource {
|
|
216
|
-
|
|
228
|
+
protected contents: string = '';
|
|
217
229
|
|
|
218
230
|
constructor(readonly uri: URI) {
|
|
219
231
|
}
|
|
@@ -278,7 +290,7 @@ export class InMemoryResources implements ResourceResolver {
|
|
|
278
290
|
const resourceUri = uri.toString();
|
|
279
291
|
const resource = this.resources.get(resourceUri);
|
|
280
292
|
if (!resource) {
|
|
281
|
-
throw new Error(`Cannot update non-
|
|
293
|
+
throw new Error(`Cannot update non-existent in-memory resource '${resourceUri}'`);
|
|
282
294
|
}
|
|
283
295
|
resource.saveContents(contents);
|
|
284
296
|
return resource;
|
|
@@ -380,7 +392,8 @@ export class UntitledResourceResolver implements ResourceResolver {
|
|
|
380
392
|
export class UntitledResource implements Resource {
|
|
381
393
|
|
|
382
394
|
protected readonly onDidChangeContentsEmitter = new Emitter<void>();
|
|
383
|
-
initiallyDirty: boolean;
|
|
395
|
+
readonly initiallyDirty: boolean;
|
|
396
|
+
readonly autosaveable = false;
|
|
384
397
|
get onDidChangeContents(): Event<void> {
|
|
385
398
|
return this.onDidChangeContentsEmitter.event;
|
|
386
399
|
}
|
|
@@ -18,11 +18,14 @@ import { inject, injectable, postConstruct } from 'inversify';
|
|
|
18
18
|
import { LoggerWatcher } from '../common/logger-watcher';
|
|
19
19
|
import { LogLevelCliContribution } from './logger-cli-contribution';
|
|
20
20
|
import { ILoggerServer, ILoggerClient, ConsoleLogger, rootLoggerName } from '../common/logger-protocol';
|
|
21
|
+
import { format } from 'util';
|
|
22
|
+
import { EOL } from 'os';
|
|
23
|
+
import * as fs from 'fs';
|
|
21
24
|
|
|
22
25
|
@injectable()
|
|
23
26
|
export class ConsoleLoggerServer implements ILoggerServer {
|
|
24
27
|
|
|
25
|
-
protected client
|
|
28
|
+
protected client?: ILoggerClient;
|
|
26
29
|
|
|
27
30
|
@inject(LoggerWatcher)
|
|
28
31
|
protected watcher: LoggerWatcher;
|
|
@@ -30,6 +33,8 @@ export class ConsoleLoggerServer implements ILoggerServer {
|
|
|
30
33
|
@inject(LogLevelCliContribution)
|
|
31
34
|
protected cli: LogLevelCliContribution;
|
|
32
35
|
|
|
36
|
+
protected logFileStream?: fs.WriteStream;
|
|
37
|
+
|
|
33
38
|
@postConstruct()
|
|
34
39
|
protected init(): void {
|
|
35
40
|
this.setLogLevel(rootLoggerName, this.cli.defaultLogLevel);
|
|
@@ -59,7 +64,22 @@ export class ConsoleLoggerServer implements ILoggerServer {
|
|
|
59
64
|
async log(name: string, logLevel: number, message: string, params: any[]): Promise<void> {
|
|
60
65
|
const configuredLogLevel = await this.getLogLevel(name);
|
|
61
66
|
if (logLevel >= configuredLogLevel) {
|
|
62
|
-
ConsoleLogger.log(name, logLevel, message, params);
|
|
67
|
+
const fullMessage = ConsoleLogger.log(name, logLevel, message, params);
|
|
68
|
+
this.logToFile(fullMessage, params);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
protected logToFile(message: string, params: any[]): void {
|
|
73
|
+
if (this.cli.logFile && !this.logFileStream) {
|
|
74
|
+
this.logFileStream = fs.createWriteStream(this.cli.logFile, { flags: 'a' });
|
|
75
|
+
// Only log errors once to avoid spamming the console
|
|
76
|
+
this.logFileStream.once('error', error => {
|
|
77
|
+
console.error(`Error writing to log file ${this.cli.logFile}`, error);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (this.logFileStream) {
|
|
81
|
+
const formatted = format(message, ...params) + EOL;
|
|
82
|
+
this.logFileStream.write(formatted);
|
|
63
83
|
}
|
|
64
84
|
}
|
|
65
85
|
|
|
@@ -16,20 +16,19 @@
|
|
|
16
16
|
|
|
17
17
|
import { ContainerModule, Container, interfaces } from 'inversify';
|
|
18
18
|
import { ConnectionHandler, RpcConnectionHandler } from '../common/messaging';
|
|
19
|
-
import { ILogger, LoggerFactory, Logger, setRootLogger, LoggerName
|
|
19
|
+
import { ILogger, LoggerFactory, Logger, setRootLogger, LoggerName } from '../common/logger';
|
|
20
20
|
import { ILoggerServer, ILoggerClient, loggerPath, DispatchingLoggerClient } from '../common/logger-protocol';
|
|
21
21
|
import { ConsoleLoggerServer } from './console-logger-server';
|
|
22
22
|
import { LoggerWatcher } from '../common/logger-watcher';
|
|
23
23
|
import { BackendApplicationContribution } from './backend-application';
|
|
24
24
|
import { CliContribution } from './cli';
|
|
25
25
|
import { LogLevelCliContribution } from './logger-cli-contribution';
|
|
26
|
+
import { bindCommonLogger } from '../common/logger-binding';
|
|
26
27
|
|
|
27
28
|
export function bindLogger(bind: interfaces.Bind, props?: {
|
|
28
29
|
onLoggerServerActivation?: (context: interfaces.Context, server: ILoggerServer) => void
|
|
29
30
|
}): void {
|
|
30
|
-
bind
|
|
31
|
-
bind(ILogger).to(Logger).inSingletonScope().whenTargetIsDefault();
|
|
32
|
-
bind(LoggerWatcher).toSelf().inSingletonScope();
|
|
31
|
+
bindCommonLogger(bind);
|
|
33
32
|
bind<ILoggerServer>(ILoggerServer).to(ConsoleLoggerServer).inSingletonScope().onActivation((context, server) => {
|
|
34
33
|
if (props && props.onLoggerServerActivation) {
|
|
35
34
|
props.onLoggerServerActivation(context, server);
|
|
@@ -43,6 +43,8 @@ export class LogLevelCliContribution implements CliContribution {
|
|
|
43
43
|
*/
|
|
44
44
|
protected _defaultLogLevel: LogLevel = LogLevel.INFO;
|
|
45
45
|
|
|
46
|
+
protected _logFile?: string;
|
|
47
|
+
|
|
46
48
|
protected logConfigChangedEvent: Emitter<void> = new Emitter<void>();
|
|
47
49
|
|
|
48
50
|
get defaultLogLevel(): LogLevel {
|
|
@@ -53,6 +55,10 @@ export class LogLevelCliContribution implements CliContribution {
|
|
|
53
55
|
return this._logLevels;
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
get logFile(): string | undefined {
|
|
59
|
+
return this._logFile;
|
|
60
|
+
}
|
|
61
|
+
|
|
56
62
|
configure(conf: yargs.Argv): void {
|
|
57
63
|
conf.option('log-level', {
|
|
58
64
|
description: 'Sets the default log level',
|
|
@@ -65,6 +71,12 @@ export class LogLevelCliContribution implements CliContribution {
|
|
|
65
71
|
type: 'string',
|
|
66
72
|
nargs: 1,
|
|
67
73
|
});
|
|
74
|
+
|
|
75
|
+
conf.option('log-file', {
|
|
76
|
+
description: 'Path to the log file',
|
|
77
|
+
type: 'string',
|
|
78
|
+
nargs: 1
|
|
79
|
+
});
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
async setArguments(args: yargs.Arguments): Promise<void> {
|
|
@@ -87,22 +99,46 @@ export class LogLevelCliContribution implements CliContribution {
|
|
|
87
99
|
console.error(`Error reading log config file ${filename}: ${e}`);
|
|
88
100
|
}
|
|
89
101
|
}
|
|
102
|
+
|
|
103
|
+
if (args['log-file'] !== undefined) {
|
|
104
|
+
let filename = args['log-file'] as string;
|
|
105
|
+
try {
|
|
106
|
+
filename = path.resolve(filename);
|
|
107
|
+
try {
|
|
108
|
+
const stat = await fs.stat(filename);
|
|
109
|
+
if (stat && stat.isFile()) {
|
|
110
|
+
// Rename the previous log file to avoid overwriting it
|
|
111
|
+
const oldFilename = `${filename}.${stat.ctime.toISOString().replace(/:/g, '-')}.old`;
|
|
112
|
+
await fs.rename(filename, oldFilename);
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
// File does not exist, just continue to create it
|
|
116
|
+
}
|
|
117
|
+
await fs.writeFile(filename, '');
|
|
118
|
+
this._logFile = filename;
|
|
119
|
+
} catch (e) {
|
|
120
|
+
console.error(`Error creating log file ${filename}: ${e}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
90
123
|
}
|
|
91
124
|
|
|
92
125
|
protected async watchLogConfigFile(filename: string): Promise<void> {
|
|
93
|
-
|
|
126
|
+
const dir = path.dirname(filename);
|
|
127
|
+
await subscribe(dir, async (err, events) => {
|
|
94
128
|
if (err) {
|
|
95
129
|
console.log(`Error during log file watching ${filename}: ${err}`);
|
|
96
130
|
return;
|
|
97
131
|
}
|
|
98
132
|
try {
|
|
99
133
|
for (const event of events) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
134
|
+
if (event.path === filename) {
|
|
135
|
+
switch (event.type) {
|
|
136
|
+
case 'create':
|
|
137
|
+
case 'update':
|
|
138
|
+
await this.slurpLogConfigFile(filename);
|
|
139
|
+
this.logConfigChangedEvent.fire(undefined);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
106
142
|
}
|
|
107
143
|
}
|
|
108
144
|
} catch (e) {
|