roarr
Advanced tools
Comparing version 7.6.1 to 7.7.0
@@ -5,4 +5,6 @@ import { logLevels } from './constants'; | ||
declare const ROARR: RoarrGlobalState; | ||
declare const Roarr: import("./types").Logger; | ||
declare const Roarr: import("./types").Logger<{ | ||
[x: string]: import("./types").JsonValue<{}> | undefined; | ||
}>; | ||
export type { Logger, LogLevelName, Message, MessageEventHandler, RoarrGlobalState, TranslateMessageFunction, } from './types'; | ||
export { getLogLevelName, logLevels, Roarr, ROARR, }; |
import type { Logger, MessageEventHandler } from '../types'; | ||
export declare const createLogger: (onMessage: MessageEventHandler, parentContext?: import("../types").JsonObject | undefined) => Logger; | ||
export declare const createLogger: (onMessage: MessageEventHandler, parentContext?: { | ||
[x: string]: import("../types").JsonValue<{}> | undefined; | ||
} | undefined) => Logger; |
import type { Logger, MessageEventHandler } from '../types'; | ||
export declare const createMockLogger: (onMessage: MessageEventHandler, parentContext?: import("../types").JsonObject | undefined) => Logger; | ||
export declare const createMockLogger: (onMessage: MessageEventHandler, parentContext?: { | ||
[x: string]: import("../types").JsonValue<{}> | undefined; | ||
} | undefined) => Logger; |
@@ -5,4 +5,6 @@ import { logLevels } from './constants'; | ||
declare const ROARR: RoarrGlobalState; | ||
declare const Roarr: import("./types").Logger; | ||
declare const Roarr: import("./types").Logger<{ | ||
[x: string]: import("./types").JsonValue<{}> | undefined; | ||
}>; | ||
export type { Logger, LogLevelName, LogWriter, Message, MessageEventHandler, RoarrGlobalState, TranslateMessageFunction, } from './types'; | ||
export { getLogLevelName, logLevels, Roarr, ROARR, }; |
/// <reference types="node" /> | ||
import type { AsyncLocalStorage } from 'async_hooks'; | ||
export declare type JsonObject = { | ||
[Key in string]?: JsonValue; | ||
export declare type JsonObject<T = {}> = T & { | ||
[Key in string]?: JsonValue<T>; | ||
}; | ||
export declare type JsonValue = JsonObject | JsonValue[] | boolean | number | string | null; | ||
export declare type JsonValue<T> = Array<JsonValue<T>> | JsonObject<T> | boolean | number | string | null; | ||
export declare type LogWriter = (message: string) => void; | ||
export declare type MessageContext = JsonObject; | ||
export declare type MessageContext<T = {}> = JsonObject<T>; | ||
export declare type RoarrGlobalState = { | ||
@@ -16,4 +16,4 @@ asyncLocalStorage?: AsyncLocalStorage<MessageContext>; | ||
export declare type SprintfArgument = boolean | number | string | null; | ||
export declare type Message = { | ||
readonly context: MessageContext; | ||
export declare type Message<T = MessageContext> = { | ||
readonly context: T; | ||
readonly message: string; | ||
@@ -24,19 +24,24 @@ readonly sequence: string; | ||
}; | ||
export declare type TranslateMessageFunction = (message: Message) => Message; | ||
export declare type LogMethod = { | ||
(context: MessageContext, message: string, c?: SprintfArgument, d?: SprintfArgument, e?: SprintfArgument, f?: SprintfArgument, g?: SprintfArgument, h?: SprintfArgument, i?: SprintfArgument, j?: SprintfArgument): void; | ||
export declare type TranslateMessageFunction<T> = (message: Message<T>) => Message<MessageContext>; | ||
export declare type LogMethod<Z> = { | ||
(context: Z, message: string, c?: SprintfArgument, d?: SprintfArgument, e?: SprintfArgument, f?: SprintfArgument, g?: SprintfArgument, h?: SprintfArgument, i?: SprintfArgument, j?: SprintfArgument): void; | ||
(message: string, b?: SprintfArgument, c?: SprintfArgument, d?: SprintfArgument, e?: SprintfArgument, f?: SprintfArgument, g?: SprintfArgument, h?: SprintfArgument, i?: SprintfArgument, j?: SprintfArgument): void; | ||
}; | ||
export declare type Logger = LogMethod & { | ||
declare type Child<Z> = { | ||
<T = Z>(context: TranslateMessageFunction<MessageContext<T>>): Logger<T | Z>; | ||
(context: MessageContext): Logger<Z>; | ||
}; | ||
export declare type Logger<Z = MessageContext> = LogMethod<Z> & { | ||
adopt: <T>(routine: () => T, context?: MessageContext) => Promise<T>; | ||
child: (context: MessageContext | TranslateMessageFunction) => Logger; | ||
debug: LogMethod; | ||
error: LogMethod; | ||
fatal: LogMethod; | ||
child: Child<Z>; | ||
debug: LogMethod<Z>; | ||
error: LogMethod<Z>; | ||
fatal: LogMethod<Z>; | ||
getContext: () => MessageContext; | ||
info: LogMethod; | ||
trace: LogMethod; | ||
warn: LogMethod; | ||
info: LogMethod<Z>; | ||
trace: LogMethod<Z>; | ||
warn: LogMethod<Z>; | ||
}; | ||
export declare type MessageEventHandler = (message: Message) => void; | ||
export declare type MessageEventHandler = (message: Message<MessageContext>) => void; | ||
export declare type LogLevelName = 'trace' | 'debug' | 'info' | 'error' | 'fatal' | 'warn'; | ||
export {}; |
@@ -184,3 +184,3 @@ "use strict"; | ||
}); | ||
(0, ava_1.default)('prepends context to the message context (is overriden)', (t) => { | ||
(0, ava_1.default)('prepends context to the message context (is overridden)', (t) => { | ||
const log = createLoggerWithHistory(); | ||
@@ -250,2 +250,73 @@ log.child({ foo: 'bar 0' })({ foo: 'bar 1' }, 'quux'); | ||
}); | ||
(0, ava_1.default)('serializes context using a transformer', (t) => { | ||
const log = createLoggerWithHistory(); | ||
const log1 = log.child((message) => { | ||
if (!message.context.error1) { | ||
return message; | ||
} | ||
return { | ||
...message, | ||
context: { | ||
...message.context, | ||
error1: 'log1 error', | ||
}, | ||
}; | ||
}); | ||
log1.error({ | ||
error1: new Error('foo'), | ||
}, 'log1'); | ||
// @ts-expect-error error2 is not allowed | ||
log1.error({ | ||
error2: new Error('foo'), | ||
}, 'log1'); | ||
const log2 = log1.child((message) => { | ||
return { | ||
...message, | ||
context: { | ||
...message.context, | ||
error2: 'log2 error', | ||
}, | ||
}; | ||
}); | ||
log2.error({ | ||
error1: new Error('foo'), | ||
error2: new Error('foo'), | ||
}, 'log2'); | ||
// @ts-expect-error error2 is not allowed | ||
log2.error({ | ||
error3: new Error('foo'), | ||
}, 'log2'); | ||
t.like(log.messages[0], { | ||
context: { | ||
error1: 'log1 error', | ||
}, | ||
message: 'log1', | ||
}); | ||
t.like(log.messages[1], { | ||
context: { | ||
error2: new Error('foo'), | ||
}, | ||
message: 'log1', | ||
}); | ||
t.like(log.messages[2], { | ||
context: { | ||
error1: 'log1 error', | ||
error2: 'log2 error', | ||
}, | ||
message: 'log2', | ||
}); | ||
t.like(log.messages[3], { | ||
context: { | ||
error3: new Error('foo'), | ||
}, | ||
message: 'log2', | ||
}); | ||
}); | ||
(0, ava_1.default)('does not allow to extend context without a transformer', (t) => { | ||
const log = createLoggerWithHistory(); | ||
// @ts-expect-error cannot type child without a translator | ||
log.child({}); | ||
log.child({}); | ||
t.true(true); | ||
}); | ||
(0, ava_1.default)('throws an error if child does not return an object', (t) => { | ||
@@ -255,3 +326,4 @@ const log = createLoggerWithHistory(); | ||
log | ||
.child((message) => { | ||
// @ts-expect-error result must be an object | ||
.child(() => { | ||
return ''; | ||
@@ -258,0 +330,0 @@ })('foo'); |
@@ -76,3 +76,3 @@ { | ||
"typings": "./dist/src/Roarr.d.ts", | ||
"version": "7.6.1" | ||
"version": "7.7.0" | ||
} |
128
README.md
@@ -62,3 +62,3 @@ <a name="roarr"></a> | ||
* Does not block the event cycle (=fast). | ||
* Does not require initialisation. | ||
* Does not require initialization. | ||
* Produces structured data. | ||
@@ -91,3 +91,3 @@ * [Decouples transports](#transports). | ||
```js | ||
```ts | ||
import { | ||
@@ -98,3 +98,2 @@ Roarr as log, | ||
log('foo'); | ||
``` | ||
@@ -114,3 +113,2 @@ | ||
ROARR_LOG=true node ./index.js | ||
``` | ||
@@ -125,3 +123,3 @@ | ||
```js | ||
```ts | ||
import { | ||
@@ -132,3 +130,2 @@ ROARR, | ||
ROARR.write = () => {}; | ||
``` | ||
@@ -138,5 +135,4 @@ | ||
```js | ||
```ts | ||
(message: string) => void; | ||
``` | ||
@@ -146,3 +142,3 @@ | ||
```js | ||
```ts | ||
import { | ||
@@ -155,3 +151,2 @@ ROARR, | ||
}; | ||
``` | ||
@@ -161,3 +156,3 @@ | ||
```js | ||
```ts | ||
// Ensure that `globalThis.ROARR` is configured. | ||
@@ -169,3 +164,2 @@ const ROARR = globalThis.ROARR = globalThis.ROARR || {}; | ||
}; | ||
``` | ||
@@ -185,11 +179,8 @@ | ||
Use [`roarr filter` CLI program](#filter-program) to filter the logs that are written to stdout by the program, e.g. | ||
Use [`@roarr/cli` program](https://github.com/gajus/roarr-cli#filtering-logs) to filter logs, e.g. | ||
```bash | ||
ROARR_LOG=true node ./index.js | roarr filter '{"context.logLevel":{gt:30}}' | ||
ROARR_LOG=true node ./index.js | roarr --filter 'context.logLevel:>30' | ||
``` | ||
Alternatively, use a JSON processor such as [jq](https://stedolan.github.io/jq/) | ||
<a name="roarr-usage-filtering-logs-browser-1"></a> | ||
@@ -200,3 +191,3 @@ #### Browser | ||
```js | ||
```ts | ||
globalThis.ROARR.write = (message) => { | ||
@@ -244,3 +235,3 @@ const payload = JSON.parse(message); | ||
```js | ||
```ts | ||
export type Logger = | ||
@@ -271,3 +262,2 @@ ( | ||
) => void; | ||
``` | ||
@@ -288,5 +278,4 @@ | ||
```js | ||
```ts | ||
<T>(routine: () => Promise<T>, context: MessageContext) => Promise<T>, | ||
``` | ||
@@ -298,3 +287,3 @@ | ||
```js | ||
```ts | ||
log.adopt( | ||
@@ -329,3 +318,3 @@ () => { | ||
``` | ||
```xml | ||
<top-level sequential invocation ID>[.<async operation sequential invocation ID>] | ||
@@ -336,3 +325,3 @@ ``` | ||
```js | ||
```ts | ||
log.adopt(() => { | ||
@@ -371,7 +360,2 @@ log('foo 0'); | ||
```js | ||
(context: TranslateMessageFunction | MessageContext) => Logger, | ||
``` | ||
The `child` function has two signatures: | ||
@@ -385,12 +369,11 @@ | ||
```js | ||
(context: MessageContext) => Logger; | ||
```ts | ||
(context: MessageContext): Logger, | ||
``` | ||
Creates a child logger appending the provided `context` object to the previous logger context. | ||
Creates a child logger that appends child `context` to every subsequent message. | ||
Example: | ||
```js | ||
```ts | ||
import { | ||
@@ -400,3 +383,3 @@ Roarr as log, | ||
const childLog = log.child({ | ||
const barLog = log.child({ | ||
foo: 'bar' | ||
@@ -406,3 +389,4 @@ }); | ||
log.debug('foo 1'); | ||
childLog.debug('foo 2'); | ||
barLog.debug('foo 2'); | ||
``` | ||
@@ -415,17 +399,14 @@ | ||
Refer to [middlewares](#middlewares) documentation for use case examples. | ||
<a name="roarr-api-child-function-parameter"></a> | ||
#### Function parameter | ||
```js | ||
(translateMessage: TranslateMessageFunction) => Logger; | ||
```ts | ||
<T>(context: TranslateMessageFunction<MessageContext<T>>): Logger<T> | ||
``` | ||
Creates a child logger where every message is intercepted. | ||
Creates a child logger that translates every subsequent message. | ||
Example: | ||
```js | ||
```ts | ||
import { | ||
@@ -435,11 +416,21 @@ Roarr as log, | ||
const childLog = log.child((message) => { | ||
const barLog = log.child<{error: Error}>((message) => { | ||
return { | ||
...message, | ||
message: message.message.replace('foo', 'bar'), | ||
} | ||
context: { | ||
...message.context, | ||
...message.context.error && { | ||
error: { | ||
message: message.context.error.message, | ||
}, | ||
}, | ||
}, | ||
}; | ||
}); | ||
log.debug('foo 1'); | ||
childLog.debug('foo 2'); | ||
barLog.debug({ | ||
error: new Error('bar'), | ||
}, 'foo 2'); | ||
``` | ||
@@ -449,5 +440,7 @@ | ||
{"context":{"logLevel":20},"message":"foo 1","sequence":"0","time":1506776210000,"version":"2.0.0"} | ||
{"context":{"logLevel":20},"message":"bar 2","sequence":"1","time":1506776210000,"version":"2.0.0"} | ||
{"context":{"logLevel":20,"error":{"message":"bar"}},"message":"bar 2","sequence":"1","time":1506776210000,"version":"2.0.0"} | ||
``` | ||
A typical use case for this pattern is serialization (e.g. of HTTP request, response or error object) and redaction of sensitive data from logs. | ||
<a name="roarr-api-getcontext"></a> | ||
@@ -460,3 +453,3 @@ ### <code>getContext</code> | ||
```js | ||
```ts | ||
import { | ||
@@ -473,3 +466,2 @@ Roarr as log, | ||
// {foo: 'bar'} | ||
``` | ||
@@ -492,3 +484,3 @@ | ||
```js | ||
```ts | ||
import { | ||
@@ -504,3 +496,2 @@ Roarr as log, | ||
log.fatal('foo'); | ||
``` | ||
@@ -510,3 +501,3 @@ | ||
``` | ||
```json | ||
{"context":{"logLevel":10},"message":"foo","sequence":"0","time":1506776210000,"version":"2.0.0"} | ||
@@ -518,3 +509,2 @@ {"context":{"logLevel":20},"message":"foo","sequence":"1","time":1506776210000,"version":"2.0.0"} | ||
{"context":{"logLevel":60},"message":"foo","sequence":"5","time":1506776210000,"version":"2.0.0"} | ||
``` | ||
@@ -534,3 +524,3 @@ | ||
```js | ||
```ts | ||
import { | ||
@@ -550,3 +540,3 @@ getLogLevelName, | ||
```js | ||
```ts | ||
import { | ||
@@ -570,3 +560,3 @@ Roarr as log, | ||
Roarr middlwares enable translation of every bit of information that is used to construct a log message. | ||
Roarr middlewares enable translation of every bit of information that is used to construct a log message. | ||
@@ -590,3 +580,2 @@ The following are the official middlewares: | ||
npm install @roarr/cli -g | ||
``` | ||
@@ -599,3 +588,3 @@ | ||
A transport in most logging libraries is something that runs in-process to perform some operation with the finalised log line. For example, a transport might send the log line to a standard syslog server after processing the log line and reformatting it. | ||
A transport in most logging libraries is something that runs in-process to perform some operation with the finalized log line. For example, a transport might send the log line to a standard syslog server after processing the log line and reformatting it. | ||
@@ -662,3 +651,3 @@ Roarr does not support in-process transports. | ||
```js | ||
```ts | ||
/** | ||
@@ -669,6 +658,6 @@ * @file Example contents of a Logger.js file. | ||
import { | ||
Roarr as log, | ||
Roarr, | ||
} from 'roarr'; | ||
const Logger = log.child({ | ||
export const Logger = Roarr.child({ | ||
// .foo property is going to appear only in the logs that are created using | ||
@@ -678,5 +667,2 @@ // the current instance of a Roarr logger. | ||
}); | ||
export default Logger; | ||
``` | ||
@@ -698,3 +684,3 @@ | ||
```js | ||
```ts | ||
import { | ||
@@ -718,6 +704,5 @@ Roarr as log, | ||
}); | ||
``` | ||
Without using serialisation, your errors will be logged without the error name and stack trace. | ||
Without using serialization, your errors will be logged without the error name and stack trace. | ||
@@ -793,3 +778,2 @@ <a name="roarr-anti-patterns"></a> | ||
} | ||
``` | ||
@@ -802,3 +786,3 @@ | ||
```js | ||
```ts | ||
{ | ||
@@ -816,3 +800,2 @@ patterns: { | ||
} | ||
``` | ||
@@ -835,3 +818,2 @@ | ||
Use [`roarr-cli`](https://github.com/gajus/roarr-cli) program to pretty-print the logs. | ||
``` | ||
@@ -838,0 +820,0 @@ |
80146
1627
781