mirror of
https://github.com/denoland/std.git
synced 2024-11-22 04:59:05 +00:00
Improve logging module (#51)
This commit is contained in:
parent
77831c34b1
commit
439885c756
@ -26,4 +26,4 @@ jobs:
|
|||||||
# steps:
|
# steps:
|
||||||
# - powershell: iex (iwr https://deno.land/x/install/install.ps1)
|
# - powershell: iex (iwr https://deno.land/x/install/install.ps1)
|
||||||
# - script: echo '##vso[task.prependpath]C:\Users\VssAdministrator\.deno\bin\'
|
# - script: echo '##vso[task.prependpath]C:\Users\VssAdministrator\.deno\bin\'
|
||||||
# - script: 'C:\Users\VssAdministrator\.deno\bin\deno.exe test.ts --allow-run --allow-net'
|
# - script: 'C:\Users\VssAdministrator\.deno\bin\deno.exe test.ts --allow-run --allow-net --allow-write'
|
||||||
|
@ -1,15 +1,38 @@
|
|||||||
# Logging module for Deno
|
# Basic usage
|
||||||
|
|
||||||
Very much work in progress. Contributions welcome.
|
```ts
|
||||||
|
import * as log from "https://deno.land/x/std/logging/index.ts";
|
||||||
|
|
||||||
This library is heavily inspired by Python's
|
// simple console logger
|
||||||
[logging](https://docs.python.org/3/library/logging.html#logging.Logger.log)
|
log.debug("Hello world");
|
||||||
module, altough it's not planned to be a direct port. Having separate loggers,
|
log.info("Hello world");
|
||||||
handlers, formatters and filters gives developer very granular control over
|
log.warning("Hello world");
|
||||||
logging which is most desirable for server side software.
|
log.error("Hello world");
|
||||||
|
log.critical("500 Internal server error");
|
||||||
|
|
||||||
Todo:
|
// configure as needed
|
||||||
|
await log.setup({
|
||||||
|
handlers: {
|
||||||
|
console: new log.handlers.ConsoleHandler("DEBUG"),
|
||||||
|
file: new log.handlers.FileHandler("WARNING", "./log.txt"),
|
||||||
|
},
|
||||||
|
|
||||||
- [ ] implement formatters
|
loggers: {
|
||||||
- [ ] implement `FileHandler`
|
default: {
|
||||||
- [ ] tests
|
level: "DEBUG",
|
||||||
|
handlers: ["console", "file"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// get configured logger
|
||||||
|
const logger = log.getLogger("default");
|
||||||
|
logger.debug("fizz") // <- logs to `console`, because `file` handler requires 'WARNING' level
|
||||||
|
logger.warning("buzz") // <- logs to both `console` and `file` handlers
|
||||||
|
|
||||||
|
// if you try to use a logger that hasn't been configured
|
||||||
|
// you're good to go, it gets created automatically with level set to 0
|
||||||
|
// so no message is logged
|
||||||
|
const unknownLogger = log.getLogger("mystery");
|
||||||
|
unknownLogger.info("foobar") // no-op
|
||||||
|
```
|
@ -1,18 +0,0 @@
|
|||||||
import { getLevelByName } from "./levels.ts";
|
|
||||||
|
|
||||||
export class BaseHandler {
|
|
||||||
level: number;
|
|
||||||
levelName: string;
|
|
||||||
|
|
||||||
constructor(levelName) {
|
|
||||||
this.level = getLevelByName(levelName);
|
|
||||||
this.levelName = levelName;
|
|
||||||
}
|
|
||||||
|
|
||||||
handle(level, ...args) {
|
|
||||||
if (this.level > level) return;
|
|
||||||
return this._log(level, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
_log(level, ...args) {}
|
|
||||||
}
|
|
65
logging/handlers.ts
Normal file
65
logging/handlers.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { open, File, Writer } from "deno";
|
||||||
|
import { getLevelByName } from "./levels.ts";
|
||||||
|
import { LogRecord } from "./logger.ts";
|
||||||
|
|
||||||
|
export class BaseHandler {
|
||||||
|
level: number;
|
||||||
|
levelName: string;
|
||||||
|
|
||||||
|
constructor(levelName: string) {
|
||||||
|
this.level = getLevelByName(levelName);
|
||||||
|
this.levelName = levelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle(logRecord: LogRecord) {
|
||||||
|
if (this.level > logRecord.level) return;
|
||||||
|
|
||||||
|
// TODO: implement formatter
|
||||||
|
const msg = `${logRecord.levelName} ${logRecord.msg}`;
|
||||||
|
|
||||||
|
return this.log(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
log(msg: string) { }
|
||||||
|
async setup() { }
|
||||||
|
async destroy() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class ConsoleHandler extends BaseHandler {
|
||||||
|
log(msg: string) {
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export abstract class WriterHandler extends BaseHandler {
|
||||||
|
protected _writer: Writer;
|
||||||
|
|
||||||
|
log(msg: string) {
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
// promise is intentionally not awaited
|
||||||
|
this._writer.write(encoder.encode(msg + "\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class FileHandler extends WriterHandler {
|
||||||
|
private _file: File;
|
||||||
|
private _filename: string;
|
||||||
|
|
||||||
|
constructor(levelName: string, filename: string) {
|
||||||
|
super(levelName);
|
||||||
|
this._filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async setup() {
|
||||||
|
// open file in append mode - write only
|
||||||
|
this._file = await open(this._filename, 'a');
|
||||||
|
this._writer = this._file;
|
||||||
|
}
|
||||||
|
|
||||||
|
async destroy() {
|
||||||
|
await this._file.close();
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +0,0 @@
|
|||||||
import { BaseHandler } from "../handler.ts";
|
|
||||||
import { LogLevel } from "../levels.ts";
|
|
||||||
|
|
||||||
export class ConsoleHandler extends BaseHandler {
|
|
||||||
_log(level, ...args) {
|
|
||||||
switch (level) {
|
|
||||||
case LogLevel.DEBUG:
|
|
||||||
console.log(...args);
|
|
||||||
return;
|
|
||||||
case LogLevel.INFO:
|
|
||||||
console.info(...args);
|
|
||||||
return;
|
|
||||||
case LogLevel.WARNING:
|
|
||||||
console.warn(...args);
|
|
||||||
return;
|
|
||||||
case LogLevel.ERROR:
|
|
||||||
console.error(...args);
|
|
||||||
return;
|
|
||||||
case LogLevel.CRITICAL:
|
|
||||||
console.error(...args);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
128
logging/index.ts
128
logging/index.ts
@ -1,21 +1,14 @@
|
|||||||
import { Logger } from "./logger.ts";
|
import { Logger } from "./logger.ts";
|
||||||
import { BaseHandler } from "./handler.ts";
|
import { BaseHandler, ConsoleHandler, WriterHandler, FileHandler } from "./handlers.ts";
|
||||||
import { ConsoleHandler } from "./handlers/console.ts";
|
|
||||||
|
|
||||||
export interface HandlerConfig {
|
|
||||||
// TODO: replace with type describing class derived from BaseHandler
|
|
||||||
class: typeof BaseHandler;
|
|
||||||
level?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LoggerConfig {
|
export class LoggerConfig {
|
||||||
level?: string;
|
level?: string;
|
||||||
handlers?: string[];
|
handlers?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoggingConfig {
|
export interface LogConfig {
|
||||||
handlers?: {
|
handlers?: {
|
||||||
[name: string]: HandlerConfig;
|
[name: string]: BaseHandler;
|
||||||
};
|
};
|
||||||
loggers?: {
|
loggers?: {
|
||||||
[name: string]: LoggerConfig;
|
[name: string]: LoggerConfig;
|
||||||
@ -24,78 +17,95 @@ export interface LoggingConfig {
|
|||||||
|
|
||||||
const DEFAULT_LEVEL = "INFO";
|
const DEFAULT_LEVEL = "INFO";
|
||||||
const DEFAULT_NAME = "";
|
const DEFAULT_NAME = "";
|
||||||
const DEFAULT_CONFIG: LoggingConfig = {
|
const DEFAULT_CONFIG: LogConfig = {
|
||||||
handlers: {
|
handlers: {
|
||||||
[DEFAULT_NAME]: {
|
|
||||||
level: DEFAULT_LEVEL,
|
|
||||||
class: ConsoleHandler
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
loggers: {
|
loggers: {
|
||||||
[DEFAULT_NAME]: {
|
"": {
|
||||||
level: DEFAULT_LEVEL,
|
level: "INFO",
|
||||||
handlers: [DEFAULT_NAME]
|
handlers: [""],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const defaultHandler = new ConsoleHandler("INFO");
|
||||||
|
const defaultLogger = new Logger("INFO", [defaultHandler]);
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
|
defaultHandler,
|
||||||
|
defaultLogger,
|
||||||
|
handlers: new Map(),
|
||||||
loggers: new Map(),
|
loggers: new Map(),
|
||||||
config: DEFAULT_CONFIG
|
config: DEFAULT_CONFIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
function createNewHandler(name: string) {
|
|
||||||
let handlerConfig = state.config.handlers[name];
|
|
||||||
|
|
||||||
if (!handlerConfig) {
|
|
||||||
handlerConfig = state.config.handlers[DEFAULT_NAME];
|
|
||||||
}
|
|
||||||
|
|
||||||
const constructor = handlerConfig.class;
|
|
||||||
console.log(constructor);
|
|
||||||
const handler = new constructor(handlerConfig.level);
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createNewLogger(name: string) {
|
|
||||||
let loggerConfig = state.config.loggers[name];
|
|
||||||
|
|
||||||
if (!loggerConfig) {
|
|
||||||
loggerConfig = state.config.loggers[DEFAULT_NAME];
|
|
||||||
}
|
|
||||||
|
|
||||||
const handlers = (loggerConfig.handlers || []).map(createNewHandler);
|
|
||||||
const levelName = loggerConfig.level || DEFAULT_LEVEL;
|
|
||||||
return new Logger(levelName, handlers);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const handlers = {
|
export const handlers = {
|
||||||
BaseHandler: BaseHandler,
|
BaseHandler,
|
||||||
ConsoleHandler: ConsoleHandler
|
ConsoleHandler,
|
||||||
|
WriterHandler,
|
||||||
|
FileHandler,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const debug = (msg: string, ...args: any[]) => defaultLogger.debug(msg, ...args);
|
||||||
|
export const info = (msg: string, ...args: any[]) => defaultLogger.info(msg, ...args);
|
||||||
|
export const warning = (msg: string, ...args: any[]) => defaultLogger.warning(msg, ...args);
|
||||||
|
export const error = (msg: string, ...args: any[]) => defaultLogger.error(msg, ...args);
|
||||||
|
export const critical = (msg: string, ...args: any[]) => defaultLogger.critical(msg, ...args);
|
||||||
|
|
||||||
export function getLogger(name?: string) {
|
export function getLogger(name?: string) {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
name = DEFAULT_NAME;
|
return defaultLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state.loggers.has(name)) {
|
if (!state.loggers.has(name)) {
|
||||||
return createNewLogger(name);
|
const logger = new Logger("NOTSET", []);
|
||||||
|
state.loggers.set(name, logger);
|
||||||
|
return logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.loggers.get(name);
|
return state.loggers.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setup(config: LoggingConfig) {
|
export async function setup(config: LogConfig) {
|
||||||
state.config = {
|
state.config = config;
|
||||||
handlers: {
|
|
||||||
...DEFAULT_CONFIG.handlers,
|
// tear down existing handlers
|
||||||
...config.handlers!
|
state.handlers.forEach(handler => {
|
||||||
},
|
handler.destroy();
|
||||||
loggers: {
|
});
|
||||||
...DEFAULT_CONFIG.loggers,
|
state.handlers.clear();
|
||||||
...config.loggers!
|
|
||||||
}
|
// setup handlers
|
||||||
};
|
const handlers = state.config.handlers || {};
|
||||||
|
|
||||||
|
for (const handlerName in handlers) {
|
||||||
|
const handler = handlers[handlerName];
|
||||||
|
await handler.setup();
|
||||||
|
state.handlers.set(handlerName, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove existing loggers
|
||||||
|
state.loggers.clear();
|
||||||
|
|
||||||
|
// setup loggers
|
||||||
|
const loggers = state.config.loggers || {};
|
||||||
|
for (const loggerName in loggers) {
|
||||||
|
const loggerConfig = loggers[loggerName];
|
||||||
|
const handlerNames = loggerConfig.handlers || [];
|
||||||
|
const handlers = [];
|
||||||
|
|
||||||
|
handlerNames.forEach(handlerName => {
|
||||||
|
if (state.handlers.has(handlerName)) {
|
||||||
|
handlers.push(state.handlers.get(handlerName));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const levelName = loggerConfig.level || DEFAULT_LEVEL;
|
||||||
|
const logger = new Logger(levelName, handlers);
|
||||||
|
state.loggers.set(loggerName, logger);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup(DEFAULT_CONFIG);
|
@ -1,4 +1,5 @@
|
|||||||
export const LogLevel = {
|
export const LogLevel = {
|
||||||
|
NOTSET: 0,
|
||||||
DEBUG: 10,
|
DEBUG: 10,
|
||||||
INFO: 20,
|
INFO: 20,
|
||||||
WARNING: 30,
|
WARNING: 30,
|
||||||
@ -7,14 +8,16 @@ export const LogLevel = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const byName = {
|
const byName = {
|
||||||
|
NOTSET: LogLevel.NOTSET,
|
||||||
DEBUG: LogLevel.DEBUG,
|
DEBUG: LogLevel.DEBUG,
|
||||||
INFO: LogLevel.INFO,
|
INFO: LogLevel.INFO,
|
||||||
WARNING: LogLevel.WARNING,
|
WARNING: LogLevel.WARNING,
|
||||||
ERROR: LogLevel.ERROR,
|
ERROR: LogLevel.ERROR,
|
||||||
CRITICAL: LogLevel.DEBUG
|
CRITICAL: LogLevel.CRITICAL
|
||||||
};
|
};
|
||||||
|
|
||||||
const byLevel = {
|
const byLevel = {
|
||||||
|
[LogLevel.NOTSET]: "NOTSET",
|
||||||
[LogLevel.DEBUG]: "DEBUG",
|
[LogLevel.DEBUG]: "DEBUG",
|
||||||
[LogLevel.INFO]: "INFO",
|
[LogLevel.INFO]: "INFO",
|
||||||
[LogLevel.WARNING]: "WARNING",
|
[LogLevel.WARNING]: "WARNING",
|
||||||
@ -22,10 +25,10 @@ const byLevel = {
|
|||||||
[LogLevel.CRITICAL]: "CRITICAL"
|
[LogLevel.CRITICAL]: "CRITICAL"
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getLevelByName(name) {
|
export function getLevelByName(name: string): number {
|
||||||
return byName[name];
|
return byName[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLevelName(level) {
|
export function getLevelName(level: number): string {
|
||||||
return byLevel[level];
|
return byLevel[level];
|
||||||
}
|
}
|
||||||
|
@ -1,44 +1,62 @@
|
|||||||
import { LogLevel, getLevelByName, getLevelName } from "./levels.ts";
|
import { LogLevel, getLevelByName, getLevelName } from "./levels.ts";
|
||||||
|
import { BaseHandler } from "./handlers.ts";
|
||||||
|
|
||||||
|
export interface LogRecord {
|
||||||
|
msg: string;
|
||||||
|
args: any[];
|
||||||
|
datetime: Date;
|
||||||
|
level: number;
|
||||||
|
levelName: string;
|
||||||
|
};
|
||||||
|
|
||||||
export class Logger {
|
export class Logger {
|
||||||
level: number;
|
level: number;
|
||||||
levelName: string;
|
levelName: string;
|
||||||
handlers: any[];
|
handlers: any[];
|
||||||
|
|
||||||
constructor(levelName, handlers) {
|
constructor(levelName: string, handlers?: BaseHandler[]) {
|
||||||
this.level = getLevelByName(levelName);
|
this.level = getLevelByName(levelName);
|
||||||
this.levelName = levelName;
|
this.levelName = levelName;
|
||||||
this.handlers = handlers;
|
|
||||||
|
this.handlers = handlers || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
_log(level, ...args) {
|
_log(level: number, msg: string, ...args: any[]) {
|
||||||
|
if (this.level > level) return;
|
||||||
|
|
||||||
|
// TODO: it'd be a good idea to make it immutable, so
|
||||||
|
// no handler mangles it by mistake
|
||||||
|
// TODO: iterpolate msg with values
|
||||||
|
const record: LogRecord = {
|
||||||
|
msg: msg,
|
||||||
|
args: args,
|
||||||
|
datetime: new Date(),
|
||||||
|
level: level,
|
||||||
|
levelName: getLevelName(level),
|
||||||
|
}
|
||||||
|
|
||||||
this.handlers.forEach(handler => {
|
this.handlers.forEach(handler => {
|
||||||
handler.handle(level, ...args);
|
handler.handle(record);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
log(level, ...args) {
|
debug(msg: string, ...args: any[]) {
|
||||||
if (this.level > level) return;
|
return this._log(LogLevel.DEBUG, msg, ...args);
|
||||||
return this._log(level, ...args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug(...args) {
|
info(msg: string, ...args: any[]) {
|
||||||
return this.log(LogLevel.DEBUG, ...args);
|
return this._log(LogLevel.INFO, msg, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
info(...args) {
|
warning(msg: string, ...args: any[]) {
|
||||||
return this.log(LogLevel.INFO, ...args);
|
return this._log(LogLevel.WARNING, msg, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
warning(...args) {
|
error(msg: string, ...args: any[]) {
|
||||||
return this.log(LogLevel.WARNING, ...args);
|
return this._log(LogLevel.ERROR, msg, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
error(...args) {
|
critical(msg: string, ...args: any[]) {
|
||||||
return this.log(LogLevel.ERROR, ...args);
|
return this._log(LogLevel.CRITICAL, msg, ...args);
|
||||||
}
|
|
||||||
|
|
||||||
critical(...args) {
|
|
||||||
return this.log(LogLevel.CRITICAL, ...args);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
101
logging/test.ts
101
logging/test.ts
@ -1,53 +1,84 @@
|
|||||||
|
import { remove, open, readAll } from "deno";
|
||||||
import { assertEqual, test } from "https://deno.land/x/testing/testing.ts";
|
import { assertEqual, test } from "https://deno.land/x/testing/testing.ts";
|
||||||
|
|
||||||
import * as logging from "index.ts";
|
import * as log from "index.ts";
|
||||||
|
import { FileHandler } from "./handlers.ts";
|
||||||
|
|
||||||
// TODO: establish something more sophisticated
|
// TODO: establish something more sophisticated
|
||||||
|
|
||||||
let testOutput = "";
|
let testOutput = "";
|
||||||
|
|
||||||
class TestHandler extends logging.handlers.BaseHandler {
|
class TestHandler extends log.handlers.BaseHandler {
|
||||||
_log(level, ...args) {
|
constructor(levelName: string) {
|
||||||
testOutput += `${level} ${args[0]}\n`;
|
super(levelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
log(msg: string) {
|
||||||
|
testOutput += `${msg}\n`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logging.setup({
|
test(function testDefaultlogMethods() {
|
||||||
handlers: {
|
log.debug("Foobar");
|
||||||
debug: {
|
log.info("Foobar");
|
||||||
level: "DEBUG",
|
log.warning("Foobar");
|
||||||
class: TestHandler
|
log.error("Foobar");
|
||||||
},
|
log.critical("Foobar");
|
||||||
|
|
||||||
info: {
|
const logger = log.getLogger('');
|
||||||
level: "INFO",
|
console.log(logger);
|
||||||
class: TestHandler
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
loggers: {
|
|
||||||
default: {
|
|
||||||
level: "DEBUG",
|
|
||||||
handlers: ["debug"]
|
|
||||||
},
|
|
||||||
|
|
||||||
info: {
|
|
||||||
level: "INFO",
|
|
||||||
handlers: ["info"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const logger = logging.getLogger("default");
|
test(async function basicTest() {
|
||||||
const unknownLogger = logging.getLogger("info");
|
const testFile = './log.txt';
|
||||||
|
|
||||||
test(function basicTest() {
|
await log.setup({
|
||||||
logger.debug("I should be printed.");
|
handlers: {
|
||||||
unknownLogger.debug("I should not be printed.");
|
debug: new TestHandler("DEBUG"),
|
||||||
unknownLogger.info("And I should be printed as well.");
|
info: new TestHandler("INFO"),
|
||||||
|
file: new FileHandler("DEBUG", testFile),
|
||||||
|
},
|
||||||
|
|
||||||
|
loggers: {
|
||||||
|
foo: {
|
||||||
|
level: "DEBUG",
|
||||||
|
handlers: ["debug", "file"]
|
||||||
|
},
|
||||||
|
|
||||||
|
bar: {
|
||||||
|
level: "INFO",
|
||||||
|
handlers: ["info"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fooLogger = log.getLogger("foo");
|
||||||
|
const barLogger = log.getLogger("bar");
|
||||||
|
const bazzLogger = log.getLogger("bazz");
|
||||||
|
|
||||||
|
|
||||||
|
fooLogger.debug("I should be logged.");
|
||||||
|
fooLogger.debug("I should be logged.");
|
||||||
|
barLogger.debug("I should not be logged.");
|
||||||
|
barLogger.info("And I should be logged as well.");
|
||||||
|
bazzLogger.critical("I shouldn't be logged neither.")
|
||||||
|
|
||||||
const expectedOutput =
|
const expectedOutput =
|
||||||
"10 I should be printed.\n20 And I should be printed as well.\n";
|
"DEBUG I should be logged.\n" +
|
||||||
|
"DEBUG I should be logged.\n" +
|
||||||
|
"INFO And I should be logged as well.\n";
|
||||||
|
|
||||||
assertEqual(testOutput, expectedOutput);
|
assertEqual(testOutput, expectedOutput);
|
||||||
|
|
||||||
|
// same check for file handler
|
||||||
|
const f = await open(testFile);
|
||||||
|
const bytes = await readAll(f);
|
||||||
|
const fileOutput = new TextDecoder().decode(bytes);
|
||||||
|
await f.close();
|
||||||
|
await remove(testFile);
|
||||||
|
|
||||||
|
const fileExpectedOutput =
|
||||||
|
"DEBUG I should be logged.\n" +
|
||||||
|
"DEBUG I should be logged.\n";
|
||||||
|
|
||||||
|
assertEqual(fileOutput, fileExpectedOutput);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user