@holz/stream-backend 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("node:os"),r=require("@holz/core");function l({stream:t}){return e=>{const n=new Date().toISOString(),i=m[e.level],o=$(e.context),s=e.origin.length?`[${e.origin.join(":")}] `:"",c=`${n} ${i} ${s}`,a=L(c.length,e.message),u=`${c}${a}${o?" "+o:""}`;t.write(`${u}${g.EOL}`)}}function L(t,e){return e.replace(/(\r?\n)/g,n=>n+" ".repeat(t))}function $(t){return Object.entries(t).map(([e,n])=>`${e}=${JSON.stringify(n)}`).join(" ")}const m={[r.LogLevel.Debug]:"DEBUG",[r.LogLevel.Info]:"INFO ",[r.LogLevel.Warn]:"WARN ",[r.LogLevel.Error]:"ERROR"};exports.createStreamBackend=l;
|
|
@@ -1,27 +1,16 @@
|
|
|
1
|
-
import { EOL as
|
|
1
|
+
import { EOL as u } from "node:os";
|
|
2
2
|
import { LogLevel as r } from "@holz/core";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
// Some messages will ruin your output without proper indentation. Stack
|
|
16
|
-
// traces are a good example of this.
|
|
17
|
-
//
|
|
18
|
-
// Supports Unix + DOS line endings.
|
|
19
|
-
multilineIndent(t, e) {
|
|
20
|
-
return e.replace(
|
|
21
|
-
/(\r?\n)/g,
|
|
22
|
-
(n) => n + " ".repeat(t)
|
|
23
|
-
);
|
|
24
|
-
}
|
|
3
|
+
function l({ stream: t }) {
|
|
4
|
+
return (e) => {
|
|
5
|
+
const n = new Date().toISOString(), c = g[e.level], o = f(e.context), s = e.origin.length ? `[${e.origin.join(":")}] ` : "", i = `${n} ${c} ${s}`, a = $(i.length, e.message), m = `${i}${a}${o ? " " + o : ""}`;
|
|
6
|
+
t.write(`${m}${u}`);
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function $(t, e) {
|
|
10
|
+
return e.replace(/(\r?\n)/g, (n) => n + " ".repeat(t));
|
|
11
|
+
}
|
|
12
|
+
function f(t) {
|
|
13
|
+
return Object.entries(t).map(([e, n]) => `${e}=${JSON.stringify(n)}`).join(" ");
|
|
25
14
|
}
|
|
26
15
|
const g = {
|
|
27
16
|
[r.Debug]: "DEBUG",
|
|
@@ -30,6 +19,5 @@ const g = {
|
|
|
30
19
|
[r.Error]: "ERROR"
|
|
31
20
|
};
|
|
32
21
|
export {
|
|
33
|
-
|
|
34
|
-
p as default
|
|
22
|
+
l as createStreamBackend
|
|
35
23
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holz/stream-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Print logs to stdout or a file.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/holz-stream-backend.cjs",
|
|
@@ -39,13 +39,13 @@
|
|
|
39
39
|
"test:types": "tsc"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@holz/core": "0.
|
|
42
|
+
"@holz/core": "^0.5.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@holz/core": "0.
|
|
45
|
+
"@holz/core": "^0.5.0",
|
|
46
46
|
"@types/node": "^18.14.0",
|
|
47
|
-
"@vitest/coverage-c8": "0.28.5",
|
|
48
|
-
"typescript": "4.9.5",
|
|
47
|
+
"@vitest/coverage-c8": "^0.28.5",
|
|
48
|
+
"typescript": "^4.9.5",
|
|
49
49
|
"vite": "^4.0.0",
|
|
50
50
|
"vitest": "^0.28.5"
|
|
51
51
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Writable } from 'node:stream';
|
|
2
2
|
import { createLogger } from '@holz/core';
|
|
3
|
-
import
|
|
3
|
+
import { createStreamBackend } from '../stream-backend';
|
|
4
4
|
|
|
5
5
|
const CURRENT_TIME = new Date('2020-06-15T12:00:00.000Z');
|
|
6
6
|
|
|
@@ -32,7 +32,7 @@ describe('Stream backend', () => {
|
|
|
32
32
|
|
|
33
33
|
it('prints the logs to the writable stream', () => {
|
|
34
34
|
const { stream, getOutput } = createStream();
|
|
35
|
-
const backend =
|
|
35
|
+
const backend = createStreamBackend({ stream });
|
|
36
36
|
|
|
37
37
|
const logger = createLogger(backend);
|
|
38
38
|
logger.debug('shout');
|
|
@@ -51,7 +51,7 @@ describe('Stream backend', () => {
|
|
|
51
51
|
|
|
52
52
|
it('includes the log namespace', () => {
|
|
53
53
|
const { stream, getOutput } = createStream();
|
|
54
|
-
const backend =
|
|
54
|
+
const backend = createStreamBackend({ stream });
|
|
55
55
|
const logger = createLogger(backend)
|
|
56
56
|
.namespace('my-lib')
|
|
57
57
|
.namespace('MyClass');
|
|
@@ -63,7 +63,7 @@ describe('Stream backend', () => {
|
|
|
63
63
|
|
|
64
64
|
it('does not print the log namespace if it is empty', () => {
|
|
65
65
|
const { stream, getOutput } = createStream();
|
|
66
|
-
const backend =
|
|
66
|
+
const backend = createStreamBackend({ stream });
|
|
67
67
|
const logger = createLogger(backend);
|
|
68
68
|
|
|
69
69
|
logger.debug('orphan log');
|
|
@@ -73,7 +73,7 @@ describe('Stream backend', () => {
|
|
|
73
73
|
|
|
74
74
|
it('includes the log context', () => {
|
|
75
75
|
const { stream, getOutput } = createStream();
|
|
76
|
-
const backend =
|
|
76
|
+
const backend = createStreamBackend({ stream });
|
|
77
77
|
const logger = createLogger(backend);
|
|
78
78
|
|
|
79
79
|
logger.info('creating session', { sessionId: 3109, enabled: true });
|
|
@@ -84,7 +84,7 @@ describe('Stream backend', () => {
|
|
|
84
84
|
|
|
85
85
|
it('includes the timestamp for each log', () => {
|
|
86
86
|
const { stream, getOutput } = createStream();
|
|
87
|
-
const backend =
|
|
87
|
+
const backend = createStreamBackend({ stream });
|
|
88
88
|
const logger = createLogger(backend);
|
|
89
89
|
|
|
90
90
|
logger.info('traveling through time');
|
|
@@ -94,7 +94,7 @@ describe('Stream backend', () => {
|
|
|
94
94
|
|
|
95
95
|
it('wraps strings in log context with quotes', () => {
|
|
96
96
|
const { stream, getOutput } = createStream();
|
|
97
|
-
const backend =
|
|
97
|
+
const backend = createStreamBackend({ stream });
|
|
98
98
|
const logger = createLogger(backend);
|
|
99
99
|
|
|
100
100
|
logger.info('creating session', { code: 'ENOBACON' });
|
|
@@ -104,7 +104,7 @@ describe('Stream backend', () => {
|
|
|
104
104
|
|
|
105
105
|
it('joins arrays in log context', () => {
|
|
106
106
|
const { stream, getOutput } = createStream();
|
|
107
|
-
const backend =
|
|
107
|
+
const backend = createStreamBackend({ stream });
|
|
108
108
|
const logger = createLogger(backend);
|
|
109
109
|
|
|
110
110
|
logger.info('adding tags', { tags: ['important', 'urgent'] });
|
|
@@ -114,7 +114,7 @@ describe('Stream backend', () => {
|
|
|
114
114
|
|
|
115
115
|
it('indents multi-line log statements', () => {
|
|
116
116
|
const { stream, getOutput } = createStream();
|
|
117
|
-
const backend =
|
|
117
|
+
const backend = createStreamBackend({ stream });
|
|
118
118
|
const logger = createLogger(backend);
|
|
119
119
|
|
|
120
120
|
logger.info('multi-line log\r\nwith a second line\nand a third line');
|
package/src/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { createStreamBackend } from './stream-backend';
|
package/src/stream-backend.ts
CHANGED
|
@@ -7,26 +7,20 @@ import type { Log, LogContext, LogProcessor } from '@holz/core';
|
|
|
7
7
|
* Prints logs to a writable stream in plaintext. Optimized for log files.
|
|
8
8
|
*
|
|
9
9
|
* @example
|
|
10
|
-
*
|
|
10
|
+
* createStreamBackend({
|
|
11
11
|
* stream: fs.createWriteStream('my-app.log', { flags: 'a' }),
|
|
12
12
|
* })
|
|
13
13
|
*/
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
constructor(options: Config) {
|
|
18
|
-
this.stream = options.stream;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
processLog(log: Log) {
|
|
14
|
+
export function createStreamBackend({ stream }: Config): LogProcessor {
|
|
15
|
+
return (log: Log) => {
|
|
22
16
|
const currentTime = new Date().toISOString();
|
|
23
17
|
const level = LOG_LEVELS[log.level];
|
|
24
|
-
const context =
|
|
18
|
+
const context = stringifyContext(log.context);
|
|
25
19
|
const namespace = log.origin.length ? `[${log.origin.join(':')}] ` : '';
|
|
26
20
|
|
|
27
21
|
const header = `${currentTime} ${level} ${namespace}`;
|
|
28
|
-
const message =
|
|
29
|
-
const output = `${header}${message}${context ? ' ' + context : ''}
|
|
22
|
+
const message = multilineIndent(header.length, log.message);
|
|
23
|
+
const output = `${header}${message}${context ? ' ' + context : ''}`;
|
|
30
24
|
|
|
31
25
|
// NOTE: If the stream applies backpressure, we will lose logs. I believe
|
|
32
26
|
// this is the right tradeoff. We can't prevent the app from generating
|
|
@@ -34,26 +28,25 @@ export default class StreamBackend implements LogProcessor {
|
|
|
34
28
|
// crashing the process.
|
|
35
29
|
//
|
|
36
30
|
// It is unlikely that a file or tty will apply backpressure in practice.
|
|
37
|
-
|
|
38
|
-
}
|
|
31
|
+
stream.write(`${output}${EOL}`);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
39
34
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Some messages will ruin your output without proper indentation. Stack
|
|
37
|
+
* traces are a good example of this.
|
|
38
|
+
*
|
|
39
|
+
* Supports Unix + DOS line endings.
|
|
40
|
+
*/
|
|
41
|
+
function multilineIndent(offset: number, message: string) {
|
|
42
|
+
return message.replace(/(\r?\n)/g, (newline) => newline + ' '.repeat(offset));
|
|
43
|
+
}
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return message.replace(
|
|
53
|
-
/(\r?\n)/g,
|
|
54
|
-
(newline) => newline + ' '.repeat(offset)
|
|
55
|
-
);
|
|
56
|
-
}
|
|
45
|
+
// { id: 123, type: 'article' } -> 'id=123 type="article"'
|
|
46
|
+
function stringifyContext(context: LogContext) {
|
|
47
|
+
return Object.entries(context)
|
|
48
|
+
.map(([key, value]) => `${key}=${JSON.stringify(value)}`)
|
|
49
|
+
.join(' ');
|
|
57
50
|
}
|
|
58
51
|
|
|
59
52
|
const LOG_LEVELS: Record<LogLevel, string> = {
|