@holz/core 0.2.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.
- package/dist/holz-core.cjs +1 -1
- package/dist/holz-core.js +24 -40
- package/package.json +3 -3
- package/src/__tests__/logger.test.ts +8 -9
- package/src/__tests__/operators.test.ts +48 -0
- package/src/index.ts +1 -2
- package/src/logger.ts +4 -4
- package/src/operators.ts +28 -0
- package/src/types.ts +1 -1
- package/src/backends/test.ts +0 -5
- package/src/operators/__tests__/combine.test.ts +0 -29
- package/src/operators/__tests__/filter.test.ts +0 -21
- package/src/operators/combine.ts +0 -22
- package/src/operators/filter.ts +0 -28
package/dist/holz-core.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var t=(o=>(o.Error="error",o.Warn="warn",o.Info="info",o.Debug="debug",o))(t||{});function i(o){return r=>o.forEach(e=>e(r))}function a(o,r){return e=>{o(e)&&r(e)}}class n{constructor(r,e){this.processor=r,this.owner=e,Object.defineProperty(this,"processor",{configurable:!1,enumerable:!1})}static create(r){return new n(r,[])}namespace(r){return new n(this.processor,this.owner.concat(r))}debug(r,e){this.forwardLog(t.Debug,r,e)}info(r,e){this.forwardLog(t.Info,r,e)}warn(r,e){this.forwardLog(t.Warn,r,e)}error(r,e){this.forwardLog(t.Error,r,e)}forwardLog(r,e,s={}){this.processor({message:e,level:r,origin:this.owner,context:s})}}const c=n.create;exports.LogLevel=t;exports.combine=i;exports.createLogger=c;exports.filter=a;
|
package/dist/holz-core.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
var
|
|
1
|
+
var n = /* @__PURE__ */ ((e) => (e.Error = "error", e.Warn = "warn", e.Info = "info", e.Debug = "debug", e))(n || {});
|
|
2
|
+
function a(e) {
|
|
3
|
+
return (r) => e.forEach((o) => o(r));
|
|
4
|
+
}
|
|
5
|
+
function i(e, r) {
|
|
6
|
+
return (o) => {
|
|
7
|
+
e(o) && r(o);
|
|
8
|
+
};
|
|
9
|
+
}
|
|
2
10
|
class t {
|
|
3
11
|
constructor(r, o) {
|
|
4
|
-
this.processor = r, this.
|
|
12
|
+
this.processor = r, this.owner = o, Object.defineProperty(this, "processor", {
|
|
5
13
|
configurable: !1,
|
|
6
14
|
enumerable: !1
|
|
7
15
|
});
|
|
@@ -17,61 +25,37 @@ class t {
|
|
|
17
25
|
}
|
|
18
26
|
/** Extend the logger to attach a class or module name to logs. */
|
|
19
27
|
namespace(r) {
|
|
20
|
-
return new t(this.processor, this.
|
|
28
|
+
return new t(this.processor, this.owner.concat(r));
|
|
21
29
|
}
|
|
22
30
|
/** Log a frequent and verbose progress update. */
|
|
23
31
|
debug(r, o) {
|
|
24
|
-
this.forwardLog(
|
|
32
|
+
this.forwardLog(n.Debug, r, o);
|
|
25
33
|
}
|
|
26
34
|
/** Log a high-level progress update. */
|
|
27
35
|
info(r, o) {
|
|
28
|
-
this.forwardLog(
|
|
36
|
+
this.forwardLog(n.Info, r, o);
|
|
29
37
|
}
|
|
30
38
|
/** Log something concerning. */
|
|
31
39
|
warn(r, o) {
|
|
32
|
-
this.forwardLog(
|
|
40
|
+
this.forwardLog(n.Warn, r, o);
|
|
33
41
|
}
|
|
34
42
|
/** Log a critical failure. */
|
|
35
43
|
error(r, o) {
|
|
36
|
-
this.forwardLog(
|
|
44
|
+
this.forwardLog(n.Error, r, o);
|
|
37
45
|
}
|
|
38
|
-
forwardLog(r, o,
|
|
39
|
-
this.processor
|
|
46
|
+
forwardLog(r, o, s = {}) {
|
|
47
|
+
this.processor({
|
|
40
48
|
message: o,
|
|
41
49
|
level: r,
|
|
42
|
-
origin: this.
|
|
43
|
-
context:
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
const a = t.create;
|
|
48
|
-
class i {
|
|
49
|
-
constructor(r) {
|
|
50
|
-
this.processors = r;
|
|
51
|
-
}
|
|
52
|
-
processLog(r) {
|
|
53
|
-
this.processors.forEach((o) => {
|
|
54
|
-
o.processLog(r);
|
|
50
|
+
origin: this.owner,
|
|
51
|
+
context: s
|
|
55
52
|
});
|
|
56
53
|
}
|
|
57
54
|
}
|
|
58
|
-
|
|
59
|
-
return new i(s);
|
|
60
|
-
}
|
|
61
|
-
class n {
|
|
62
|
-
constructor(r, o) {
|
|
63
|
-
this.predicate = r, this.processor = o;
|
|
64
|
-
}
|
|
65
|
-
processLog(r) {
|
|
66
|
-
this.predicate(r) && this.processor.processLog(r);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
function h(s, r) {
|
|
70
|
-
return new n(s, r);
|
|
71
|
-
}
|
|
55
|
+
const c = t.create;
|
|
72
56
|
export {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
57
|
+
n as LogLevel,
|
|
58
|
+
a as combine,
|
|
59
|
+
c as createLogger,
|
|
60
|
+
i as filter
|
|
77
61
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holz/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "A structured and composable logger",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/holz-core.cjs",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"test:types": "tsc"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@vitest/coverage-c8": "0.28.5",
|
|
42
|
-
"typescript": "4.9.5",
|
|
41
|
+
"@vitest/coverage-c8": "^0.28.5",
|
|
42
|
+
"typescript": "^4.9.5",
|
|
43
43
|
"vite": "^4.0.0",
|
|
44
44
|
"vitest": "^0.28.5"
|
|
45
45
|
}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import TestBackend from '../backends/test';
|
|
2
1
|
import { createLogger } from '../logger';
|
|
3
2
|
import { LogLevel } from '../types';
|
|
4
3
|
|
|
5
4
|
describe('Logger', () => {
|
|
6
5
|
it('sends structured logs to the log processor', () => {
|
|
7
|
-
const backend =
|
|
6
|
+
const backend = vi.fn();
|
|
8
7
|
const logger = createLogger(backend);
|
|
9
8
|
|
|
10
9
|
logger.info('Hello world', { audience: 'testers' });
|
|
11
10
|
|
|
12
|
-
expect(backend
|
|
13
|
-
expect(backend
|
|
11
|
+
expect(backend).toHaveBeenCalledOnce();
|
|
12
|
+
expect(backend).toHaveBeenCalledWith({
|
|
14
13
|
message: 'Hello world',
|
|
15
14
|
level: 'info',
|
|
16
15
|
origin: [],
|
|
@@ -24,11 +23,11 @@ describe('Logger', () => {
|
|
|
24
23
|
[LogLevel.Warn, 'There are irregularities in the pension fund', {}],
|
|
25
24
|
[LogLevel.Error, 'Leadership has taken a dive', { windows: 'open' }],
|
|
26
25
|
])('correctly processes %s log messages', (level, message, context) => {
|
|
27
|
-
const backend =
|
|
26
|
+
const backend = vi.fn();
|
|
28
27
|
const logger = createLogger(backend);
|
|
29
28
|
|
|
30
29
|
logger[level](message, context);
|
|
31
|
-
expect(backend
|
|
30
|
+
expect(backend).toHaveBeenCalledWith({
|
|
32
31
|
message,
|
|
33
32
|
level,
|
|
34
33
|
context,
|
|
@@ -38,15 +37,15 @@ describe('Logger', () => {
|
|
|
38
37
|
|
|
39
38
|
describe('namespace', () => {
|
|
40
39
|
it('extends the origin of the logger', () => {
|
|
41
|
-
const backend =
|
|
40
|
+
const backend = vi.fn();
|
|
42
41
|
const logger = createLogger(backend)
|
|
43
42
|
.namespace('signaling')
|
|
44
43
|
.namespace('socket');
|
|
45
44
|
|
|
46
45
|
logger.info('opening socket');
|
|
47
46
|
|
|
48
|
-
expect(backend
|
|
49
|
-
expect(backend
|
|
47
|
+
expect(backend).toHaveBeenCalledOnce();
|
|
48
|
+
expect(backend).toHaveBeenCalledWith({
|
|
50
49
|
message: 'opening socket',
|
|
51
50
|
level: 'info',
|
|
52
51
|
origin: ['signaling', 'socket'],
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createLogger } from '../logger';
|
|
2
|
+
import { combine, filter } from '../operators';
|
|
3
|
+
import { LogLevel } from '../types';
|
|
4
|
+
|
|
5
|
+
describe('operators', () => {
|
|
6
|
+
describe('combine', () => {
|
|
7
|
+
it('combines several log processors backends into one', () => {
|
|
8
|
+
const b1 = vi.fn();
|
|
9
|
+
const b2 = vi.fn();
|
|
10
|
+
const backend = combine([b1, b2]);
|
|
11
|
+
const logger = createLogger(backend);
|
|
12
|
+
|
|
13
|
+
logger.info('tee message');
|
|
14
|
+
|
|
15
|
+
expect(b1).toHaveBeenCalledWith(
|
|
16
|
+
expect.objectContaining({ message: 'tee message' })
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
expect(b2).toHaveBeenCalledWith(
|
|
20
|
+
expect.objectContaining({ message: 'tee message' })
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('works even if you provide no logging backend', () => {
|
|
25
|
+
const backend = combine([]);
|
|
26
|
+
const logger = createLogger(backend);
|
|
27
|
+
|
|
28
|
+
expect(() => logger.info('no backend')).not.toThrow();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('filter', () => {
|
|
33
|
+
it('filters out logs that do not match the predicate', () => {
|
|
34
|
+
const backend = vi.fn();
|
|
35
|
+
const logger = createLogger(
|
|
36
|
+
filter((log) => log.level !== LogLevel.Debug, backend)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
logger.info('keep me');
|
|
40
|
+
logger.debug('discard');
|
|
41
|
+
|
|
42
|
+
expect(backend).toHaveBeenCalledOnce();
|
|
43
|
+
expect(backend).toHaveBeenCalledWith(
|
|
44
|
+
expect.objectContaining({ message: 'keep me' })
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export type { LogProcessor, LogContext, Log } from './types';
|
|
2
2
|
export { LogLevel } from './types';
|
|
3
|
+
export { combine, filter } from './operators';
|
|
3
4
|
export { createLogger } from './logger';
|
|
4
|
-
export { default as combine } from './operators/combine';
|
|
5
|
-
export { default as filter } from './operators/filter';
|
package/src/logger.ts
CHANGED
|
@@ -14,7 +14,7 @@ class Logger {
|
|
|
14
14
|
|
|
15
15
|
private constructor(
|
|
16
16
|
private processor: LogProcessor,
|
|
17
|
-
readonly
|
|
17
|
+
readonly owner: ReadonlyArray<string>
|
|
18
18
|
) {
|
|
19
19
|
// Non-enumerable to keep the repls clean.
|
|
20
20
|
Object.defineProperty(this, 'processor', {
|
|
@@ -25,7 +25,7 @@ class Logger {
|
|
|
25
25
|
|
|
26
26
|
/** Extend the logger to attach a class or module name to logs. */
|
|
27
27
|
namespace(owner: string): Logger {
|
|
28
|
-
return new Logger(this.processor, this.
|
|
28
|
+
return new Logger(this.processor, this.owner.concat(owner));
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/** Log a frequent and verbose progress update. */
|
|
@@ -53,10 +53,10 @@ class Logger {
|
|
|
53
53
|
message: string,
|
|
54
54
|
context: LogContext = {}
|
|
55
55
|
) {
|
|
56
|
-
this.processor
|
|
56
|
+
this.processor({
|
|
57
57
|
message,
|
|
58
58
|
level,
|
|
59
|
-
origin: this.
|
|
59
|
+
origin: this.owner,
|
|
60
60
|
context,
|
|
61
61
|
});
|
|
62
62
|
}
|
package/src/operators.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Log, LogProcessor } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Combine several log processors into a single log processor. Each one is
|
|
5
|
+
* called in sequence. Useful for sending a single log to multiple log
|
|
6
|
+
* destinations.
|
|
7
|
+
*/
|
|
8
|
+
export function combine(processors: Array<LogProcessor>): LogProcessor {
|
|
9
|
+
return (log: Log) => processors.forEach((processor) => processor(log));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Filter logs based on a filter function. If the function returns true, the
|
|
14
|
+
* log is kept and forwarded onto the next processor, otherwise it is
|
|
15
|
+
* discarded.
|
|
16
|
+
*/
|
|
17
|
+
export function filter(
|
|
18
|
+
/** Returns `true` to forward the log. */
|
|
19
|
+
predicate: (log: Log) => boolean,
|
|
20
|
+
/** Where to send the log if it passes the filter. */
|
|
21
|
+
processor: LogProcessor
|
|
22
|
+
): LogProcessor {
|
|
23
|
+
return (log: Log) => {
|
|
24
|
+
if (predicate(log)) {
|
|
25
|
+
processor(log);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
package/src/types.ts
CHANGED
package/src/backends/test.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import TestBackend from '../../backends/test';
|
|
2
|
-
import { createLogger } from '../../logger';
|
|
3
|
-
import combine from '../combine';
|
|
4
|
-
|
|
5
|
-
describe('combine operator', () => {
|
|
6
|
-
it('combines several log processors backends into one', () => {
|
|
7
|
-
const b1 = new TestBackend();
|
|
8
|
-
const b2 = new TestBackend();
|
|
9
|
-
const backend = combine([b1, b2]);
|
|
10
|
-
const logger = createLogger(backend);
|
|
11
|
-
|
|
12
|
-
logger.info('tee message');
|
|
13
|
-
|
|
14
|
-
expect(b1.processLog).toHaveBeenCalledWith(
|
|
15
|
-
expect.objectContaining({ message: 'tee message' })
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
expect(b2.processLog).toHaveBeenCalledWith(
|
|
19
|
-
expect.objectContaining({ message: 'tee message' })
|
|
20
|
-
);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('works even if you provide no logging backend', () => {
|
|
24
|
-
const backend = combine([]);
|
|
25
|
-
const logger = createLogger(backend);
|
|
26
|
-
|
|
27
|
-
expect(() => logger.info('no backend')).not.toThrow();
|
|
28
|
-
});
|
|
29
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import TestBackend from '../../backends/test';
|
|
2
|
-
import { createLogger } from '../../logger';
|
|
3
|
-
import { LogLevel } from '../../types';
|
|
4
|
-
import filter from '../filter';
|
|
5
|
-
|
|
6
|
-
describe('filter operator', () => {
|
|
7
|
-
it('filters out logs that do not match the predicate', () => {
|
|
8
|
-
const backend = new TestBackend();
|
|
9
|
-
const logger = createLogger(
|
|
10
|
-
filter((log) => log.level !== LogLevel.Debug, backend)
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
logger.info('keep me');
|
|
14
|
-
logger.debug('discard');
|
|
15
|
-
|
|
16
|
-
expect(backend.processLog).toHaveBeenCalledOnce();
|
|
17
|
-
expect(backend.processLog).toHaveBeenCalledWith(
|
|
18
|
-
expect.objectContaining({ message: 'keep me' })
|
|
19
|
-
);
|
|
20
|
-
});
|
|
21
|
-
});
|
package/src/operators/combine.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { Log, LogProcessor } from '../types';
|
|
2
|
-
|
|
3
|
-
class CombinedLogProcessor implements LogProcessor {
|
|
4
|
-
constructor(private processors: Array<LogProcessor>) {
|
|
5
|
-
// empty
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
processLog(log: Log) {
|
|
9
|
-
this.processors.forEach((processor) => {
|
|
10
|
-
processor.processLog(log);
|
|
11
|
-
});
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Combine several log processors into a single log processor. Each one is
|
|
17
|
-
* called in sequence. Useful for sending a single log to multiple log
|
|
18
|
-
* destinations.
|
|
19
|
-
*/
|
|
20
|
-
export default function combine(processors: Array<LogProcessor>): LogProcessor {
|
|
21
|
-
return new CombinedLogProcessor(processors);
|
|
22
|
-
}
|
package/src/operators/filter.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { Log, LogProcessor } from '../types';
|
|
2
|
-
|
|
3
|
-
class LogFilter implements LogProcessor {
|
|
4
|
-
constructor(
|
|
5
|
-
private predicate: (log: Log) => boolean,
|
|
6
|
-
private processor: LogProcessor
|
|
7
|
-
) {}
|
|
8
|
-
|
|
9
|
-
processLog(log: Log) {
|
|
10
|
-
if (this.predicate(log)) {
|
|
11
|
-
this.processor.processLog(log);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Filter logs based on a filter function. If the function returns true, the
|
|
18
|
-
* log is kept and forwarded onto the next processor, otherwise it is
|
|
19
|
-
* discarded.
|
|
20
|
-
*/
|
|
21
|
-
export default function filter(
|
|
22
|
-
/** Returns `true` to forward the log. */
|
|
23
|
-
predicate: (log: Log) => boolean,
|
|
24
|
-
/** Where to send the log if it passes the filter. */
|
|
25
|
-
processor: LogProcessor
|
|
26
|
-
): LogProcessor {
|
|
27
|
-
return new LogFilter(predicate, processor);
|
|
28
|
-
}
|