@cley_faye/boilerplate 3.9.0 → 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.
@@ -1,9 +1,11 @@
1
1
  import expressWinston, { BaseLoggerOptions } from "express-winston";
2
2
  import { Request, Router } from "express";
3
3
  import { LogOptions, UserFromReqFunc } from "./pipelinebuilder.js";
4
- export declare type LoggerOptions = expressWinston.LoggerOptions | boolean;
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 {
@@ -16,7 +18,7 @@ export interface RequestWithLoggingData extends Request {
16
18
  };
17
19
  }
18
20
  /** Return the default value for route logger is it is set as `true` */
19
- export declare const defaultRouteLoggerConfig: (userFromReq?: UserFromReqFunc | undefined) => BaseLoggerOptions;
20
- export declare const registerRouteLogger: (app: Router, logOptions?: LogOptions | undefined) => void;
21
- export declare const registerErrorLogger: (app: Router, logOptions?: LogOptions | undefined) => void;
21
+ export declare const defaultRouteLoggerConfig: (userFromReq?: UserFromReqFunc) => BaseLoggerOptions;
22
+ export declare const registerRouteLogger: (app: Router, logOptions?: LogOptions) => void;
23
+ export declare const registerErrorLogger: (app: Router, logOptions?: LogOptions) => void;
22
24
  export {};
@@ -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: winston_1.default.format.combine(winston_1.default.format.errors(), winston_1.default.format.colorize(), customErrorFormat(timestamp, config)),
117
+ format: (0, winston_js_1.customFormat)(timestamp, config.collapseStacktrace ?? config.collapseNodeModules),
128
118
  meta: false,
129
119
  }));
130
120
  }
@@ -6,4 +6,4 @@ export interface ExtraLoggingOptions {
6
6
  /** Do not expose the "hidden" body props */
7
7
  noHiddenBodyProps?: boolean;
8
8
  }
9
- export declare const bodyLogger: (bodyProps?: string[] | undefined, extraLoggingData?: ExtraLoggingData | undefined, options?: ExtraLoggingOptions) => (req: Request, res: Response, next: NextFunction) => void;
9
+ export declare const bodyLogger: (bodyProps?: Array<string>, extraLoggingData?: ExtraLoggingData, options?: ExtraLoggingOptions) => (req: Request, res: Response, next: NextFunction) => void;
@@ -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/express.d.ts CHANGED
@@ -99,11 +99,11 @@ import { PipelineSettings, LogFunction } from "./express/pipelinebuilder.js";
99
99
  * @return
100
100
  * The returned object can be used
101
101
  */
102
- export declare const createPipeline: (settings: PipelineSettings, debugLog?: LogFunction | undefined) => express.Router;
102
+ export declare const createPipeline: (settings: PipelineSettings, debugLog?: LogFunction) => express.Router;
103
103
  /**
104
104
  * Configure the views rendering engine for an ExpressJS App
105
105
  */
106
- export declare const setViewEngine: (app: express.Express, viewEngine: string, viewsDirectory: string, extraLocals?: Record<string, string | number> | undefined) => void;
106
+ export declare const setViewEngine: (app: express.Express, viewEngine: string, viewsDirectory: string, extraLocals?: Record<string, string | number>) => void;
107
107
  export interface StartDefinition {
108
108
  app: express.Application;
109
109
  /** @deprecated use listenInterface instead */
@@ -85,7 +85,7 @@ export declare type HandlerFunction = (gruntConfig: GruntConfig, targetName: str
85
85
  * @return
86
86
  * List of tasks to build the application
87
87
  */
88
- export declare const reactApp: (gruntConfig: GruntConfig, targetName?: string, options?: ReactAppOptions | undefined) => Array<string>;
88
+ export declare const reactApp: (gruntConfig: GruntConfig, targetName?: string, options?: ReactAppOptions) => Array<string>;
89
89
  export interface HelperOptions {
90
90
  production?: boolean;
91
91
  watch?: boolean | number;
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 all lines containing /node_modules/ into an ellipsis
4
+ * Collapse useless lines in stacktrace
4
5
  */
5
- export declare const filterNodeModules: (message: string) => Generator<string>;
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.filterNodeModules = void 0;
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 = 19;
35
+ const LOG_LEVEL_PADDING_SIZE = 10;
36
+ const stackFilterRegex = /(?:at process|at runMicrotasks)/u;
36
37
  /**
37
- * Collapse all lines containing /node_modules/ into an ellipsis
38
+ * Collapse useless lines in stacktrace
38
39
  */
39
- const filterNodeModules = function* (message) {
40
- let inNodeModules = false;
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 (/\/node_modules\//u.exec(line)) {
44
- if (!inNodeModules) {
45
- inNodeModules = true;
44
+ if (stackFilterRegex.exec(line)) {
45
+ if (!inCollapse) {
46
+ inCollapse = true;
46
47
  yield "[...]";
47
48
  }
48
49
  }
49
50
  else {
50
- inNodeModules = false;
51
+ inCollapse = false;
51
52
  yield line;
52
53
  }
53
54
  }
54
55
  };
55
- exports.filterNodeModules = filterNodeModules;
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
- return message.split("\n").map(line => `${timestampPrefix}${levelPrefix}${line}`)
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 customFormat = winston_1.default.format.printf((info) => {
73
- const message = ("stack" in info) ? info.stack : info.message;
74
- const filteredMessage = logConfig.collapseNodeModules
75
- ? [...(0, exports.filterNodeModules)(message)].join("\n")
76
- : message;
77
- return (0, exports.prefixOutput)(info.level, filteredMessage, logConfig.timestamp);
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: winston_1.default.format.combine(winston_1.default.format.colorize(), customFormat),
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.9.0",
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.7.1",
21
- "@types/express": "^4.17.11",
22
- "@types/grunt": "^0.4.25",
23
- "@types/http-errors": "^1.8.0",
24
- "@types/node": "^16.0.0",
25
- "@typescript-eslint/eslint-plugin": "^5.12.0",
26
- "@typescript-eslint/parser": "^5.12.0",
27
- "eslint": "^8.7.0",
28
- "eslint-plugin-import": "^2.25.4",
29
- "eslint-plugin-promise": "^6.0.0",
30
- "eslint-webpack-plugin": "^3.0.1",
31
- "express-winston": "^4.0.5",
32
- "grunt": "^1.4.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.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.3.2",
38
- "typescript": "^4.1.5",
39
- "winston": "^3.3.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.1.1",
58
+ "resolve-typescript-plugin": "^1.2.0",
59
59
  "sass": "1.x",
60
- "ts-loader": "^9.2.6",
60
+ "ts-loader": "^9.4.0",
61
61
  "winston": "3.x"
62
62
  },
63
63
  "peerDependenciesMeta": {