@emartech/json-logger 9.0.1 → 9.2.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 CHANGED
@@ -193,6 +193,8 @@ The separate steps of the logging process can be configured here.
193
193
  These modifications affect all the instances of the library.
194
194
  With transformers we can alter the data to be logged before passing to the formatter and then to the output.
195
195
  It is a perfect place to add the name of the machine is running on or the request id associated with the current thread stored on a continuation local storage.
196
+ With the 'enhancedStackTrace' option set to true, the error stack traces will include the causes of the errors as well (if any) including their stack traces
197
+ with a significantly improved truncation limit.
196
198
 
197
199
  ```javascript
198
200
  const { createLogger } = require('@emartech/json-logger');
@@ -201,7 +203,8 @@ createLogger.configure({
201
203
  formatter: JSON.stringify,
202
204
  output: console.log,
203
205
  transformers: [],
204
- outputFormat: 'ecs'
206
+ outputFormat: 'ecs',
207
+ enhancedStackTrace: true
205
208
  });
206
209
 
207
210
  ```
@@ -4,6 +4,7 @@ export interface LoggerConfig {
4
4
  output: Function;
5
5
  transformers: Function[];
6
6
  outputFormat: string;
7
+ enhancedStackTrace: boolean;
7
8
  }
8
9
  export declare class Logger {
9
10
  private readonly namespace;
@@ -29,5 +30,6 @@ export declare class Logger {
29
30
  private shortenData;
30
31
  private getErrorDetails;
31
32
  private getBaseErrorDetails;
33
+ private getEnhancedStackTrace;
32
34
  private getAxiosErrorDetails;
33
35
  }
@@ -7,8 +7,9 @@ const json_1 = require("../formatter/json");
7
7
  const console_1 = require("../output/console");
8
8
  const timer_1 = require("../timer/timer");
9
9
  const STACK_TRACE_LIMIT = 3000;
10
+ const ENHANCED_STACK_TRACE_LIMIT = 15000;
10
11
  const DATA_LIMIT = 3000;
11
- const allowedKeys = ['output', 'formatter', 'transformers', 'outputFormat'];
12
+ const allowedKeys = ['output', 'formatter', 'transformers', 'outputFormat', 'enhancedStackTrace'];
12
13
  /* eslint-enable @typescript-eslint/no-unsafe-function-type */
13
14
  class Logger {
14
15
  namespace;
@@ -33,6 +34,7 @@ class Logger {
33
34
  output: console_1.consoleOutput,
34
35
  transformers: [],
35
36
  outputFormat: 'ecs',
37
+ enhancedStackTrace: false,
36
38
  };
37
39
  isEnabled() {
38
40
  return this.enabled;
@@ -117,26 +119,83 @@ class Logger {
117
119
  return (0, lodash_1.merge)(this.getBaseErrorDetails(error), this.getAxiosErrorDetails(error));
118
120
  }
119
121
  getBaseErrorDetails(error) {
122
+ const shortenedData = this.shortenData(error.data);
120
123
  if (Logger.config.outputFormat === 'legacy') {
121
124
  return {
122
125
  error_name: error.name,
123
126
  error_stack: this.shortenStackTrace(error.stack || ''),
124
127
  error_message: error.message,
125
- error_data: this.shortenData(error.data),
128
+ error_data: shortenedData,
126
129
  };
127
130
  }
131
+ const stackTrace = Logger.config.enhancedStackTrace
132
+ ? this.getEnhancedStackTrace(error)
133
+ : this.shortenStackTrace(error.stack || '');
128
134
  return {
129
135
  error: {
130
136
  type: error.name,
131
137
  message: error.message,
132
- context: this.shortenData(error.data),
133
- stack_trace: this.shortenStackTrace(error.stack || ''),
138
+ ...(shortenedData && { context: shortenedData }),
139
+ stack_trace: stackTrace,
134
140
  },
135
141
  event: {
136
142
  reason: error.message,
137
143
  },
138
144
  };
139
145
  }
146
+ getEnhancedStackTrace(error) {
147
+ const getNumberOfCommonFrames = (ownTrace, enclosingTrace) => {
148
+ let m = ownTrace.length - 1;
149
+ let n = enclosingTrace.length - 1;
150
+ while (m > 0 && n > 0 && ownTrace[m] === enclosingTrace[n]) {
151
+ m--;
152
+ n--;
153
+ }
154
+ return ownTrace.length - 1 - m;
155
+ };
156
+ const getEnclosedStackTrace = (error, enclosingTrace, caption) => {
157
+ const output = [];
158
+ let errorName;
159
+ let errorStack;
160
+ const errorStackLines = error.stack ? error.stack.split('\n') : [];
161
+ const firstLine = errorStackLines.at(0);
162
+ if (error.stack) {
163
+ if (firstLine?.includes(error.name)) {
164
+ errorName = firstLine;
165
+ errorStack = errorStackLines.slice(1);
166
+ }
167
+ else {
168
+ errorName = error.name;
169
+ errorStack = errorStackLines;
170
+ }
171
+ }
172
+ else {
173
+ errorName = error.name;
174
+ errorStack = [];
175
+ }
176
+ const commonFrames = getNumberOfCommonFrames(errorStack, enclosingTrace);
177
+ const uniqueFrames = errorStack.length - commonFrames;
178
+ output.push(caption + errorName);
179
+ errorStack.slice(0, uniqueFrames).forEach((line) => output.push(line));
180
+ if (commonFrames > 0) {
181
+ output.push(`\t... ${commonFrames} more`);
182
+ }
183
+ if (error.cause instanceof Error) {
184
+ output.push(...getEnclosedStackTrace(error.cause, errorStackLines, 'Caused by: '));
185
+ }
186
+ return output;
187
+ };
188
+ const stackTrace = getEnclosedStackTrace(error, [], '');
189
+ const joinedStackTrace = stackTrace.join('\n');
190
+ let resultStackTraceStr;
191
+ if (joinedStackTrace.length > ENHANCED_STACK_TRACE_LIMIT) {
192
+ resultStackTraceStr = joinedStackTrace.substring(0, ENHANCED_STACK_TRACE_LIMIT) + ' ...';
193
+ }
194
+ else {
195
+ resultStackTraceStr = joinedStackTrace;
196
+ }
197
+ return resultStackTraceStr;
198
+ }
140
199
  getAxiosErrorDetails(error) {
141
200
  if (!error.isAxiosError) {
142
201
  return {};
package/package.json CHANGED
@@ -9,8 +9,8 @@
9
9
  "scripts": {
10
10
  "test": "mocha --require ts-node/register --extension ts ./src --recursive",
11
11
  "test:watch": "mocha --require ts-node/register --extension ts ./src --recursive --watch",
12
- "lint": "eslint .",
13
- "lint:fix": "eslint . --fix",
12
+ "lint": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint .",
13
+ "lint:fix": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint . --fix",
14
14
  "build": "rm -rf dist && tsc --project ./tsconfig.json",
15
15
  "release": "CI=true semantic-release",
16
16
  "example-js": "DEBUG=* node examples/index-js.js",
@@ -42,17 +42,18 @@
42
42
  "lodash": "^4.17.21"
43
43
  },
44
44
  "devDependencies": {
45
- "@types/chai": "4.3.20",
45
+ "@types/chai": "5.2.2",
46
46
  "@types/lodash": "4.17.20",
47
47
  "@types/mocha": "10.0.10",
48
48
  "@types/node": "20.19.22",
49
49
  "@types/sinon": "17.0.4",
50
- "@types/sinon-chai": "3.2.12",
50
+ "@types/sinon-chai": "4.0.0",
51
51
  "@typescript-eslint/eslint-plugin": "8.46.1",
52
52
  "@typescript-eslint/parser": "8.46.1",
53
53
  "axios": "1.12.2",
54
- "chai": "4.5.0",
55
- "eslint": "8.57.1",
54
+ "chai": "6.2.0",
55
+ "cross-env": "10.1.0",
56
+ "eslint": "9.38.0",
56
57
  "eslint-config-emarsys": "5.1.0",
57
58
  "eslint-config-prettier": "10.1.8",
58
59
  "eslint-plugin-chai-friendly": "1.1.0",
@@ -63,9 +64,9 @@
63
64
  "prettier": "3.6.2",
64
65
  "semantic-release": "24.2.9",
65
66
  "sinon": "21.0.0",
66
- "sinon-chai": "3.7.0",
67
+ "sinon-chai": "4.0.1",
67
68
  "ts-node": "10.9.2",
68
69
  "typescript": "5.9.3"
69
70
  },
70
- "version": "9.0.1"
71
+ "version": "9.2.0"
71
72
  }