diff --git a/.gitignore b/.gitignore index 7b191c6..dcc92bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /lib/ /samples/ /node_modules/ +*.log diff --git a/.npmignore b/.npmignore index 03bf7ff..a1ed8d1 100644 --- a/.npmignore +++ b/.npmignore @@ -7,3 +7,4 @@ /tslint.json /tsconfig.json /samples/ +*.log diff --git a/.vscode/launch.json b/.vscode/launch.json index 220b28c..c525ae3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,6 +12,7 @@ "sourceMaps": true, "outFiles": [ "${workspaceFolder}/lib/*.js", + "${workspaceFolder}/lib/Drivers/*.js", "${workspaceFolder}/samples/*.js" ] } diff --git a/README.md b/README.md index 5c02bda..d39425c 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ npm i @litert/logger@dev --save ### 简体中文版 -- [开发版本](./docs/zh-CN/index.md) +- [开发版本](./docs/zh-CN/README.md) ## License diff --git a/docs/zh-CN/APIs.md b/docs/zh-CN/APIs.md deleted file mode 100644 index f23949a..0000000 --- a/docs/zh-CN/APIs.md +++ /dev/null @@ -1,203 +0,0 @@ -# Logger API 文档 - -## 抽象接口类 Logger - -Logger 抽象接口类描述了一个日志控制器的基本方法。 - -### 方法 debug - -```ts -function debug(log: T): Logger; -``` - -该方法用于输出一条 DEBUG 等级的日志。 - -### 方法 error - -```ts -function error(log: T): Logger; -``` - -该方法用于输出一条 ERROR 等级的日志。 - -### 方法 getSubject - -```ts -function getSubject(): string; -``` - -该方法用于获取当前控制器的主题。 - -### 方法 info - -```ts -function info(log: T): Logger; -``` - -该方法用于输出一条 INFO 等级的日志。 - -### 方法 notice - -```ts -function notice(log: T): Logger; -``` - -该方法用于输出一条 NOTICE 等级的日志。 - -### 方法 warning - -```ts -function warning(log: T): Logger; -``` - -该方法用于输出一条 WARNING 等级的日志。 - -### 方法 mute - -```ts -function mute( - lv?: LogLevel -): Logger; -``` - -该方法用于关闭当前控制器的全部或者指定等级的日志输出。 - -> 当参数 lv 省略时,则对所有等级的日志都生效。 - -### 方法 unmute - -```ts -function unmute( - lv?: LogLevel -): Logger; -``` - -该方法用于开启当前控制器的全部或者指定等级的日志输出。 - -> 当参数 lv 省略时,则对所有等级的日志都生效。 - -### 方法 enableTrace - -```ts -function enableTrace( - enable: boolean = true, - lv?: LogLevel -): Logger; -``` - -该方法用于开启或关闭当前控制器的全部或者指定等级的追踪信息。 - -> 当参数 lv 省略时,则对所有等级的日志都生效。 - -### 方法 useFullTrace - -```ts -function useFullTrace( - enable: boolean = true, - lv?: LogLevel -): Logger; -``` - -该方法用于开启或关闭当前控制器的全部或者指定等级的完整追踪信息。 - -> 当参数 lv 省略时,则对所有等级的日志都生效。 - -## 抽象接口类 LoggerFactory - -LoggerFactory 抽象接口类描述了一个日志控制器工厂的基本方法。 - -### 方法 createTextLogger - -```ts -function createTextLogger( - subject: string = "default", - driver: string = "console" -): Logger; -``` - -该方法用于创建一个指定主题的文本日志控制器。如果该主题对应的控制器已经存在,则返回 -现有的控制器对象。 - -### 方法 createDataLogger - -```ts -function createDataLogger( - subject: string = "default", - formatter: LogFormatter = DEFAULT_FORMATTER, - driver: string = "console" -): Logger; -``` - -该方法用于创建一个指定主题的对象日志控制器。如果该主题对应的控制器已经存在,则返回 -现有的控制器对象。 - -> 默认格式化函数是将数据转换为 JSON。 - -### 方法 registerDriver - -```ts -function registerDriver( - name: string, - driver: LogDriver -): LoggerFactory; -``` - -该方法用于注册一个新的日志输出驱动,如果对应名称的驱动已经存在,则抛出一个异常。 - -### 方法 getDriver - -```ts -function getDriver(name: string): LogDriver | null; -``` - -该方法用于根据驱动名称获取一个已经存在的日志输出驱动。如果驱动不存在,则抛出一个异常。 - -### 方法 mute - -```ts -function mute( - lv?: LogLevel -): LoggerFactory; -``` - -该方法用于关闭**所有控制器**的全部或者指定等级的日志输出。 - -> 当参数 lv 省略时,则对所有等级的日志都生效。 - -### 方法 unmute - -```ts -function unmute( - lv?: LogLevel -): LoggerFactory; -``` - -该方法用于开启**所有控制器**的全部或者指定等级的日志输出。 - -> 当参数 lv 省略时,则对所有等级的日志都生效。 - -### 方法 enableTrace - -```ts -function enableTrace( - enable: boolean = true, - lv?: LogLevel -): LoggerFactory; -``` - -该方法用于开启或关闭**所有控制器**的全部或者指定等级的追踪信息。 - -> 当参数 lv 省略时,则对所有等级的日志都生效。 - -### 方法 useFullTrace - -```ts -function useFullTrace( - enable: boolean = true, - lv?: LogLevel -): LoggerFactory; -``` - -该方法用于开启或关闭**所有控制器**的全部或者指定等级的完整追踪信息。 - -> 当参数 lv 省略时,则对所有等级的日志都生效。 diff --git a/docs/zh-CN/README.md b/docs/zh-CN/README.md new file mode 100644 index 0000000..961e714 --- /dev/null +++ b/docs/zh-CN/README.md @@ -0,0 +1,4 @@ +# LiteRT/Logger 文档 + +- [快速入门](./tutorial/README.md) +- [API 文档](./apis/README.md) diff --git a/docs/zh-CN/apis/README.md b/docs/zh-CN/apis/README.md new file mode 100644 index 0000000..a04dba9 --- /dev/null +++ b/docs/zh-CN/apis/README.md @@ -0,0 +1,15 @@ +# LiteRT/Logger API 文档 + +## 目录 + +- [`模块方法 createColorfulTTYDriver`](./functions/createColorfulTTYDriver.md) +- [`模块方法 createConsoleDriver`](./functions/createConsoleDriver.md) +- [`模块方法 createFactory`](./functions/createFactory.md) +- [`模块方法 getDefaultFactory`](./functions/getDefaultFactory.md) +- [`模块方法 DEFAULT_TEXT_FORMATTER`](./functions/DEFAULT_TEXT_FORMATTER.md) +- [`模块方法 DEFAULT_JSON_FORMATTER`](./functions/DEFAULT_JSON_FORMATTER.md) +- [`接口 IColorfulTTYDriver`](./interfaces/IColorfulTTYDriver.md) +- [`接口 IDriver`](./interfaces/IDriver.md) +- [`接口 IFactory`](./interfaces/IFactory.md) +- [`接口 IFormatter`](./interfaces/IFormatter.md) +- [`接口 ILogger`](./interfaces/ILogger.md) diff --git a/docs/zh-CN/apis/functions/DEFAULT_JSON_FORMATTER.md b/docs/zh-CN/apis/functions/DEFAULT_JSON_FORMATTER.md new file mode 100644 index 0000000..2aff81d --- /dev/null +++ b/docs/zh-CN/apis/functions/DEFAULT_JSON_FORMATTER.md @@ -0,0 +1,9 @@ +# 模块方法 DEFAULT_JSON_FORMATTER + +该方法是默认的自定义输入类型日志格式化函数。 + +## 声明 + +```ts +declare const DEFAULT_JSON_FORMATTER: IFormatter; +``` diff --git a/docs/zh-CN/apis/functions/DEFAULT_TEXT_FORMATTER.md b/docs/zh-CN/apis/functions/DEFAULT_TEXT_FORMATTER.md new file mode 100644 index 0000000..1e45832 --- /dev/null +++ b/docs/zh-CN/apis/functions/DEFAULT_TEXT_FORMATTER.md @@ -0,0 +1,9 @@ +# 模块方法 DEFAULT_TEXT_FORMATTER + +该方法是默认的文本日志格式化函数。 + +## 声明 + +```ts +declare const DEFAULT_TEXT_FORMATTER: IFormatter; +``` diff --git a/docs/zh-CN/apis/functions/createColorfulTTYDriver.md b/docs/zh-CN/apis/functions/createColorfulTTYDriver.md new file mode 100644 index 0000000..bd8b08a --- /dev/null +++ b/docs/zh-CN/apis/functions/createColorfulTTYDriver.md @@ -0,0 +1,13 @@ +# 模块方法 createColorfulTTYDriver + +该方法用于创建一个新的彩色命令行输出驱动对象。 + +## 声明 + +```ts +function createColorfulTTYDriver(): IColorfulTTYDriver; +``` + +## 注意 + +如果当前输出环境不支持彩色输出,则降级为控制台输出。 diff --git a/docs/zh-CN/apis/functions/createConsoleDriver.md b/docs/zh-CN/apis/functions/createConsoleDriver.md new file mode 100644 index 0000000..aed07e2 --- /dev/null +++ b/docs/zh-CN/apis/functions/createConsoleDriver.md @@ -0,0 +1,9 @@ +# 模块方法 createConsoleDriver + +该方法用于创建一个新的控制台输出驱动对象。 + +## 声明 + +```ts +function createConsoleDriver(): IDriver; +``` diff --git a/docs/zh-CN/apis/functions/createFactory.md b/docs/zh-CN/apis/functions/createFactory.md new file mode 100644 index 0000000..59e00dd --- /dev/null +++ b/docs/zh-CN/apis/functions/createFactory.md @@ -0,0 +1,25 @@ +# 模块方法 createFactory + +该方法用于创建一个新的日志控制器工厂。 + +## 声明 + +```ts +type DefaultLevels = "error" | "notice" | "warning" | "debug" | "info"; + +function createFactory< + L extends string = DefaultLevels +>(levels: L[]): IFactory; +``` + +## 参数 + +- 泛型参数 `L` + + 指定可以使用的日志等级,用于静态类型检查和 IDE 自动完成。 + +- 形参 `levels` + + 真正起定义日志等级的作用。 + + diff --git a/docs/zh-CN/apis/functions/getDefaultFactory.md b/docs/zh-CN/apis/functions/getDefaultFactory.md new file mode 100644 index 0000000..a6afca8 --- /dev/null +++ b/docs/zh-CN/apis/functions/getDefaultFactory.md @@ -0,0 +1,11 @@ +# 模块方法 getDefaultFactory + +该方法用于获取默认的日志控制器工厂。 + +## 声明 + +```ts +type DefaultLevels = "error" | "notice" | "warning" | "debug" | "info"; + +function getDefaultFactory(): IFactory; +``` diff --git a/docs/zh-CN/apis/interfaces/IColorfulTTYDriver.md b/docs/zh-CN/apis/interfaces/IColorfulTTYDriver.md new file mode 100644 index 0000000..b6a37b0 --- /dev/null +++ b/docs/zh-CN/apis/interfaces/IColorfulTTYDriver.md @@ -0,0 +1,28 @@ +# 接口 IColorfulTTYDriver + +该接口定义彩色命令行输出驱动的方法列表。 + +```ts +type ColorSet = "blue" | "cyan" | "green" | "magenta" | "grey" | + "red" | "yellow" | "white" | "black" | "default"; + +interface IColorfulTTYDriver +extends IDriver { + + /** + * 设置指定等级的日志的输出前景色。 + * + * @param color 颜色名称 + * @param level 指定要设置的日志等级。如果不指定,则修改默认的日志输出颜色。 + */ + foreColor(color: ColorSet, level?: string): this; + + /** + * 设置指定等级的日志的输出背景色。 + * + * @param color 颜色名称 + * @param level 指定要设置的日志等级。如果不指定,则修改默认的日志输出颜色。 + */ + bgColor(color: ColorSet, level?: string): this; +} +``` diff --git a/docs/zh-CN/apis/interfaces/IDriver.md b/docs/zh-CN/apis/interfaces/IDriver.md new file mode 100644 index 0000000..8997869 --- /dev/null +++ b/docs/zh-CN/apis/interfaces/IDriver.md @@ -0,0 +1,33 @@ +# 接口 IDriver + +该接口定义日志控制器输出驱动的方法列表。 + +```ts +interface IDriver { + + /** + * 该方法提供给日志控制器调用,用于写日志到输出设备。 + * + * @param text 已经格式化的日志文本 + * @param subject 日志的主题 + * @param level 日志的等级 + * @param date 日志的时间 + */ + write( + text: string, + subject: string, + level: string, + date: Date + ): void; + + /** + * 将输出缓存中的日志全部输出到输出设备。 + */ + flush(): void | Promise; + + /** + * 关闭驱动。 + */ + close(): void | Promise; +} +``` diff --git a/docs/zh-CN/apis/interfaces/IFactory.md b/docs/zh-CN/apis/interfaces/IFactory.md new file mode 100644 index 0000000..49744a9 --- /dev/null +++ b/docs/zh-CN/apis/interfaces/IFactory.md @@ -0,0 +1,97 @@ +# 接口 IFactory + +该接口定义日志控制器工厂的方法列表。 + +```ts +interface IFactory< + /** + * L 是日志控制器工厂支持的日志等级列表。 + */ + L extends string +> { + + /** + * 对于所有该工厂创建的控制器对象,关闭输出指定等级的日志。 + * + * @param level 指定一个或者多个日志等级,留空或者输入空数组表示所有等级 + */ + mute(level?: L | L[]): this; + + /** + * 对于所有该工厂创建的控制器对象,打开输出指定等级的日志。 + * + * @param level 指定一个或者多个日志等级,留空或者输入空数组表示所有等级 + */ + unmute(level?: L | L[]): this; + + /** + * 对于所有该工厂创建的控制器对象,打开或者关闭日志输出位置的追踪信息。 + * + * @param depth 指定要输出的追踪信息层数,默认为 1 层,设置为 0 则不输出、 + * @param level 指定一个或者多个日志等级,留空或者输入空数组则表示所有等级 + */ + enableTrace(depth?: number, level?: L | L[]): this; + + /** + * 注册一个新的日志输出驱动。 + * + * @param name 驱动唯一名称。 + * @param driver 驱动对象。 + */ + registerDriver(name: string, driver: IDriver): boolean; + + /** + * 根据驱动的唯一注册名称,获取驱动对象。 + * + * 如果不存在,则返回 null。 + * + * @param name 驱动的唯一注册名称 + */ + getDriver(name: string): IDriver | null; + + /** + * 获取所有已经注册的驱动对象唯一注册名称列表。 + */ + getDriverNames(): string[]; + + /** + * 获取所有该工厂创建的日志控制器对象的主题列表。 + */ + getSubjects(): string[]; + + /** + * 获取该工厂支持的所有日至等级列表。 + */ + getLevels(): L[]; + + /** + * 创建一个文本型的日志控制器。 + * + * 已经存在则返回已存在的控制器对象。 + * + * @param subject 日志的主题。(默认值:default) + * @param formatter 日志格式化函数。(默认值:DEFAULT_TEXT_FORMATTER) + * @param driver 已注册的驱动名称。(默认值:console) + */ + createTextLogger( + subject?: string, + formatter?: IFormatter, + driver?: string + ): ILogger; + + /** + * 创建一个自定义输入类型的日志控制器。 + * + * 已经存在则返回已存在的控制器对象。 + * + * @param subject 日志的主题。(默认值:default) + * @param formatter 日志格式化函数。(默认值:DEFAULT_JSON_FORMATTER) + * @param driver 已注册的驱动名称。(默认值:console) + */ + createDataLogger( + subject?: string, + formatter?: IFormatter, + driver?: string + ): ILogger; +} +``` \ No newline at end of file diff --git a/docs/zh-CN/apis/interfaces/IFormatter.md b/docs/zh-CN/apis/interfaces/IFormatter.md new file mode 100644 index 0000000..876b6b1 --- /dev/null +++ b/docs/zh-CN/apis/interfaces/IFormatter.md @@ -0,0 +1,22 @@ +# 接口 IFactory + +该接口定义日志格式化函数。 + +```ts +/** + * 用于格式化日志为字符串的函数。 + * + * @param log 日志的输入内容。 + * @param subject 日志的主题。 + * @param level 日志等级。 + * @param date 日志写入时间。 + * @param traces 日志的追踪信息。 + */ +export type IFormatter = ( + log: T, + subject: string, + level: L, + date: Date, + traces?: string[] +) => string; +``` diff --git a/docs/zh-CN/apis/interfaces/ILogger.md b/docs/zh-CN/apis/interfaces/ILogger.md new file mode 100644 index 0000000..bfebd9d --- /dev/null +++ b/docs/zh-CN/apis/interfaces/ILogger.md @@ -0,0 +1,53 @@ +# 接口 ILogger + +该接口定义日志控制器的方法列表。 + +```ts +interface ILogger { + + /** + * 获取该控制器的日志主题。 + */ + getSubject(): string; + + /** + * 获取该控制器支持的所有日至等级列表。 + */ + getLevels(): L[]; + + /** + * 打开或者关闭日志输出位置的追踪信息。 + * + * @param depth 指定要输出的追踪信息层数,默认为 1 层,设置为 0 则不输出、 + * @param level 指定一个或者多个日志等级,留空或者输入空数组则表示所有等级 + */ + enableTrace(depth?: number, level?: L | L[]): this; + + /** + * 打开输出指定等级的日志。 + * + * @param level 指定一个或者多个日志等级,留空或者输入空数组表示所有等级 + */ + unmute(level?: L | L[]): this; + + /** + * 关闭输出指定等级的日志。 + * + * @param level 指定一个或者多个日志等级,留空或者输入空数组表示所有等级 + */ + mute(level?: L | L[]): this; + + /** + * 刷新输出驱动的缓存。 + */ + flush(): void | Promise; + + /** + * 日志等级名称对应的日志写入方法。 + * + * @param log 输入的日志内容 + * @param date 日志的产生时间,默认为当前时间。 + */ + [key in L]: (log: T, date?: Date): this; +} +``` \ No newline at end of file diff --git a/docs/zh-CN/index.md b/docs/zh-CN/index.md deleted file mode 100644 index 191b00a..0000000 --- a/docs/zh-CN/index.md +++ /dev/null @@ -1,4 +0,0 @@ -# LiteRT/Logger 文档 - -- [快速入门](./quick-start.md) -- [API 文档](./APIs.md) diff --git a/docs/zh-CN/quick-start.md b/docs/zh-CN/quick-start.md deleted file mode 100644 index 0ae9429..0000000 --- a/docs/zh-CN/quick-start.md +++ /dev/null @@ -1,179 +0,0 @@ -# 快速入门 - -## 安装 - -目前只能通过 NPM 安装: - -```sh -npm i @litert/logger -S -``` - -## Hello world! - -```ts -import Loggers from "@litert/logger"; - -/** - * 创建一个文本日志控制器。 - */ -const logs = Loggers.createTextLogger("app"); - -/** - * 默认日志是关闭的,通过 unmute 方法打开所有等级的日志。 - */ -logs.unmute(); - -/** - * Logger 一共有 debug, info, notice, warning, error 五个日志等级,通过同名方法 - * 调用即可。 - */ -logs.debug("Hello"); -logs.info("world"); - -/** - * 将所有等级的日志都禁止。 - */ -logs.mute(); - -logs.notice("这条日志不会被输出。"); - -/** - * 可以将等级名称传递给 mute/unmute 方法,从而禁止或开启指定等级的日志。 - */ -logs.unmute("info"); - -logs.info("INFO 日志又可以输出了。"); - -logs.debug("但是其它等级的日志还是不会被输出。"); - -/** - * 开启 error 等级日志的追踪信息。 - */ -logs.enableTrace(true, "error"); - -logs.unmute("error"); - -logs.error("This is an error."); - -/** - * 使用完整的追踪信息,而不是只显示写入日志的位置。 - */ -logs.useFullTrace(); - -logs.error("This is an error 2."); -``` - -## 使用对象日志 - -有时候日志记录的信息可能包含大量信息,比如错误码,IP 地址之类的,需要进行格式化。 -如果每次都在写日志的地方手动格式化就太麻烦了,因此可以使用对象日志控制器。 - -```ts -import Loggers, { LogLevel } from "@litert/logger"; - -/** - * 日志对象的数据结果 - */ -interface LogInfo { - - action: string; - - result: number; -} - -/** - * 创建一个主题为 data-logger 的对象日志控制器,第二个参数为日志格式化回调方法。 - */ -let log = Loggers.createDataLogger("data-logger", function( - data: LogInfo, - subject: string, - level: LogLevel, - date: Date -): string { - - return `[${date.toISOString()}][${level}][${subject}] Executed action ${data.action}, with result ${data.result}.`; -}); - -log.unmute(); - -log.debug({ - action: "SendMessage", - result: 1 -}); -``` - -## 使用日志输出驱动 - -默认日志是输出到控制台的(使用 `console.log`),但是如果需要更高级的,那么可以用自定义 -的输出驱动,比如输出到文件。这里举个煎蛋栗子,就不输出到文件了。 - -```ts -import Loggers, { LogLevel } from "@litert/logger"; - -interface LogInfo { - - action: string; - - result: number; -} - -/** - * 注册一个新的驱动,名为 driver-sample。 - */ -Loggers.registerDriver("driver-sample", { - log(text: string): void { - - /** - * 这个驱动和默认驱动不一样的是,它会在日志内容前面加上一句“Sample Driver:”。 - * - * 注:驱动收到的 text 是文本日志或者已经格式化的对象日志。 - */ - console.log("Sample Driver:", text); - } -}); - -let log = Loggers.createDataLogger("data-logger", function( - data: LogInfo, - subject: string, - level: LogLevel, - date: Date -): string { - - // tslint:disable-next-line:max-line-length - return `${date.toISOString()} - ${level} - ${subject} - Executed action ${data.action}, with result ${data.result}.`; - -}, "driver-sample"); // 此处指定使用驱动 driver-sample - -Loggers.unmute(); - -log.debug({ - action: "SendMessage", - result: 1 -}); -``` - -## 控制全局日志 - -使用日志控制器工厂对象的 mute、unmute、enableTrace、useFullTrace 方法可以对所有的 -控制器进行配置。以 mute 为例: - -```ts -import Loggers from "@litert/logger"; - -const logs1 = Loggers.createTextLogger("app1"); -const logs2 = Loggers.createTextLogger("app2"); - -Loggers.unmute("debug"); - -const logs3 = Loggers.createTextLogger("app3"); - -logs1.debug("test 1"); -logs2.debug("test 2"); -logs3.debug("test 3"); - -Loggers.mute("debug"); - -logs1.debug("test 4"); -logs2.debug("test 5"); -logs3.debug("test 6"); -``` diff --git a/docs/zh-CN/tutorial/01-install.md b/docs/zh-CN/tutorial/01-install.md new file mode 100644 index 0000000..1d54b19 --- /dev/null +++ b/docs/zh-CN/tutorial/01-install.md @@ -0,0 +1,29 @@ +# 安装与使用 + +## 安装 + +推荐使用 NPM 安装,例如: + +```sh +npm i @litert/logger -S +``` + +如果想使用开发版本,则使用下面的语句 + +```sh +npm i @litert/logger@dev -S +``` + +## 使用 + +通过 import/require 导入即可使用。 + +```ts +import Loggers from "@litert/logger"; + +let log = Loggers.createTextLogger("Sample"); + +log.unmute(); + +log.info("Hello world!"); +``` diff --git a/docs/zh-CN/tutorial/02-basic-usage.md b/docs/zh-CN/tutorial/02-basic-usage.md new file mode 100644 index 0000000..1a9cf10 --- /dev/null +++ b/docs/zh-CN/tutorial/02-basic-usage.md @@ -0,0 +1,179 @@ +# 基本使用 + +## 1. 文本日志 + +通常日志都是写入一些文本记录。 + +先来看一个例子: + +```ts +/** + * 导入 Logger 库,并命名为 Loggers。 + * + * 此处 Loggers 其实是一个日志控制器工厂对象,用来创建不同的日志控制器对象。 + */ +import Loggers from "@litert/logger"; + +/** + * 使用日志控制器工厂对象创建一个主题为 Text-Log 的文本日志控制器对象。 + */ +let log = Loggers.createTextLogger("Text-Log"); + +/** + * 默认情况下,所有的日志都是被关闭输出的,通过 unmute 方法可以打开一个或者所有等级的 + * 日志的输出。 + */ +log.unmute(); + +/** + * 好了,现在可以输出日志,来输出一条 INFO 等级的日志试试。 + */ +log.info("Hello world!"); +``` + +编译并运行上面的代码,将会看到一行输出如下: + +``` +[2018-08-12T07:57:23.400Z][info] Text-Log: Hello world! +``` + +## 2. 基本概念 + +上面的代码里,我们接触到了如下概念: + +- 日志控制器 +- 日志控制器工厂 +- 日志等级 + +让我逐个解释下。 + +### 2.1. 日志控制器 + +日志控制器是指直接在代码里用来输出日志的对象,也就是上面代码里面的 `log` 变量,它是 +一个仅支持文本输入的日志控制器对象。 + +### 2.2. 日志控制器工厂 + +正如字面意思,日志控制器是由一个工厂对象创建的,这个工厂对象就叫做**日志控制器工厂**。 +我们通过 TypeScript 的 `import` 语法导入了 `Loggers` 这个变量,其实它是一个默认的 +日志控制器工厂对象,你也可以再创建一个新的日志控制器工厂,具体请看后文。 + +### 2.3. 日志等级 + +日志是用来记录程序运行过程中的一些事件的,不同事件的重要程度不同,这个程度也就是 +“日志等级”。日志有多少个等级是在创建日志控制工厂时就确定的,其下所有日志控制器都有 +相同的日志等级, + +> 默认日志控制器工厂提供 `debug`、`info`、`error`、`warning`、`notice` 五个等级。 +> 如果不能满足,请尝试创建新的日志控制器工厂。 + +## 3. 日志控制器的基本方法 + +### 3.1. mute/unmute 方法 + +前面提到,所有日志等级都是默认关闭输出的,可以使用日志控制器的 `unmute` 方法打开。 + +```ts +log.unmute(); // 打开所有等级的日志输出 +log.unmute("debug"); // 打开 DEBUG 等级的日志输出 +log.unmute([ // 打开 INFO 和 ERROR 等级的日志输出 + "info", + "error" +]); +``` + +同理,可以用 `mute` 方法关闭各个等级的日志输出。 + +```ts +log.mute(); // 关闭所有等级的日志输出 +log.mute("debug"); // 关闭 DEBUG 等级的日志输出 +log.mute([ // 关闭 INFO 和 ERROR 等级的日志输出 + "info", + "error" +]); +``` + +### 3.2. 日志输出方法 + +使用日志等级名称相同的方法名,即可输出该等级的日志,例如: + +```ts +log.error("This is a piece of ERROR log."); +log.warning("This is a piece of WARNING log."); +log.notice("This is a piece of NOTICE log."); +log.info("This is a piece of INFO log."); +log.debug("This is a piece of DEBUG log."); +``` + +这些日志输出方法声明如下:(以 `error` 为例) + +```ts +public error( + log: string, + data?: Date +): this; +``` + +可见,它都返回日志控制器对象本身。所以上面的代码可以用链式写法: + +```ts +log.error("This is a piece of ERROR log.") +.warning("This is a piece of WARNING log.") +.notice("This is a piece of NOTICE log.") +.info("This is a piece of INFO log.") +.debug("This is a piece of DEBUG log."); +``` + +此外,我们注意到它还有第二个参数,一个可选的 Date 类型的参数。这个参数用于指定日志的 +发生时间,如果省略,则会使用系统当前时间,例如: + +```ts +log.info("Using default."); +log.info("Using custom time.", new Date("2018-02-01 00:00:00")); +``` + +### 3.3. 日志追踪 + +很多时候,日志都是用于调试的,那么很可能需要得到日志的写入位置。那么,可以使用 +日志控制器的 `enableTrace` 方法。 + +```ts +log.enableTrace(); // 打开所有等级日志的追踪信息。 +log.info("See the trace info below."); +``` + +将会看到类型如下的输出: + +``` +[2018-08-12T08:32:08.341Z][info] Trace: See the trace info below. + at traceDemo (/home/fenying/logger/samples/demo.js:58:4) +``` + +可以看到日志的输出位置。 + +该方法声明如下: + +```ts +public enableTrace( + depth: number = 1, + levels?: string | string[] +): this; +``` + +第一个参数指定要显示的调用栈深度,设置为 0 则不显示。 +第二个参数指定要配置的日志等级,默认是配置所有的日志等级。 + +例如: + +```ts +log.enableTrace(); // 将所有等级的日志追踪信息设置为 1 层。 +log.enableTrace(5); // 将所有等级的日志追踪信息设置为 5 层。 +log.enableTrace(0); // 关闭所有等级的日志追踪信息。 +log.enableTrace(0, []); // 关闭所有等级的日志追踪信息。 +log.enableTrace( // 将 DEBUG 日志追踪信息设置为 3 层。 + 3, "debug" +); +log.enableTrace( // 关闭 INFO/ERROR 日志的追踪信息。 + 0, ["info", "error"] +); +``` diff --git a/docs/zh-CN/tutorial/03-formatter.md b/docs/zh-CN/tutorial/03-formatter.md new file mode 100644 index 0000000..5e9229f --- /dev/null +++ b/docs/zh-CN/tutorial/03-formatter.md @@ -0,0 +1,97 @@ +# 日志格式化 + +我们注意到,日志的输出都是如下格式的 + +``` +[2018-08-12T07:57:23.400Z][info] Text-Log: Hello world! +``` + +也就是 + +``` +[yyyy-mm-ddThh:mm:ss.###Z][LEVEL] SUBJECT: LOG_TEXT +``` + +这样的格式。 + +如果希望换一个格式怎么办呢?很简单,来看看日志控制器工厂的 `createTextLogger` 方法。 + +```ts +public createTextLogger( + subject?: string, + formatter?: IFormatter, + driver?: string +): ILogger; +``` + +第一个参数 `subject` 我们已经知道,是控制器的主题。 +第二个参数 `formatter` 是我们要关注的格式化方法。 + +> 暂且忽略第三个参数,将在后文中提到。 + +`formatter` 是一个 `IFormatter` 类型的参数,来看看 `IFormatter` +的定义。 + + +```ts +/** + * 一个用于格式化日志为字符串的函数。 + * + * @param log 日志的输入内容。 + * @param subject 日志的主题。 + * @param level 日志等级。 + * @param date 日志写入时间。 + * @param traces 日志的追踪信息。 + */ +export type IFormatter = ( + log: T, + subject: string, + level: L, + date: Date, + traces?: string[] +) => string; +``` + +> - 对于文本日志,`T` 总是 `string`。 +> - 对于默认的日志控制器工厂,`L` 总是 `DefaultLevels`。也就是 +> +> ```ts +> type DefaultLevels = "error" | "notice" | "warning" | +> "debug" | "info"; +> ``` + +因此,它其实是一个函数,将日志的内容进行处理,返回格式化之后的文本内容。 + +根据上面的信息,我们可以实现一个自定义的格式化函数: + +```ts +const log = Loggers.createTextLogger( + "Custom-Formatter", + function(text, subject, level, date, traces): string { + + let ret = `${date} - ${subject} - ${level} - ${text}`; + + if (traces) { + + ret += `\nTrace Stack:\n ${traces.join("\n ")}`; + } + + return ret; + } +); + +log.info("Hello"); + +log.enableTrace(); + +log.info("world"); +``` + +尝试运行,可以得到如下输出: + +``` +Sun Aug 12 2018 17:04:26 GMT+0800 (中国标准时间) - Custom-Formatter - info - Hello +Sun Aug 12 2018 17:04:26 GMT+0800 (中国标准时间) - Custom-Formatter - info - world +Trace Stack: + formatterDemo (/home/fenying/logger/samples/demo.js:99:4) +``` diff --git a/docs/zh-CN/tutorial/04-custom-input.md b/docs/zh-CN/tutorial/04-custom-input.md new file mode 100644 index 0000000..b1c31e6 --- /dev/null +++ b/docs/zh-CN/tutorial/04-custom-input.md @@ -0,0 +1,112 @@ +# 自定义输入格式 + +前面我们使用的都是将字符串文本作为日志内容,传递给日志控制器对象。假如需要更复杂的输入 +内容呢?例如某些 API 网关需要记录 API 访问日志,那么肯定不是用字符串能简单解决的。 + +下面来看看日志控制器工厂对象的 `createDataLogger` 方法。 + +```ts +public createDataLogger( + subject?: string, + formatter?: IFormatter, + driver?: string +): ILogger; +``` + +这个方法有一个可选的泛型参数 `T`,这个泛型参数也就是用于指定创建出来的控制器能接受什么 +作为日志的输入内容。下面看个示例: + +```ts +interface HTTPLog { + + method: "GET" | "POST" | "HEAD"; + + ip: string; + + uri: string; +} + +const logs = Loggers.createDataLogger("HTTP-Logs"); + +logs.unmute(); + +logs.info({ + ip: "192.168.1.122", + method: "GET", + uri: "/index.html" +}); + +logs.info({ + ip: "192.168.1.128", + method: "POST", + uri: "/upload.php" +}); +``` + +运行得到输出如下: + +``` +{"subject":"HTTP-Logs","level":"info","date":1534066661287,"log":{"ip":"192.168.1.122","method":"GET","uri":"/index.html"}} +{"subject":"HTTP-Logs","level":"info","date":1534066661287,"log":{"ip":"192.168.1.122","method":"POST","uri":"/upload.php"}} +``` + +咦,输出变成了 JSON ?是的,这不是出错了。因为 `createDataLogger` 方法使用的默认的 +格式化函数就是将日志格式化为 JSON。 + +所以你也可以自己实现一个格式化函数,例如: + +```ts +interface HTTPLog { + + method: "GET" | "POST" | "HEAD"; + + ip: string; + + uri: string; +} + +const logs = Loggers.createDataLogger( + "HTTP-Logs", + function(log, subject, level, date, traces): string { + + /** + * 注意这里 log 不是 string 类型,而是 HTTPLog 类型的对象。 + */ + return `${date} - ${log.ip} - ${log.method} ${log.uri}`; + } +); + +logs.unmute(); + +logs.info({ + ip: "192.168.1.122", + method: "GET", + uri: "/index.html" +}); + +logs.info({ + ip: "192.168.1.128", + method: "POST", + uri: "/upload.php" +}); +``` + +得到如下输出: + +``` +Sun Aug 12 2018 17:30:16 GMT+0800 (中国标准时间) - 192.168.1.122 - GET /index.html +Sun Aug 12 2018 17:30:16 GMT+0800 (中国标准时间) - 192.168.1.128 - POST /upload.php +``` + +> 从 `createDataLogger` 方法声明可以看出, `createTextLogger` 方法只是对 +> `createDataLogger` 方法的一层封装。相当于 +> +> ```ts +> Loggers.createDataLogger( +> subject, +> DEFAULT_TEXT_FORMATTER +> ); +> ``` +> +> 是的,`createTextLogger` 使用的默认格式化函数为 `DEFAULT_TEXT_FORMATTER`, +> 而 `createDataLogger` 则是使用 `DEFAULT_JSON_FORMATTER`。 diff --git a/docs/zh-CN/tutorial/05-custom-output.md b/docs/zh-CN/tutorial/05-custom-output.md new file mode 100644 index 0000000..e9dae53 --- /dev/null +++ b/docs/zh-CN/tutorial/05-custom-output.md @@ -0,0 +1,179 @@ +# 自定义输出位置 + +## 1. 使用驱动 + +到目前为止,我们讨论的日志全部都是输出到控制台。假如我们需要输出到文件该怎么办? + +在之前的内容里,`createTextLogger` 和 `createDataLogger` 方法的第三个参数 `driver` +一直都被忽略了。其实,这个参数就是用于指定日志的输出驱动的名字。 + +`driver` 一词取自“驱动”之意,意味着只要改动这个参数,就可以完成输出位置的改动,将 +格式化好的日志内容输出到指定的地方。例如文件、数据库、Redis…… + +下面我们看看驱动如何使用。 + +控制器工厂提供了三个与驱动相关的方法。 + +```ts +/** + * 获取已经注册的驱动名称列表。 + */ +public getDriverNames(): string[]; + +/** + * 根据驱动注册的名称,获取驱动对象。 + */ +public getDriver(name: string): IDriver | null; + +/** + * 注册一个新的驱动。 + */ +public registerDriver(name: string, driver: IDriver): boolean; +``` + +从这三个方法可以看出,驱动是要先注册才能使用的。 + +由于每个驱动对象都可以注册一个名称,也就是说,同一种驱动的不同实例对象,可以注册为多个 +不同名称的驱动。 + +例如:(假设有一个驱动叫 `FileLogDriver`,用于将日志写到文件里) + +```ts +Loggers.registerDriver( + "file-a", + new FileLogDriver("/home/fenying/a.log") +); + +Loggers.registerDriver( + "file-b", + new FileLogDriver("/home/fenying/b.log") +); +``` + +然后在创建日志控制器的时候,指定对应的驱动: + +```ts +const logs = Loggers.createTextLogger( + "Sample", + undefined, // 使用默认的格式化函数 + "file-a" +); +``` + +## 2. 实现自定义驱动 + +可以根据需要自行实现一个驱动,先看看 `IDriver` 的定义: + +```ts +interface IDriver { + + /** + * 该方法提供给日志控制器调用,用于写日志到输出设备。 + * + * @param text 已经格式化的日志文本 + * @param subject 日志的主题 + * @param level 日志的等级 + * @param date 日志的时间 + */ + write( + text: string, + subject: string, + level: string, + date: Date + ): void; + + /** + * 将输出缓存中的日志全部输出到输出设备。 + */ + flush(): void | Promise; + + /** + * 关闭驱动。 + */ + close(): void | Promise; +} +``` + +对于一个驱动,只需要实现上面三个方法即可。 + +下面来写一个简单的文件驱动。 + +```ts +import * as fs from "fs"; + +class FileLogDriver +implements IDriver { + + private _ws: fs.WriteStream; + + public constructor(file: string) { + + this._ws = fs.createWriteStream(file); + } + + public write( + text: string, + subject: string, + level: string, + date: Date + ): void { + + if (this._ws) { + + this._ws.write(text + "\n"); + } + } + + public flush(): void | Promise { + + // 未使用缓存,此处什么都不用做。 + return; + } + + public close(): void | Promise { + + this._ws.end(); + delete this._ws; + } +} +``` + +然后就可以使用它了。 + +```ts + +const fd = new FileLogDriver("a.log"); + +Loggers.registerDriver( + "file-a", + fd +); + +const logs = Loggers.createTextLogger( + "Sample", + undefined, + "file-a" +); + +logs.unmute(); + +logs.info("HI"); + +logs.debug("Hello"); + +fd.close(); +``` + +执行后看看当前目录下的 `a.log` 文件,是否有日志内容? + +## 3. 内置的驱动 + +内置的驱动有两种: + +- `Console` + + 默认的驱动类型,注册名为 `console`。 + +- `ColorfulTTY` + + 提供输出颜色支持的命令行输出功能,可以使用 `createColorfulTTYDriver` 方法创建。 diff --git a/docs/zh-CN/tutorial/06-factory.md b/docs/zh-CN/tutorial/06-factory.md new file mode 100644 index 0000000..de5f709 --- /dev/null +++ b/docs/zh-CN/tutorial/06-factory.md @@ -0,0 +1,102 @@ +# 工厂与日志等级 + +## 1. 创建自定义工厂 + +至此,与日志控制器有关的内容基本都学完了,最后来看一下控制器工厂的使用。到目前为止, +我们使用的都是默认的控制器工厂,那要如何创建一个控制器工厂呢? + +使用 `createFactory` 方法即可,它的声明如下: + +```ts +function createFactory< + L extends string = DefaultLevels +>(levels: L[]): IFactory; +``` + +这个方法有两个参数: + +- 泛型参数 `L` ,指定可以使用的日志等级,这个参数用于静态类型检查和 IDE 自动完成。 +- 形参 `levels`,它是 `L` 类型的数组,这个参数才真正起定义日志等级的作用。 + +也就是说通过 `L` 指定 `levels` 可以输入的值,用于 TypeScript 静态类型检查,和 IDE 的 +自动完成、语法提示等。 `levels` 才是真正在运行时定义可用日志等级的参数。 + +> 对于默认工厂,参数 `L = DefaultLevels`,`levels = DEFAULT_LEVELS`。 + +例如: + +```ts +import Loggers, { createFactory } from "@litert/logger"; + +/** + * 定义三种日志等级。 + */ +type MyLevels = "normal" | "secure" | "failure"; + +const factory1 = createFactory([ + "normal", "secure", "failure" +]); + +const logs = factory1.createTextLogger("Test"); + +logs.unmute(); + +logs.normal("This is a NORMAL log."); + +logs.secure("This is a SECURE log."); +``` + +## 2. 工厂的基本方法 + +### 2.1. mute/unmute + +类似日志控制器,每个工厂也提供 mute/unmute 方法,这两个方法作用于所有由该工厂创建的 +控制器对象。 + +> 即不同的工厂之间,互不干扰。 + +```ts +factory.unmute(); // 打开所有等级的日志输出 +factory.unmute("debug"); // 打开 DEBUG 等级的日志输出 +factory.unmute([ // 打开 INFO 和 ERROR 等级的日志输出 + "info", + "error" +]); +``` + +同理,可以用 `mute` 方法关闭各个等级的日志输出。 + +```ts +factory.mute(); // 关闭所有等级的日志输出 +factory.mute("debug"); // 关闭 DEBUG 等级的日志输出 +factory.mute([ // 关闭 INFO 和 ERROR 等级的日志输出 + "info", + "error" +]); +``` + +### 2.2. enableTrace + +类似日志控制器,每个工厂也提供 enableTrace 方法,这个方法作用于所有由该工厂创建的 +控制器对象。 + +```ts +factory.enableTrace(); // 将所有等级的日志追踪信息设置为 1 层。 +factory.enableTrace(5); // 将所有等级的日志追踪信息设置为 5 层。 +factory.enableTrace(0); // 关闭所有等级的日志追踪信息。 +factory.enableTrace(0, []); // 关闭所有等级的日志追踪信息。 +factory.enableTrace( // 将 DEBUG 日志追踪信息设置为 3 层。 + 3, "debug" +); +factory.enableTrace( // 关闭 INFO/ERROR 日志的追踪信息。 + 0, ["info", "error"] +); +``` + +## 2.3. getSubjects + +该方法可以获取所有由该工厂创建的控制器对象的主题列表。 + +## 2.4. getLevels + +该方法可以获取所有由该工厂支持的日志等级名称数组。 diff --git a/docs/zh-CN/tutorial/README.md b/docs/zh-CN/tutorial/README.md new file mode 100644 index 0000000..34a94d5 --- /dev/null +++ b/docs/zh-CN/tutorial/README.md @@ -0,0 +1,10 @@ +# 入门教程 + +## 目录 + +1. [安装与使用](./01-install.md) +2. [基本使用](./02-basic-usage.md) +3. [日志格式化](./03-formatter.md) +4. [自定义输入格式](./04-custom-input.md) +5. [自定义输出位置](./05-custom-output.md) +6. [工厂与日志等级](./06-factory.md) \ No newline at end of file diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index ff689de..de12de9 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -4,15 +4,10 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@litert/core": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@litert/core/-/core-0.6.0.tgz", - "integrity": "sha512-cbbfhCYzpCxOpl8JjoJ3pVJOi2pOYbUFPLzz0Fwkd1zlzwh9rUSpcZ3EY7Hsa/fweKkVx2VgxSplzM/kRKyNDQ==" - }, "@types/node": { - "version": "9.6.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.27.tgz", - "integrity": "sha512-fGWGG9Wypv6JZLIrnq9jXFX/FhQzgNccTlojez9hBbQ9UiBdxtc0ONMMe4/vnB2nDgOMDpPR/7HhenUB+Bw5yQ==", + "version": "10.5.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.8.tgz", + "integrity": "sha512-sWSjw+bYW/2W+1V3m8tVsm9PKJcxk3NHN7oRqNUfEdofKg0Imbdu1dQbFvLKjZQXEDXRN6IfSMACjJ7Wv4NGCQ==", "dev": true }, "typescript": { diff --git a/package.json b/package.json index 592b3d4..0fa3d93 100644 --- a/package.json +++ b/package.json @@ -27,12 +27,11 @@ "url": "https://github.com/litert/logger.js/issues" }, "homepage": "https://github.com/litert/logger.js#readme", - "dependencies": { - "@litert/core": "^0.6.0" - }, + "dependencies": {}, "types": "lib/index.d.ts", "typings": "lib/index.d.ts", "devDependencies": { + "@types/node": "^10.5.8", "typescript": "^2.9.2" }, "engines": { diff --git a/src/lib/Common.ts b/src/lib/Common.ts index 4c7bdeb..d3a7969 100644 --- a/src/lib/Common.ts +++ b/src/lib/Common.ts @@ -24,12 +24,10 @@ export const DEFAULT_DRIVER = "console"; */ export const DEFAULT_SUBJECT = "default"; -export const EXCEPTION_TYPE = "litert/logger"; - /** * The names of default levels. */ -export const DEFAULT_LEVEL_NAMES: DefaultLogLevels[] = [ +export const DEFAULT_LEVELS: DefaultLevels[] = [ "error", "notice", "warning", @@ -46,7 +44,7 @@ export const DEFAULT_LEVEL_NAMES: DefaultLogLevels[] = [ * @param date The datetime of log. * @param traces The trace-info of log. */ -export type ILogFormatter = ( +export type IFormatter = ( log: T, subject: string, level: L, @@ -54,8 +52,17 @@ export type ILogFormatter = ( traces?: string[] ) => string; -export interface ILogDriver { +export interface IDriver { + /** + * This method is provied to be called by logger, to send logs + * to target device. + * + * @param text The formatted log text. + * @param subject The subject of log + * @param level The level of log + * @param date The data of log + */ write( text: string, subject: string, @@ -76,41 +83,46 @@ export interface IBaseLogger { getSubject(): string; /** - * Enable or disable trace info of all levels or determined level of - * current logger. - * - * @param enable Set to false to disable trace info. (Default: true) - * @param lv Determine a level to be disabled tracing. + * Get the levels list of this logger supports. */ - enableTrace(enable?: boolean, lv?: L): this; + getLevels(): L[]; /** - * Enable tracing for all levels of all loggers, or for determined level - * of all loggers. + * Enable or disable trace info of all levels or determined level of + * current logger. * - * @param enable Set to false to use short form trace info. (Default: true) - * @param lv Determine a level to be enabled tracing. + * @param depth Set the depth of tracing stack, by default it's 1. + * Set to 0 to shutdown displaying trace stack. + * @param level Determine a level or a list of level to be disabled tracing. + * By default it will be all levels. */ - useFullTrace(enable?: boolean, lv?: L): this; + enableTrace(depth?: number, level?: L | L[]): this; /** * Unmute all levels or determined level of current logger. * - * @param level (Optional) The determined level. + * @param level Determine a level or a list of level to be unmuted. + * By default it will be all levels. */ - unmute(level?: L): this; + unmute(level?: L | L[]): this; /** * Mute all levels or determined level of current logger. * - * @param level (Optional) The determined level. + * @param level Determine a level or a list of level to be muted. + * By default it will be all levels. + */ + mute(level?: L | L[]): this; + + /** + * Flush the logs in driver's buffer. */ - mute(level?: L): this; + flush(): void | Promise; } export type LoggerMethod = ( log: T, - data?: Date + date?: Date ) => ILogger; export type ILogger = IBaseLogger & Record< @@ -118,67 +130,78 @@ export type ILogger = IBaseLogger & Record< LoggerMethod >; -export type DefaultLogLevels = "error" | "notice" | "warning" | "debug" | "info"; +export type DefaultLevels = "error" | "notice" | "warning" | "debug" | "info"; -export interface ILoggerFactory { +export interface IFactory { /** * Mute all levels of all loggers, or determined level of all loggers. * - * @param lv Determine a level to be muted. + * @param level Determine a level or a list of level to be muted. + * By default it will be all levels. */ - mute(lv?: L): this; + mute(level?: L | L[]): this; /** * Enable all levels of all loggers, or determined level of all loggers. * - * @param lv Determine a level to be enabled. + * @param level Determine a level or a list of level to be unmuted. + * By default it will be all levels. */ - unmute(lv?: L): this; + unmute(level?: L | L[]): this; /** * Disable or enable trace info for all levels of all loggers, or for * determined level of all loggers. * - * @param enable Set to false to disable trace info. (Default: true) - * @param lv Determine a level to be disabled tracing. + * @param depth Set the depth of tracing stack, by default it's 1. + * Set to 0 to shutdown displaying trace stack. + * @param level Determine a level or a list of level to be disabled tracing. + * By default it will be all levels. */ - enableTrace(enable?: boolean, lv?: L): this; + enableTrace(depth?: number, level?: L | L[]): this; /** - * Setup the trace info format for all levels of all loggers, or for - * determined level of all loggers. - * - * @param enable Set to false to use short form trace info. (Default: true) - * @param lv Determine a level to be enabled tracing. - */ - useFullTrace(enable?: boolean, lv?: L): this; - - /** - * Added a new driver. If the driver of the name already exists, an - * exception will be thrown. + * Added a new driver. * * @param name The unique name of driver * @param driver The driver object. */ - registerDriver(name: string, driver: ILogDriver): this; + registerDriver(name: string, driver: IDriver): boolean; /** * Find and return an existing driver by its unique name. * * @param name The unique name of driver */ - getDriver(name: string): ILogDriver | null; + getDriver(name: string): IDriver | null; + + /** + * Get the names list of registered drivers. + */ + getDriverNames(): string[]; + + /** + * Get the subjects list of created loggers. + */ + getSubjects(): string[]; + + /** + * Get the levels list of this factory supports. + */ + getLevels(): L[]; /** * Create a simple text logger. * - * @param subject The unique subject of logger. (default: default) - * @param driver The driver to write logs. (default: console) + * @param subject The unique subject of logger. (default: default) + * @param formatter The formatter helps stringify input data. + * (default: DEFAULT_TEXT_FORMATTER) + * @param driver The driver to write logs. (default: console) */ createTextLogger( subject?: string, - formatter?: ILogFormatter, + formatter?: IFormatter, driver?: string ): ILogger; @@ -186,12 +209,13 @@ export interface ILoggerFactory { * Create a simple data logger. * * @param subject The unique subject of logger. (default: default) - * @param formatter The formatter helps stringify input data. (default: json) + * @param formatter The formatter helps stringify input data. + * (default: DEFAULT_JSON_FORMATTER) * @param driver The driver to write logs. (default: console) */ createDataLogger( - subject: string, - formatter: ILogFormatter, + subject?: string, + formatter?: IFormatter, driver?: string ): ILogger; } diff --git a/src/lib/ColorfulConsoleDriver.ts b/src/lib/Drivers/ColorfulTTY.ts similarity index 54% rename from src/lib/ColorfulConsoleDriver.ts rename to src/lib/Drivers/ColorfulTTY.ts index 7165048..5b78394 100644 --- a/src/lib/ColorfulConsoleDriver.ts +++ b/src/lib/Drivers/ColorfulTTY.ts @@ -16,7 +16,7 @@ // tslint:disable:no-console -import { ILogDriver } from "./Common"; +import { IDriver } from "../Common"; export type ForeColorSet = "blue" | "cyan" | "green" | "magenta" | "grey" | "red" | "yellow" | "white" | "black" | "default"; @@ -26,6 +26,23 @@ export type BgColorSet = ForeColorSet; const BG_COLOR_ENDING = "\x1B[49m"; const FORE_COLOR_ENDING = "\x1B[39m"; +type Writer = ( + text: string, + subject: string, + level: string, + date: Date +) => void; + +function NON_COLORFUL_WRITER( + text: string, + subject: string, + level: string, + date: Date +): void { + + console.log(text); +} + const FORE_COLORS: Record = { "default": "", "blue": "\u001b[34m", @@ -52,11 +69,25 @@ const BG_COLORS: Record = { "yellow": "\u001b[43m" }; -export interface IColorfulConsoleDriver -extends ILogDriver { +export interface IColorfulTTYDriver +extends IDriver { + /** + * Set the fore-color for the logs of a level. + * + * @param color The color of the level. + * @param level Specify the level to be colorified. + * If no level specified, then the default color will be set. + */ foreColor(color: ForeColorSet, level?: string): this; + /** + * Set the background-color for the logs of a level. + * + * @param color The color of the level. + * @param level Specify the level to be colorified. + * If no level specified, then the default color will be set. + */ bgColor(color: BgColorSet, level?: string): this; } @@ -67,10 +98,14 @@ interface IStyle { end: string; } -const DEFAULT_LEVEL = Symbol("__default__"); +/** + * This ugly line is due to the breaking changes after TypeScript 2.9.x. + * @see https://github.com/Microsoft/TypeScript/issues/24587 + */ +const DEFAULT_LEVEL: string = Symbol("__default__") as any; -class ColorfulConsoleDriver -implements IColorfulConsoleDriver { +class ColorfulTTYDriver +implements IColorfulTTYDriver { private _foreColors: Record; @@ -81,10 +116,10 @@ implements IColorfulConsoleDriver { public constructor() { this._bgColors = { - [DEFAULT_LEVEL]: "" + [DEFAULT_LEVEL]: "default" }; this._foreColors = { - [DEFAULT_LEVEL]: "" + [DEFAULT_LEVEL]: "default" }; this._levels = { @@ -93,6 +128,8 @@ implements IColorfulConsoleDriver { end: "" } }; + + this.write = this._buildWriter(); } public bgColor(color: BgColorSet, level?: string): this { @@ -115,7 +152,7 @@ implements IColorfulConsoleDriver { return this; } - private _rebuild(level: string | symbol): void { + private _rebuild(level: string/* | symbol*/): void { let start: string = ""; let end: string = ""; @@ -142,13 +179,7 @@ implements IColorfulConsoleDriver { date: Date ): void { - const dec = this._levels[level] || this._levels[DEFAULT_LEVEL]; - - return console.log( - text.split("\n").map( - (x) => `${dec.start}${x}${dec.end}` - ).join("\n") - ); + return; } public flush(): void { @@ -160,9 +191,65 @@ implements IColorfulConsoleDriver { // do nothing. } + + public static isTerminal(): boolean { + + // @ts-ignore + return this.isNodeJS() && ( + // @ts-ignore + process.stdout.isTTY || + // @ts-ignore + process.stdout.constructor.name === "Socket" // Debugging + ); + } + + public static isNodeJS(): boolean { + + // @ts-ignore + return typeof process === "object" && typeof process.stdout === "object"; + } + + private _buildWriter(): Writer { + + if (ColorfulTTYDriver.isTerminal()) { + + return this._buildWriterForTerminal(); + } + + return NON_COLORFUL_WRITER; + } + + private _buildWriterForTerminal(): Writer { + + const cs: string[] = []; + + cs.push(`return function(text, subject, level, date) {`); + cs.push(`const dec = this._levels[level] || this._levels[DEFAULT_LEVEL];`); + cs.push(`return console.log(`); + cs.push(` text.split("\\n").map(`); + cs.push(` (x) => \`\${dec.start}\${x}\${dec.end}\``); + cs.push(` ).join("\\n")`); + cs.push(`);`); + cs.push(`};`); + + return (new Function( + "DEFAULT_LEVEL", + cs.join("\n") + ))(DEFAULT_LEVEL); + } } -export function createColorfulConsoleDriver(): IColorfulConsoleDriver { +/** + * Create a colorful-tty driver. + */ +export function createColorfulTTYDriver(): IColorfulTTYDriver { + + if (!ColorfulTTYDriver.isTerminal()) { + + console.warn( + "The ColorfulTTYDriver is only usable in Node.JS terminal." + ); + } - return new ColorfulConsoleDriver(); + return new ColorfulTTYDriver(); } diff --git a/src/lib/ConsoleDriver.ts b/src/lib/Drivers/Console.ts similarity index 82% rename from src/lib/ConsoleDriver.ts rename to src/lib/Drivers/Console.ts index e32912c..29cf0b3 100644 --- a/src/lib/ConsoleDriver.ts +++ b/src/lib/Drivers/Console.ts @@ -16,10 +16,10 @@ // tslint:disable:no-console -import { ILogDriver } from "./Common"; +import { IDriver } from "../Common"; -export class ConsoleDriver -implements ILogDriver { +class ConsoleDriver +implements IDriver { public write( text: string, @@ -41,3 +41,11 @@ implements ILogDriver { // do nothing. } } + +/** + * Create a console driver. + */ +export function createConsoleDriver(): IDriver { + + return new ConsoleDriver(); +} diff --git a/src/lib/Exception.ts b/src/lib/Exception.ts deleted file mode 100644 index b957e94..0000000 --- a/src/lib/Exception.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright 2018 Angus.Fenying - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as L from "@litert/core"; -import { EXCEPTION_TYPE } from "./Common"; - -export const E_DRIVER_NOT_FOUND = 1; -export const E_DRIVER_FOUND = 2; - -export class Exception extends L.Exception { - - public constructor(error: number, message: string, origin?: any) { - - super(error, message, origin); - - this._type = EXCEPTION_TYPE; - } -} - -export default Exception; diff --git a/src/lib/Factory.ts b/src/lib/Factory.ts index 86f1ef5..429edb3 100644 --- a/src/lib/Factory.ts +++ b/src/lib/Factory.ts @@ -14,33 +14,34 @@ * limitations under the License. */ -import * as E from "./Exception"; - import Logger from "./Logger"; import { - ILevelOptions, - DEFAULT_FORMATTER, - DEFAULT_TEXT_FORMATTER + ILevelOptions } from "./Internal"; -import { ConsoleDriver } from "./ConsoleDriver"; +import { + DEFAULT_JSON_FORMATTER, + DEFAULT_TEXT_FORMATTER +} from "./Formatters"; + +import { createConsoleDriver } from "./Drivers/Console"; import { - ILoggerFactory, - ILogFormatter, + IFactory, + IFormatter, DEFAULT_SUBJECT, DEFAULT_DRIVER, ILogger, - DefaultLogLevels, - ILogDriver, - DEFAULT_LEVEL_NAMES + DefaultLevels, + IDriver, + DEFAULT_LEVELS } from "./Common"; class LoggerFactory -implements ILoggerFactory { +implements IFactory { - protected _drivers: Record; + protected _drivers: Record; protected _loggers: Record>; @@ -48,12 +49,12 @@ implements ILoggerFactory { protected _levels: string[]; - public constructor(levels: string[] = DEFAULT_LEVEL_NAMES) { + public constructor(levels: string[] = DEFAULT_LEVELS) { this._loggers = {}; this._drivers = { - [DEFAULT_DRIVER]: new ConsoleDriver() + [DEFAULT_DRIVER]: createConsoleDriver() }; this._levels = levels; @@ -64,151 +65,140 @@ implements ILoggerFactory { this._globalConfig[lv] = { enabled: false, - trace: false, - fullTrace: false + trace: 0 }; } } - public mute(lv?: string): this { - - if (lv) { - - this._globalConfig[lv].enabled = false; - } - else { + /** + * Get the names list of registered drivers. + */ + public getDriverNames(): string[] { - for (let level of this._levels) { + return Object.keys(this._drivers); + } - this._globalConfig[level].enabled = false; - } - } + /** + * Get the subjects list of created loggers. + */ + public getSubjects(): string[] { - for (let subject in this._loggers) { + return Object.keys(this._loggers); + } - this._loggers[subject].mute(lv); - } + /** + * Get the levels list of this factory supports. + */ + public getLevels(): string[] { - return this; + return [...this._levels]; } - public unmute(lv?: string): this { + public mute(levels?: string | string[]): this { + + if (!levels || !levels.length) { - if (lv) { + levels = this._levels; + } + else if (typeof levels === "string") { - this._globalConfig[lv].enabled = true; + levels = [ levels ]; } - else { - for (let level of this._levels) { + for (let level of levels) { - this._globalConfig[level].enabled = true; - } + this._globalConfig[level].enabled = false; } for (let subject in this._loggers) { - this._loggers[subject].unmute(lv); + this._loggers[subject].mute(levels); } return this; } - public useFullTrace(enabled: boolean = true, lv?: string): this { + public unmute(levels?: string | string[]): this { - if (lv) { + if (!levels || !levels.length) { - this._globalConfig[lv].fullTrace = enabled; + levels = this._levels; } - else { + else if (typeof levels === "string") { - for (let level of this._levels) { + levels = [ levels ]; + } - this._globalConfig[level].fullTrace = enabled; - } + for (let level of levels) { + + this._globalConfig[level].enabled = true; } for (let subject in this._loggers) { - this._loggers[subject].useFullTrace(enabled, lv); + this._loggers[subject].unmute(levels); } return this; } - public enableTrace(enabled: boolean = true, lv?: string): this { + public enableTrace(depth: number = 1, levels?: string | string[]): this { - if (lv) { + if (!levels || levels.length === 0) { - this._globalConfig[lv].trace = enabled; + levels = this._levels.slice(); } - else { + else if (typeof levels === "string") { - for (let level of this._levels) { - - this._globalConfig[level].trace = enabled; - } + levels = [ levels ]; } - for (let subject in this._loggers) { + for (let lv of levels) { + + this._globalConfig[lv].trace = depth; + + for (let subject in this._loggers) { - this._loggers[subject].enableTrace(enabled, lv); + this._loggers[subject].enableTrace(depth, lv); + } } return this; } - public registerDriver(name: string, driver: ILogDriver): this { + public registerDriver(name: string, driver: IDriver): boolean { if (this._drivers[name]) { - throw new E.Exception( - E.E_DRIVER_FOUND, - `The driver of name "${name}" already exists.` - ); + return false; } this._drivers[name] = driver; - return this; + return true; } - public getDriver(name: string): ILogDriver | null { - - if (!this._drivers[name]) { - - throw new E.Exception( - E.E_DRIVER_NOT_FOUND, - `The driver of name "${name}" doesn't exist.` - ); - } + public getDriver(name: string): IDriver { return this._drivers[name] || null; } public createTextLogger( subject: string = DEFAULT_SUBJECT, - formatter: ILogFormatter = DEFAULT_TEXT_FORMATTER, + formatter: IFormatter = DEFAULT_TEXT_FORMATTER, driver: string = DEFAULT_DRIVER ): ILogger { - if (this._loggers[subject]) { - - return this._loggers[subject]; - } - - return this._loggers[subject] = new Logger( + return this.createDataLogger( subject, - this.getDriver(driver), - this._globalConfig, formatter, - this._levels - ) as any; + driver + ); } public createDataLogger( subject: string = DEFAULT_SUBJECT, - formatter: ILogFormatter = DEFAULT_FORMATTER, + formatter: IFormatter = DEFAULT_JSON_FORMATTER, driver: string = DEFAULT_DRIVER ): ILogger { @@ -227,18 +217,25 @@ implements ILoggerFactory { } } -const factory = new LoggerFactory(DEFAULT_LEVEL_NAMES); - -export function getDefaultFactory< - L extends string = DefaultLogLevels ->(): ILoggerFactory { +/** + * Create a new factory object. + */ +export function createFactory< + L extends string = DefaultLevels +>(levels: L[]): IFactory { - return factory as any; + return new LoggerFactory(levels) as any; } -export function createLoggerFactory< - L extends string = DefaultLogLevels ->(levels: L[]): ILoggerFactory { +/** + * The default factory object. + */ +const factory = createFactory(DEFAULT_LEVELS); - return new LoggerFactory(levels) as any; +/** + * Get the default factory object. + */ +export function getDefaultFactory(): IFactory { + + return factory as any; } diff --git a/src/lib/Formatters.ts b/src/lib/Formatters.ts new file mode 100644 index 0000000..ab30255 --- /dev/null +++ b/src/lib/Formatters.ts @@ -0,0 +1,57 @@ +/** + * Copyright 2018 Angus.Fenying + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { IFormatter } from "./Common"; + +/** + * The default formatter for text log. + */ +export const DEFAULT_TEXT_FORMATTER: IFormatter = function( + log: string, + subject: string, + level: string, + date: Date, + traces?: string[] +): string { + + if (traces) { + + return `[${date.toISOString()}][${level}] ${subject}: ${log} + at ${traces.join("\n at ")}`; + } + + return `[${date.toISOString()}][${level}] ${subject}: ${log}`; +}; + +/** + * The default formatter for customized log. + */ +export const DEFAULT_JSON_FORMATTER: IFormatter = function( + log: any, + subject: string, + level: string, + date: Date, + traces?: string[] +): string { + + return JSON.stringify({ + subject, + level, + date: date.getTime(), + log, + traces + }); +}; diff --git a/src/lib/Internal.ts b/src/lib/Internal.ts index 10b3c03..1550f73 100644 --- a/src/lib/Internal.ts +++ b/src/lib/Internal.ts @@ -14,47 +14,9 @@ * limitations under the License. */ -// tslint:disable:no-console - export interface ILevelOptions { "enabled": boolean; - "trace": boolean; - - "fullTrace": boolean; -} - -export function DEFAULT_TEXT_FORMATTER( - log: string, - subject: string, - level: string, - date: Date, - traces?: string[] -): string { - - if (traces) { - - return `[${date.toISOString()}][${level}] ${subject}: ${log} - at ${traces.join("\n at ")}`; - } - - return `[${date.toISOString()}][${level}] ${subject}: ${log}`; -} - -export function DEFAULT_FORMATTER( - log: any, - subject: string, - level: string, - date: Date, - traces?: string[] -): string { - - return JSON.stringify({ - subject, - level, - date: date.getTime(), - log, - traces - }); + "trace": number; } diff --git a/src/lib/Logger.ts b/src/lib/Logger.ts index 52261ae..8fc53a1 100644 --- a/src/lib/Logger.ts +++ b/src/lib/Logger.ts @@ -17,10 +17,10 @@ import { ILevelOptions } from "./Internal"; import { - ILogFormatter, - ILogDriver, + IFormatter, + IDriver, IBaseLogger, - DEFAULT_LEVEL_NAMES + DEFAULT_LEVELS } from "./Common"; @@ -32,30 +32,23 @@ function _emptyLogMethod(this: Logger, x: string) { function createLogMethod( subject: string, level: string, - tracing: boolean, - fullTrace: boolean, - driver: ILogDriver, - formatter: ILogFormatter, - textInput: boolean + traceDepth: number, + driver: IDriver, + formatter: IFormatter ): any { let cs: string[] = []; cs.push(`return function(log, now = new Date()) {`); - if (tracing) { + if (traceDepth) { cs.push('let tmpObj = {};'); cs.push(`Error.captureStackTrace(tmpObj, this.${level});`); - if (fullTrace) { - - cs.push('let traces = tmpObj.stack.split(/\\n\\s+at\\s+/).slice(1);'); - } - else { - - cs.push('let traces = [tmpObj.stack.split(/\\n\\s+at\\s+/)[1]];'); - } + cs.push('let traces = tmpObj.stack.split('); + cs.push(' /\\n\\s+at\\s+/'); + cs.push(`).slice(1, ${traceDepth + 1});`); } subject = subject.replace(/"/g, "\\\""); @@ -67,7 +60,7 @@ function createLogMethod( cs.push(` "${subject}",`); cs.push(` "${level}",`); - if (tracing) { + if (traceDepth) { cs.push(` now,`); cs.push(` traces`); @@ -106,18 +99,18 @@ implements IBaseLogger { protected _subject: string; - protected _formatter!: ILogFormatter; + protected _formatter!: IFormatter; - protected _driver: ILogDriver; + protected _driver: IDriver; protected _levels: string[]; public constructor( subject: string, - driver: ILogDriver, + driver: IDriver, settings: Record, - wraper?: ILogFormatter, - levels: string[] = DEFAULT_LEVEL_NAMES + wraper?: IFormatter, + levels: string[] = DEFAULT_LEVELS ) { this._options = {}; @@ -134,90 +127,83 @@ implements IBaseLogger { this._options[lv] = { enabled: settings[lv].enabled, - trace: settings[lv].trace, - fullTrace: settings[lv].fullTrace + trace: settings[lv].trace }; this._updateMethod(lv); } } + public flush(): void | Promise { + + return this._driver.flush(); + } + public getSubject(): string { return this._subject; } - public useFullTrace(enable: boolean = true, lv?: string): this { + public getLevels(): string[] { - if (lv !== undefined) { + return [...this._levels]; + } - this._options[lv].fullTrace = enable; - this._updateMethod(lv); - } - else { + public enableTrace(depth: number = 1, levels?: string | string[]): this { - for (let level in this._options) { + if (!levels || levels.length === 0) { - this._options[level].fullTrace = enable; - this._updateMethod( level); - } + levels = this._levels.slice(); } + else if (typeof levels === "string") { - return this; - } - - public enableTrace(enable: boolean = true, lv?: string): this { - - if (lv !== undefined) { - - this._options[lv].trace = enable; - this._updateMethod(lv); + levels = [ levels ]; } - else { - for (let level in this._options) { + for (let level of levels) { - this._options[level].trace = enable; - this._updateMethod( level); - } + this._options[level].trace = depth; + this._updateMethod(level); } return this; } - public unmute(lv?: string): this { + public unmute(levels?: string | string[]): this { - if (lv !== undefined) { + if (!levels || !levels.length) { - this._options[lv].enabled = true; - this._updateMethod(lv); + levels = this._levels; } - else { + else if (typeof levels === "string") { - for (let level in this._options) { + levels = [ levels ]; + } + + for (let level of levels) { - this._options[level].enabled = true; - this._updateMethod( level); - } + this._options[level].enabled = true; + this._updateMethod( level); } return this; } - public mute(lv?: string): this { + public mute(levels?: string | string[]): this { - if (lv !== undefined) { + if (!levels || !levels.length) { - this._options[lv].enabled = false; - this._updateMethod(lv); + levels = this._levels; + } + else if (typeof levels === "string") { + + levels = [ levels ]; } - else { - for (let level in this._options) { + for (let level of levels) { - this._options[level].enabled = false; - this._updateMethod( level); - } + this._options[level].enabled = false; + this._updateMethod( level); } return this; @@ -230,7 +216,6 @@ implements IBaseLogger { this._subject, lv, this._options[lv].trace, - this._options[lv].fullTrace, this._driver, this._formatter ) : _emptyLogMethod; diff --git a/src/lib/index.ts b/src/lib/index.ts index 8bb878c..06e5b7b 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -14,24 +14,16 @@ * limitations under the License. */ -import { - ILoggerFactory, - DefaultLogLevels -} from "./Common"; import { getDefaultFactory } from "./Factory"; -const defaultFactory: ILoggerFactory< - DefaultLogLevels -> = getDefaultFactory(); - -export default defaultFactory; - -export * from "./Exception"; +export default getDefaultFactory(); export * from "./Common"; export * from "./Factory"; -export * from "./ConsoleDriver"; +export * from "./Formatters"; + +export * from "./Drivers/Console"; -export * from "./ColorfulConsoleDriver"; +export * from "./Drivers/ColorfulTTY"; diff --git a/src/samples/01.quick-start.ts b/src/samples/01.quick-start.ts index 7c8c903..b7cfbc5 100644 --- a/src/samples/01.quick-start.ts +++ b/src/samples/01.quick-start.ts @@ -65,29 +65,29 @@ import Loggers from "../lib"; * If you wanna trace where the log is logged, just turn on the log-tracing. * And now the calling spot will be appended after the logs' output. */ - logs.enableTrace(true); + logs.enableTrace(); logs.info("This is INFO log."); /** * Or if you wanna print the whole calling-stack? */ - logs.useFullTrace(true); + logs.enableTrace(10); logs.notice("This is NOTICE log."); - logs.useFullTrace(false); + logs.enableTrace(0); /** * And you can turn on the whole calling-stack for DEBUG level only. */ - logs.useFullTrace(true, "debug"); + logs.enableTrace(10, "debug"); logs.error("This is ERROR log."); logs.debug("This is DEBUG log."); - logs.enableTrace(false); + logs.enableTrace(0); /** * Besides, you can pass a Date object for the log, instead of the current diff --git a/src/samples/02.custom-formatter.ts b/src/samples/02.custom-formatter.ts index e2e7565..09162ce 100644 --- a/src/samples/02.custom-formatter.ts +++ b/src/samples/02.custom-formatter.ts @@ -56,11 +56,11 @@ import Loggers from "../lib"; */ logs.debug("This is DEBUG log."); - logs.enableTrace(true); + logs.enableTrace(); logs.warning("This is WARNING log."); - logs.useFullTrace(true); + logs.enableTrace(10); logs.notice("This is NOTICE log."); diff --git a/src/samples/03.built-in-colorful-driver.ts b/src/samples/03.built-in-colorful-driver.ts index 2903a85..e578d04 100644 --- a/src/samples/03.built-in-colorful-driver.ts +++ b/src/samples/03.built-in-colorful-driver.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import Loggers, { createColorfulConsoleDriver } from "../lib"; +import Loggers, { createColorfulTTYDriver } from "../lib"; (function builtInColorfulDriver(): void { - const theColorDriver = createColorfulConsoleDriver(); + const theColorDriver = createColorfulTTYDriver(); theColorDriver.foreColor("green", "info"); theColorDriver.foreColor("red", "error"); @@ -56,11 +56,11 @@ import Loggers, { createColorfulConsoleDriver } from "../lib"; */ logs.debug("This is DEBUG log."); - logs.enableTrace(true); + logs.enableTrace(); logs.warning("This is WARNING log."); - logs.useFullTrace(true); + logs.enableTrace(10); logs.notice("This is NOTICE log."); diff --git a/src/samples/04.object-logs.ts b/src/samples/04.object-logs.ts index 20bc5a6..bb14349 100644 --- a/src/samples/04.object-logs.ts +++ b/src/samples/04.object-logs.ts @@ -31,7 +31,7 @@ interface LogInfo { * First, create a log controller, giving a subject and a formater. */ let logs = Loggers.createDataLogger( - "Custom-Formatter", + "Object-Formatter", function(log, subj, lv, dt, traces): string { if (traces) { @@ -77,7 +77,7 @@ interface LogInfo { result: "failed" }); - logs.enableTrace(true); + logs.enableTrace(); logs.warning({ action: "DeleteAccount", @@ -85,7 +85,7 @@ interface LogInfo { result: "succeed" }); - logs.useFullTrace(true); + logs.enableTrace(10); logs.notice({ action: "RegisterAccount", diff --git a/src/samples/05.using-factory.ts b/src/samples/05.using-factory.ts index 4972a01..0f08866 100644 --- a/src/samples/05.using-factory.ts +++ b/src/samples/05.using-factory.ts @@ -15,8 +15,8 @@ */ import { - createLoggerFactory, - DEFAULT_LEVEL_NAMES + createFactory, + DEFAULT_LEVELS } from "../lib"; interface LogInfo { @@ -30,8 +30,8 @@ interface LogInfo { (function objectLogs(): void { - let factory1 = createLoggerFactory(DEFAULT_LEVEL_NAMES); - let factory2 = createLoggerFactory(DEFAULT_LEVEL_NAMES); + let factory1 = createFactory(DEFAULT_LEVELS); + let factory2 = createFactory(DEFAULT_LEVELS); /** * First, create a log controller, giving a subject. @@ -107,7 +107,7 @@ interface LogInfo { result: "failed" }); - logs1.enableTrace(true); + logs1.enableTrace(); logs1.warning({ action: "DeleteAccount", @@ -115,7 +115,7 @@ interface LogInfo { result: "succeed" }); - logs1.useFullTrace(true); + logs1.enableTrace(10); logs1.debug({ action: "RegisterAccount", diff --git a/src/samples/06.custom-levels.ts b/src/samples/06.custom-levels.ts index e69de29..7eb845f 100644 --- a/src/samples/06.custom-levels.ts +++ b/src/samples/06.custom-levels.ts @@ -0,0 +1,34 @@ +/** + * Copyright 2018 Angus.Fenying + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createFactory +} from "../lib"; + +/** + * Define the customized levels of logs. + */ +type MyLevels = "normal" | "secure" | "failure"; + +const factory1 = createFactory([ + "normal", "secure", "failure" +]); + +const logs = factory1.createTextLogger("Test"); + +logs.unmute(); + +logs.normal("This is a normal log."); diff --git a/src/samples/07.custom-driver.ts b/src/samples/07.custom-driver.ts new file mode 100644 index 0000000..7827cd5 --- /dev/null +++ b/src/samples/07.custom-driver.ts @@ -0,0 +1,75 @@ +/** + * Copyright 2018 Angus.Fenying + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Loggers, { IDriver } from "../lib"; +import * as fs from "fs"; + +class FileLogDriver +implements IDriver { + + private _ws: fs.WriteStream; + + public constructor(file: string) { + + this._ws = fs.createWriteStream(file); + } + + public write( + text: string, + subject: string, + level: string, + date: Date + ): void { + + if (this._ws) { + + this._ws.write(text + "\n"); + } + } + + public flush(): void | Promise { + + // No buffer here + return; + } + + public close(): void | Promise { + + this._ws.end(); + delete this._ws; + } +} + +const fd = new FileLogDriver("a.log"); + +Loggers.registerDriver( + "file-a", + fd +); + +const logs = Loggers.createTextLogger( + "Sample", + undefined, + "file-a" +); + +logs.unmute(); + +logs.info("HI"); + +logs.debug("Hello"); + +fd.close(); diff --git a/src/samples/data-logs.ts b/src/samples/data-logs.ts deleted file mode 100644 index 143991d..0000000 --- a/src/samples/data-logs.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2018 Angus.Fenying - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import Loggers from "../lib"; - -interface LogInfo { - - action: string; - - result: number; -} - -let log = Loggers.createDataLogger("data-logger", function( - data: LogInfo, - subject: string, - level: string, - date: Date, - trace -): string { - - // tslint:disable-next-line:max-line-length - return `${date.toISOString()} - ${level} - ${subject} - Executed action ${data.action}, with result ${data.result}.`; -}); - -Loggers.unmute(); - -log.debug({ - action: "SendMessage", - result: 1 -}); diff --git a/src/samples/text-logs.ts b/src/samples/text-logs.ts deleted file mode 100644 index b78af4f..0000000 --- a/src/samples/text-logs.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright 2018 Angus.Fenying - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import Loggers from "../lib"; - -const logs1 = Loggers.createTextLogger("app1"); -const logs2 = Loggers.createTextLogger("app2"); - -Loggers.unmute("debug"); - -const logs3 = Loggers.createTextLogger("app3"); - -logs1.debug("test 1"); -Loggers.enableTrace(true); -logs2.debug("test 2"); -Loggers.useFullTrace(true); -logs3.debug("test 3"); - -Loggers.mute("debug"); - -logs1.debug("test 4"); -logs2.debug("test 5"); -logs3.debug("test 6"); diff --git a/src/samples/using-driver.ts b/src/samples/using-driver.ts deleted file mode 100644 index 42ab6f8..0000000 --- a/src/samples/using-driver.ts +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright 2018 Angus.Fenying - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import Loggers from "../lib"; - -interface LogInfo { - - action: string; - - result: number; -} - -Loggers.registerDriver("driver-sample", { - write(text: string, subject: string, level: string, date: Date): void { - - // tslint:disable-next-line:no-console - console.log("Sample Driver:", text); - }, - close(): void { - return; - }, - flush(): void { - return; - } -}); - -let log = Loggers.createDataLogger("data-logger", function( - data: LogInfo, - subject: string, - level: string, - date: Date -): string { - - // tslint:disable-next-line:max-line-length - return `${date.toISOString()} - ${level} - ${subject} - Executed action ${data.action}, with result ${data.result}.`; - -}, "driver-sample"); - -Loggers.unmute(); - -log.debug({ - action: "SendMessage", - result: 1 -});