@cley_faye/boilerplate 3.9.1 → 3.10.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/lib/express/logger.d.ts +2 -0
- package/lib/express/logger.js +1 -11
- package/lib/express/pipelinebuilder.js +1 -0
- package/lib/winston.d.ts +6 -2
- package/lib/winston.js +121 -18
- package/package.json +20 -20
package/lib/express/logger.d.ts
CHANGED
|
@@ -3,7 +3,9 @@ import { Request, Router } from "express";
|
|
|
3
3
|
import { LogOptions, UserFromReqFunc } from "./pipelinebuilder.js";
|
|
4
4
|
export declare type LoggerOptions = expressWinston.BaseLoggerOptions | boolean;
|
|
5
5
|
interface ErrorLoggerConfiguration {
|
|
6
|
+
/** @deprecated Use collapseStacktrace */
|
|
6
7
|
collapseNodeModules?: boolean;
|
|
8
|
+
collapseStacktrace?: boolean;
|
|
7
9
|
}
|
|
8
10
|
export declare type ErrorLoggerOptions = ErrorLoggerConfiguration | boolean;
|
|
9
11
|
export interface LoggingData {
|
package/lib/express/logger.js
CHANGED
|
@@ -99,16 +99,6 @@ const registerRouteLogger = (app, logOptions) => {
|
|
|
99
99
|
}));
|
|
100
100
|
};
|
|
101
101
|
exports.registerRouteLogger = registerRouteLogger;
|
|
102
|
-
const customErrorFormat = (outputTimestamp, config) => {
|
|
103
|
-
const { collapseNodeModules } = config;
|
|
104
|
-
return winston_1.default.format.printf((info) => {
|
|
105
|
-
const meta = info.meta;
|
|
106
|
-
const finalMessage = collapseNodeModules
|
|
107
|
-
? [...(0, winston_js_1.filterNodeModules)(meta.message)].join("\n")
|
|
108
|
-
: meta.message;
|
|
109
|
-
return (0, winston_js_1.prefixOutput)(info.level, finalMessage, outputTimestamp);
|
|
110
|
-
});
|
|
111
|
-
};
|
|
112
102
|
const registerErrorLogger = (app, logOptions) => {
|
|
113
103
|
const { error, logger, timestamp } = logOptions ?? {};
|
|
114
104
|
const config = typeof error === "boolean"
|
|
@@ -124,7 +114,7 @@ const registerErrorLogger = (app, logOptions) => {
|
|
|
124
114
|
else {
|
|
125
115
|
app.use(express_winston_1.default.errorLogger({
|
|
126
116
|
transports: winston_js_1.transports,
|
|
127
|
-
format:
|
|
117
|
+
format: (0, winston_js_1.customFormat)(timestamp, config.collapseStacktrace ?? config.collapseNodeModules),
|
|
128
118
|
meta: false,
|
|
129
119
|
}));
|
|
130
120
|
}
|
|
@@ -106,6 +106,7 @@ class PipelineBuilder {
|
|
|
106
106
|
(0, winston_js_1.setConfig)({
|
|
107
107
|
timestamp: log.timestamp ?? false,
|
|
108
108
|
collapseNodeModules: errorConfig.collapseNodeModules ?? true,
|
|
109
|
+
collapseStacktrace: errorConfig.collapseStacktrace ?? true,
|
|
109
110
|
});
|
|
110
111
|
}
|
|
111
112
|
const router = express_1.default.Router();
|
package/lib/winston.d.ts
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import winston from "winston";
|
|
2
|
+
import { Format } from "logform";
|
|
2
3
|
/**
|
|
3
|
-
* Collapse
|
|
4
|
+
* Collapse useless lines in stacktrace
|
|
4
5
|
*/
|
|
5
|
-
export declare const
|
|
6
|
+
export declare const filterStacktrace: (message: string) => Generator<string>;
|
|
6
7
|
/**
|
|
7
8
|
* Prefix all lines with the level and the timestamp if needed
|
|
8
9
|
*/
|
|
9
10
|
export declare const prefixOutput: (level: string, message: string, timestamp: boolean | undefined) => string;
|
|
10
11
|
export interface LogConfig {
|
|
11
12
|
timestamp: boolean;
|
|
13
|
+
/** @deprecated Use collapseStacktrace instead */
|
|
12
14
|
collapseNodeModules: boolean;
|
|
15
|
+
collapseStacktrace: boolean;
|
|
13
16
|
}
|
|
17
|
+
export declare const customFormat: (timestamp?: boolean, collapseStacktrace?: boolean) => Format;
|
|
14
18
|
/** Edit the configuration applied to consoleLogger */
|
|
15
19
|
export declare const setConfig: (config: LogConfig) => void;
|
|
16
20
|
export declare const transports: winston.transports.ConsoleTransportInstance[];
|
package/lib/winston.js
CHANGED
|
@@ -29,30 +29,31 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
29
29
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
30
30
|
};
|
|
31
31
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
-
exports.consoleLogger = exports.transports = exports.setConfig = exports.prefixOutput = exports.
|
|
32
|
+
exports.consoleLogger = exports.transports = exports.setConfig = exports.customFormat = exports.prefixOutput = exports.filterStacktrace = void 0;
|
|
33
33
|
const winston_1 = __importDefault(require("winston"));
|
|
34
34
|
// High value because of colorize()
|
|
35
|
-
const LOG_LEVEL_PADDING_SIZE =
|
|
35
|
+
const LOG_LEVEL_PADDING_SIZE = 10;
|
|
36
|
+
const stackFilterRegex = /(?:at process|at runMicrotasks)/u;
|
|
36
37
|
/**
|
|
37
|
-
* Collapse
|
|
38
|
+
* Collapse useless lines in stacktrace
|
|
38
39
|
*/
|
|
39
|
-
const
|
|
40
|
-
let
|
|
40
|
+
const filterStacktrace = function* (message) {
|
|
41
|
+
let inCollapse = false;
|
|
41
42
|
const lines = message.split("\n");
|
|
42
43
|
for (const line of lines) {
|
|
43
|
-
if (
|
|
44
|
-
if (!
|
|
45
|
-
|
|
44
|
+
if (stackFilterRegex.exec(line)) {
|
|
45
|
+
if (!inCollapse) {
|
|
46
|
+
inCollapse = true;
|
|
46
47
|
yield "[...]";
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
else {
|
|
50
|
-
|
|
51
|
+
inCollapse = false;
|
|
51
52
|
yield line;
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
};
|
|
55
|
-
exports.
|
|
56
|
+
exports.filterStacktrace = filterStacktrace;
|
|
56
57
|
/**
|
|
57
58
|
* Prefix all lines with the level and the timestamp if needed
|
|
58
59
|
*/
|
|
@@ -61,21 +62,123 @@ const prefixOutput = (level, message, timestamp) => {
|
|
|
61
62
|
? `${new Date().toISOString()} `
|
|
62
63
|
: "";
|
|
63
64
|
const levelPrefix = `${level.toString().padStart(LOG_LEVEL_PADDING_SIZE)}: `;
|
|
64
|
-
|
|
65
|
+
const levelEmpty = `${" ".repeat(LOG_LEVEL_PADDING_SIZE)} `;
|
|
66
|
+
return message.split("\n").map((line, id) => `${timestampPrefix}${id === 0 ? levelPrefix : levelEmpty}${line}`)
|
|
65
67
|
.join("\n");
|
|
66
68
|
};
|
|
67
69
|
exports.prefixOutput = prefixOutput;
|
|
68
70
|
const logConfig = {
|
|
69
71
|
timestamp: true,
|
|
70
72
|
collapseNodeModules: true,
|
|
73
|
+
collapseStacktrace: true,
|
|
71
74
|
};
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
const indent = (msg, indentLevel) => {
|
|
76
|
+
if (indentLevel === 0)
|
|
77
|
+
return msg;
|
|
78
|
+
const indentList = [];
|
|
79
|
+
for (let i = 0; i < indentLevel;) {
|
|
80
|
+
++i;
|
|
81
|
+
const str = `${i}|`;
|
|
82
|
+
if (i < indentLevel) {
|
|
83
|
+
indentList.push(" ".repeat(str.length));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
indentList.push(str);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const indentStr = indentList.join("");
|
|
90
|
+
return msg.split("\n")
|
|
91
|
+
.map(c => `${indentStr} ${c.trimEnd()}`)
|
|
92
|
+
.join("\n");
|
|
93
|
+
};
|
|
94
|
+
/** Add context from axios */
|
|
95
|
+
const addAxiosContent = (error) => {
|
|
96
|
+
const res = [];
|
|
97
|
+
if (error.request?._currentUrl) {
|
|
98
|
+
res.push(`HTTP Request URL: ${error.request._currentUrl}`);
|
|
99
|
+
}
|
|
100
|
+
if (error.response?.data) {
|
|
101
|
+
res.push("HTTP Response body:");
|
|
102
|
+
if (typeof error.response.data === "string") {
|
|
103
|
+
res.push(error.response.data);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
try {
|
|
107
|
+
res.push(JSON.stringify(error.response.data));
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
try {
|
|
111
|
+
res.push(error.response.data.toString());
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
res.push("<cannot output body>");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (res.length === 0)
|
|
120
|
+
return;
|
|
121
|
+
return res.join("\n");
|
|
122
|
+
};
|
|
123
|
+
/** Add context from http-errors */
|
|
124
|
+
const addHttpErrorContent = (error) => {
|
|
125
|
+
if (error.statusCode === undefined)
|
|
126
|
+
return;
|
|
127
|
+
return `HttpError status: ${error.statusCode}`;
|
|
128
|
+
};
|
|
129
|
+
/** Return a string with the full error and stacktrace, including causes */
|
|
130
|
+
const filterError = (error, collapseStacktrace) => {
|
|
131
|
+
const resultRows = [];
|
|
132
|
+
let cursor = error;
|
|
133
|
+
let indentLevel = 0;
|
|
134
|
+
while (cursor) {
|
|
135
|
+
if (indentLevel === 0) {
|
|
136
|
+
resultRows.push(cursor.name);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
resultRows.push(indent(`Caused by: ${cursor.name}`, indentLevel));
|
|
140
|
+
}
|
|
141
|
+
resultRows.push(indent(cursor.message, indentLevel));
|
|
142
|
+
if (cursor.stack) {
|
|
143
|
+
if (collapseStacktrace) {
|
|
144
|
+
resultRows.push(indent([...(0, exports.filterStacktrace)(cursor.stack)].join("\n"), indentLevel));
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
resultRows.push(indent(cursor.stack, indentLevel));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const axiosContent = addAxiosContent(cursor);
|
|
151
|
+
if (axiosContent)
|
|
152
|
+
resultRows.push(indent(axiosContent, indentLevel));
|
|
153
|
+
const httpErrorsContent = addHttpErrorContent(cursor);
|
|
154
|
+
if (httpErrorsContent)
|
|
155
|
+
resultRows.push(indent(httpErrorsContent, indentLevel));
|
|
156
|
+
cursor = cursor.cause;
|
|
157
|
+
++indentLevel;
|
|
158
|
+
}
|
|
159
|
+
return resultRows.join("\n");
|
|
160
|
+
};
|
|
161
|
+
const getErrorFromTransformable = (info) => {
|
|
162
|
+
if (info instanceof Error)
|
|
163
|
+
return info;
|
|
164
|
+
if (info.meta) {
|
|
165
|
+
const meta = info.meta;
|
|
166
|
+
if (meta.error && meta.error instanceof Error)
|
|
167
|
+
return meta.error;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
const customFormat = (timestamp, collapseStacktrace) => winston_1.default.format.printf((info) => {
|
|
171
|
+
const effectiveTimestamp = timestamp === undefined
|
|
172
|
+
? logConfig.timestamp
|
|
173
|
+
: timestamp;
|
|
174
|
+
const effectiveCollapse = collapseStacktrace === undefined
|
|
175
|
+
? logConfig.collapseNodeModules || logConfig.collapseStacktrace
|
|
176
|
+
: collapseStacktrace;
|
|
177
|
+
const error = getErrorFromTransformable(info);
|
|
178
|
+
const message = error ? filterError(error, effectiveCollapse) : info.message;
|
|
179
|
+
return (0, exports.prefixOutput)(info.level, message, effectiveTimestamp);
|
|
78
180
|
});
|
|
181
|
+
exports.customFormat = customFormat;
|
|
79
182
|
/** Edit the configuration applied to consoleLogger */
|
|
80
183
|
const setConfig = (config) => {
|
|
81
184
|
Object.assign(logConfig, config);
|
|
@@ -84,6 +187,6 @@ exports.setConfig = setConfig;
|
|
|
84
187
|
exports.transports = [new winston_1.default.transports.Console()];
|
|
85
188
|
exports.consoleLogger = winston_1.default.createLogger({
|
|
86
189
|
level: "info",
|
|
87
|
-
format:
|
|
190
|
+
format: (0, exports.customFormat)(),
|
|
88
191
|
transports: exports.transports,
|
|
89
192
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cley_faye/boilerplate",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"description": "Boilerplate code generator for generic projects",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,26 +17,26 @@
|
|
|
17
17
|
},
|
|
18
18
|
"homepage": "https://github.com/CleyFaye/boilerplate#readme",
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@keeex/eslint-config": "^1.
|
|
21
|
-
"@types/express": "^4.17.
|
|
22
|
-
"@types/grunt": "^0.4.
|
|
23
|
-
"@types/http-errors": "^1.8.
|
|
24
|
-
"@types/node": "^16.
|
|
25
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
26
|
-
"@typescript-eslint/parser": "^5.
|
|
27
|
-
"eslint": "^8.
|
|
28
|
-
"eslint-plugin-import": "^2.
|
|
29
|
-
"eslint-plugin-promise": "^6.0.
|
|
30
|
-
"eslint-webpack-plugin": "^3.0
|
|
31
|
-
"express-winston": "^4.0
|
|
32
|
-
"grunt": "^1.
|
|
20
|
+
"@keeex/eslint-config": "^1.8.2",
|
|
21
|
+
"@types/express": "^4.17.14",
|
|
22
|
+
"@types/grunt": "^0.4.27",
|
|
23
|
+
"@types/http-errors": "^1.8.2",
|
|
24
|
+
"@types/node": "^16.11.59",
|
|
25
|
+
"@typescript-eslint/eslint-plugin": "^5.38.0",
|
|
26
|
+
"@typescript-eslint/parser": "^5.38.0",
|
|
27
|
+
"eslint": "^8.23.1",
|
|
28
|
+
"eslint-plugin-import": "^2.26.0",
|
|
29
|
+
"eslint-plugin-promise": "^6.0.1",
|
|
30
|
+
"eslint-webpack-plugin": "^3.2.0",
|
|
31
|
+
"express-winston": "^4.2.0",
|
|
32
|
+
"grunt": "^1.5.3",
|
|
33
33
|
"grunt-banner": "^0.6.0",
|
|
34
|
-
"grunt-contrib-clean": "^2.0.
|
|
34
|
+
"grunt-contrib-clean": "^2.0.1",
|
|
35
35
|
"grunt-run": "^0.8.1",
|
|
36
36
|
"load-grunt-tasks": "^5.1.0",
|
|
37
|
-
"logform": "^2.
|
|
38
|
-
"typescript": "^4.
|
|
39
|
-
"winston": "^3.
|
|
37
|
+
"logform": "^2.4.2",
|
|
38
|
+
"typescript": "^4.8.3",
|
|
39
|
+
"winston": "^3.8.2"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@babel/core": "7.x",
|
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
"grunt-contrib-watch": "1.x",
|
|
56
56
|
"grunt-sass": "3.x",
|
|
57
57
|
"grunt-webpack": "5.x",
|
|
58
|
-
"resolve-typescript-plugin": "^1.
|
|
58
|
+
"resolve-typescript-plugin": "^1.2.0",
|
|
59
59
|
"sass": "1.x",
|
|
60
|
-
"ts-loader": "^9.
|
|
60
|
+
"ts-loader": "^9.4.0",
|
|
61
61
|
"winston": "3.x"
|
|
62
62
|
},
|
|
63
63
|
"peerDependenciesMeta": {
|