فهرست منبع

Add rudimentary support for log levels

Jason Grout 5 سال پیش
والد
کامیت
fdb61db802

+ 40 - 4
packages/logconsole-extension/src/index.tsx

@@ -20,7 +20,8 @@ import { ISettingRegistry } from '@jupyterlab/coreutils';
 import {
   ILoggerRegistry,
   LogConsolePanel,
-  LoggerRegistry
+  LoggerRegistry,
+  LogLevel
 } from '@jupyterlab/logconsole';
 
 import { IMainMenu } from '@jupyterlab/mainmenu';
@@ -44,6 +45,7 @@ namespace CommandIDs {
   export const addTimestamp = 'logconsole:add-timestamp';
   export const clear = 'logconsole:clear';
   export const open = 'logconsole:open';
+  export const setLevel = 'logconsole:set-level';
 }
 
 /**
@@ -144,11 +146,31 @@ function activateLogConsole(
       id: CommandIDs.clear
     });
 
+    const logLevelInfoButton = new CommandToolbarButton({
+      commands: app.commands,
+      id: CommandIDs.setLevel,
+      args: { level: 'info' }
+    });
+
+    const logLevelWarningButton = new CommandToolbarButton({
+      commands: app.commands,
+      id: CommandIDs.setLevel,
+      args: { level: 'warning' }
+    });
+
     logConsoleWidget.toolbar.addItem(
-      'lab-output-console-add-timestamp',
+      'lab-log-console-add-timestamp',
       addTimestampButton
     );
-    logConsoleWidget.toolbar.addItem('lab-output-console-clear', clearButton);
+    logConsoleWidget.toolbar.addItem('lab-log-console-clear', clearButton);
+    logConsoleWidget.toolbar.addItem(
+      'lab-log-console-info',
+      logLevelInfoButton
+    );
+    logConsoleWidget.toolbar.addItem(
+      'lab-log-console-warning',
+      logLevelWarningButton
+    );
 
     logConsolePanel.sourceChanged.connect(() => {
       app.commands.notifyCommandChanged();
@@ -193,7 +215,7 @@ function activateLogConsole(
     label: 'Add Timestamp',
     execute: () => {
       const logger = loggerRegistry.getLogger(logConsolePanel.source);
-      logger.log({ type: 'html', data: '<hr>' });
+      logger.log({ type: 'html', data: '<hr>', level: 'critical' });
     },
     isEnabled: () => logConsolePanel && logConsolePanel.source !== null,
     iconClass: 'jp-AddIcon'
@@ -209,6 +231,20 @@ function activateLogConsole(
     iconClass: 'fa fa-ban clear-icon'
   });
 
+  function toTitleCase(value: string) {
+    return value.length === 0 ? value : value[0].toUpperCase() + value.slice(1);
+  }
+
+  app.commands.addCommand(CommandIDs.setLevel, {
+    label: args => `Set Log Level to ${toTitleCase(args.level as string)}`,
+    execute: (args: { level: LogLevel }) => {
+      const logger = loggerRegistry.getLogger(logConsolePanel.source);
+      logger.level = args.level;
+    },
+    isEnabled: () => logConsolePanel && logConsolePanel.source !== null
+    // TODO: find good icon class
+  });
+
   app.contextMenu.addItem({
     command: CommandIDs.open,
     selector: '.jp-Notebook'

+ 1 - 1
packages/logconsole-extension/src/nboutput.ts

@@ -44,7 +44,7 @@ function activateNBOutput(
             ...msg.content,
             output_type: msg.header.msg_type
           };
-          logger.log({ type: 'output', data });
+          logger.log({ type: 'output', data, level: 'info' });
         }
       }
     );

+ 48 - 12
packages/logconsole/src/logger.ts

@@ -17,23 +17,24 @@ import {
   ILogger,
   ILoggerChange,
   ILoggerOutputAreaModel,
-  ILogPayload
+  ILogPayload,
+  LogLevel
 } from './tokens';
 
 /**
- * Custom Notebook Output with timestamp member.
+ * Custom Notebook Output with log info.
  */
-interface ITimestampedOutput extends nbformat.IBaseOutput {
+type ILogOutput = nbformat.IOutput & {
   /**
    * Date & time when output is logged in integer representation.
    */
   timestamp: number;
-}
 
-/**
- * Custom Notebook Output with optional timestamp.
- */
-type IOutputWithTimestamp = nbformat.IOutput | ITimestampedOutput;
+  /**
+   * Log level
+   */
+  level: LogLevel;
+};
 
 /**
  * Log Output Model with timestamp which provides
@@ -49,12 +50,18 @@ export class LogOutputModel extends OutputModel {
     super(options);
 
     this.timestamp = new Date(options.value.timestamp as number);
+    this.level = options.value.level;
   }
 
   /**
    * Date & time when output is logged.
    */
   timestamp: Date = null;
+
+  /**
+   * Log level
+   */
+  level: LogLevel;
 }
 
 /**
@@ -62,7 +69,7 @@ export class LogOutputModel extends OutputModel {
  */
 namespace LogOutputModel {
   export interface IOptions extends IOutputModel.IOptions {
-    value: IOutputWithTimestamp;
+    value: ILogOutput;
   }
 }
 
