summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md10
-rw-r--r--logging/README.md12
-rw-r--r--logging/handler.ts18
-rw-r--r--logging/handlers/console.ts26
-rw-r--r--logging/index.ts101
-rw-r--r--logging/levels.ts31
-rw-r--r--logging/logger.ts44
-rw-r--r--logging/test.ts53
-rwxr-xr-xtest.ts3
9 files changed, 293 insertions, 5 deletions
diff --git a/README.md b/README.md
index d3da80550..1aa6eb5d6 100644
--- a/README.md
+++ b/README.md
@@ -7,11 +7,11 @@ for Deno.
| Collection | Description |
| ---------------------------- | --------------------------------------------------------------- |
-| [colors](./colors/README.md) | Modules that generate ANSI color codes for the console. |
-| [net](./net/README.md) | A framework for creating HTTP/HTTPS servers inspired by GoLang. |
-| [path](./path/README.md) | A path manipulation library. |
-| [flags](./flags/README.md) | Command line arguments parser based on minimist. |
-
+| [colors](./colors/) | Modules that generate ANSI color codes for the console. |
+| [net](./net/) | A framework for creating HTTP/HTTPS servers inspired by GoLang. |
+| [path](./path/) | File path manipulation. |
+| [flags](./flags/) | Command line arguments parser. |
+| [logging](./logging/) | Command line logging |
---
Copyright 2018 the Deno authors. All rights reserved. MIT license.
diff --git a/logging/README.md b/logging/README.md
new file mode 100644
index 000000000..b444b411b
--- /dev/null
+++ b/logging/README.md
@@ -0,0 +1,12 @@
+# Logging module for Deno
+
+Very much work in progress. Contributions welcome.
+
+This library is heavily inspired by Python's [logging](https://docs.python.org/3/library/logging.html#logging.Logger.log) module, altough
+it's not planned to be a direct port. Having separate loggers, handlers, formatters and filters gives developer very granular control over logging
+which is most desirable for server side software.
+
+Todo:
+- [ ] implement formatters
+- [ ] implement `FileHandler`
+- [ ] tests \ No newline at end of file
diff --git a/logging/handler.ts b/logging/handler.ts
new file mode 100644
index 000000000..2d76f5a78
--- /dev/null
+++ b/logging/handler.ts
@@ -0,0 +1,18 @@
+import { getLevelByName } from "./levels";
+
+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) {}
+}
diff --git a/logging/handlers/console.ts b/logging/handlers/console.ts
new file mode 100644
index 000000000..219a3baec
--- /dev/null
+++ b/logging/handlers/console.ts
@@ -0,0 +1,26 @@
+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;
+ }
+ }
+}
diff --git a/logging/index.ts b/logging/index.ts
new file mode 100644
index 000000000..5fabff60f
--- /dev/null
+++ b/logging/index.ts
@@ -0,0 +1,101 @@
+import { Logger } from "./logger.ts";
+import { BaseHandler } from "./handler.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 {
+ level?: string;
+ handlers?: string[];
+}
+
+export interface LoggingConfig {
+ handlers?: {
+ [name: string]: HandlerConfig;
+ };
+ loggers?: {
+ [name: string]: LoggerConfig;
+ };
+}
+
+const DEFAULT_LEVEL = "INFO";
+const DEFAULT_NAME = "";
+const DEFAULT_CONFIG: LoggingConfig = {
+ handlers: {
+ [DEFAULT_NAME]: {
+ level: DEFAULT_LEVEL,
+ class: ConsoleHandler
+ }
+ },
+
+ loggers: {
+ [DEFAULT_NAME]: {
+ level: DEFAULT_LEVEL,
+ handlers: [DEFAULT_NAME]
+ }
+ }
+};
+
+const state = {
+ loggers: new Map(),
+ 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 = {
+ BaseHandler: BaseHandler,
+ ConsoleHandler: ConsoleHandler
+};
+
+export function getLogger(name?: string) {
+ if (!name) {
+ name = DEFAULT_NAME;
+ }
+
+ if (!state.loggers.has(name)) {
+ return createNewLogger(name);
+ }
+
+ return state.loggers.get(name);
+}
+
+export function setup(config: LoggingConfig) {
+ state.config = {
+ handlers: {
+ ...DEFAULT_CONFIG.handlers,
+ ...config.handlers!
+ },
+ loggers: {
+ ...DEFAULT_CONFIG.loggers,
+ ...config.loggers!
+ }
+ };
+}
diff --git a/logging/levels.ts b/logging/levels.ts
new file mode 100644
index 000000000..8ba8a8fec
--- /dev/null
+++ b/logging/levels.ts
@@ -0,0 +1,31 @@
+export const LogLevel = {
+ DEBUG: 10,
+ INFO: 20,
+ WARNING: 30,
+ ERROR: 40,
+ CRITICAL: 50
+};
+
+const byName = {
+ DEBUG: LogLevel.DEBUG,
+ INFO: LogLevel.INFO,
+ WARNING: LogLevel.WARNING,
+ ERROR: LogLevel.ERROR,
+ CRITICAL: LogLevel.DEBUG
+};
+
+const byLevel = {
+ [LogLevel.DEBUG]: "DEBUG",
+ [LogLevel.INFO]: "INFO",
+ [LogLevel.WARNING]: "WARNING",
+ [LogLevel.ERROR]: "ERROR",
+ [LogLevel.CRITICAL]: "CRITICAL"
+};
+
+export function getLevelByName(name) {
+ return byName[name];
+}
+
+export function getLevelName(level) {
+ return byLevel[level];
+}
diff --git a/logging/logger.ts b/logging/logger.ts
new file mode 100644
index 000000000..733b1fd09
--- /dev/null
+++ b/logging/logger.ts
@@ -0,0 +1,44 @@
+import { LogLevel, getLevelByName, getLevelName } from "./levels.ts";
+
+export class Logger {
+ level: number;
+ levelName: string;
+ handlers: any[];
+
+ constructor(levelName, handlers) {
+ this.level = getLevelByName(levelName);
+ this.levelName = levelName;
+ this.handlers = handlers;
+ }
+
+ _log(level, ...args) {
+ this.handlers.forEach(handler => {
+ handler.handle(level, ...args);
+ });
+ }
+
+ log(level, ...args) {
+ if (this.level > level) return;
+ return this._log(level, ...args);
+ }
+
+ debug(...args) {
+ return this.log(LogLevel.DEBUG, ...args);
+ }
+
+ info(...args) {
+ return this.log(LogLevel.INFO, ...args);
+ }
+
+ warning(...args) {
+ return this.log(LogLevel.WARNING, ...args);
+ }
+
+ error(...args) {
+ return this.log(LogLevel.ERROR, ...args);
+ }
+
+ critical(...args) {
+ return this.log(LogLevel.CRITICAL, ...args);
+ }
+}
diff --git a/logging/test.ts b/logging/test.ts
new file mode 100644
index 000000000..365064cbf
--- /dev/null
+++ b/logging/test.ts
@@ -0,0 +1,53 @@
+import { assertEqual, test } from "https://deno.land/x/testing/testing.ts";
+
+import * as logging from "index.ts";
+
+// TODO: establish something more sophisticated
+
+let testOutput = "";
+
+class TestHandler extends logging.handlers.BaseHandler {
+ _log(level, ...args) {
+ testOutput += `${level} ${args[0]}\n`;
+ }
+}
+
+logging.setup({
+ handlers: {
+ debug: {
+ level: "DEBUG",
+ class: TestHandler
+ },
+
+ info: {
+ level: "INFO",
+ class: TestHandler
+ }
+ },
+
+ loggers: {
+ default: {
+ level: "DEBUG",
+ handlers: ["debug"]
+ },
+
+ info: {
+ level: "INFO",
+ handlers: ["info"]
+ }
+ }
+});
+
+const logger = logging.getLogger("default");
+const unknownLogger = logging.getLogger("info");
+
+test(function basicTest() {
+ logger.debug("I should be printed.");
+ unknownLogger.debug("I should not be printed.");
+ unknownLogger.info("And I should be printed as well.");
+
+ const expectedOutput =
+ "10 I should be printed.\n20 And I should be printed as well.\n";
+
+ assertEqual(testOutput, expectedOutput);
+});
diff --git a/test.ts b/test.ts
index f64e2ae95..94534825d 100755
--- a/test.ts
+++ b/test.ts
@@ -13,6 +13,9 @@ import "net/http_test.ts";
import "net/textproto_test.ts";
import { runTests, completePromise } from "net/file_server_test.ts";
+// logging tests
+import "logging/test.ts";
+
// file server test
const fileServer = run({
args: ["deno", "--allow-net", "net/file_server.ts", "."]