@holz/core 0.5.0 → 0.7.0-rc.1
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/README.md +115 -0
- package/dist/holz-core.cjs +1 -1
- package/dist/holz-core.d.ts +98 -0
- package/dist/holz-core.js +39 -40
- package/package.json +10 -9
- package/src/__tests__/logger.test.ts +13 -0
- package/src/__tests__/operators.test.ts +4 -4
- package/src/index.ts +1 -1
- package/src/logger.ts +29 -26
- package/src/operators.ts +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# `@holz/core`
|
|
2
|
+
|
|
3
|
+
`@holz/core` is a flexible and extensible logging library for TypeScript applications. It provides a simple but powerful interface for logging progress updates and errors with varying levels of severity.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
Here is an example of how to create a logger and use it to log a message:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { createLogger } from '@holz/core';
|
|
11
|
+
|
|
12
|
+
const logger = createLogger((log) => {
|
|
13
|
+
console.log(`[${log.level}]`, log.message);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
logger.info('Hello, world!');
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This will log a message with the info level to the console.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
[info] Hello, world!
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Logger Interface
|
|
26
|
+
|
|
27
|
+
The `Logger` class is the core of the library. It provides a set of methods for logging messages with different levels of severity. Each method takes a message and an optional context object.
|
|
28
|
+
|
|
29
|
+
You can also use the `namespace` method to create a new logger with a specific owner, such as a class or module. This makes it easier to identify the origin of log messages.
|
|
30
|
+
|
|
31
|
+
## Log Levels
|
|
32
|
+
|
|
33
|
+
The library provides four log levels:
|
|
34
|
+
|
|
35
|
+
- `LogLevel.Debug`: Extremely verbose progress updates (usually hidden).
|
|
36
|
+
- `LogLevel.Info`: High-level progress updates.
|
|
37
|
+
- `LogLevel.Warn`: Something is concerning, but we can keep going.
|
|
38
|
+
- `LogLevel.Error`: Something critical failed and we can't continue.
|
|
39
|
+
|
|
40
|
+
You can use these levels to indicate the severity of a log message. The severity levels can be configured to perform actions based on the level of severity of the log messages.
|
|
41
|
+
|
|
42
|
+
## Log Structure
|
|
43
|
+
|
|
44
|
+
Every log message processed by Holz follows a specific structure defined by the `Log` interface. Understanding this structure is crucial for effective logging and log processing.
|
|
45
|
+
|
|
46
|
+
A `Log` object contains the following properties:
|
|
47
|
+
|
|
48
|
+
- `message`: The verbatim log message. This property should not contain any interpolated data.
|
|
49
|
+
- `level`: The severity of the log message, expressed as a member of the `LogLevel` enum. The available log levels are, in increasing order of severity: `Debug`, `Info`, `Warn`, `Error`.
|
|
50
|
+
- `origin`: The source of the log message. This property is an array of strings that typically identifies the library, module, or component that generated the log message, followed by more specific information. This property can be used to filter and group log messages based on their origin.
|
|
51
|
+
- `context`: A dictionary of key-value pairs that provides additional context for the log message. The values in this object must be JSON serializable. Because it's easy to accidentally include unsuitable log context, such as PII or deeply nested objects, the use of nested objects in the context is discouraged.
|
|
52
|
+
|
|
53
|
+
Here is an example of a log message expressed as a `Log` object:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
{
|
|
57
|
+
message: 'Connection to database established.',
|
|
58
|
+
level: LogLevel.Info,
|
|
59
|
+
origin: ['my-app', 'database-connection'],
|
|
60
|
+
context: {
|
|
61
|
+
host: 'localhost',
|
|
62
|
+
port: 5432,
|
|
63
|
+
user: 'postgres',
|
|
64
|
+
database: 'my_database',
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
In this example, the log message describes a successful connection to a database, with additional context about the database host, port, user, and name.
|
|
70
|
+
|
|
71
|
+
## Log Processors
|
|
72
|
+
|
|
73
|
+
In Holz, a `LogProcessor` function is responsible for processing log messages. The `createLogger` function takes this function as an argument. A `LogProcessor` is a plain function that takes a `Log` object, which contains the message, level, origin, and context of the log.
|
|
74
|
+
|
|
75
|
+
Holz provides a set of off-the-shelf plugins for logging to various destinations, filtering, formatting, and more. You can also write your own plugins to suit your specific needs. These plugins can be combined into a `LogProcessor` function using the utility function `combine()`, allowing you to send a single log to multiple destinations.
|
|
76
|
+
|
|
77
|
+
Holz's plugin system is designed to be flexible and extensible. If none of the provided plugins meet your needs, you can easily create your own plugin and still build on plugins from the rest of the ecosystem. Check out the [`@holz/logger`](https://github.com/PsychoLlama/holz/tree/main/packages/holz-logger) package for a bundled example of Holz's logging plugins.
|
|
78
|
+
|
|
79
|
+
## Utilities
|
|
80
|
+
|
|
81
|
+
In addition to the core `Logger` class, `@holz/core` provides some utility processors that you can use to extend the functionality of your logging solution. These processors are optional and can be combined with each other or with third-party processors as needed.
|
|
82
|
+
|
|
83
|
+
### `combine`
|
|
84
|
+
|
|
85
|
+
The `combine` processor takes an array of log processors and returns a single log processor that forwards each log to all of the input processors. This is useful when you want to send a single log to multiple log destinations.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { combine } from '@holz/core';
|
|
89
|
+
import {
|
|
90
|
+
consoleBackend,
|
|
91
|
+
fileBackend,
|
|
92
|
+
logUploadService,
|
|
93
|
+
} from './custom-processors';
|
|
94
|
+
|
|
95
|
+
const logger = createLogger(
|
|
96
|
+
combine([consoleBackend, fileBackend, logUploadService])
|
|
97
|
+
);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `filter`
|
|
101
|
+
|
|
102
|
+
The `filter` processor takes a filter function and another log processor as input. If the filter function returns `true` for a log, it is forwarded to the second processor. If the filter function returns `false`, the log is discarded. This is useful when you want to selectively forward logs based on some criteria.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { filter } from '@holz/core';
|
|
106
|
+
|
|
107
|
+
const debugLogFilter = filter(
|
|
108
|
+
(log) => log.level !== LogLevel.Debug,
|
|
109
|
+
consoleProcessor
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const logger = createLogger(debugLogFilter);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Note that you can chain multiple filter processors together to create more complex filters.
|
package/dist/holz-core.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
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
|
|
1
|
+
"use strict";var a=Object.defineProperty;var c=(o,r,e)=>r in o?a(o,r,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[r]=e;var i=(o,r,e)=>c(o,typeof r!="symbol"?r+"":r,e);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 f(o){return r=>o.forEach(e=>e(r))}function u(o,r){return e=>{o(e)&&r(e)}}class s{constructor(r,e){i(this,"debug",(r,e)=>{this.forwardLog(t.Debug,r,e)});i(this,"info",(r,e)=>{this.forwardLog(t.Info,r,e)});i(this,"warn",(r,e)=>{this.forwardLog(t.Warn,r,e)});i(this,"error",(r,e)=>{this.forwardLog(t.Error,r,e)});this.processor=r,this.owner=e;const n={configurable:!1,enumerable:!1};Object.defineProperties(this,{processor:n,debug:n,info:n,warn:n,error:n})}namespace(r){return new s(this.processor,this.owner.concat(r))}forwardLog(r,e,n={}){this.processor({message:e,level:r,origin:this.owner,context:n})}}const g=o=>new s(o,[]);exports.LogLevel=t;exports.combine=f;exports.createLogger=g;exports.filter=u;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Combine several log processors into a single log processor. Each one is
|
|
3
|
+
* called in sequence. Useful for sending a single log to multiple log
|
|
4
|
+
* destinations.
|
|
5
|
+
*/
|
|
6
|
+
export declare function combine(processors: Array<LogProcessor>): LogProcessor;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Create a new logger. The processor is up to you. There are plugins for
|
|
10
|
+
* filtering, formatting, combining multiple processors together, and more.
|
|
11
|
+
*
|
|
12
|
+
* If you wish to use more than one processor, `combine(...)` them first.
|
|
13
|
+
*/
|
|
14
|
+
export declare const createLogger: (processor: LogProcessor) => Logger;
|
|
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 declare 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): LogProcessor;
|
|
26
|
+
|
|
27
|
+
declare type JsonPrimitive = string | number | boolean | null | undefined;
|
|
28
|
+
|
|
29
|
+
/** A log message where variables are carried as structured data. */
|
|
30
|
+
export declare interface Log {
|
|
31
|
+
/** The verbatim log message. Should not contain interpolated data. */
|
|
32
|
+
readonly message: string;
|
|
33
|
+
/** Log severity. */
|
|
34
|
+
readonly level: LogLevel;
|
|
35
|
+
/**
|
|
36
|
+
* Where the log message originated. Usually starts with a library or app name,
|
|
37
|
+
* followed by something more specific.
|
|
38
|
+
*
|
|
39
|
+
* @example ['logger-library', 'ConsoleBackend']
|
|
40
|
+
*/
|
|
41
|
+
readonly origin: ReadonlyArray<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Key-value pairs that provide additional context for the log message. If
|
|
44
|
+
* you're tempted to interpolate data into the message, consider using log
|
|
45
|
+
* context instead.
|
|
46
|
+
*
|
|
47
|
+
* These values must be JSON serializable.
|
|
48
|
+
*
|
|
49
|
+
* Because it's easy to accidentally include unsuitable log context (e.g.
|
|
50
|
+
* redux state, PII) nested objects are not allowed. The restriction doesn't
|
|
51
|
+
* make it impossible, but it makes it harder to miss during code review.
|
|
52
|
+
*
|
|
53
|
+
* @example { userId: 123, reason: 'disconnect' }
|
|
54
|
+
*/
|
|
55
|
+
readonly context: LogContext;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export declare type LogContext = Record<string, JsonPrimitive | ReadonlyArray<JsonPrimitive>>;
|
|
59
|
+
|
|
60
|
+
export declare class Logger {
|
|
61
|
+
private processor;
|
|
62
|
+
readonly owner: ReadonlyArray<string>;
|
|
63
|
+
constructor(processor: LogProcessor, owner: ReadonlyArray<string>);
|
|
64
|
+
/** Extend the logger to attach a class or module name to logs. */
|
|
65
|
+
namespace(owner: string): Logger;
|
|
66
|
+
/** Log a frequent and verbose progress update. */
|
|
67
|
+
debug: (message: string, context?: LogContext) => void;
|
|
68
|
+
/** Log a high-level progress update. */
|
|
69
|
+
info: (message: string, context?: LogContext) => void;
|
|
70
|
+
/** Log something concerning. */
|
|
71
|
+
warn: (message: string, context?: LogContext) => void;
|
|
72
|
+
/** Log a critical failure. */
|
|
73
|
+
error: (message: string, context?: LogContext) => void;
|
|
74
|
+
private forwardLog;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export declare enum LogLevel {
|
|
78
|
+
/** Something critical failed and we can't continue. */
|
|
79
|
+
Error = "error",
|
|
80
|
+
/** Something is concerning, but we can keep going. */
|
|
81
|
+
Warn = "warn",
|
|
82
|
+
/** High-level progress updates. */
|
|
83
|
+
Info = "info",
|
|
84
|
+
/** Extremely verbose progress updates (usually hidden). */
|
|
85
|
+
Debug = "debug"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* A logger is made up of log processors. These processors take structured
|
|
90
|
+
* logs and do something with them. Examples are logging backends (console,
|
|
91
|
+
* file, uploads) and operators (filtering, transforming, aggregating).
|
|
92
|
+
*/
|
|
93
|
+
export declare interface LogProcessor {
|
|
94
|
+
/** Do something with a log message. */
|
|
95
|
+
(log: Log): void;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export { }
|
package/dist/holz-core.js
CHANGED
|
@@ -1,61 +1,60 @@
|
|
|
1
|
-
var
|
|
2
|
-
|
|
1
|
+
var a = Object.defineProperty;
|
|
2
|
+
var c = (e, r, o) => r in e ? a(e, r, { enumerable: !0, configurable: !0, writable: !0, value: o }) : e[r] = o;
|
|
3
|
+
var s = (e, r, o) => c(e, typeof r != "symbol" ? r + "" : r, o);
|
|
4
|
+
var t = /* @__PURE__ */ ((e) => (e.Error = "error", e.Warn = "warn", e.Info = "info", e.Debug = "debug", e))(t || {});
|
|
5
|
+
function u(e) {
|
|
3
6
|
return (r) => e.forEach((o) => o(r));
|
|
4
7
|
}
|
|
5
|
-
function
|
|
8
|
+
function h(e, r) {
|
|
6
9
|
return (o) => {
|
|
7
10
|
e(o) && r(o);
|
|
8
11
|
};
|
|
9
12
|
}
|
|
10
|
-
class
|
|
13
|
+
class i {
|
|
11
14
|
constructor(r, o) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
/** Log a frequent and verbose progress update. */
|
|
16
|
+
s(this, "debug", (r, o) => {
|
|
17
|
+
this.forwardLog(t.Debug, r, o);
|
|
18
|
+
});
|
|
19
|
+
/** Log a high-level progress update. */
|
|
20
|
+
s(this, "info", (r, o) => {
|
|
21
|
+
this.forwardLog(t.Info, r, o);
|
|
22
|
+
});
|
|
23
|
+
/** Log something concerning. */
|
|
24
|
+
s(this, "warn", (r, o) => {
|
|
25
|
+
this.forwardLog(t.Warn, r, o);
|
|
26
|
+
});
|
|
27
|
+
/** Log a critical failure. */
|
|
28
|
+
s(this, "error", (r, o) => {
|
|
29
|
+
this.forwardLog(t.Error, r, o);
|
|
30
|
+
});
|
|
31
|
+
this.processor = r, this.owner = o;
|
|
32
|
+
const n = { configurable: !1, enumerable: !1 };
|
|
33
|
+
Object.defineProperties(this, {
|
|
34
|
+
processor: n,
|
|
35
|
+
debug: n,
|
|
36
|
+
info: n,
|
|
37
|
+
warn: n,
|
|
38
|
+
error: n
|
|
15
39
|
});
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Create a new logger. The processor is up to you. There are plugins for
|
|
19
|
-
* filtering, formatting, combining multiple processors together, and more.
|
|
20
|
-
*
|
|
21
|
-
* If you wish to use more than one processor, `combine(...)` them first.
|
|
22
|
-
*/
|
|
23
|
-
static create(r) {
|
|
24
|
-
return new t(r, []);
|
|
25
40
|
}
|
|
26
41
|
/** Extend the logger to attach a class or module name to logs. */
|
|
27
42
|
namespace(r) {
|
|
28
|
-
return new
|
|
29
|
-
}
|
|
30
|
-
/** Log a frequent and verbose progress update. */
|
|
31
|
-
debug(r, o) {
|
|
32
|
-
this.forwardLog(n.Debug, r, o);
|
|
33
|
-
}
|
|
34
|
-
/** Log a high-level progress update. */
|
|
35
|
-
info(r, o) {
|
|
36
|
-
this.forwardLog(n.Info, r, o);
|
|
37
|
-
}
|
|
38
|
-
/** Log something concerning. */
|
|
39
|
-
warn(r, o) {
|
|
40
|
-
this.forwardLog(n.Warn, r, o);
|
|
41
|
-
}
|
|
42
|
-
/** Log a critical failure. */
|
|
43
|
-
error(r, o) {
|
|
44
|
-
this.forwardLog(n.Error, r, o);
|
|
43
|
+
return new i(this.processor, this.owner.concat(r));
|
|
45
44
|
}
|
|
46
|
-
forwardLog(r, o,
|
|
45
|
+
forwardLog(r, o, n = {}) {
|
|
47
46
|
this.processor({
|
|
48
47
|
message: o,
|
|
49
48
|
level: r,
|
|
50
49
|
origin: this.owner,
|
|
51
|
-
context:
|
|
50
|
+
context: n
|
|
52
51
|
});
|
|
53
52
|
}
|
|
54
53
|
}
|
|
55
|
-
const
|
|
54
|
+
const w = (e) => new i(e, []);
|
|
56
55
|
export {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
t as LogLevel,
|
|
57
|
+
u as combine,
|
|
58
|
+
w as createLogger,
|
|
59
|
+
h as filter
|
|
61
60
|
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holz/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0-rc.1",
|
|
4
4
|
"description": "A structured and composable logger",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/holz-core.cjs",
|
|
7
|
-
"module": "./dist/holz-core.js",
|
|
8
|
-
"types": "./src/index.ts",
|
|
9
6
|
"repository": {
|
|
10
7
|
"type": "git",
|
|
11
8
|
"url": "https://github.com/PsychoLlama/holz",
|
|
@@ -13,6 +10,7 @@
|
|
|
13
10
|
},
|
|
14
11
|
"exports": {
|
|
15
12
|
".": {
|
|
13
|
+
"types": "./dist/holz-core.d.ts",
|
|
16
14
|
"require": "./dist/holz-core.cjs",
|
|
17
15
|
"import": "./dist/holz-core.js"
|
|
18
16
|
}
|
|
@@ -38,9 +36,12 @@
|
|
|
38
36
|
"test:types": "tsc"
|
|
39
37
|
},
|
|
40
38
|
"devDependencies": {
|
|
41
|
-
"@vitest/coverage-
|
|
42
|
-
"typescript": "^
|
|
43
|
-
"vite": "^
|
|
44
|
-
"
|
|
45
|
-
|
|
39
|
+
"@vitest/coverage-v8": "^3.0.8",
|
|
40
|
+
"typescript": "^5.0.0",
|
|
41
|
+
"vite": "^6.0.0",
|
|
42
|
+
"vite-plugin-dts": "^4.5.3",
|
|
43
|
+
"vite-tsconfig-paths": "^5.1.4",
|
|
44
|
+
"vitest": "^3.0.8"
|
|
45
|
+
},
|
|
46
|
+
"stableVersion": "0.6.0"
|
|
46
47
|
}
|
|
@@ -35,6 +35,19 @@ describe('Logger', () => {
|
|
|
35
35
|
});
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
+
it('binds the log methods to the logger', () => {
|
|
39
|
+
const backend = vi.fn();
|
|
40
|
+
const logger = createLogger(backend);
|
|
41
|
+
|
|
42
|
+
const { debug, info, warn, error } = logger;
|
|
43
|
+
debug('Debugging message');
|
|
44
|
+
info('Informative message');
|
|
45
|
+
warn('Warning message');
|
|
46
|
+
error('Error message');
|
|
47
|
+
|
|
48
|
+
expect(backend).toHaveBeenCalledTimes(4);
|
|
49
|
+
});
|
|
50
|
+
|
|
38
51
|
describe('namespace', () => {
|
|
39
52
|
it('extends the origin of the logger', () => {
|
|
40
53
|
const backend = vi.fn();
|
|
@@ -13,11 +13,11 @@ describe('operators', () => {
|
|
|
13
13
|
logger.info('tee message');
|
|
14
14
|
|
|
15
15
|
expect(b1).toHaveBeenCalledWith(
|
|
16
|
-
expect.objectContaining({ message: 'tee message' })
|
|
16
|
+
expect.objectContaining({ message: 'tee message' }),
|
|
17
17
|
);
|
|
18
18
|
|
|
19
19
|
expect(b2).toHaveBeenCalledWith(
|
|
20
|
-
expect.objectContaining({ message: 'tee message' })
|
|
20
|
+
expect.objectContaining({ message: 'tee message' }),
|
|
21
21
|
);
|
|
22
22
|
});
|
|
23
23
|
|
|
@@ -33,7 +33,7 @@ describe('operators', () => {
|
|
|
33
33
|
it('filters out logs that do not match the predicate', () => {
|
|
34
34
|
const backend = vi.fn();
|
|
35
35
|
const logger = createLogger(
|
|
36
|
-
filter((log) => log.level !== LogLevel.Debug, backend)
|
|
36
|
+
filter((log) => log.level !== LogLevel.Debug, backend),
|
|
37
37
|
);
|
|
38
38
|
|
|
39
39
|
logger.info('keep me');
|
|
@@ -41,7 +41,7 @@ describe('operators', () => {
|
|
|
41
41
|
|
|
42
42
|
expect(backend).toHaveBeenCalledOnce();
|
|
43
43
|
expect(backend).toHaveBeenCalledWith(
|
|
44
|
-
expect.objectContaining({ message: 'keep me' })
|
|
44
|
+
expect.objectContaining({ message: 'keep me' }),
|
|
45
45
|
);
|
|
46
46
|
});
|
|
47
47
|
});
|
package/src/index.ts
CHANGED
package/src/logger.ts
CHANGED
|
@@ -2,24 +2,18 @@ import type { LogProcessor, LogContext } from './types';
|
|
|
2
2
|
import { LogLevel } from './types';
|
|
3
3
|
|
|
4
4
|
class Logger {
|
|
5
|
-
|
|
6
|
-
* Create a new logger. The processor is up to you. There are plugins for
|
|
7
|
-
* filtering, formatting, combining multiple processors together, and more.
|
|
8
|
-
*
|
|
9
|
-
* If you wish to use more than one processor, `combine(...)` them first.
|
|
10
|
-
*/
|
|
11
|
-
static create(processor: LogProcessor): Logger {
|
|
12
|
-
return new Logger(processor, []);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
private constructor(
|
|
5
|
+
constructor(
|
|
16
6
|
private processor: LogProcessor,
|
|
17
|
-
readonly owner: ReadonlyArray<string
|
|
7
|
+
readonly owner: ReadonlyArray<string>,
|
|
18
8
|
) {
|
|
19
|
-
// Non-enumerable to keep the
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
9
|
+
// Non-enumerable to keep the repl clean.
|
|
10
|
+
const hidden = { configurable: false, enumerable: false };
|
|
11
|
+
Object.defineProperties(this, {
|
|
12
|
+
processor: hidden,
|
|
13
|
+
debug: hidden,
|
|
14
|
+
info: hidden,
|
|
15
|
+
warn: hidden,
|
|
16
|
+
error: hidden,
|
|
23
17
|
});
|
|
24
18
|
}
|
|
25
19
|
|
|
@@ -29,29 +23,29 @@ class Logger {
|
|
|
29
23
|
}
|
|
30
24
|
|
|
31
25
|
/** Log a frequent and verbose progress update. */
|
|
32
|
-
debug(message: string, context?: LogContext) {
|
|
26
|
+
debug = (message: string, context?: LogContext) => {
|
|
33
27
|
this.forwardLog(LogLevel.Debug, message, context);
|
|
34
|
-
}
|
|
28
|
+
};
|
|
35
29
|
|
|
36
30
|
/** Log a high-level progress update. */
|
|
37
|
-
info(message: string, context?: LogContext) {
|
|
31
|
+
info = (message: string, context?: LogContext) => {
|
|
38
32
|
this.forwardLog(LogLevel.Info, message, context);
|
|
39
|
-
}
|
|
33
|
+
};
|
|
40
34
|
|
|
41
35
|
/** Log something concerning. */
|
|
42
|
-
warn(message: string, context?: LogContext) {
|
|
36
|
+
warn = (message: string, context?: LogContext) => {
|
|
43
37
|
this.forwardLog(LogLevel.Warn, message, context);
|
|
44
|
-
}
|
|
38
|
+
};
|
|
45
39
|
|
|
46
40
|
/** Log a critical failure. */
|
|
47
|
-
error(message: string, context?: LogContext) {
|
|
41
|
+
error = (message: string, context?: LogContext) => {
|
|
48
42
|
this.forwardLog(LogLevel.Error, message, context);
|
|
49
|
-
}
|
|
43
|
+
};
|
|
50
44
|
|
|
51
45
|
private forwardLog(
|
|
52
46
|
level: LogLevel,
|
|
53
47
|
message: string,
|
|
54
|
-
context: LogContext = {}
|
|
48
|
+
context: LogContext = {},
|
|
55
49
|
) {
|
|
56
50
|
this.processor({
|
|
57
51
|
message,
|
|
@@ -62,4 +56,13 @@ class Logger {
|
|
|
62
56
|
}
|
|
63
57
|
}
|
|
64
58
|
|
|
65
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Create a new logger. The processor is up to you. There are plugins for
|
|
61
|
+
* filtering, formatting, combining multiple processors together, and more.
|
|
62
|
+
*
|
|
63
|
+
* If you wish to use more than one processor, `combine(...)` them first.
|
|
64
|
+
*/
|
|
65
|
+
export const createLogger = (processor: LogProcessor): Logger =>
|
|
66
|
+
new Logger(processor, []);
|
|
67
|
+
|
|
68
|
+
export type { Logger };
|
package/src/operators.ts
CHANGED
|
@@ -18,7 +18,7 @@ export function filter(
|
|
|
18
18
|
/** Returns `true` to forward the log. */
|
|
19
19
|
predicate: (log: Log) => boolean,
|
|
20
20
|
/** Where to send the log if it passes the filter. */
|
|
21
|
-
processor: LogProcessor
|
|
21
|
+
processor: LogProcessor,
|
|
22
22
|
): LogProcessor {
|
|
23
23
|
return (log: Log) => {
|
|
24
24
|
if (predicate(log)) {
|