@@ -74,7 +81,7 @@ class LogConsoleModelContentFactory extends OutputAreaModel.ContentFactory {
   /**
    * Create a rendermime output model from notebook output.
    */
-  createOutputModel(options: IOutputModel.IOptions): LogOutputModel {
+  createOutputModel(options: LogOutputModel.IOptions): LogOutputModel {
     return new LogOutputModel(options);
   }
 }
@@ -100,7 +107,7 @@ export class LoggerOutputAreaModel extends OutputAreaModel
    * are combined. The oldest outputs are possibly removed to ensure the total
    * number of outputs is at most `.maxLength`.
    */
-  add(output: nbformat.IOutput): number {
+  add(output: ILogOutput): number {
     super.add(output);
     this._applyMaxLength();
     return this.length;
@@ -169,6 +176,16 @@ export class Logger implements ILogger {
     this.outputAreaModel.maxLength = value;
   }
 
+  /**
+   * The level of outputs logged
+   */
+  get level(): LogLevel {
+    return Private.LogLevel[this._level] as keyof typeof Private.LogLevel;
+  }
+  set level(value: LogLevel) {
+    this._level = Private.LogLevel[value];
+  }
+
   /**
    * Number of outputs logged.
    */
@@ -230,6 +247,10 @@ export class Logger implements ILogger {
    * @param log - The output to be logged.
    */
   log(log: ILogPayload) {
+    // Filter by our current log level
+    if (Private.LogLevel[log.level] < this._level) {
+      return;
+    }
     const timestamp = new Date();
     let output: nbformat.IOutput = null;
 
@@ -263,7 +284,11 @@ export class Logger implements ILogger {
       this._version++;
 
       // Next, trigger any displays of the message
-      this.outputAreaModel.add({ ...output, timestamp: timestamp.valueOf() });
+      this.outputAreaModel.add({
+        ...output,
+        timestamp: timestamp.valueOf(),
+        level: log.level
+      });
 
       // Finally, tell people that the message was appended (and possibly
       // already displayed).
@@ -283,6 +308,7 @@ export class Logger implements ILogger {
   private _rendermime: IRenderMimeRegistry | null = null;
   private _rendermimeChanged = new Signal<this, void>(this);
   private _version = 0;
+  private _level: Private.LogLevel = Private.LogLevel.warning;
 }
 
 export namespace Logger {
@@ -297,3 +323,13 @@ export namespace Logger {
     maxLength: number;
   }
 }
+
+namespace Private {
+  export enum LogLevel {
+    debug,
+    info,
+    warning,
+    error,
+    critical
+  }
+}

+ 14 - 0
packages/logconsole/src/tokens.ts

@@ -46,6 +46,11 @@ export interface ILoggerRegistry {
   readonly registryChanged: ISignal<this, ILoggerRegistryChange>;
 }
 
+/**
+ * Log severity level
+ */
+export type LogLevel = 'critical' | 'error' | 'warning' | 'info' | 'debug';
+
 /**
  * The base log payload type.
  */
@@ -55,6 +60,11 @@ export interface ILogPayloadBase {
    */
   type: string;
 
+  /**
+   * Log level
+   */
+  level: LogLevel;
+
   /**
    * Data
    */
@@ -129,6 +139,10 @@ export interface ILogger {
    * Max number of messages.
    */
   maxLength: number;
+  /**
+   * Log level.
+   */
+  level: LogLevel;
   /**
    * Rendermime to use when rendering outputs logged.
    */

+ 17 - 2
packages/logconsole/src/widget.ts

@@ -21,7 +21,8 @@ import {
   ILogger,
   ILoggerChange,
   ILoggerRegistry,
-  ILoggerRegistryChange
+  ILoggerRegistryChange,
+  LogLevel
 } from './tokens';
 
 /**
@@ -33,6 +34,10 @@ class LogConsoleOutputPrompt extends Widget implements IOutputPrompt {
 
     this._timestampNode = document.createElement('div');
     this.node.append(this._timestampNode);
+
+    // TODO: make a better level display
+    this._levelNode = document.createElement('div');
+    this.node.append(this._levelNode);
   }
 
   /**
@@ -42,12 +47,20 @@ class LogConsoleOutputPrompt extends Widget implements IOutputPrompt {
     this._timestampNode.innerHTML = value.toLocaleTimeString();
   }
 
+  /**
+   * Log level
+   */
+  set level(value: LogLevel) {
+    this._levelNode.innerHTML = value;
+  }
+
   /**
    * The execution count for the prompt.
    */
   executionCount: nbformat.ExecutionCount;
 
   private _timestampNode: HTMLDivElement;
+  private _levelNode: HTMLDivElement;
 }
 
 /**
@@ -70,7 +83,9 @@ class LogConsoleOutputArea extends OutputArea {
   protected createOutputItem(model: LogOutputModel): Widget | null {
     const panel = super.createOutputItem(model) as Panel;
     // first widget in panel is prompt of type LoggerOutputPrompt
-    (panel.widgets[0] as LogConsoleOutputPrompt).timestamp = model.timestamp;
+    let prompt = panel.widgets[0] as LogConsoleOutputPrompt;
+    prompt.timestamp = model.timestamp;
+    prompt.level = model.level;
     return panel;
   }