@3fv/logger-proxy 中文文档教程
# @3fv/logger-proxy
Overview
有这么多的日志库,事实上我觉得我正在创建相同的样板配置 不同的库取决于目标平台以及日志记录后端等。我最终决定实现一个简单的 旨在与其他框架一起使用的日志记录框架 & 记录器; 猎空
、摩根
、温斯顿
。
适用于浏览器
& <代码>节点 & deno
现在,这是编写包括上述日志框架在内的那些人的一个相当普遍的声明; 但是这个 真正意味着成为一个代理
& 这样一来,它就可以启用后端异步上下文堆栈之类的东西。 即默认配置去 到一个文件追加器,但你的工作也有一个额外的追加通过异步上下文(想想 ThreadLocal
in java
或 c++
中的 std::thread_local
)。
@3fv/logger-proxy
Install
yarn add @3fv/logger-proxy
Usage
Basic
import {
getLogger,
LevelNames, getLoggingManager
} from "@3fv/logger-proxy"
getLoggingManager().configure({
// Default appenders list is [ConsoleAppender],
// so the following is not needed and only
// remains as an example:
//
// appenders: [new ConsoleAppender()],
rootLevel: "trace"
})
const log = getLogger(__filename)
LevelNames.forEach((name) =>
log[name].call(log, `example %s`, name)
)
Context Stacks (the coolest bit)
hotswap logging backends 为了冗长以及我很懒惰的事实,这里有一个完整的单元测试来说明功能(在 jest
中)
import {
Appender,
getLoggingManager,
LogContext,
Logger,
getLogger
} from "@3fv/logger-proxy"
type Jest = typeof jest
type MockAppender = Appender & {
append: Appender["append"] & ReturnType<Jest["fn"]>
}
function newMockAppender(): MockAppender {
const fn = jest.fn((record: any) => {
console.log(`record`, record)
})
return {
append: fn
}
}
describe("NodeContextProvider", () => {
jest.setTimeout(10000)
const manager = getLoggingManager()
let baseAppender: MockAppender
let contextAppender1: MockAppender
let contextAppender2: MockAppender
let context1: LogContext
let context2: LogContext
let log1: Logger
let log2: Logger
beforeEach(() => {
baseAppender = newMockAppender()
contextAppender1 = newMockAppender()
contextAppender2 = newMockAppender()
context1 = LogContext.with([contextAppender1])
context2 = LogContext.with([contextAppender2])
manager.setAppenders(baseAppender).setRootLevel("debug")
log1 = getLogger("log1")
log2 = getLogger("log2")
})
it("works with no contexts", async () => {
log1.info("test1")
log2.info("test2")
expect(baseAppender.append).toBeCalledTimes(2)
})
it("works with no context provider", async () => {
log1.info("test1")
await context1.use(async () => {
log1.info("test2")
})
expect(baseAppender.append).toBeCalledTimes(2)
expect(contextAppender1.append).toBeCalledTimes(0)
})
it("works with 1 contexts", async () => {
// You must explicitly `install` the context provider to use contexts
await import("@3fv/logger-proxy/context/providers/node")
log1.info("test1")
await context1.use(async () => {
log1.info("test2")
})
expect(baseAppender.append).toBeCalledTimes(2)
expect(contextAppender1.append).toBeCalledTimes(1)
})
it("works with n contexts", async () => {
// You must explicitly `install` the context provider to use contexts
await import("@3fv/logger-proxy/context/providers/node")
log1.info("test1")
await context1.use(async () => {
log1.info("test2")
await context2.use(async () => {
log1.info("test3")
})
})
expect(baseAppender.append).toBeCalledTimes(3)
expect(contextAppender1.append).toBeCalledTimes(2)
expect(contextAppender2.append).toBeCalledTimes(1)
})
})
# @3fv/logger-proxy
Overview
With so many logging libraries out there, and the fact that I felt I was creating the same boilerplate configs with different libs depending on target platforms as well as logging backends, etc. I finally decided to implement a simple logging framework that's meant to be used with other frameworks & loggers; Tracer
, Morgan
, Winston
.
Works across browser
& node
& deno
Now, that is a fairly common statement from those that write logging frameworks including the aforementioned; but this is truly meant to be a proxy
& with that it enables things like backend async context stacks. i.e. default config goes to a file appender, but your job's also have an additional append via an async context (Think ThreadLocal
in the java
or std::thread_local
in c++
).
@3fv/logger-proxy
hotswap logging backends
Install
yarn add @3fv/logger-proxy
Usage
Basic
import {
getLogger,
LevelNames, getLoggingManager
} from "@3fv/logger-proxy"
getLoggingManager().configure({
// Default appenders list is [ConsoleAppender],
// so the following is not needed and only
// remains as an example:
//
// appenders: [new ConsoleAppender()],
rootLevel: "trace"
})
const log = getLogger(__filename)
LevelNames.forEach((name) =>
log[name].call(log, `example %s`, name)
)
Context Stacks (the coolest bit)
For verboseness as well as the fact I'm lazy, here's a complete unit test illustrating the capabilities (in jest
)
import {
Appender,
getLoggingManager,
LogContext,
Logger,
getLogger
} from "@3fv/logger-proxy"
type Jest = typeof jest
type MockAppender = Appender & {
append: Appender["append"] & ReturnType<Jest["fn"]>
}
function newMockAppender(): MockAppender {
const fn = jest.fn((record: any) => {
console.log(`record`, record)
})
return {
append: fn
}
}
describe("NodeContextProvider", () => {
jest.setTimeout(10000)
const manager = getLoggingManager()
let baseAppender: MockAppender
let contextAppender1: MockAppender
let contextAppender2: MockAppender
let context1: LogContext
let context2: LogContext
let log1: Logger
let log2: Logger
beforeEach(() => {
baseAppender = newMockAppender()
contextAppender1 = newMockAppender()
contextAppender2 = newMockAppender()
context1 = LogContext.with([contextAppender1])
context2 = LogContext.with([contextAppender2])
manager.setAppenders(baseAppender).setRootLevel("debug")
log1 = getLogger("log1")
log2 = getLogger("log2")
})
it("works with no contexts", async () => {
log1.info("test1")
log2.info("test2")
expect(baseAppender.append).toBeCalledTimes(2)
})
it("works with no context provider", async () => {
log1.info("test1")
await context1.use(async () => {
log1.info("test2")
})
expect(baseAppender.append).toBeCalledTimes(2)
expect(contextAppender1.append).toBeCalledTimes(0)
})
it("works with 1 contexts", async () => {
// You must explicitly `install` the context provider to use contexts
await import("@3fv/logger-proxy/context/providers/node")
log1.info("test1")
await context1.use(async () => {
log1.info("test2")
})
expect(baseAppender.append).toBeCalledTimes(2)
expect(contextAppender1.append).toBeCalledTimes(1)
})
it("works with n contexts", async () => {
// You must explicitly `install` the context provider to use contexts
await import("@3fv/logger-proxy/context/providers/node")
log1.info("test1")
await context1.use(async () => {
log1.info("test2")
await context2.use(async () => {
log1.info("test3")
})
})
expect(baseAppender.append).toBeCalledTimes(3)
expect(contextAppender1.append).toBeCalledTimes(2)
expect(contextAppender2.append).toBeCalledTimes(1)
})
})