@xrystal/core 3.5.3 → 3.5.5
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/package.json
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
import winston from
|
|
2
|
-
import
|
|
1
|
+
import winston from "winston";
|
|
2
|
+
import "winston-daily-rotate-file";
|
|
3
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
4
|
interface CustomLogger extends winston.Logger {
|
|
4
5
|
critical: winston.LeveledLogMethod;
|
|
5
6
|
http: winston.LeveledLogMethod;
|
|
6
7
|
}
|
|
7
8
|
export default class LoggerService {
|
|
9
|
+
static readonly storage: AsyncLocalStorage<Map<string, string>>;
|
|
8
10
|
private serviceName;
|
|
9
11
|
private environment;
|
|
10
12
|
private kafkaProducer;
|
|
11
13
|
private kafkaTopic;
|
|
12
14
|
private isKafkaReady;
|
|
15
|
+
private getTracingFormat;
|
|
13
16
|
private getConsoleFormat;
|
|
14
17
|
winston: CustomLogger;
|
|
15
18
|
constructor();
|
|
19
|
+
runWithId: (id: string, callback: () => void) => void;
|
|
16
20
|
load: (config: Record<string, any>) => Promise<void>;
|
|
17
21
|
winstonLoader: ({ loadPath, loggerLevel }: {
|
|
18
22
|
loadPath: string;
|
|
@@ -1,37 +1,47 @@
|
|
|
1
|
-
import winston, { format } from
|
|
2
|
-
import
|
|
3
|
-
import path from
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import winston, { format } from "winston";
|
|
2
|
+
import "winston-daily-rotate-file";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
|
+
import { Kafka, Partitioners, logLevel } from "kafkajs";
|
|
6
|
+
import { LoggerLayerEnum } from "../../utils";
|
|
6
7
|
const customLevels = {
|
|
7
|
-
critical: LoggerLayerEnum.CRITICAL,
|
|
8
|
-
error: LoggerLayerEnum.ERROR,
|
|
9
|
-
info: LoggerLayerEnum.INFO,
|
|
10
|
-
http: LoggerLayerEnum.HTTP,
|
|
11
|
-
debug: LoggerLayerEnum.DEBUG,
|
|
8
|
+
critical: LoggerLayerEnum.CRITICAL,
|
|
9
|
+
error: LoggerLayerEnum.ERROR,
|
|
10
|
+
info: LoggerLayerEnum.INFO,
|
|
11
|
+
http: LoggerLayerEnum.HTTP,
|
|
12
|
+
debug: LoggerLayerEnum.DEBUG,
|
|
12
13
|
};
|
|
13
14
|
const customColors = {
|
|
14
|
-
critical:
|
|
15
|
-
error:
|
|
16
|
-
warn:
|
|
17
|
-
info:
|
|
18
|
-
http:
|
|
19
|
-
debug:
|
|
15
|
+
critical: "red",
|
|
16
|
+
error: "magenta",
|
|
17
|
+
warn: "yellow",
|
|
18
|
+
info: "green",
|
|
19
|
+
http: "cyan",
|
|
20
|
+
debug: "blue"
|
|
20
21
|
};
|
|
21
22
|
export default class LoggerService {
|
|
23
|
+
static storage = new AsyncLocalStorage();
|
|
22
24
|
serviceName = "";
|
|
23
25
|
environment = "";
|
|
24
26
|
kafkaProducer = null;
|
|
25
27
|
kafkaTopic = "";
|
|
26
28
|
isKafkaReady = false;
|
|
29
|
+
getTracingFormat = format((info) => {
|
|
30
|
+
const store = LoggerService.storage.getStore();
|
|
31
|
+
if (store) {
|
|
32
|
+
info.id = store.get("correlationId");
|
|
33
|
+
}
|
|
34
|
+
return info;
|
|
35
|
+
});
|
|
27
36
|
getConsoleFormat() {
|
|
28
|
-
return format.combine(format.timestamp({ format:
|
|
29
|
-
const msg = typeof info.message ===
|
|
30
|
-
|
|
37
|
+
return format.combine(this.getTracingFormat(), format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), format.colorize({ all: true }), format.printf((info) => {
|
|
38
|
+
const msg = typeof info.message === "object" ? JSON.stringify(info.message) : info.message;
|
|
39
|
+
const idPart = info.id ? ` : id: ${info.id}` : "";
|
|
40
|
+
return `${info.timestamp} [${this.serviceName}] ${info.level}: ${msg}${idPart}`;
|
|
31
41
|
}));
|
|
32
42
|
}
|
|
33
43
|
winston = winston.createLogger({
|
|
34
|
-
level:
|
|
44
|
+
level: "debug",
|
|
35
45
|
levels: customLevels,
|
|
36
46
|
transports: [
|
|
37
47
|
new winston.transports.Console({
|
|
@@ -42,6 +52,11 @@ export default class LoggerService {
|
|
|
42
52
|
constructor() {
|
|
43
53
|
winston.addColors(customColors);
|
|
44
54
|
}
|
|
55
|
+
runWithId = (id, callback) => {
|
|
56
|
+
const store = new Map();
|
|
57
|
+
store.set("correlationId", id);
|
|
58
|
+
LoggerService.storage.run(store, callback);
|
|
59
|
+
};
|
|
45
60
|
load = async (config) => {
|
|
46
61
|
this.serviceName = config?.serviceName || "service";
|
|
47
62
|
this.environment = config?.env || "dev";
|
|
@@ -51,7 +66,7 @@ export default class LoggerService {
|
|
|
51
66
|
loggerLevel: config?.loggerLevel || "debug"
|
|
52
67
|
});
|
|
53
68
|
const rawBrokers = config?.kafkaBrokers;
|
|
54
|
-
const brokers = rawBrokers ? String(rawBrokers).split(
|
|
69
|
+
const brokers = rawBrokers ? String(rawBrokers).split(",").map((b) => b.trim()) : [];
|
|
55
70
|
if (brokers.length > 0) {
|
|
56
71
|
const kafka = new Kafka({
|
|
57
72
|
clientId: this.serviceName,
|
|
@@ -67,7 +82,7 @@ export default class LoggerService {
|
|
|
67
82
|
this.kafkaProducer = kafka.producer({ createPartitioner: Partitioners.LegacyPartitioner });
|
|
68
83
|
const connectWithRetry = async () => {
|
|
69
84
|
try {
|
|
70
|
-
await this.kafkaProducer
|
|
85
|
+
await this.kafkaProducer?.connect();
|
|
71
86
|
this.isKafkaReady = true;
|
|
72
87
|
}
|
|
73
88
|
catch (err) {
|
|
@@ -80,7 +95,7 @@ export default class LoggerService {
|
|
|
80
95
|
};
|
|
81
96
|
winstonLoader = ({ loadPath, loggerLevel }) => {
|
|
82
97
|
const { combine, timestamp, json, errors } = format;
|
|
83
|
-
const jsonFileFormat = combine(timestamp({ format:
|
|
98
|
+
const jsonFileFormat = combine(this.getTracingFormat(), timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), errors({ stack: true }), json());
|
|
84
99
|
const winstonLogger = winston.createLogger({
|
|
85
100
|
level: loggerLevel,
|
|
86
101
|
levels: customLevels,
|
|
@@ -89,22 +104,22 @@ export default class LoggerService {
|
|
|
89
104
|
format: this.getConsoleFormat()
|
|
90
105
|
}),
|
|
91
106
|
new winston.transports.DailyRotateFile({
|
|
92
|
-
filename: path.resolve(loadPath,
|
|
93
|
-
level:
|
|
107
|
+
filename: path.resolve(loadPath, "error", "%DATE%_error.log"),
|
|
108
|
+
level: "error",
|
|
94
109
|
format: jsonFileFormat,
|
|
95
|
-
maxSize:
|
|
96
|
-
maxFiles:
|
|
110
|
+
maxSize: "2mb",
|
|
111
|
+
maxFiles: "7d"
|
|
97
112
|
}),
|
|
98
113
|
new winston.transports.DailyRotateFile({
|
|
99
|
-
filename: path.resolve(loadPath,
|
|
100
|
-
level:
|
|
114
|
+
filename: path.resolve(loadPath, "critical", "%DATE%_critical.log"),
|
|
115
|
+
level: "critical",
|
|
101
116
|
format: jsonFileFormat,
|
|
102
|
-
maxSize:
|
|
103
|
-
maxFiles:
|
|
117
|
+
maxSize: "2mb",
|
|
118
|
+
maxFiles: "14d"
|
|
104
119
|
})
|
|
105
120
|
]
|
|
106
121
|
});
|
|
107
|
-
winstonLogger.on(
|
|
122
|
+
winstonLogger.on("data", (info) => {
|
|
108
123
|
if (this.isKafkaReady) {
|
|
109
124
|
this.logToKafka(info);
|
|
110
125
|
}
|
|
@@ -120,9 +135,10 @@ export default class LoggerService {
|
|
|
120
135
|
topic: this.kafkaTopic,
|
|
121
136
|
messages: [{
|
|
122
137
|
value: JSON.stringify({
|
|
123
|
-
...info,
|
|
124
138
|
service: this.serviceName,
|
|
139
|
+
id: info.id || null,
|
|
125
140
|
env: this.environment,
|
|
141
|
+
...info,
|
|
126
142
|
timestamp: new Date().toISOString()
|
|
127
143
|
})
|
|
128
144
|
}]
|
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
import winston from
|
|
2
|
-
import
|
|
1
|
+
import winston from "winston";
|
|
2
|
+
import "winston-daily-rotate-file";
|
|
3
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
4
|
interface CustomLogger extends winston.Logger {
|
|
4
5
|
critical: winston.LeveledLogMethod;
|
|
5
6
|
http: winston.LeveledLogMethod;
|
|
6
7
|
}
|
|
7
8
|
export default class LoggerService {
|
|
9
|
+
static readonly storage: AsyncLocalStorage<Map<string, string>>;
|
|
8
10
|
private serviceName;
|
|
9
11
|
private environment;
|
|
10
12
|
private kafkaProducer;
|
|
11
13
|
private kafkaTopic;
|
|
12
14
|
private isKafkaReady;
|
|
15
|
+
private getTracingFormat;
|
|
13
16
|
private getConsoleFormat;
|
|
14
17
|
winston: CustomLogger;
|
|
15
18
|
constructor();
|
|
19
|
+
runWithId: (id: string, callback: () => void) => void;
|
|
16
20
|
load: (config: Record<string, any>) => Promise<void>;
|
|
17
21
|
winstonLoader: ({ loadPath, loggerLevel }: {
|
|
18
22
|
loadPath: string;
|
|
@@ -1,37 +1,47 @@
|
|
|
1
|
-
import winston, { format } from
|
|
2
|
-
import
|
|
3
|
-
import path from
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import winston, { format } from "winston";
|
|
2
|
+
import "winston-daily-rotate-file";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
|
+
import { Kafka, Partitioners, logLevel } from "kafkajs";
|
|
6
|
+
import { LoggerLayerEnum } from "../../utils";
|
|
6
7
|
const customLevels = {
|
|
7
|
-
critical: LoggerLayerEnum.CRITICAL,
|
|
8
|
-
error: LoggerLayerEnum.ERROR,
|
|
9
|
-
info: LoggerLayerEnum.INFO,
|
|
10
|
-
http: LoggerLayerEnum.HTTP,
|
|
11
|
-
debug: LoggerLayerEnum.DEBUG,
|
|
8
|
+
critical: LoggerLayerEnum.CRITICAL,
|
|
9
|
+
error: LoggerLayerEnum.ERROR,
|
|
10
|
+
info: LoggerLayerEnum.INFO,
|
|
11
|
+
http: LoggerLayerEnum.HTTP,
|
|
12
|
+
debug: LoggerLayerEnum.DEBUG,
|
|
12
13
|
};
|
|
13
14
|
const customColors = {
|
|
14
|
-
critical:
|
|
15
|
-
error:
|
|
16
|
-
warn:
|
|
17
|
-
info:
|
|
18
|
-
http:
|
|
19
|
-
debug:
|
|
15
|
+
critical: "red",
|
|
16
|
+
error: "magenta",
|
|
17
|
+
warn: "yellow",
|
|
18
|
+
info: "green",
|
|
19
|
+
http: "cyan",
|
|
20
|
+
debug: "blue"
|
|
20
21
|
};
|
|
21
22
|
export default class LoggerService {
|
|
23
|
+
static storage = new AsyncLocalStorage();
|
|
22
24
|
serviceName = "";
|
|
23
25
|
environment = "";
|
|
24
26
|
kafkaProducer = null;
|
|
25
27
|
kafkaTopic = "";
|
|
26
28
|
isKafkaReady = false;
|
|
29
|
+
getTracingFormat = format((info) => {
|
|
30
|
+
const store = LoggerService.storage.getStore();
|
|
31
|
+
if (store) {
|
|
32
|
+
info.id = store.get("correlationId");
|
|
33
|
+
}
|
|
34
|
+
return info;
|
|
35
|
+
});
|
|
27
36
|
getConsoleFormat() {
|
|
28
|
-
return format.combine(format.timestamp({ format:
|
|
29
|
-
const msg = typeof info.message ===
|
|
30
|
-
|
|
37
|
+
return format.combine(this.getTracingFormat(), format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), format.colorize({ all: true }), format.printf((info) => {
|
|
38
|
+
const msg = typeof info.message === "object" ? JSON.stringify(info.message) : info.message;
|
|
39
|
+
const idPart = info.id ? ` : id: ${info.id}` : "";
|
|
40
|
+
return `${info.timestamp} [${this.serviceName}] ${info.level}: ${msg}${idPart}`;
|
|
31
41
|
}));
|
|
32
42
|
}
|
|
33
43
|
winston = winston.createLogger({
|
|
34
|
-
level:
|
|
44
|
+
level: "debug",
|
|
35
45
|
levels: customLevels,
|
|
36
46
|
transports: [
|
|
37
47
|
new winston.transports.Console({
|
|
@@ -42,6 +52,11 @@ export default class LoggerService {
|
|
|
42
52
|
constructor() {
|
|
43
53
|
winston.addColors(customColors);
|
|
44
54
|
}
|
|
55
|
+
runWithId = (id, callback) => {
|
|
56
|
+
const store = new Map();
|
|
57
|
+
store.set("correlationId", id);
|
|
58
|
+
LoggerService.storage.run(store, callback);
|
|
59
|
+
};
|
|
45
60
|
load = async (config) => {
|
|
46
61
|
this.serviceName = config?.serviceName || "service";
|
|
47
62
|
this.environment = config?.env || "dev";
|
|
@@ -51,7 +66,7 @@ export default class LoggerService {
|
|
|
51
66
|
loggerLevel: config?.loggerLevel || "debug"
|
|
52
67
|
});
|
|
53
68
|
const rawBrokers = config?.kafkaBrokers;
|
|
54
|
-
const brokers = rawBrokers ? String(rawBrokers).split(
|
|
69
|
+
const brokers = rawBrokers ? String(rawBrokers).split(",").map((b) => b.trim()) : [];
|
|
55
70
|
if (brokers.length > 0) {
|
|
56
71
|
const kafka = new Kafka({
|
|
57
72
|
clientId: this.serviceName,
|
|
@@ -67,7 +82,7 @@ export default class LoggerService {
|
|
|
67
82
|
this.kafkaProducer = kafka.producer({ createPartitioner: Partitioners.LegacyPartitioner });
|
|
68
83
|
const connectWithRetry = async () => {
|
|
69
84
|
try {
|
|
70
|
-
await this.kafkaProducer
|
|
85
|
+
await this.kafkaProducer?.connect();
|
|
71
86
|
this.isKafkaReady = true;
|
|
72
87
|
}
|
|
73
88
|
catch (err) {
|
|
@@ -80,7 +95,7 @@ export default class LoggerService {
|
|
|
80
95
|
};
|
|
81
96
|
winstonLoader = ({ loadPath, loggerLevel }) => {
|
|
82
97
|
const { combine, timestamp, json, errors } = format;
|
|
83
|
-
const jsonFileFormat = combine(timestamp({ format:
|
|
98
|
+
const jsonFileFormat = combine(this.getTracingFormat(), timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), errors({ stack: true }), json());
|
|
84
99
|
const winstonLogger = winston.createLogger({
|
|
85
100
|
level: loggerLevel,
|
|
86
101
|
levels: customLevels,
|
|
@@ -89,22 +104,22 @@ export default class LoggerService {
|
|
|
89
104
|
format: this.getConsoleFormat()
|
|
90
105
|
}),
|
|
91
106
|
new winston.transports.DailyRotateFile({
|
|
92
|
-
filename: path.resolve(loadPath,
|
|
93
|
-
level:
|
|
107
|
+
filename: path.resolve(loadPath, "error", "%DATE%_error.log"),
|
|
108
|
+
level: "error",
|
|
94
109
|
format: jsonFileFormat,
|
|
95
|
-
maxSize:
|
|
96
|
-
maxFiles:
|
|
110
|
+
maxSize: "2mb",
|
|
111
|
+
maxFiles: "7d"
|
|
97
112
|
}),
|
|
98
113
|
new winston.transports.DailyRotateFile({
|
|
99
|
-
filename: path.resolve(loadPath,
|
|
100
|
-
level:
|
|
114
|
+
filename: path.resolve(loadPath, "critical", "%DATE%_critical.log"),
|
|
115
|
+
level: "critical",
|
|
101
116
|
format: jsonFileFormat,
|
|
102
|
-
maxSize:
|
|
103
|
-
maxFiles:
|
|
117
|
+
maxSize: "2mb",
|
|
118
|
+
maxFiles: "14d"
|
|
104
119
|
})
|
|
105
120
|
]
|
|
106
121
|
});
|
|
107
|
-
winstonLogger.on(
|
|
122
|
+
winstonLogger.on("data", (info) => {
|
|
108
123
|
if (this.isKafkaReady) {
|
|
109
124
|
this.logToKafka(info);
|
|
110
125
|
}
|
|
@@ -120,9 +135,10 @@ export default class LoggerService {
|
|
|
120
135
|
topic: this.kafkaTopic,
|
|
121
136
|
messages: [{
|
|
122
137
|
value: JSON.stringify({
|
|
123
|
-
...info,
|
|
124
138
|
service: this.serviceName,
|
|
139
|
+
id: info.id || null,
|
|
125
140
|
env: this.environment,
|
|
141
|
+
...info,
|
|
126
142
|
timestamp: new Date().toISOString()
|
|
127
143
|
})
|
|
128
144
|
}]
|