@travetto/log 7.0.0-rc.0 → 7.0.0-rc.2
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 +9 -9
- package/package.json +4 -4
- package/src/appender/console.ts +2 -2
- package/src/appender/file.ts +8 -8
- package/src/common.ts +2 -2
- package/src/formatter/google.ts +7 -7
- package/src/formatter/json.ts +8 -8
- package/src/formatter/line.ts +20 -20
- package/src/formatter/util.ts +7 -7
- package/src/service.ts +8 -8
- package/src/types.ts +4 -4
package/README.md
CHANGED
|
@@ -39,8 +39,8 @@ import { LogFormatter, LogCommonSymbol, LogEvent } from '@travetto/log';
|
|
|
39
39
|
@Injectable(LogCommonSymbol)
|
|
40
40
|
export class SampleFormatter implements LogFormatter {
|
|
41
41
|
|
|
42
|
-
format(
|
|
43
|
-
return `${
|
|
42
|
+
format(event: LogEvent): string {
|
|
43
|
+
return `${event.timestamp} [${event.level}]#[${event.scope ?? 'unknown'}] ${event.message ?? 'NO MESSAGE'} ${(event.args ?? []).join(' ')}`;
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
```
|
|
@@ -53,7 +53,7 @@ The default pattern for logging is to create a [Logger](https://github.com/trave
|
|
|
53
53
|
**Code: Logger Shape**
|
|
54
54
|
```typescript
|
|
55
55
|
export interface Logger {
|
|
56
|
-
log(
|
|
56
|
+
log(event: LogEvent): unknown;
|
|
57
57
|
}
|
|
58
58
|
```
|
|
59
59
|
|
|
@@ -98,10 +98,10 @@ import { LogEvent, Logger } from '@travetto/log';
|
|
|
98
98
|
|
|
99
99
|
@Injectable()
|
|
100
100
|
export class CustomLogger implements Logger {
|
|
101
|
-
log(
|
|
101
|
+
log(event: LogEvent): void {
|
|
102
102
|
const headers = new Headers();
|
|
103
103
|
headers.set('Content-Type', 'application/json');
|
|
104
|
-
const body = JSON.stringify(
|
|
104
|
+
const body = JSON.stringify(event);
|
|
105
105
|
fetch('http://localhost:8080/log', { method: 'POST', headers, body, });
|
|
106
106
|
}
|
|
107
107
|
}
|
|
@@ -113,7 +113,7 @@ In addition to being able to control the entire logging experience, there are al
|
|
|
113
113
|
**Code: Log Decorator Shape**
|
|
114
114
|
```typescript
|
|
115
115
|
export interface LogDecorator {
|
|
116
|
-
decorate(
|
|
116
|
+
decorate(event: LogEvent): LogEvent;
|
|
117
117
|
}
|
|
118
118
|
```
|
|
119
119
|
|
|
@@ -126,12 +126,12 @@ import { LogDecorator, LogEvent } from '@travetto/log';
|
|
|
126
126
|
|
|
127
127
|
@Injectable()
|
|
128
128
|
export class CustomDecorator implements LogDecorator {
|
|
129
|
-
decorate(
|
|
130
|
-
|
|
129
|
+
decorate(event: LogEvent): LogEvent {
|
|
130
|
+
event.args.push({
|
|
131
131
|
memory: process.memoryUsage,
|
|
132
132
|
hostname: os.hostname()
|
|
133
133
|
});
|
|
134
|
-
return
|
|
134
|
+
return event;
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/log",
|
|
3
|
-
"version": "7.0.0-rc.
|
|
3
|
+
"version": "7.0.0-rc.2",
|
|
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": "^7.0.0-rc.
|
|
27
|
-
"@travetto/di": "^7.0.0-rc.
|
|
28
|
-
"@travetto/terminal": "^7.0.0-rc.
|
|
26
|
+
"@travetto/config": "^7.0.0-rc.2",
|
|
27
|
+
"@travetto/di": "^7.0.0-rc.2",
|
|
28
|
+
"@travetto/terminal": "^7.0.0-rc.2"
|
|
29
29
|
},
|
|
30
30
|
"travetto": {
|
|
31
31
|
"displayName": "Logging"
|
package/src/appender/console.ts
CHANGED
|
@@ -20,7 +20,7 @@ export class ConsoleLogAppender implements LogAppender {
|
|
|
20
20
|
this.config = config;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
append(
|
|
24
|
-
console;
|
|
25
25
|
}
|
|
26
26
|
}
|
package/src/appender/file.ts
CHANGED
|
@@ -27,22 +27,22 @@ export class FileLogAppenderConfig {
|
|
|
27
27
|
@Injectable()
|
|
28
28
|
export class FileLogAppender implements LogAppender {
|
|
29
29
|
stream?: WriteStream;
|
|
30
|
-
|
|
30
|
+
appendDescriptor?: number;
|
|
31
31
|
|
|
32
|
-
constructor(
|
|
33
|
-
mkdirSync(path.dirname(
|
|
34
|
-
if (
|
|
35
|
-
this.
|
|
32
|
+
constructor(config: FileLogAppenderConfig) {
|
|
33
|
+
mkdirSync(path.dirname(config.output!), { recursive: true });
|
|
34
|
+
if (config.writeSync) {
|
|
35
|
+
this.appendDescriptor = openSync(config.output!, 'a');
|
|
36
36
|
} else {
|
|
37
|
-
this.stream = createWriteStream(
|
|
37
|
+
this.stream = createWriteStream(config.output!, { autoClose: true, flags: 'a' });
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
append(
|
|
41
|
+
append(event: LogEvent, formatted: string): void {
|
|
42
42
|
if (this.stream) {
|
|
43
43
|
this.stream.write(`${formatted}\n`);
|
|
44
44
|
} else {
|
|
45
|
-
appendFileSync(this.
|
|
45
|
+
appendFileSync(this.appendDescriptor!, `${formatted}\n`);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
}
|
package/src/common.ts
CHANGED
|
@@ -39,7 +39,7 @@ export class CommonLogger implements Logger {
|
|
|
39
39
|
this.appender ??= await DependencyRegistryIndex.getInstance(appenderCls);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
log(
|
|
43
|
-
this.appender.append(
|
|
42
|
+
log(event: LogEvent): void {
|
|
43
|
+
this.appender.append(event, this.formatter.format(event));
|
|
44
44
|
}
|
|
45
45
|
}
|
package/src/formatter/google.ts
CHANGED
|
@@ -10,8 +10,8 @@ import { LogFormatUtil } from './util.ts';
|
|
|
10
10
|
*/
|
|
11
11
|
@Injectable()
|
|
12
12
|
export class GoogleLogFormatter implements LogFormatter {
|
|
13
|
-
format(
|
|
14
|
-
const context = LogFormatUtil.getContext(
|
|
13
|
+
format(event: LogEvent): string {
|
|
14
|
+
const context = LogFormatUtil.getContext(event);
|
|
15
15
|
|
|
16
16
|
const extra: Record<string, unknown> = {};
|
|
17
17
|
// Http request specific
|
|
@@ -28,11 +28,11 @@ export class GoogleLogFormatter implements LogFormatter {
|
|
|
28
28
|
|
|
29
29
|
return JSON.stringify({
|
|
30
30
|
context,
|
|
31
|
-
'logging.googleapis.com/sourceLocation': { file: `${
|
|
32
|
-
'logging.googleapis.com/labels': { module:
|
|
33
|
-
severity:
|
|
34
|
-
message: LogFormatUtil.getLogMessage(
|
|
35
|
-
timestamp:
|
|
31
|
+
'logging.googleapis.com/sourceLocation': { file: `${event.module}/${event.modulePath}`, line: event.line },
|
|
32
|
+
'logging.googleapis.com/labels': { module: event.module, scope: event.scope },
|
|
33
|
+
severity: event.level,
|
|
34
|
+
message: LogFormatUtil.getLogMessage(event),
|
|
35
|
+
timestamp: event.timestamp,
|
|
36
36
|
...extra,
|
|
37
37
|
});
|
|
38
38
|
}
|
package/src/formatter/json.ts
CHANGED
|
@@ -14,20 +14,20 @@ export class JSONLogFormatterConfig {
|
|
|
14
14
|
*/
|
|
15
15
|
@Injectable()
|
|
16
16
|
export class JsonLogFormatter implements LogFormatter {
|
|
17
|
-
|
|
17
|
+
config: JSONLogFormatterConfig;
|
|
18
18
|
|
|
19
|
-
constructor(
|
|
20
|
-
this.
|
|
19
|
+
constructor(config: JSONLogFormatterConfig) {
|
|
20
|
+
this.config = config;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
format(
|
|
24
|
-
const { message: _m, args: _a, ...rest } =
|
|
25
|
-
const message = LogFormatUtil.getLogMessage(
|
|
26
|
-
const context = LogFormatUtil.getContext(
|
|
23
|
+
format(event: LogEvent): string {
|
|
24
|
+
const { message: _m, args: _a, ...rest } = event;
|
|
25
|
+
const message = LogFormatUtil.getLogMessage(event);
|
|
26
|
+
const context = LogFormatUtil.getContext(event);
|
|
27
27
|
return JSON.stringify({
|
|
28
28
|
...rest,
|
|
29
29
|
...(message ? { message } : {}),
|
|
30
30
|
...(context ? { context } : {}),
|
|
31
|
-
}, null, this.
|
|
31
|
+
}, null, this.config.jsonIndent);
|
|
32
32
|
}
|
|
33
33
|
}
|
package/src/formatter/line.ts
CHANGED
|
@@ -80,50 +80,50 @@ export class LineLogFormatterConfig {
|
|
|
80
80
|
@Injectable()
|
|
81
81
|
export class LineLogFormatter implements LogFormatter {
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
config: LineLogFormatterConfig;
|
|
84
84
|
|
|
85
|
-
constructor(
|
|
86
|
-
this.
|
|
85
|
+
constructor(config: LineLogFormatterConfig) {
|
|
86
|
+
this.config = config;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
90
|
* Format an event into a single line
|
|
91
91
|
*/
|
|
92
|
-
format(
|
|
92
|
+
format(event: LogEvent): string {
|
|
93
93
|
const out = [];
|
|
94
94
|
|
|
95
|
-
if (this.
|
|
96
|
-
let timestamp =
|
|
97
|
-
if (this.
|
|
95
|
+
if (this.config.timestamp) {
|
|
96
|
+
let timestamp = event.timestamp.toISOString();
|
|
97
|
+
if (this.config.timestamp === 's') {
|
|
98
98
|
timestamp = timestamp.replace(/[.]\d{3}/, '');
|
|
99
99
|
}
|
|
100
|
-
if (this.
|
|
100
|
+
if (this.config.colorize) {
|
|
101
101
|
timestamp = STYLES.timestamp(timestamp);
|
|
102
102
|
}
|
|
103
103
|
out.push(timestamp);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
if (this.
|
|
107
|
-
let level: string =
|
|
108
|
-
if (this.
|
|
106
|
+
if (this.config.level) {
|
|
107
|
+
let level: string = event.level;
|
|
108
|
+
if (this.config.align) {
|
|
109
109
|
level = level.padEnd(5, ' ');
|
|
110
110
|
}
|
|
111
|
-
if (this.
|
|
112
|
-
level = STYLES[
|
|
111
|
+
if (this.config.colorize) {
|
|
112
|
+
level = STYLES[event.level](level);
|
|
113
113
|
}
|
|
114
114
|
out.push(level);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
if (
|
|
118
|
-
const
|
|
119
|
-
let
|
|
120
|
-
if (this.
|
|
121
|
-
|
|
117
|
+
if (event.modulePath && this.config.location) {
|
|
118
|
+
const namespace = `${event.module}:${event.modulePath}`;
|
|
119
|
+
let location = event.line ? `${namespace}:${event.line}` : namespace;
|
|
120
|
+
if (this.config.colorize) {
|
|
121
|
+
location = STYLES.location(location);
|
|
122
122
|
}
|
|
123
|
-
out.push(`[${
|
|
123
|
+
out.push(`[${location}]`);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
out.push(LogFormatUtil.getLogMessage(
|
|
126
|
+
out.push(LogFormatUtil.getLogMessage(event, this.config.inspectOptions));
|
|
127
127
|
|
|
128
128
|
return out.join(' ');
|
|
129
129
|
}
|
package/src/formatter/util.ts
CHANGED
|
@@ -9,19 +9,19 @@ const INSPECT_OPTIONS = { colors: false, showHidden: false, depth: 5, breakLengt
|
|
|
9
9
|
|
|
10
10
|
export class LogFormatUtil {
|
|
11
11
|
/** Generate log context */
|
|
12
|
-
static getContext(
|
|
12
|
+
static getContext(event: LogEvent): Record<string, unknown> | undefined {
|
|
13
13
|
const out: Record<string, unknown> = {};
|
|
14
|
-
for (const
|
|
15
|
-
if (DataUtil.isPlainObject(
|
|
16
|
-
safeAssign(out,
|
|
14
|
+
for (const arg of event.args ?? []) {
|
|
15
|
+
if (DataUtil.isPlainObject(arg)) {
|
|
16
|
+
safeAssign(out, arg);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
return out && Object.keys(out).length > 0 ? out : undefined;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/** Get log message */
|
|
23
|
-
static getLogMessage(
|
|
24
|
-
const formatted =
|
|
25
|
-
return (
|
|
23
|
+
static getLogMessage(event: LogEvent, options: InspectOptions = INSPECT_OPTIONS): string {
|
|
24
|
+
const formatted = event.args?.map(arg => typeof arg === 'string' ? arg : inspect(arg, options)) ?? [];
|
|
25
|
+
return (event.message ? [event.message, ...formatted] : formatted).join(' ');
|
|
26
26
|
}
|
|
27
27
|
}
|
package/src/service.ts
CHANGED
|
@@ -21,7 +21,7 @@ export class LogService implements ConsoleListener {
|
|
|
21
21
|
#decorators: LogDecorator[] = [];
|
|
22
22
|
|
|
23
23
|
async postConstruct(): Promise<void> {
|
|
24
|
-
this.#listeners = await DependencyRegistryIndex.getInstances(toConcrete<Logger>(),
|
|
24
|
+
this.#listeners = await DependencyRegistryIndex.getInstances(toConcrete<Logger>(), candidate => candidate.class !== CommonLogger);
|
|
25
25
|
if (!this.#listeners.length) {
|
|
26
26
|
this.#listeners = [await DependencyRegistryIndex.getInstance(CommonLogger)];
|
|
27
27
|
}
|
|
@@ -34,8 +34,8 @@ export class LogService implements ConsoleListener {
|
|
|
34
34
|
/**
|
|
35
35
|
* Endpoint for listening, endpoint registered with ConsoleManager
|
|
36
36
|
*/
|
|
37
|
-
log(
|
|
38
|
-
const args = [...
|
|
37
|
+
log(event: ConsoleEvent): void {
|
|
38
|
+
const args = [...event.args];
|
|
39
39
|
let message: string | undefined;
|
|
40
40
|
if (typeof args[0] === 'string') {
|
|
41
41
|
message = args[0];
|
|
@@ -43,15 +43,15 @@ export class LogService implements ConsoleListener {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// Allow for controlled order of event properties
|
|
46
|
-
let outEvent: LogEvent = { ...
|
|
46
|
+
let outEvent: LogEvent = { ...event, message, args };
|
|
47
47
|
|
|
48
48
|
// Decorate event as needed
|
|
49
|
-
for (const
|
|
50
|
-
outEvent =
|
|
49
|
+
for (const decorators of this.#decorators) {
|
|
50
|
+
outEvent = decorators.decorate(outEvent);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
for (const
|
|
54
|
-
|
|
53
|
+
for (const listener of this.#listeners) {
|
|
54
|
+
listener.log(outEvent);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
package/src/types.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface LogEvent extends ConsoleEvent {
|
|
|
18
18
|
* @concrete
|
|
19
19
|
*/
|
|
20
20
|
export interface LogDecorator {
|
|
21
|
-
decorate(
|
|
21
|
+
decorate(event: LogEvent): LogEvent;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -26,7 +26,7 @@ export interface LogDecorator {
|
|
|
26
26
|
* @concrete
|
|
27
27
|
*/
|
|
28
28
|
export interface LogAppender {
|
|
29
|
-
append(
|
|
29
|
+
append(event: LogEvent, formatted: string): void;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
@@ -34,7 +34,7 @@ export interface LogAppender {
|
|
|
34
34
|
* @concrete
|
|
35
35
|
*/
|
|
36
36
|
export interface LogFormatter {
|
|
37
|
-
format(
|
|
37
|
+
format(event: LogEvent): string;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
@@ -42,5 +42,5 @@ export interface LogFormatter {
|
|
|
42
42
|
* @concrete
|
|
43
43
|
*/
|
|
44
44
|
export interface Logger {
|
|
45
|
-
log(
|
|
45
|
+
log(event: LogEvent): unknown;
|
|
46
46
|
}
|