@jupyterlab/logconsole 4.0.0-alpha.9 → 4.0.0-beta.1

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/src/logger.ts ADDED
@@ -0,0 +1,436 @@
1
+ // Copyright (c) Jupyter Development Team.
2
+ // Distributed under the terms of the Modified BSD License.
3
+
4
+ import * as nbformat from '@jupyterlab/nbformat';
5
+ import { IOutputAreaModel, OutputAreaModel } from '@jupyterlab/outputarea';
6
+ import {
7
+ IOutputModel,
8
+ IRenderMimeRegistry,
9
+ OutputModel
10
+ } from '@jupyterlab/rendermime';
11
+ import { ISignal, Signal } from '@lumino/signaling';
12
+ import {
13
+ IContentChange,
14
+ ILogger,
15
+ ILoggerOutputAreaModel,
16
+ ILogPayload,
17
+ IStateChange,
18
+ LogLevel
19
+ } from './tokens';
20
+
21
+ /**
22
+ * All severity levels, including an internal one for metadata.
23
+ */
24
+ type FullLogLevel = LogLevel | 'metadata';
25
+
26
+ /**
27
+ * Custom Notebook Output with log info.
28
+ */
29
+ type ILogOutput = nbformat.IOutput & {
30
+ /**
31
+ * Date & time when output is logged in integer representation.
32
+ */
33
+ timestamp: number;
34
+
35
+ /**
36
+ * Log level
37
+ */
38
+ level: FullLogLevel;
39
+ };
40
+
41
+ export interface ILogOutputModel extends IOutputModel {
42
+ /**
43
+ * Date & time when output is logged.
44
+ */
45
+ readonly timestamp: Date;
46
+
47
+ /**
48
+ * Log level
49
+ */
50
+ readonly level: FullLogLevel;
51
+ }
52
+
53
+ /**
54
+ * Log Output Model with timestamp which provides
55
+ * item information for Output Area Model.
56
+ */
57
+ export class LogOutputModel extends OutputModel implements ILogOutputModel {
58
+ /**
59
+ * Construct a LogOutputModel.
60
+ *
61
+ * @param options - The model initialization options.
62
+ */
63
+ constructor(options: LogOutputModel.IOptions) {
64
+ super(options);
65
+
66
+ this.timestamp = new Date(options.value.timestamp);
67
+ this.level = options.value.level;
68
+ }
69
+
70
+ /**
71
+ * Date & time when output is logged.
72
+ */
73
+ readonly timestamp: Date;
74
+
75
+ /**
76
+ * Log level
77
+ */
78
+ readonly level: FullLogLevel;
79
+ }
80
+
81
+ /**
82
+ * Log Output Model namespace that defines initialization options.
83
+ */
84
+ namespace LogOutputModel {
85
+ export interface IOptions extends IOutputModel.IOptions {
86
+ value: ILogOutput;
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Implementation of `IContentFactory` for Output Area Model
92
+ * which creates LogOutputModel instances.
93
+ */
94
+ class LogConsoleModelContentFactory extends OutputAreaModel.ContentFactory {
95
+ /**
96
+ * Create a rendermime output model from notebook output.
97
+ */
98
+ createOutputModel(options: LogOutputModel.IOptions): LogOutputModel {
99
+ return new LogOutputModel(options);
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Output Area Model implementation which is able to
105
+ * limit number of outputs stored.
106
+ */
107
+ export class LoggerOutputAreaModel
108
+ extends OutputAreaModel
109
+ implements ILoggerOutputAreaModel
110
+ {
111
+ constructor({ maxLength, ...options }: LoggerOutputAreaModel.IOptions) {
112
+ super(options);
113
+ this.maxLength = maxLength;
114
+ }
115
+
116
+ /**
117
+ * Add an output, which may be combined with previous output.
118
+ *
119
+ * @returns The total number of outputs.
120
+ *
121
+ * #### Notes
122
+ * The output bundle is copied. Contiguous stream outputs of the same `name`
123
+ * are combined. The oldest outputs are possibly removed to ensure the total
124
+ * number of outputs is at most `.maxLength`.
125
+ */
126
+ add(output: ILogOutput): number {
127
+ super.add(output);
128
+ this._applyMaxLength();
129
+ return this.length;
130
+ }
131
+
132
+ /**
133
+ * Whether an output should combine with the previous output.
134
+ *
135
+ * We combine if the two outputs are in the same second, which is the
136
+ * resolution for our time display.
137
+ */
138
+ protected shouldCombine(options: {
139
+ value: ILogOutput;
140
+ lastModel: ILogOutputModel;
141
+ }): boolean {
142
+ const { value, lastModel } = options;
143
+
144
+ const oldSeconds = Math.trunc(lastModel.timestamp.getTime() / 1000);
145
+ const newSeconds = Math.trunc(value.timestamp / 1000);
146
+
147
+ return oldSeconds === newSeconds;
148
+ }
149
+
150
+ /**
151
+ * Get an item at the specified index.
152
+ */
153
+ get(index: number): ILogOutputModel {
154
+ return super.get(index) as ILogOutputModel;
155
+ }
156
+
157
+ /**
158
+ * Maximum number of outputs to store in the model.
159
+ */
160
+ get maxLength(): number {
161
+ return this._maxLength;
162
+ }
163
+ set maxLength(value: number) {
164
+ this._maxLength = value;
165
+ this._applyMaxLength();
166
+ }
167
+
168
+ /**
169
+ * Manually apply length limit.
170
+ */
171
+ private _applyMaxLength() {
172
+ if (this.list.length > this._maxLength) {
173
+ this.list.removeRange(0, this.list.length - this._maxLength);
174
+ }
175
+ }
176
+
177
+ private _maxLength: number;
178
+ }
179
+
180
+ export namespace LoggerOutputAreaModel {
181
+ export interface IOptions extends IOutputAreaModel.IOptions {
182
+ /**
183
+ * The maximum number of messages stored.
184
+ */
185
+ maxLength: number;
186
+ }
187
+ }
188
+
189
+ /**
190
+ * A concrete implementation of ILogger.
191
+ */
192
+ export class Logger implements ILogger {
193
+ /**
194
+ * Construct a Logger.
195
+ *
196
+ * @param source - The name of the log source.
197
+ */
198
+ constructor(options: Logger.IOptions) {
199
+ this.source = options.source;
200
+ this.outputAreaModel = new LoggerOutputAreaModel({
201
+ contentFactory: new LogConsoleModelContentFactory(),
202
+ maxLength: options.maxLength
203
+ });
204
+ }
205
+
206
+ /**
207
+ * The maximum number of outputs stored.
208
+ *
209
+ * #### Notes
210
+ * Oldest entries will be trimmed to ensure the length is at most
211
+ * `.maxLength`.
212
+ */
213
+ get maxLength(): number {
214
+ return this.outputAreaModel.maxLength;
215
+ }
216
+ set maxLength(value: number) {
217
+ this.outputAreaModel.maxLength = value;
218
+ }
219
+
220
+ /**
221
+ * The level of outputs logged
222
+ */
223
+ get level(): LogLevel {
224
+ return this._level;
225
+ }
226
+ set level(newValue: LogLevel) {
227
+ const oldValue = this._level;
228
+ if (oldValue === newValue) {
229
+ return;
230
+ }
231
+ this._level = newValue;
232
+ this._log({
233
+ output: {
234
+ output_type: 'display_data',
235
+ data: {
236
+ 'text/plain': `Log level set to ${newValue}`
237
+ }
238
+ },
239
+ level: 'metadata'
240
+ });
241
+ this._stateChanged.emit({ name: 'level', oldValue, newValue });
242
+ }
243
+
244
+ /**
245
+ * Number of outputs logged.
246
+ */
247
+ get length(): number {
248
+ return this.outputAreaModel.length;
249
+ }
250
+
251
+ /**
252
+ * A signal emitted when the list of log messages changes.
253
+ */
254
+ get contentChanged(): ISignal<this, IContentChange> {
255
+ return this._contentChanged;
256
+ }
257
+
258
+ /**
259
+ * A signal emitted when the log state changes.
260
+ */
261
+ get stateChanged(): ISignal<this, IStateChange> {
262
+ return this._stateChanged;
263
+ }
264
+
265
+ /**
266
+ * Rendermime to use when rendering outputs logged.
267
+ */
268
+ get rendermime(): IRenderMimeRegistry | null {
269
+ return this._rendermime;
270
+ }
271
+ set rendermime(value: IRenderMimeRegistry | null) {
272
+ if (value !== this._rendermime) {
273
+ const oldValue = this._rendermime;
274
+ const newValue = (this._rendermime = value);
275
+ this._stateChanged.emit({ name: 'rendermime', oldValue, newValue });
276
+ }
277
+ }
278
+
279
+ /**
280
+ * The number of messages that have ever been stored.
281
+ */
282
+ get version(): number {
283
+ return this._version;
284
+ }
285
+
286
+ /**
287
+ * The source for the logger.
288
+ */
289
+ readonly source: string;
290
+
291
+ /**
292
+ * The output area model used for the logger.
293
+ *
294
+ * #### Notes
295
+ * This will usually not be accessed directly. It is a public attribute so
296
+ * that the renderer can access it.
297
+ */
298
+ readonly outputAreaModel: LoggerOutputAreaModel;
299
+
300
+ /**
301
+ * Log an output to logger.
302
+ *
303
+ * @param log - The output to be logged.
304
+ */
305
+ log(log: ILogPayload): void {
306
+ // Filter by our current log level
307
+ if (
308
+ Private.LogLevel[log.level as keyof typeof Private.LogLevel] <
309
+ Private.LogLevel[this._level as keyof typeof Private.LogLevel]
310
+ ) {
311
+ return;
312
+ }
313
+ let output: nbformat.IOutput | null = null;
314
+ switch (log.type) {
315
+ case 'text':
316
+ output = {
317
+ output_type: 'display_data',
318
+ data: {
319
+ 'text/plain': log.data
320
+ }
321
+ };
322
+ break;
323
+ case 'html':
324
+ output = {
325
+ output_type: 'display_data',
326
+ data: {
327
+ 'text/html': log.data
328
+ }
329
+ };
330
+ break;
331
+ case 'output':
332
+ output = log.data;
333
+ break;
334
+ default:
335
+ break;
336
+ }
337
+
338
+ if (output) {
339
+ this._log({
340
+ output,
341
+ level: log.level
342
+ });
343
+ }
344
+ }
345
+
346
+ /**
347
+ * Clear all outputs logged.
348
+ */
349
+ clear(): void {
350
+ this.outputAreaModel.clear(false);
351
+ this._contentChanged.emit('clear');
352
+ }
353
+
354
+ /**
355
+ * Add a checkpoint to the log.
356
+ */
357
+ checkpoint(): void {
358
+ this._log({
359
+ output: {
360
+ output_type: 'display_data',
361
+ data: {
362
+ 'text/html': '<hr/>'
363
+ }
364
+ },
365
+ level: 'metadata'
366
+ });
367
+ }
368
+
369
+ /**
370
+ * Whether the logger is disposed.
371
+ */
372
+ get isDisposed(): boolean {
373
+ return this._isDisposed;
374
+ }
375
+
376
+ /**
377
+ * Dispose the logger.
378
+ */
379
+ dispose(): void {
380
+ if (this.isDisposed) {
381
+ return;
382
+ }
383
+ this._isDisposed = true;
384
+ this.clear();
385
+ this._rendermime = null!;
386
+ Signal.clearData(this);
387
+ }
388
+
389
+ private _log(options: { output: nbformat.IOutput; level: FullLogLevel }) {
390
+ // First, make sure our version reflects the new message so things
391
+ // triggering from the signals below have the correct version.
392
+ this._version++;
393
+
394
+ // Next, trigger any displays of the message
395
+ this.outputAreaModel.add({
396
+ ...options.output,
397
+ timestamp: Date.now(),
398
+ level: options.level
399
+ });
400
+
401
+ // Finally, tell people that the message was appended (and possibly
402
+ // already displayed).
403
+ this._contentChanged.emit('append');
404
+ }
405
+
406
+ private _isDisposed = false;
407
+ private _contentChanged = new Signal<this, IContentChange>(this);
408
+ private _stateChanged = new Signal<this, IStateChange>(this);
409
+ private _rendermime: IRenderMimeRegistry | null = null;
410
+ private _version = 0;
411
+ private _level: LogLevel = 'warning';
412
+ }
413
+
414
+ export namespace Logger {
415
+ export interface IOptions {
416
+ /**
417
+ * The log source identifier.
418
+ */
419
+ source: string;
420
+ /**
421
+ * The maximum number of messages to store.
422
+ */
423
+ maxLength: number;
424
+ }
425
+ }
426
+
427
+ namespace Private {
428
+ export enum LogLevel {
429
+ debug,
430
+ info,
431
+ warning,
432
+ error,
433
+ critical,
434
+ metadata
435
+ }
436
+ }
@@ -0,0 +1,107 @@
1
+ // Copyright (c) Jupyter Development Team.
2
+ // Distributed under the terms of the Modified BSD License.
3
+
4
+ import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
5
+ import { ISignal, Signal } from '@lumino/signaling';
6
+ import { Logger } from './logger';
7
+ import { ILogger, ILoggerRegistry, ILoggerRegistryChange } from './tokens';
8
+
9
+ /**
10
+ * A concrete implementation of ILoggerRegistry.
11
+ */
12
+ export class LoggerRegistry implements ILoggerRegistry {
13
+ /**
14
+ * Construct a LoggerRegistry.
15
+ *
16
+ * @param defaultRendermime - Default rendermime to render outputs
17
+ * with when logger is not supplied with one.
18
+ */
19
+ constructor(options: LoggerRegistry.IOptions) {
20
+ this._defaultRendermime = options.defaultRendermime;
21
+ this._maxLength = options.maxLength;
22
+ }
23
+
24
+ /**
25
+ * Get the logger for the specified source.
26
+ *
27
+ * @param source - The name of the log source.
28
+ *
29
+ * @returns The logger for the specified source.
30
+ */
31
+ getLogger(source: string): ILogger {
32
+ const loggers = this._loggers;
33
+ let logger = loggers.get(source);
34
+ if (logger) {
35
+ return logger;
36
+ }
37
+
38
+ logger = new Logger({ source, maxLength: this.maxLength });
39
+ logger.rendermime = this._defaultRendermime;
40
+ loggers.set(source, logger);
41
+
42
+ this._registryChanged.emit('append');
43
+
44
+ return logger;
45
+ }
46
+
47
+ /**
48
+ * Get all loggers registered.
49
+ *
50
+ * @returns The array containing all registered loggers.
51
+ */
52
+ getLoggers(): ILogger[] {
53
+ return Array.from(this._loggers.values());
54
+ }
55
+
56
+ /**
57
+ * A signal emitted when the logger registry changes.
58
+ */
59
+ get registryChanged(): ISignal<this, ILoggerRegistryChange> {
60
+ return this._registryChanged;
61
+ }
62
+
63
+ /**
64
+ * The max length for loggers.
65
+ */
66
+ get maxLength(): number {
67
+ return this._maxLength;
68
+ }
69
+ set maxLength(value: number) {
70
+ this._maxLength = value;
71
+ this._loggers.forEach(logger => {
72
+ logger.maxLength = value;
73
+ });
74
+ }
75
+
76
+ /**
77
+ * Whether the register is disposed.
78
+ */
79
+ get isDisposed(): boolean {
80
+ return this._isDisposed;
81
+ }
82
+
83
+ /**
84
+ * Dispose the registry and all loggers.
85
+ */
86
+ dispose(): void {
87
+ if (this.isDisposed) {
88
+ return;
89
+ }
90
+ this._isDisposed = true;
91
+ this._loggers.forEach(x => x.dispose());
92
+ Signal.clearData(this);
93
+ }
94
+
95
+ private _defaultRendermime: IRenderMimeRegistry;
96
+ private _loggers = new Map<string, ILogger>();
97
+ private _maxLength: number;
98
+ private _registryChanged = new Signal<this, ILoggerRegistryChange>(this);
99
+ private _isDisposed = false;
100
+ }
101
+
102
+ export namespace LoggerRegistry {
103
+ export interface IOptions {
104
+ defaultRendermime: IRenderMimeRegistry;
105
+ maxLength: number;
106
+ }
107
+ }
package/src/tokens.ts ADDED
@@ -0,0 +1,189 @@
1
+ // Copyright (c) Jupyter Development Team.
2
+ // Distributed under the terms of the Modified BSD License.
3
+
4
+ import { IChangedArgs } from '@jupyterlab/coreutils';
5
+ import * as nbformat from '@jupyterlab/nbformat';
6
+ import { IOutputAreaModel } from '@jupyterlab/outputarea';
7
+ import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
8
+ import { Token } from '@lumino/coreutils';
9
+ import { IDisposable } from '@lumino/disposable';
10
+ import { ISignal } from '@lumino/signaling';
11
+
12
+ /**
13
+ * The Logger Registry token.
14
+ */
15
+ export const ILoggerRegistry = new Token<ILoggerRegistry>(
16
+ '@jupyterlab/logconsole:ILoggerRegistry'
17
+ );
18
+
19
+ export type ILoggerRegistryChange = 'append';
20
+
21
+ /**
22
+ * A Logger Registry that registers and provides loggers by source.
23
+ */
24
+ export interface ILoggerRegistry extends IDisposable {
25
+ /**
26
+ * Get the logger for the specified source.
27
+ *
28
+ * @param source - The name of the log source.
29
+ *
30
+ * @returns The logger for the specified source.
31
+ */
32
+ getLogger(source: string): ILogger;
33
+ /**
34
+ * Get all loggers registered.
35
+ *
36
+ * @returns The array containing all registered loggers.
37
+ */
38
+ getLoggers(): ILogger[];
39
+
40
+ /**
41
+ * A signal emitted when the logger registry changes.
42
+ */
43
+ readonly registryChanged: ISignal<this, ILoggerRegistryChange>;
44
+ }
45
+
46
+ /**
47
+ * Log severity level
48
+ */
49
+ export type LogLevel = 'critical' | 'error' | 'warning' | 'info' | 'debug';
50
+
51
+ /**
52
+ * The base log payload type.
53
+ */
54
+ export interface ILogPayloadBase {
55
+ /**
56
+ * Type of log data.
57
+ */
58
+ type: string;
59
+
60
+ /**
61
+ * Log level
62
+ */
63
+ level: LogLevel;
64
+
65
+ /**
66
+ * Data
67
+ */
68
+ data: any;
69
+ }
70
+
71
+ /**
72
+ * Plain text log payload.
73
+ */
74
+ export interface ITextLog extends ILogPayloadBase {
75
+ /**
76
+ * Type of log data.
77
+ */
78
+ type: 'text';
79
+ /**
80
+ * Log data as plain text.
81
+ */
82
+ data: string;
83
+ }
84
+
85
+ /**
86
+ * HTML log payload.
87
+ */
88
+ export interface IHtmlLog extends ILogPayloadBase {
89
+ /**
90
+ * Type of log data.
91
+ */
92
+ type: 'html';
93
+ /**
94
+ * Log data as HTML string.
95
+ */
96
+ data: string;
97
+ }
98
+
99
+ /**
100
+ * Notebook kernel output log payload.
101
+ */
102
+ export interface IOutputLog extends ILogPayloadBase {
103
+ /**
104
+ * Type of log data.
105
+ */
106
+ type: 'output';
107
+ /**
108
+ * Log data as Notebook kernel output.
109
+ */
110
+ data: nbformat.IOutput;
111
+ }
112
+
113
+ /**
114
+ * Log payload union type.
115
+ */
116
+ export type ILogPayload = ITextLog | IHtmlLog | IOutputLog;
117
+
118
+ export type IContentChange = 'append' | 'clear';
119
+
120
+ export type IStateChange =
121
+ | IChangedArgs<
122
+ IRenderMimeRegistry | null,
123
+ IRenderMimeRegistry | null,
124
+ 'rendermime'
125
+ >
126
+ | IChangedArgs<LogLevel, LogLevel, 'level'>;
127
+
128
+ export interface ILoggerOutputAreaModel extends IOutputAreaModel {
129
+ /**
130
+ * The maximum number of outputs to store.
131
+ */
132
+ maxLength: number;
133
+ }
134
+
135
+ /**
136
+ * A Logger that manages logs from a particular source.
137
+ */
138
+ export interface ILogger extends IDisposable {
139
+ /**
140
+ * Number of outputs logged.
141
+ */
142
+ readonly length: number;
143
+ /**
144
+ * Max number of messages.
145
+ */
146
+ maxLength: number;
147
+ /**
148
+ * Log level.
149
+ */
150
+ level: LogLevel;
151
+ /**
152
+ * Rendermime to use when rendering outputs logged.
153
+ */
154
+ rendermime: IRenderMimeRegistry | null;
155
+ /**
156
+ * A signal emitted when the log model changes.
157
+ */
158
+ readonly contentChanged: ISignal<this, IContentChange>;
159
+ /**
160
+ * A signal emitted when the rendermime changes.
161
+ */
162
+ readonly stateChanged: ISignal<this, IStateChange>;
163
+ /**
164
+ * The name of the log source.
165
+ */
166
+ readonly source: string;
167
+ /**
168
+ * Output Area Model used to manage log storage in memory.
169
+ */
170
+ readonly outputAreaModel: ILoggerOutputAreaModel;
171
+ /**
172
+ * The cumulative number of messages the log has stored.
173
+ */
174
+ readonly version: number;
175
+ /**
176
+ * Log an output to logger.
177
+ *
178
+ * @param log - The output to be logged.
179
+ */
180
+ log(log: ILogPayload): void;
181
+ /**
182
+ * Add a checkpoint in the log.
183
+ */
184
+ checkpoint(): void;
185
+ /**
186
+ * Clear all outputs logged.
187
+ */
188
+ clear(): void;
189
+ }