@travetto/log 3.3.1 → 3.3.3
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 +35 -3
- package/package.json +4 -4
- package/src/internal/types.ts +2 -1
- package/src/service.ts +27 -24
- package/src/types.ts +7 -0
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ export class CommonLoggerConfig {
|
|
|
29
29
|
}
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
In addition to these simple overrides, the [CommonLogger](https://github.com/travetto/travetto/tree/main/module/log/src/common.ts#L11) can be extended by providing an implementation of either a [LogFormatter](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#
|
|
32
|
+
In addition to these simple overrides, the [CommonLogger](https://github.com/travetto/travetto/tree/main/module/log/src/common.ts#L11) can be extended by providing an implementation of either a [LogFormatter](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#L38) or [LogAppender](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#L30), with the declared symbol of `LogCommonⲐ`.
|
|
33
33
|
|
|
34
34
|
**Code: Sample Common Formatter**
|
|
35
35
|
```typescript
|
|
@@ -45,10 +45,10 @@ export class SampleFormatter implements LogFormatter {
|
|
|
45
45
|
}
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
As you can see, implementing [LogFormatter](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#
|
|
48
|
+
As you can see, implementing [LogFormatter](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#L38)/[LogAppender](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#L30) with the appropriate symbol is all that is necessary to customize the general logging functionality.
|
|
49
49
|
|
|
50
50
|
## Creating a Logger
|
|
51
|
-
The default pattern for logging is to create a [Logger](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#
|
|
51
|
+
The default pattern for logging is to create a [Logger](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#L45) which simply consumes a logging event. The method is not asynchronous as ensuring the ordering of append calls will be the responsibility of the logger. The default logger uses `console.log` and that is synchronous by default.
|
|
52
52
|
|
|
53
53
|
**Code: Logger Shape**
|
|
54
54
|
```typescript
|
|
@@ -113,6 +113,38 @@ export class CustomLogger implements Logger {
|
|
|
113
113
|
}
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
+
## Creating a Decorator
|
|
117
|
+
In addition to being able to control the entire logging experience, there are also scenarios in which the caller may want to only add information to the log event, without affecting control of the formatting or appending. The [Logger](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#L22) is an interface that provides a contract that allows transforming the [LogEvent](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#L8) data. A common scenario for this would be to add additional metadata data (e.g. server name, ip, code revision, CPU usage, memory usage, etc) into the log messages.
|
|
118
|
+
|
|
119
|
+
**Code: Log Decorator Shape**
|
|
120
|
+
```typescript
|
|
121
|
+
export interface LogDecorator {
|
|
122
|
+
decorate(ev: LogEvent): LogEvent;
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Code: Custom Logger**
|
|
127
|
+
```typescript
|
|
128
|
+
import os from 'os';
|
|
129
|
+
|
|
130
|
+
import { Injectable } from '@travetto/di';
|
|
131
|
+
import { LogDecorator, LogEvent } from '@travetto/log';
|
|
132
|
+
|
|
133
|
+
@Injectable()
|
|
134
|
+
export class CustomDecorator implements LogDecorator {
|
|
135
|
+
decorate(ev: LogEvent): LogEvent {
|
|
136
|
+
|
|
137
|
+
// Add memory usage, and hostname
|
|
138
|
+
Object.assign(ev.context ??= {}, {
|
|
139
|
+
memory: process.memoryUsage,
|
|
140
|
+
hostname: os.hostname()
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
return ev;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
116
148
|
## Logging to External Systems
|
|
117
149
|
By default the logging functionality logs messages directly to the console, relying on the `util.inspect` method, as is the standard behavior. When building distributed systems, with multiple separate logs, it is useful to rely on structured logging for common consumption. The framework supports logging as [JSON](https://www.json.org), which is easily consumable by services like [elasticsearch](https://elastic.co) or [AWS Cloudwatch](https://aws.amazon.com/cloudwatch/) if running as a lambda or in a docker container.
|
|
118
150
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/log",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.3",
|
|
4
4
|
"description": "Logging framework that integrates at the console.log level.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"directory": "module/log"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@travetto/config": "^3.3.
|
|
27
|
-
"@travetto/di": "^3.3.
|
|
28
|
-
"@travetto/terminal": "^3.3.
|
|
26
|
+
"@travetto/config": "^3.3.3",
|
|
27
|
+
"@travetto/di": "^3.3.3",
|
|
28
|
+
"@travetto/terminal": "^3.3.1"
|
|
29
29
|
},
|
|
30
30
|
"travetto": {
|
|
31
31
|
"displayName": "Logging"
|
package/src/internal/types.ts
CHANGED
package/src/service.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { ObjectUtil, ConsoleListener, ConsoleManager, ConsoleEvent } from '@trav
|
|
|
2
2
|
import { AutoCreate, DependencyRegistry, Injectable } from '@travetto/di';
|
|
3
3
|
import { GlobalTerminal } from '@travetto/terminal';
|
|
4
4
|
|
|
5
|
-
import { LogEvent, Logger } from './types';
|
|
6
|
-
import { LoggerTarget } from './internal/types';
|
|
5
|
+
import { LogDecorator, LogEvent, Logger } from './types';
|
|
6
|
+
import { LogDecoratorTarget, LoggerTarget } from './internal/types';
|
|
7
7
|
import { CommonLogger } from './common';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -13,24 +13,25 @@ import { CommonLogger } from './common';
|
|
|
13
13
|
export class LogService implements ConsoleListener, AutoCreate {
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* Log listeners
|
|
17
17
|
*/
|
|
18
18
|
#listeners: Logger[] = [];
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Log decorators
|
|
22
|
+
*/
|
|
23
|
+
#decorators: LogDecorator[] = [];
|
|
24
|
+
|
|
20
25
|
async postConstruct(): Promise<void> {
|
|
21
26
|
await GlobalTerminal.init();
|
|
22
27
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (loggers.length) {
|
|
27
|
-
const instances = await Promise.all(loggers.map(l => DependencyRegistry.getInstance<Logger>(l.class, l.qualifier)));
|
|
28
|
-
for (const inst of instances) {
|
|
29
|
-
this.#listeners.push(inst);
|
|
30
|
-
}
|
|
31
|
-
} else { // Otherwise fall back to the common logger
|
|
32
|
-
this.#listeners.push(await DependencyRegistry.getInstance(CommonLogger));
|
|
28
|
+
this.#listeners = await DependencyRegistry.getCandidateInstances<Logger>(LoggerTarget, c => c.class !== CommonLogger);
|
|
29
|
+
if (!this.#listeners.length) {
|
|
30
|
+
this.#listeners = [await DependencyRegistry.getInstance(CommonLogger)];
|
|
33
31
|
}
|
|
32
|
+
|
|
33
|
+
this.#decorators = await DependencyRegistry.getCandidateInstances<LogDecorator>(LogDecoratorTarget);
|
|
34
|
+
|
|
34
35
|
// Take over
|
|
35
36
|
ConsoleManager.set(this, true);
|
|
36
37
|
}
|
|
@@ -40,27 +41,29 @@ export class LogService implements ConsoleListener, AutoCreate {
|
|
|
40
41
|
*/
|
|
41
42
|
onLog(ev: ConsoleEvent): void {
|
|
42
43
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, prefer-const
|
|
43
|
-
let [message, context, ...args] = ev.args as [string, Record<string, unknown>, ...unknown[]];
|
|
44
|
+
let [message, context, ...args] = ev.args as [string | undefined, Record<string, unknown>, ...unknown[]];
|
|
44
45
|
if (!ObjectUtil.isPlainObject(context)) {
|
|
45
|
-
|
|
46
|
+
if (context !== undefined) {
|
|
47
|
+
args.unshift(context);
|
|
48
|
+
}
|
|
46
49
|
context = {};
|
|
47
50
|
}
|
|
48
51
|
|
|
49
|
-
if (typeof message !== 'string') {
|
|
52
|
+
if (typeof message !== 'string' && message !== undefined) {
|
|
50
53
|
args.unshift(message);
|
|
51
|
-
message =
|
|
54
|
+
message = undefined;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
// Allow for controlled order of event properties
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
58
|
+
let outEvent: LogEvent = { ...ev, message, context, args };
|
|
59
|
+
|
|
60
|
+
// Decorate event as needed
|
|
61
|
+
for (const d of this.#decorators) {
|
|
62
|
+
outEvent = d.decorate(outEvent);
|
|
63
|
+
}
|
|
61
64
|
|
|
62
65
|
for (const l of this.#listeners) {
|
|
63
|
-
l.onLog(
|
|
66
|
+
l.onLog(outEvent);
|
|
64
67
|
}
|
|
65
68
|
}
|
|
66
69
|
}
|
package/src/types.ts
CHANGED
|
@@ -16,6 +16,13 @@ export interface LogEvent extends ConsoleEvent {
|
|
|
16
16
|
context?: Record<string, unknown>;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* @concrete ./internal/types:LogDecoratorTarget
|
|
21
|
+
*/
|
|
22
|
+
export interface LogDecorator {
|
|
23
|
+
decorate(ev: LogEvent): LogEvent;
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
/**
|
|
20
27
|
* Output appender for the logger
|
|
21
28
|
* @concrete ./internal/types:LogAppenderTarget
|