summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--std/log/README.md4
-rw-r--r--std/log/handlers.ts18
-rw-r--r--std/log/handlers_test.ts38
-rw-r--r--std/log/levels.ts71
-rw-r--r--std/log/logger.ts21
-rw-r--r--std/log/logger_test.ts8
-rw-r--r--std/log/mod.ts5
-rw-r--r--std/log/test.ts20
8 files changed, 121 insertions, 64 deletions
diff --git a/std/log/README.md b/std/log/README.md
index 12a089942..cc99bbcd3 100644
--- a/std/log/README.md
+++ b/std/log/README.md
@@ -19,7 +19,7 @@ await log.setup({
handlers: {
console: new log.handlers.ConsoleHandler("DEBUG"),
- file: new log.handlers.FileHandler("WARNING", {
+ file: new log.handlers.FileHandler(log.LogLevels.DEBUG, {
filename: "./log.txt",
// you can change format of output message using any keys in `LogRecord`
formatter: "{levelName} {msg}",
@@ -34,7 +34,7 @@ await log.setup({
},
tasks: {
- level: "ERROR",
+ level: log.LogLevels.ERROR,
handlers: ["console"],
},
},
diff --git a/std/log/handlers.ts b/std/log/handlers.ts
index 041f101ed..b22f458ac 100644
--- a/std/log/handlers.ts
+++ b/std/log/handlers.ts
@@ -3,7 +3,7 @@ const { open, openSync, close, renameSync, statSync } = Deno;
type File = Deno.File;
type Writer = Deno.Writer;
type OpenOptions = Deno.OpenOptions;
-import { getLevelByName, LogLevel } from "./levels.ts";
+import { getLevelByName, LevelName, LogLevels } from "./levels.ts";
import { LogRecord } from "./logger.ts";
import { red, yellow, blue, bold } from "../fmt/colors.ts";
import { existsSync, exists } from "../fs/exists.ts";
@@ -18,10 +18,10 @@ interface HandlerOptions {
export class BaseHandler {
level: number;
- levelName: string;
+ levelName: LevelName;
formatter: string | FormatterFunction;
- constructor(levelName: string, options: HandlerOptions = {}) {
+ constructor(levelName: LevelName, options: HandlerOptions = {}) {
this.level = getLevelByName(levelName);
this.levelName = levelName;
@@ -62,16 +62,16 @@ export class ConsoleHandler extends BaseHandler {
let msg = super.format(logRecord);
switch (logRecord.level) {
- case LogLevel.INFO:
+ case LogLevels.INFO:
msg = blue(msg);
break;
- case LogLevel.WARNING:
+ case LogLevels.WARNING:
msg = yellow(msg);
break;
- case LogLevel.ERROR:
+ case LogLevels.ERROR:
msg = red(msg);
break;
- case LogLevel.CRITICAL:
+ case LogLevels.CRITICAL:
msg = bold(red(msg));
break;
default:
@@ -105,7 +105,7 @@ export class FileHandler extends WriterHandler {
protected _openOptions: OpenOptions;
#encoder = new TextEncoder();
- constructor(levelName: string, options: FileHandlerOptions) {
+ constructor(levelName: LevelName, options: FileHandlerOptions) {
super(levelName, options);
this._filename = options.filename;
// default to append mode, write only
@@ -143,7 +143,7 @@ export class RotatingFileHandler extends FileHandler {
#maxBytes: number;
#maxBackupCount: number;
- constructor(levelName: string, options: RotatingFileHandlerOptions) {
+ constructor(levelName: LevelName, options: RotatingFileHandlerOptions) {
super(levelName, options);
this.#maxBytes = options.maxBytes;
this.#maxBackupCount = options.maxBackupCount;
diff --git a/std/log/handlers_test.ts b/std/log/handlers_test.ts
index 13b6de3bd..561b5c04a 100644
--- a/std/log/handlers_test.ts
+++ b/std/log/handlers_test.ts
@@ -1,7 +1,13 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
const { test } = Deno;
import { assert, assertEquals, assertThrowsAsync } from "../testing/asserts.ts";
-import { LogLevel, getLevelName, getLevelByName } from "./levels.ts";
+import {
+ LogLevels,
+ LogLevelNames,
+ getLevelName,
+ getLevelByName,
+ LevelName,
+} from "./levels.ts";
import { BaseHandler, FileHandler, RotatingFileHandler } from "./handlers.ts";
import { LogRecord } from "./logger.ts";
import { existsSync } from "../fs/exists.ts";
@@ -19,7 +25,7 @@ class TestHandler extends BaseHandler {
test(function simpleHandler(): void {
const cases = new Map<number, string[]>([
[
- LogLevel.DEBUG,
+ LogLevels.DEBUG,
[
"DEBUG debug-test",
"INFO info-test",
@@ -29,7 +35,7 @@ test(function simpleHandler(): void {
],
],
[
- LogLevel.INFO,
+ LogLevels.INFO,
[
"INFO info-test",
"WARNING warning-test",
@@ -38,19 +44,19 @@ test(function simpleHandler(): void {
],
],
[
- LogLevel.WARNING,
+ LogLevels.WARNING,
["WARNING warning-test", "ERROR error-test", "CRITICAL critical-test"],
],
- [LogLevel.ERROR, ["ERROR error-test", "CRITICAL critical-test"]],
- [LogLevel.CRITICAL, ["CRITICAL critical-test"]],
+ [LogLevels.ERROR, ["ERROR error-test", "CRITICAL critical-test"]],
+ [LogLevels.CRITICAL, ["CRITICAL critical-test"]],
]);
for (const [testCase, messages] of cases.entries()) {
const testLevel = getLevelName(testCase);
const handler = new TestHandler(testLevel);
- for (const levelName in LogLevel) {
- const level = getLevelByName(levelName);
+ for (const levelName of LogLevelNames) {
+ const level = getLevelByName(levelName as LevelName);
handler.handle(
new LogRecord(`${levelName.toLowerCase()}-test`, [], level)
);
@@ -67,7 +73,7 @@ test(function testFormatterAsString(): void {
formatter: "test {levelName} {msg}",
});
- handler.handle(new LogRecord("Hello, world!", [], LogLevel.DEBUG));
+ handler.handle(new LogRecord("Hello, world!", [], LogLevels.DEBUG));
assertEquals(handler.messages, ["test DEBUG Hello, world!"]);
});
@@ -78,7 +84,7 @@ test(function testFormatterAsFunction(): void {
`fn formatter ${logRecord.levelName} ${logRecord.msg}`,
});
- handler.handle(new LogRecord("Hello, world!", [], LogLevel.ERROR));
+ handler.handle(new LogRecord("Hello, world!", [], LogLevels.ERROR));
assertEquals(handler.messages, ["fn formatter ERROR Hello, world!"]);
});
@@ -92,12 +98,12 @@ test({
});
await fileHandler.setup();
- fileHandler.handle(new LogRecord("Hello World", [], LogLevel.WARNING));
+ fileHandler.handle(new LogRecord("Hello World", [], LogLevels.WARNING));
await fileHandler.destroy();
const firstFileSize = (await Deno.stat(LOG_FILE)).size;
await fileHandler.setup();
- fileHandler.handle(new LogRecord("Hello World", [], LogLevel.WARNING));
+ fileHandler.handle(new LogRecord("Hello World", [], LogLevels.WARNING));
await fileHandler.destroy();
const secondFileSize = (await Deno.stat(LOG_FILE)).size;
@@ -198,11 +204,11 @@ test({
});
await fileHandler.setup();
- fileHandler.handle(new LogRecord("AAA", [], LogLevel.ERROR)); // 'ERROR AAA\n' = 10 bytes
+ fileHandler.handle(new LogRecord("AAA", [], LogLevels.ERROR)); // 'ERROR AAA\n' = 10 bytes
assertEquals((await Deno.stat(LOG_FILE)).size, 10);
- fileHandler.handle(new LogRecord("AAA", [], LogLevel.ERROR));
+ fileHandler.handle(new LogRecord("AAA", [], LogLevels.ERROR));
assertEquals((await Deno.stat(LOG_FILE)).size, 20);
- fileHandler.handle(new LogRecord("AAA", [], LogLevel.ERROR));
+ fileHandler.handle(new LogRecord("AAA", [], LogLevels.ERROR));
// Rollover occurred. Log file now has 1 record, rollover file has the original 2
assertEquals((await Deno.stat(LOG_FILE)).size, 10);
assertEquals((await Deno.stat(LOG_FILE + ".1")).size, 20);
@@ -238,7 +244,7 @@ test({
mode: "a",
});
await fileHandler.setup();
- fileHandler.handle(new LogRecord("AAA", [], LogLevel.ERROR)); // 'ERROR AAA\n' = 10 bytes
+ fileHandler.handle(new LogRecord("AAA", [], LogLevels.ERROR)); // 'ERROR AAA\n' = 10 bytes
await fileHandler.destroy();
const decoder = new TextDecoder();
diff --git a/std/log/levels.ts b/std/log/levels.ts
index be960dd57..ed6010ba2 100644
--- a/std/log/levels.ts
+++ b/std/log/levels.ts
@@ -1,26 +1,59 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-export const LogLevel: Record<string, number> = {
- NOTSET: 0,
- DEBUG: 10,
- INFO: 20,
- WARNING: 30,
- ERROR: 40,
- CRITICAL: 50,
-};
+/** Get log level numeric values through enum constants
+ */
+export enum LogLevels {
+ NOTSET = 0,
+ DEBUG = 10,
+ INFO = 20,
+ WARNING = 30,
+ ERROR = 40,
+ CRITICAL = 50,
+}
+
+/** Permitted log level names */
+export const LogLevelNames = Object.keys(LogLevels).filter((key) =>
+ isNaN(Number(key))
+);
+
+/** Union of valid log level strings */
+export type LevelName = keyof typeof LogLevels;
-const byLevel = {
- [LogLevel.NOTSET]: "NOTSET",
- [LogLevel.DEBUG]: "DEBUG",
- [LogLevel.INFO]: "INFO",
- [LogLevel.WARNING]: "WARNING",
- [LogLevel.ERROR]: "ERROR",
- [LogLevel.CRITICAL]: "CRITICAL",
+const byLevel: Record<string, LevelName> = {
+ [String(LogLevels.NOTSET)]: "NOTSET",
+ [String(LogLevels.DEBUG)]: "DEBUG",
+ [String(LogLevels.INFO)]: "INFO",
+ [String(LogLevels.WARNING)]: "WARNING",
+ [String(LogLevels.ERROR)]: "ERROR",
+ [String(LogLevels.CRITICAL)]: "CRITICAL",
};
-export function getLevelByName(name: string): number {
- return LogLevel[name];
+/** Returns the numeric log level associated with the passed,
+ * stringy log level name.
+ */
+export function getLevelByName(name: LevelName): number {
+ switch (name) {
+ case "NOTSET":
+ return LogLevels.NOTSET;
+ case "DEBUG":
+ return LogLevels.DEBUG;
+ case "INFO":
+ return LogLevels.INFO;
+ case "WARNING":
+ return LogLevels.WARNING;
+ case "ERROR":
+ return LogLevels.ERROR;
+ case "CRITICAL":
+ return LogLevels.CRITICAL;
+ default:
+ throw new Error(`no log level found for "${name}"`);
+ }
}
-export function getLevelName(level: number): string {
- return byLevel[level];
+/** Returns the stringy log level name provided the numeric log level */
+export function getLevelName(level: number): LevelName {
+ const levelName = byLevel[level];
+ if (levelName) {
+ return levelName;
+ }
+ throw new Error(`no level name found for level: ${level}`);
}
diff --git a/std/log/logger.ts b/std/log/logger.ts
index 9653d9008..6a12325e8 100644
--- a/std/log/logger.ts
+++ b/std/log/logger.ts
@@ -1,5 +1,10 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-import { LogLevel, getLevelByName, getLevelName } from "./levels.ts";
+import {
+ LogLevels,
+ getLevelByName,
+ getLevelName,
+ LevelName,
+} from "./levels.ts";
import { BaseHandler } from "./handlers.ts";
export class LogRecord {
@@ -26,11 +31,11 @@ export class LogRecord {
export class Logger {
level: number;
- levelName: string;
+ levelName: LevelName;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
handlers: any[];
- constructor(levelName: string, handlers?: BaseHandler[]) {
+ constructor(levelName: LevelName, handlers?: BaseHandler[]) {
this.level = getLevelByName(levelName);
this.levelName = levelName;
@@ -48,22 +53,22 @@ export class Logger {
}
debug(msg: string, ...args: unknown[]): void {
- this._log(LogLevel.DEBUG, msg, ...args);
+ this._log(LogLevels.DEBUG, msg, ...args);
}
info(msg: string, ...args: unknown[]): void {
- this._log(LogLevel.INFO, msg, ...args);
+ this._log(LogLevels.INFO, msg, ...args);
}
warning(msg: string, ...args: unknown[]): void {
- this._log(LogLevel.WARNING, msg, ...args);
+ this._log(LogLevels.WARNING, msg, ...args);
}
error(msg: string, ...args: unknown[]): void {
- this._log(LogLevel.ERROR, msg, ...args);
+ this._log(LogLevels.ERROR, msg, ...args);
}
critical(msg: string, ...args: unknown[]): void {
- this._log(LogLevel.CRITICAL, msg, ...args);
+ this._log(LogLevels.CRITICAL, msg, ...args);
}
}
diff --git a/std/log/logger_test.ts b/std/log/logger_test.ts
index 804591b4f..1c02dbb1a 100644
--- a/std/log/logger_test.ts
+++ b/std/log/logger_test.ts
@@ -2,7 +2,7 @@
const { test } = Deno;
import { assertEquals } from "../testing/asserts.ts";
import { LogRecord, Logger } from "./logger.ts";
-import { LogLevel } from "./levels.ts";
+import { LogLevels, LevelName } from "./levels.ts";
import { BaseHandler } from "./handlers.ts";
class TestHandler extends BaseHandler {
@@ -23,7 +23,7 @@ test(function simpleLogger(): void {
const handler = new TestHandler("DEBUG");
let logger = new Logger("DEBUG");
- assertEquals(logger.level, LogLevel.DEBUG);
+ assertEquals(logger.level, LogLevels.DEBUG);
assertEquals(logger.levelName, "DEBUG");
assertEquals(logger.handlers, []);
@@ -41,14 +41,14 @@ test(function customHandler(): void {
const record = handler.records[0];
assertEquals(record.msg, "foo");
assertEquals(record.args, [1, 2]);
- assertEquals(record.level, LogLevel.DEBUG);
+ assertEquals(record.level, LogLevels.DEBUG);
assertEquals(record.levelName, "DEBUG");
assertEquals(handler.messages, ["DEBUG foo"]);
});
test(function logFunctions(): void {
- const doLog = (level: string): TestHandler => {
+ const doLog = (level: LevelName): TestHandler => {
const handler = new TestHandler(level);
const logger = new Logger(level, [handler]);
logger.debug("foo");
diff --git a/std/log/mod.ts b/std/log/mod.ts
index 2f068f8ba..4032937a2 100644
--- a/std/log/mod.ts
+++ b/std/log/mod.ts
@@ -8,9 +8,12 @@ import {
RotatingFileHandler,
} from "./handlers.ts";
import { assert } from "../testing/asserts.ts";
+import { LevelName } from "./levels.ts";
+
+export { LogLevels } from "./levels.ts";
export class LoggerConfig {
- level?: string;
+ level?: LevelName;
handlers?: string[];
}
diff --git a/std/log/test.ts b/std/log/test.ts
index 858f722e2..47c75ba6e 100644
--- a/std/log/test.ts
+++ b/std/log/test.ts
@@ -1,8 +1,13 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
const { test } = Deno;
-import { assertEquals } from "../testing/asserts.ts";
+import { assertEquals, assertThrows } from "../testing/asserts.ts";
import * as log from "./mod.ts";
-import { LogLevel } from "./levels.ts";
+import {
+ LogLevelNames,
+ LevelName,
+ getLevelByName,
+ getLevelName,
+} from "./levels.ts";
class TestHandler extends log.handlers.BaseHandler {
public messages: string[] = [];
@@ -23,13 +28,13 @@ test(async function defaultHandlers(): Promise<void> {
CRITICAL: log.critical,
};
- for (const levelName in LogLevel) {
+ for (const levelName of LogLevelNames) {
if (levelName === "NOTSET") {
continue;
}
const logger = loggers[levelName];
- const handler = new TestHandler(levelName);
+ const handler = new TestHandler(levelName as LevelName);
await log.setup({
handlers: {
@@ -37,7 +42,7 @@ test(async function defaultHandlers(): Promise<void> {
},
loggers: {
default: {
- level: levelName,
+ level: levelName as LevelName,
handlers: ["default"],
},
},
@@ -103,3 +108,8 @@ test(async function getLoggerUnknown(): Promise<void> {
assertEquals(logger.levelName, "NOTSET");
assertEquals(logger.handlers, []);
});
+
+test(function getInvalidLoggerLevels(): void {
+ assertThrows(() => getLevelByName("FAKE_LOG_LEVEL" as LevelName));
+ assertThrows(() => getLevelName(5000));
+});