@travetto/log 4.0.0-rc.8 → 4.0.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/README.md +5 -9
- package/__index__.ts +1 -0
- package/package.json +4 -4
- package/src/formatter/google.ts +21 -25
- package/src/formatter/json.ts +9 -1
- package/src/formatter/line.ts +2 -18
- package/src/formatter/util.ts +24 -0
- package/src/service.ts +1 -12
- package/src/types.ts +0 -4
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ yarn add @travetto/log
|
|
|
16
16
|
This module provides logging functionality, building upon [ConsoleManager](https://github.com/travetto/travetto/tree/main/module/base/src/console.ts) in the [Base](https://github.com/travetto/travetto/tree/main/module/base#readme "Environment config and common utilities for travetto applications.") module. This is all ultimately built upon [console](https://nodejs.org/api/console.html) operations. The logging infrastructure is built upon the [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support.") system, and so new loggers can be created that rely upon dependency injected services and sources.
|
|
17
17
|
|
|
18
18
|
## Extending the Common Logger
|
|
19
|
-
By default, the system ships with the [CommonLogger](https://github.com/travetto/travetto/tree/main/module/log/src/common.ts#L12), and by default will leverage the [LineLogFormatter](https://github.com/travetto/travetto/tree/main/module/log/src/formatter/line.ts#
|
|
19
|
+
By default, the system ships with the [CommonLogger](https://github.com/travetto/travetto/tree/main/module/log/src/common.ts#L12), and by default will leverage the [LineLogFormatter](https://github.com/travetto/travetto/tree/main/module/log/src/formatter/line.ts#L37) and the [ConsoleLogAppender](https://github.com/travetto/travetto/tree/main/module/log/src/appender/console.ts#L7). The configuration [CommonLoggerConfig](https://github.com/travetto/travetto/tree/main/module/log/src/common.ts#L12) provides two configuration variables that allows for switching out [LineLogFormatter](https://github.com/travetto/travetto/tree/main/module/log/src/formatter/line.ts#L37) for the [JsonLogFormatter](https://github.com/travetto/travetto/tree/main/module/log/src/formatter/json.ts#L16), depending on the value of `CommonLoggerConfig.format`. Additionally the [ConsoleLogAppender](https://github.com/travetto/travetto/tree/main/module/log/src/appender/console.ts#L7) can be swapped out for the [FileLogAppender](https://github.com/travetto/travetto/tree/main/module/log/src/appender/file.ts#L11) depending on the value of `CommonLoggerConfig.output`.
|
|
20
20
|
|
|
21
21
|
**Code: Standard Logging Config**
|
|
22
22
|
```typescript
|
|
@@ -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#L12) 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#L12) can be extended by providing an implementation of either a [LogFormatter](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#L34) or [LogAppender](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#L26), 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#L34)/[LogAppender](https://github.com/travetto/travetto/tree/main/module/log/src/types.ts#L26) 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#L41) 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
|
|
@@ -64,10 +64,6 @@ export interface LogEvent extends ConsoleEvent {
|
|
|
64
64
|
* Log message
|
|
65
65
|
*/
|
|
66
66
|
message?: string;
|
|
67
|
-
/**
|
|
68
|
-
* Log Message context
|
|
69
|
-
*/
|
|
70
|
-
context?: Record<string, unknown>;
|
|
71
67
|
}
|
|
72
68
|
```
|
|
73
69
|
|
|
@@ -114,7 +110,7 @@ export class CustomLogger implements Logger {
|
|
|
114
110
|
```
|
|
115
111
|
|
|
116
112
|
## 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#
|
|
113
|
+
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#L18) 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
114
|
|
|
119
115
|
**Code: Log Decorator Shape**
|
|
120
116
|
```typescript
|
package/__index__.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from './src/service';
|
|
|
3
3
|
export * from './src/formatter/json';
|
|
4
4
|
export * from './src/formatter/line';
|
|
5
5
|
export * from './src/formatter/google';
|
|
6
|
+
export * from './src/formatter/util';
|
|
6
7
|
export * from './src/appender/console';
|
|
7
8
|
export * from './src/appender/file';
|
|
8
9
|
export * from './src/types';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/log",
|
|
3
|
-
"version": "4.0.0
|
|
3
|
+
"version": "4.0.0",
|
|
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": "^4.0.0
|
|
27
|
-
"@travetto/di": "^4.0.0
|
|
28
|
-
"@travetto/terminal": "^4.0.0
|
|
26
|
+
"@travetto/config": "^4.0.0",
|
|
27
|
+
"@travetto/di": "^4.0.0",
|
|
28
|
+
"@travetto/terminal": "^4.0.0"
|
|
29
29
|
},
|
|
30
30
|
"travetto": {
|
|
31
31
|
"displayName": "Logging"
|
package/src/formatter/google.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import util from 'node:util';
|
|
2
|
-
|
|
3
1
|
import { Injectable } from '@travetto/di';
|
|
4
2
|
|
|
5
3
|
import { LogFormatter, LogEvent } from '../types';
|
|
4
|
+
import { LogFormatUtil } from './util';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Google Logging Formatter
|
|
@@ -11,33 +10,30 @@ import { LogFormatter, LogEvent } from '../types';
|
|
|
11
10
|
*/
|
|
12
11
|
@Injectable()
|
|
13
12
|
export class GoogleLogFormatter implements LogFormatter {
|
|
14
|
-
|
|
13
|
+
format(ev: LogEvent): string {
|
|
14
|
+
const context = LogFormatUtil.getContext(ev);
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
context
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
const extra: Record<string, unknown> = {};
|
|
17
|
+
// Http request specific
|
|
18
|
+
if (context && ('method' in context && 'path' in context && 'statusCode' in context)) {
|
|
19
|
+
extra.httpRequest = {
|
|
20
|
+
requestMethod: context.method,
|
|
21
|
+
requestUrl: context.path,
|
|
22
|
+
status: context.statusCode
|
|
23
|
+
};
|
|
24
|
+
delete context.method;
|
|
25
|
+
delete context.path;
|
|
26
|
+
delete context.statusCode;
|
|
26
27
|
}
|
|
28
|
+
|
|
27
29
|
return JSON.stringify({
|
|
28
30
|
context,
|
|
29
|
-
'logging.googleapis.com/sourceLocation': { file, line },
|
|
30
|
-
'logging.googleapis.com/labels': { module, scope },
|
|
31
|
-
severity: level,
|
|
32
|
-
message:
|
|
33
|
-
timestamp,
|
|
34
|
-
...
|
|
35
|
-
httpRequest: {
|
|
36
|
-
requestMethod: method,
|
|
37
|
-
requestUrl: path,
|
|
38
|
-
status: statusCode
|
|
39
|
-
}
|
|
40
|
-
} : {})
|
|
31
|
+
'logging.googleapis.com/sourceLocation': { file: ev.source, line: ev.line },
|
|
32
|
+
'logging.googleapis.com/labels': { module: ev.module, scope: ev.scope },
|
|
33
|
+
severity: ev.level,
|
|
34
|
+
message: LogFormatUtil.getLogMessage(ev),
|
|
35
|
+
timestamp: ev.timestamp,
|
|
36
|
+
...extra,
|
|
41
37
|
});
|
|
42
38
|
}
|
|
43
39
|
}
|
package/src/formatter/json.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Injectable } from '@travetto/di';
|
|
|
2
2
|
import { Config } from '@travetto/config';
|
|
3
3
|
|
|
4
4
|
import { LogEvent, LogFormatter } from '../types';
|
|
5
|
+
import { LogFormatUtil } from './util';
|
|
5
6
|
|
|
6
7
|
@Config('log')
|
|
7
8
|
export class JSONLogFormatterConfig {
|
|
@@ -20,6 +21,13 @@ export class JsonLogFormatter implements LogFormatter {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
format(ev: LogEvent): string {
|
|
23
|
-
|
|
24
|
+
const { message: _m, args: _a, ...rest } = ev;
|
|
25
|
+
const message = LogFormatUtil.getLogMessage(ev);
|
|
26
|
+
const context = LogFormatUtil.getContext(ev);
|
|
27
|
+
return JSON.stringify({
|
|
28
|
+
...rest,
|
|
29
|
+
...(message ? { message } : {}),
|
|
30
|
+
...(context ? { context } : {}),
|
|
31
|
+
}, null, this.opts.jsonIndent);
|
|
24
32
|
}
|
|
25
33
|
}
|
package/src/formatter/line.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { Ignore } from '@travetto/schema';
|
|
|
7
7
|
import { StyleUtil } from '@travetto/terminal';
|
|
8
8
|
|
|
9
9
|
import { LogEvent, LogFormatter } from '../types';
|
|
10
|
+
import { LogFormatUtil } from './util';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Level coloring
|
|
@@ -85,13 +86,6 @@ export class LineLogFormatter implements LogFormatter {
|
|
|
85
86
|
this.opts = opts;
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
pretty(ev: LogEvent, o: unknown): string {
|
|
89
|
-
return util.inspect(o, {
|
|
90
|
-
...this.opts.inspectOptions,
|
|
91
|
-
showHidden: ev.level === 'debug',
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
89
|
/**
|
|
96
90
|
* Format an event into a single line
|
|
97
91
|
*/
|
|
@@ -129,17 +123,7 @@ export class LineLogFormatter implements LogFormatter {
|
|
|
129
123
|
out.push(`[${loc}]`);
|
|
130
124
|
}
|
|
131
125
|
|
|
132
|
-
|
|
133
|
-
out.push(ev.message);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (ev.args && ev.args.length) {
|
|
137
|
-
out.push(...ev.args.map(a => this.pretty(ev, a)));
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (ev.context && Object.keys(ev.context).length) {
|
|
141
|
-
out.push(this.pretty(ev, ev.context));
|
|
142
|
-
}
|
|
126
|
+
out.push(LogFormatUtil.getLogMessage(ev, this.opts.inspectOptions));
|
|
143
127
|
|
|
144
128
|
return out.join(' ');
|
|
145
129
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { inspect, type InspectOptions } from 'node:util';
|
|
2
|
+
import { ObjectUtil } from '@travetto/base';
|
|
3
|
+
import { LogEvent } from '../types';
|
|
4
|
+
|
|
5
|
+
export class LogFormatUtil {
|
|
6
|
+
static #inspectOptions = { colors: false, showHidden: false, depth: 5, breakLength: 200 };
|
|
7
|
+
|
|
8
|
+
/** Generate log context */
|
|
9
|
+
static getContext(ev: LogEvent): Record<string, unknown> | undefined {
|
|
10
|
+
const out: Record<string, unknown> = {};
|
|
11
|
+
for (const o of ev.args ?? []) {
|
|
12
|
+
if (ObjectUtil.isPlainObject(o)) {
|
|
13
|
+
Object.assign(out, o);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return out && Object.keys(out).length > 0 ? out : undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Get log message */
|
|
20
|
+
static getLogMessage(ev: LogEvent, options: InspectOptions = this.#inspectOptions): string {
|
|
21
|
+
const formatted = ev.args?.map(x => inspect(x, options)) ?? [];
|
|
22
|
+
return (ev.message ? [ev.message, ...formatted] : formatted).join(' ');
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/service.ts
CHANGED
|
@@ -38,25 +38,14 @@ export class LogService implements ConsoleListener, AutoCreate {
|
|
|
38
38
|
*/
|
|
39
39
|
onLog(ev: ConsoleEvent): void {
|
|
40
40
|
const args = [...ev.args];
|
|
41
|
-
let context: Record<string, unknown> | undefined;
|
|
42
41
|
let message: string | undefined;
|
|
43
42
|
if (typeof args[0] === 'string') {
|
|
44
43
|
message = args[0];
|
|
45
44
|
args.shift(); // First arg is now the message
|
|
46
45
|
}
|
|
47
46
|
|
|
48
|
-
// More flexible on context
|
|
49
|
-
const last = args[args.length - 1];
|
|
50
|
-
if (last !== null && last !== undefined && typeof last === 'object') {
|
|
51
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
52
|
-
context = Object.fromEntries(
|
|
53
|
-
Object.entries(last).filter(x => typeof x[1] !== 'function')
|
|
54
|
-
);
|
|
55
|
-
args.pop();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
47
|
// Allow for controlled order of event properties
|
|
59
|
-
let outEvent: LogEvent = { ...ev, message,
|
|
48
|
+
let outEvent: LogEvent = { ...ev, message, args };
|
|
60
49
|
|
|
61
50
|
// Decorate event as needed
|
|
62
51
|
for (const d of this.#decorators) {
|