feat(handler): implement StreamHandler, ConsoleHandler, StderrHandler emit
StreamHandler.emit() writes formatted output to a Writable stream. ConsoleHandler maps log levels to console.warn/error/log. StderrHandler emits via console.error. handleError() logs diagnostics instead of throwing. FileHandler throws NotImplementedError on construction. Removed Node.js stream import and conditional require() block.
This commit is contained in:
parent
e6b7f02166
commit
3a6332a855
1 changed files with 83 additions and 42 deletions
121
src/handler.ts
121
src/handler.ts
|
|
@ -1,17 +1,9 @@
|
||||||
import * as stream from 'stream';
|
import { LogLevel, checkLevel, NOTSET, WARNING, ERROR } from './log-level';
|
||||||
|
|
||||||
import { LogLevel, checkLevel, NOTSET } from './log-level';
|
|
||||||
import { LogRecord } from './log-record';
|
import { LogRecord } from './log-record';
|
||||||
import { Formatter, DEFAULT_FORMATTER } from './formatter';
|
import { Formatter, DEFAULT_FORMATTER } from './formatter';
|
||||||
import { Filterer } from './filter';
|
import { Filterer } from './filter';
|
||||||
import { NotImplementedError } from './helper/error';
|
import { NotImplementedError } from './helper/error';
|
||||||
|
import { Writable, DEFAULT_STREAM, StderrWritable } from './helper/stream';
|
||||||
if (typeof window === 'undefined') {
|
|
||||||
const stream = require('stream');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const stream = require('./helper/stream');
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Handler classes and functions
|
// Handler classes and functions
|
||||||
|
|
@ -115,14 +107,13 @@ export class Handler extends Filterer {
|
||||||
* I/O thread lock.
|
* I/O thread lock.
|
||||||
*/
|
*/
|
||||||
handle(record: LogRecord) {
|
handle(record: LogRecord) {
|
||||||
var rv = this.filter(record);
|
const rv = this.filter(record);
|
||||||
|
if (!rv) { return }
|
||||||
|
let filtered = record;
|
||||||
if ((rv as any) instanceof LogRecord) {
|
if ((rv as any) instanceof LogRecord) {
|
||||||
record = rv as unknown as LogRecord
|
filtered = rv as unknown as LogRecord
|
||||||
}
|
|
||||||
if (rv) {
|
|
||||||
//locking here
|
|
||||||
this.emit(record)
|
|
||||||
}
|
}
|
||||||
|
this.emit(filtered)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -144,23 +135,73 @@ export class Handler extends Filterer {
|
||||||
* Handle errors which occur during an emit() call.
|
* Handle errors which occur during an emit() call.
|
||||||
*
|
*
|
||||||
* This method should be called from handlers when an exception is
|
* This method should be called from handlers when an exception is
|
||||||
* encountered during an emit() call. If raiseExceptions is false,
|
* encountered during an emit() call.
|
||||||
* exceptions get silently ignored. This is what is mostly wanted
|
|
||||||
* for a logging system - most users will not care about errors in
|
|
||||||
* the logging system, they are more interested in application errors.
|
|
||||||
* You could, however, replace this with a custom handler if you wish.
|
|
||||||
* The record which was being processed is passed in to this method.
|
|
||||||
*/
|
*/
|
||||||
handleError(record: LogRecord) {
|
handleError(record: LogRecord) {
|
||||||
throw new NotImplementedError(
|
try {
|
||||||
'still need to find portable way for stacktracing...'
|
console.error('--- Logging error ---');
|
||||||
)
|
console.error('Error in handler for record:', record.scope, record.msg);
|
||||||
|
}
|
||||||
|
catch (_) {
|
||||||
|
// silently ignore errors in error handling
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get formatter(): Formatter|null { return this._formatter }
|
get formatter(): Formatter|null { return this._formatter }
|
||||||
set formatter(fmt: Formatter) { this._formatter = fmt }
|
set formatter(fmt: Formatter) { this._formatter = fmt }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handler class which writes logging records, appropriately formatted,
|
||||||
|
* to a stream. Note that this class does not close the stream, as
|
||||||
|
* the default stream may be shared.
|
||||||
|
*/
|
||||||
|
export class StreamHandler extends Handler {
|
||||||
|
protected stream: Writable;
|
||||||
|
|
||||||
|
constructor(stream?: Writable) {
|
||||||
|
super();
|
||||||
|
this.stream = stream ?? DEFAULT_STREAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(record: LogRecord) {
|
||||||
|
try {
|
||||||
|
const msg = this.format(record);
|
||||||
|
this.stream.write(msg);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
this.handleError(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handler class which writes logging records to the browser console,
|
||||||
|
* mapping log levels to the appropriate console method.
|
||||||
|
*
|
||||||
|
* This is the primary handler for browser environments.
|
||||||
|
*/
|
||||||
|
export class ConsoleHandler extends Handler {
|
||||||
|
emit(record: LogRecord) {
|
||||||
|
try {
|
||||||
|
const msg = this.format(record);
|
||||||
|
|
||||||
|
if (record.levelno >= ERROR) {
|
||||||
|
console.error(msg);
|
||||||
|
}
|
||||||
|
else if (record.levelno >= WARNING) {
|
||||||
|
console.warn(msg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
this.handleError(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface FileHandlerOptions {
|
export interface FileHandlerOptions {
|
||||||
filename: string
|
filename: string
|
||||||
filemode?: string
|
filemode?: string
|
||||||
|
|
@ -168,20 +209,13 @@ export interface FileHandlerOptions {
|
||||||
errors?: string
|
errors?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A handler class which writes logging records, appropriately formatted,
|
|
||||||
to a stream. Note that this class does not close the stream, as
|
|
||||||
sys.stdout or sys.stderr may be used.
|
|
||||||
*/
|
|
||||||
export class StreamHandler extends Handler {
|
|
||||||
constructor(stream?: stream.Writable) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FileHandler extends StreamHandler {
|
export class FileHandler extends StreamHandler {
|
||||||
constructor(options: FileHandlerOptions) {
|
constructor(options: FileHandlerOptions) {
|
||||||
super();
|
super();
|
||||||
|
throw new NotImplementedError(
|
||||||
|
'FileHandler is not available in browser environments. ' +
|
||||||
|
'Use ConsoleHandler or a storage-backed handler instead.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,9 +224,16 @@ export class FileHandler extends StreamHandler {
|
||||||
* whatever sys.stderr is currently set to rather than the value of
|
* whatever sys.stderr is currently set to rather than the value of
|
||||||
* sys.stderr at handler construction time.
|
* sys.stderr at handler construction time.
|
||||||
*/
|
*/
|
||||||
export class StderrHandler extends Handler {
|
export class StderrHandler extends Handler {
|
||||||
/**
|
|
||||||
* Initialize the handler.
|
|
||||||
*/
|
|
||||||
constructor(level: LogLevel) { super(level) }
|
constructor(level: LogLevel) { super(level) }
|
||||||
|
|
||||||
|
emit(record: LogRecord) {
|
||||||
|
try {
|
||||||
|
const msg = this.format(record);
|
||||||
|
console.error(msg);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
this.handleError(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue