@mimik/sumologic-winston-logger 2.1.11 → 2.1.13

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.
@@ -0,0 +1,8 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npx mocha:*)",
5
+ "Bash(done)"
6
+ ]
7
+ }
8
+ }
package/.husky/pre-commit CHANGED
@@ -1,4 +1,2 @@
1
1
  #!/bin/sh
2
- . "$(dirname "$0")/_/husky.sh"
3
-
4
2
  npm run commit-ready
package/.husky/pre-push CHANGED
@@ -1,4 +1,2 @@
1
1
  #!/bin/sh
2
- . "$(dirname "$0")/_/husky.sh"
3
-
4
2
  npm run test
package/README.md CHANGED
@@ -11,7 +11,8 @@ The following environment variables are used to configure the logger:
11
11
  | LOG_LEVEL | Log level for the running instance | debug | |
12
12
  | CONSOLE_LEVEL | Console log level | debug | |
13
13
  | FILTER_FILE | Filename containing filter rules | null | |
14
- | EXIT_DELAY | Delay for flushing the transports and exiting | 2000 | in millisecond |
14
+ | FLUSH_EXIT_DELAY | Delay for flushing the transports and exiting | 2000 | in millisecond |
15
+ | FLUSH_EXIT_TIMEOUT | Timeout safety net in case flush never completes | 5000 | in millisecond |
15
16
  | NO_STACK | Whether to include call stacks in all log messages | yes | expected: yes/no |
16
17
  | LOG_MODE | Comma-separated list defining the log mode/backends | none | enum: awsS3, awsKinesis, sumologic, all, none |
17
18
 
@@ -52,12 +53,12 @@ If `LOG_MODE` includes `awsS3`, the following environment variables are required
52
53
  | S3_AWS_SECRET_ACCESS_KEY | AWS secret access key | | |
53
54
 
54
55
  When `LOG_MODE` is `none`, logs are written to the console only.
55
- When `LOG_MODE` is `all`, it is equivalent to `sumologic,awsS3`.
56
+ When `LOG_MODE` is `all`, it is equivalent to `sumologic,awsS3` (does not include `awsKinesis`).
56
57
 
57
58
  `SERVER_TYPE` and `SERVER_ID` are used to build the S3 filename and are included in the
58
59
  log payload for S3 and Kinesis.
59
- If `global.serverType` is set, it overrides `SERVER_TYPE`.
60
- If `global.serverId` is set, it overrides `SERVER_ID`.
60
+ If `globalThis.serverType` is set, it overrides `SERVER_TYPE`.
61
+ If `globalThis.serverId` is set, it overrides `SERVER_ID`.
61
62
 
62
63
  **Kind**: global function
63
64
  **Returns**: <code>object</code> - configuration - Logger configuration.
@@ -139,7 +140,7 @@ To find the values that you will apply the environment variables, `SUMO_LOGIC_EN
139
140
  The endpoint is the part of the url that ends with a slash. i.e.
140
141
  `https://endpoint1.collection.us2.sumologic.com/receiver/v1/http/`
141
142
 
142
- The collector code is the Base64 encrypted part of the URL that follows the last slash in the url.
143
+ The collector code is the Base64 encoded part of the URL that follows the last slash in the url.
143
144
 
144
145
  ### `FILTER_FILE` ###
145
146
 
@@ -162,7 +163,7 @@ Formatting of SumoLogic logs is handled by this module in the following ways:
162
163
 
163
164
 
164
165
  ### Logging Examples ###
165
- Listing 2 below show you how to declare a logger to run under ECMAScript 6 and then log using the various log levels supported by the Sumologic-Winston-Logger.
166
+ Listing 2 below shows you how to declare a logger to run under ECMAScript 6 and then log using the various log levels supported by the Sumologic-Winston-Logger.
166
167
 
167
168
  ``` javascript
168
169
  import logger from '@mimik/sumologic-winston-logger';
@@ -185,7 +186,7 @@ The log() method is also supported, and adds a level parameter in position 1.
185
186
 
186
187
  ### Tailing ###
187
188
 
188
- Trailing allows you to scroll through log output in real time. You can trail log data in SumoLogic.
189
+ Tailing allows you to scroll through log output in real time. You can trail log data in SumoLogic.
189
190
 
190
191
  To trail in SumoLogic go to Search > Live Tail in the SumoLogic user interface and enter `sourceCategory=<source category>` in the search bar, where `<source category>` is the log you want to trail. Then click, Run
191
192
 
@@ -194,7 +195,7 @@ To trail in SumoLogic go to Search > Live Tail in the SumoLogic user interface a
194
195
  |`sourceCategory=local/node/challengeAPI/logs`|
195
196
 
196
197
  ### Stack Trace ###
197
- All logging to `error()` are added the stack trace.
198
+ All calls to `error()` include the stack trace.
198
199
  All other log levels will include a line number and file name.
199
200
 
200
201
  ## License ##
@@ -76,7 +76,7 @@ To find the values that you will apply the environment variables, `SUMO_LOGIC_EN
76
76
  The endpoint is the part of the url that ends with a slash. i.e.
77
77
  `https://endpoint1.collection.us2.sumologic.com/receiver/v1/http/`
78
78
 
79
- The collector code is the Base64 encrypted part of the URL that follows the last slash in the url.
79
+ The collector code is the Base64 encoded part of the URL that follows the last slash in the url.
80
80
 
81
81
  ### `FILTER_FILE` ###
82
82
 
@@ -99,7 +99,7 @@ Formatting of SumoLogic logs is handled by this module in the following ways:
99
99
 
100
100
 
101
101
  ### Logging Examples ###
102
- Listing 2 below show you how to declare a logger to run under ECMAScript 6 and then log using the various log levels supported by the Sumologic-Winston-Logger.
102
+ Listing 2 below shows you how to declare a logger to run under ECMAScript 6 and then log using the various log levels supported by the Sumologic-Winston-Logger.
103
103
 
104
104
  ``` javascript
105
105
  import logger from '@mimik/sumologic-winston-logger';
@@ -122,7 +122,7 @@ The log() method is also supported, and adds a level parameter in position 1.
122
122
 
123
123
  ### Tailing ###
124
124
 
125
- Trailing allows you to scroll through log output in real time. You can trail log data in SumoLogic.
125
+ Tailing allows you to scroll through log output in real time. You can trail log data in SumoLogic.
126
126
 
127
127
  To trail in SumoLogic go to Search > Live Tail in the SumoLogic user interface and enter `sourceCategory=<source category>` in the search bar, where `<source category>` is the log you want to trail. Then click, Run
128
128
 
@@ -131,7 +131,7 @@ To trail in SumoLogic go to Search > Live Tail in the SumoLogic user interface a
131
131
  |`sourceCategory=local/node/challengeAPI/logs`|
132
132
 
133
133
  ### Stack Trace ###
134
- All logging to `error()` are added the stack trace.
134
+ All calls to `error()` include the stack trace.
135
135
  All other log levels will include a line number and file name.
136
136
 
137
137
  ## License ##
@@ -8,6 +8,7 @@ import {
8
8
  ENV_LOCAL,
9
9
  NONE_MODE,
10
10
  SUMOLOGIC,
11
+ isNil,
11
12
  } from '../lib/common.js';
12
13
  import process from 'node:process';
13
14
  import { readFileSync } from 'node:fs';
@@ -30,7 +31,8 @@ const DECIMAL = 10;
30
31
  * | LOG_LEVEL | Log level for the running instance | debug | |
31
32
  * | CONSOLE_LEVEL | Console log level | debug | |
32
33
  * | FILTER_FILE | Filename containing filter rules | null | |
33
- * | EXIT_DELAY | Delay for flushing the transports and exiting | 2000 | in millisecond |
34
+ * | FLUSH_EXIT_DELAY | Delay for flushing the transports and exiting | 2000 | in millisecond |
35
+ * | FLUSH_EXIT_TIMEOUT | Timeout safety net in case flush never completes | 5000 | in millisecond |
34
36
  * | NO_STACK | Whether to include call stacks in all log messages | yes | expected: yes/no |
35
37
  * | LOG_MODE | Comma-separated list defining the log mode/backends | none | enum: awsS3, awsKinesis, sumologic, all, none |
36
38
  *
@@ -71,12 +73,12 @@ const DECIMAL = 10;
71
73
  * | S3_AWS_SECRET_ACCESS_KEY | AWS secret access key | | |
72
74
  *
73
75
  * When `LOG_MODE` is `none`, logs are written to the console only.
74
- * When `LOG_MODE` is `all`, it is equivalent to `sumologic,awsS3`.
76
+ * When `LOG_MODE` is `all`, it is equivalent to `sumologic,awsS3` (does not include `awsKinesis`).
75
77
  *
76
78
  * `SERVER_TYPE` and `SERVER_ID` are used to build the S3 filename and are included in the
77
79
  * log payload for S3 and Kinesis.
78
- * If `global.serverType` is set, it overrides `SERVER_TYPE`.
79
- * If `global.serverId` is set, it overrides `SERVER_ID`.
80
+ * If `globalThis.serverType` is set, it overrides `SERVER_TYPE`.
81
+ * If `globalThis.serverId` is set, it overrides `SERVER_ID`.
80
82
  */
81
83
 
82
84
  const checkConfig = (config) => {
@@ -123,7 +125,8 @@ const configuration = {
123
125
  filter: {
124
126
  file: process.env.FILTER_FILE || null,
125
127
  },
126
- exitDelay: parseInt(process.env.EXIT_DELAY, DECIMAL) || 2000, // in millisecond
128
+ flushExitDelay: parseInt(process.env.FLUSH_EXIT_DELAY, DECIMAL) || 2000, // in millisecond
129
+ flushExitTimeout: parseInt(process.env.FLUSH_EXIT_TIMEOUT, DECIMAL) || 5000, // in millisecond
127
130
  noStack: process.env.NO_STACK || 'yes',
128
131
  };
129
132
  configuration.mode = checkMode(process.env.LOG_MODE) || [NONE_MODE];
@@ -150,8 +153,8 @@ if (configuration.mode.includes(AWS_KINESIS)) {
150
153
  },
151
154
  };
152
155
 
153
- if (process.env.KINESIS_AWS_ACCESS_KEY_ID !== undefined) configuration[AWS_KINESIS].accessKeyId = process.env.KINESIS_AWS_ACCESS_KEY_ID;
154
- if (process.env.KINESIS_AWS_SECRET_ACCESS_KEY !== undefined) configuration[AWS_KINESIS].secretAccessKey = process.env.KINESIS_AWS_SECRET_ACCESS_KEY;
156
+ if (!isNil(process.env.KINESIS_AWS_ACCESS_KEY_ID)) configuration[AWS_KINESIS].accessKeyId = process.env.KINESIS_AWS_ACCESS_KEY_ID;
157
+ if (!isNil(process.env.KINESIS_AWS_SECRET_ACCESS_KEY)) configuration[AWS_KINESIS].secretAccessKey = process.env.KINESIS_AWS_SECRET_ACCESS_KEY;
155
158
  }
156
159
  if (configuration.mode.includes(AWS_S3)) {
157
160
  configuration[AWS_S3] = {
@@ -162,8 +165,8 @@ if (configuration.mode.includes(AWS_S3)) {
162
165
  maxEvents: parseInt(process.env.S3_AWS_MAX_EVENTS, DECIMAL) || 1000,
163
166
  };
164
167
 
165
- if (process.env.S3_AWS_ACCESS_KEY_ID !== undefined) configuration[AWS_S3].accessKeyId = process.env.S3_AWS_ACCESS_KEY_ID;
166
- if (process.env.S3_AWS_SECRET_ACCESS_KEY !== undefined) configuration[AWS_S3].secretAccessKey = process.env.S3_AWS_SECRET_ACCESS_KEY;
168
+ if (!isNil(process.env.S3_AWS_ACCESS_KEY_ID)) configuration[AWS_S3].accessKeyId = process.env.S3_AWS_ACCESS_KEY_ID;
169
+ if (!isNil(process.env.S3_AWS_SECRET_ACCESS_KEY)) configuration[AWS_S3].secretAccessKey = process.env.S3_AWS_SECRET_ACCESS_KEY;
167
170
  }
168
171
  const { filter } = configuration;
169
172
  let filterConfig = [];
@@ -180,3 +183,4 @@ filter.config = filterConfig;
180
183
  checkConfig(configuration);
181
184
 
182
185
  export default configuration;
186
+ export { checkConfig, checkMode };
package/eslint.config.js CHANGED
@@ -17,7 +17,7 @@ const ALLOWED_CONSTANTS = [0, 1, -1];
17
17
 
18
18
  export default [
19
19
  {
20
- ignores: ['mochawesome-report/**', 'node_modules/**', 'dist/**'],
20
+ ignores: ['coverage/**', 'mochawesome-report/**', 'node_modules/**', 'dist/**'],
21
21
  },
22
22
  importPlugin.flatConfigs.recommended,
23
23
  stylistic.configs.recommended,
@@ -29,9 +29,8 @@ export default [
29
29
  languageOptions: {
30
30
  ecmaVersion: ECMA_VERSION,
31
31
  globals: {
32
+ ...globals.mocha,
32
33
  ...globals.nodeBuiltin,
33
- describe: 'readonly',
34
- it: 'readonly',
35
34
  },
36
35
  sourceType: 'module',
37
36
  },
@@ -50,7 +49,7 @@ export default [
50
49
  'init-declarations': ['off'],
51
50
  'linebreak-style': ['off'],
52
51
  'max-depth': ['error', MAX_DEPTH],
53
- 'max-len': 'off',
52
+ 'max-len': ['off'],
54
53
  'max-lines': ['warn', { max: MAX_LINES_IN_FILES, skipComments: true, skipBlankLines: true }],
55
54
  'max-lines-per-function': ['warn', { max: MAX_LINES_IN_FUNCTION, skipComments: true, skipBlankLines: true }],
56
55
  'max-params': ['error', MAX_FUNCTION_PARAMETERS],
@@ -63,7 +62,7 @@ export default [
63
62
  'no-undefined': ['off'],
64
63
  'one-var': ['error', 'never'],
65
64
  'processDoc/validate-document-env': ['error'],
66
- 'quotes': 'off',
65
+ 'quotes': ['off'],
67
66
  'sort-imports': ['error', { allowSeparatedGroups: true }],
68
67
  'sort-keys': ['error', 'asc', { caseSensitive: true, minKeys: MIN_KEYS_IN_OBJECT, natural: false, allowLineSeparatedGroups: true }],
69
68
  },
package/index.js CHANGED
@@ -115,11 +115,17 @@ logger.flushAndExit = (code) => {
115
115
  let awsS3Done = false;
116
116
  let awsKinesisDone = false;
117
117
 
118
- if (config.mode.includes(NONE_MODE)) return process.exit(code);
118
+ const doExit = () => {
119
+ clearTimeout(logger.safetyTimer);
120
+ process.exit(code);
121
+ };
122
+
123
+ if (config.mode.includes(NONE_MODE)) return doExit();
124
+ logger.safetyTimer = setTimeout(doExit, config.flushExitTimeout); // safety net in case flush never completes
119
125
  if (awsS3) {
120
126
  awsS3.flush(FLUSH_EXIT);
121
127
  awsS3.once(FLUSH_EXIT, () => {
122
- if ((!sumo || sumoDone) && (!awsKinesis || awsKinesisDone)) return process.exit(code);
128
+ if ((!sumo || sumoDone) && (!awsKinesis || awsKinesisDone)) return doExit();
123
129
  awsS3Done = true;
124
130
  return null;
125
131
  });
@@ -127,7 +133,7 @@ logger.flushAndExit = (code) => {
127
133
  if (sumo) {
128
134
  sumo.flush(FLUSH_EXIT);
129
135
  sumo.once(FLUSH_EXIT, () => {
130
- if ((!awsS3 || awsS3Done) && (!awsKinesis || awsKinesisDone)) return process.exit(code);
136
+ if ((!awsS3 || awsS3Done) && (!awsKinesis || awsKinesisDone)) return doExit();
131
137
  sumoDone = true;
132
138
  return null;
133
139
  });
@@ -135,7 +141,7 @@ logger.flushAndExit = (code) => {
135
141
  if (awsKinesis) {
136
142
  awsKinesis.flush(FLUSH_EXIT);
137
143
  awsKinesis.once(FLUSH_EXIT, () => {
138
- if ((!awsS3 || awsS3Done) && (!sumo || sumoDone)) return process.exit(code);
144
+ if ((!awsS3 || awsS3Done) && (!sumo || sumoDone)) return doExit();
139
145
  awsKinesisDone = true;
140
146
  return null;
141
147
  });
@@ -143,7 +149,7 @@ logger.flushAndExit = (code) => {
143
149
  return null;
144
150
  };
145
151
 
146
- setTimeout(flushing, config.exitDelay);
152
+ setTimeout(flushing, config.flushExitDelay);
147
153
  };
148
154
 
149
155
  logger.flush = () => {
@@ -180,7 +186,7 @@ logger.flush = () => {
180
186
  return null;
181
187
  };
182
188
 
183
- setTimeout(flushing, config.exitDelay);
189
+ setTimeout(flushing, config.flushExitDelay);
184
190
  };
185
191
 
186
192
  logger.LEVELS = ['error', 'warn', 'info', 'verbose', 'debug', 'silly'];
@@ -158,4 +158,8 @@ export default class AwsKinesis extends Transport {
158
158
  return this.flushEvent()
159
159
  .then(() => this.emit(type, { message: `logs ${type} to ${AWS_KINESIS}` }));
160
160
  }
161
+
162
+ close() {
163
+ clearInterval(this.time);
164
+ }
161
165
  };
@@ -245,4 +245,8 @@ export default class AwsS3 extends Transport {
245
245
  .then(() => this.flushTypeEvent())
246
246
  .then(() => this.emit(type, { message: `logs ${type} to ${AWS_S3}` }));
247
247
  }
248
+
249
+ close() {
250
+ clearInterval(this.time);
251
+ }
248
252
  };
package/lib/common.js CHANGED
@@ -34,8 +34,8 @@ const SYSTEM_ERROR = 500;
34
34
 
35
35
  const OK_RESPONSE = 200;
36
36
 
37
- const START_TIMEOUT = 30000; // in millisecond
38
- const FLUSH_TIMEOUT = 1000; // in millisecond
37
+ const TEST_START_TIMEOUT = 30000; // in millisecond
38
+ const TEST_FLUSH_TIMEOUT = 1000; // in millisecond
39
39
  const OK_EXIT = 0;
40
40
 
41
41
  const MEGA = 1048576; // 2^20 conversion to mega
@@ -53,6 +53,8 @@ const safeStringify = (obj) => {
53
53
  });
54
54
  };
55
55
 
56
+ const isNil = value => value === null || value === undefined;
57
+
56
58
  export {
57
59
  ALL_MODE,
58
60
  ALL_MODES,
@@ -65,7 +67,6 @@ export {
65
67
  ERROR,
66
68
  FLUSH,
67
69
  FLUSH_EXIT,
68
- FLUSH_TIMEOUT,
69
70
  INFO,
70
71
  LEVEL,
71
72
  LOG,
@@ -79,13 +80,15 @@ export {
79
80
  OTHER,
80
81
  PARTITION_KEY,
81
82
  SPLAT,
82
- START_TIMEOUT,
83
83
  SUMOLOGIC,
84
84
  SYSTEM_ERROR,
85
85
  TEAPOT_ERROR,
86
+ TEST_FLUSH_TIMEOUT,
87
+ TEST_START_TIMEOUT,
86
88
  UNAUTHORIZED_ERROR,
87
89
  UNKNOWN_TYPE,
88
90
  UNKNOWN_ID,
89
91
  WARN,
90
92
  safeStringify,
93
+ isNil,
91
94
  };
package/lib/formatLib.js CHANGED
@@ -20,7 +20,7 @@ const isReserved = (value) => {
20
20
 
21
21
  const stackInfo = format((origInfo, opts) => {
22
22
  const { env, noStack } = opts;
23
- const info = origInfo;
23
+ const info = { ...origInfo };
24
24
 
25
25
  if (info.level === 'error') {
26
26
  info.stackInfo = parseStack(new Error());
@@ -36,7 +36,7 @@ const stackInfo = format((origInfo, opts) => {
36
36
  });
37
37
 
38
38
  const correlationId = format((origInfo) => {
39
- const info = origInfo;
39
+ const info = { ...origInfo };
40
40
  const meta = info[SPLAT];
41
41
 
42
42
  if (meta && typeof meta[meta.length - INDEX_ADJUST] === 'string') {
@@ -58,7 +58,7 @@ const filterMeta = format((origInfo, opts) => {
58
58
  const { config } = opts;
59
59
  const info = { ...origInfo };
60
60
 
61
- const meta = info[SPLAT];
61
+ const meta = info[SPLAT] ? [...info[SPLAT]] : undefined;
62
62
  let target;
63
63
  let index;
64
64
 
package/lib/stackLib.js CHANGED
@@ -45,8 +45,8 @@ const parseStack = (newError) => {
45
45
  stackInfo.hash = createHash('sha256')
46
46
  .update(stackInfo.stack)
47
47
  .digest('hex');
48
- // this is a hash of the stacktrace for easier searching for the stacktrace
49
- // security of this is not a concern since stacktrace is also sent unencrypted
48
+ // this is a hash of the stack trace for easier searching for the stack trace
49
+ // security of this is not a concern since the stack trace is also sent unencrypted
50
50
  return stackInfo;
51
51
  };
52
52
 
@@ -48,9 +48,14 @@ export default class Sumo extends Transport {
48
48
  .catch((err) => {
49
49
  const { response } = err;
50
50
 
51
- const resp = { endpoint: this.endpoint, info, message: `could not log to ${SUMOLOGIC}` };
51
+ const resp = { endpoint: this.endpoint, data, message: `could not log to ${SUMOLOGIC}` };
52
52
 
53
- if (info && info[SPLAT] && Array.isArray(info[SPLAT])) [, resp.correlationId] = info[SPLAT];
53
+ if (data.correlationId) resp.correlationId = data.correlationId;
54
+ else if (data[SPLAT] && Array.isArray(data[SPLAT])) {
55
+ const last = data[SPLAT][data[SPLAT].length - 1];
56
+
57
+ if (typeof last === 'string') resp.correlationId = last;
58
+ }
54
59
  if (!response) {
55
60
  resp.error = { statusCode: SYSTEM_ERROR, code: err.code, message: err.message };
56
61
  return this.emit(WARN, resp);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mimik/sumologic-winston-logger",
3
- "version": "2.1.11",
3
+ "version": "2.1.13",
4
4
  "description": "Log wrapper for sumo, s3, kinesis and winston",
5
5
  "main": "./index.js",
6
6
  "type": "module",
@@ -31,9 +31,9 @@
31
31
  "url": "https://bitbucket.org/mimiktech/sumologic-winston-logger"
32
32
  },
33
33
  "dependencies": {
34
- "@mimik/lib-filters": "^2.0.6",
35
- "@aws-sdk/client-s3": "3.993.0",
36
- "@aws-sdk/client-kinesis": "3.993.0",
34
+ "@mimik/lib-filters": "^2.0.7",
35
+ "@aws-sdk/client-s3": "3.995.0",
36
+ "@aws-sdk/client-kinesis": "3.995.0",
37
37
  "@smithy/node-http-handler": "4.4.10",
38
38
  "axios": "1.13.5",
39
39
  "winston": "3.19.0",
@@ -42,8 +42,8 @@
42
42
  "devDependencies": {
43
43
  "@eslint/js": "9.39.2",
44
44
  "@mimik/eslint-plugin-document-env": "^2.0.8",
45
- "@mimik/request-helper": "^2.0.3",
46
- "@stylistic/eslint-plugin": "5.8.0",
45
+ "@mimik/request-helper": "^2.0.5",
46
+ "@stylistic/eslint-plugin": "5.9.0",
47
47
  "aws-sdk-client-mock": "4.1.0",
48
48
  "c8": "10.1.3",
49
49
  "chai": "6.2.2",
@@ -1,16 +1,16 @@
1
1
  import './testEnv.js';
2
+ import { KinesisClient, PutRecordsCommand } from '@aws-sdk/client-kinesis';
2
3
  import {
3
- FLUSH_TIMEOUT,
4
4
  NOT_FOUND_ERROR,
5
5
  OK_EXIT,
6
6
  OK_RESPONSE,
7
7
  SPLAT,
8
- START_TIMEOUT,
9
8
  SYSTEM_ERROR,
10
9
  TEAPOT_ERROR,
10
+ TEST_FLUSH_TIMEOUT,
11
+ TEST_START_TIMEOUT,
11
12
  UNAUTHORIZED_ERROR,
12
13
  } from '../lib/common.js';
13
- import { KinesisClient, PutRecordsCommand } from '@aws-sdk/client-kinesis';
14
14
  import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
15
15
  import { after, afterEach, before, beforeEach, describe, it } from 'mocha';
16
16
  import Sumo from '../lib/sumologicTransport.js';
@@ -23,6 +23,9 @@ import { setTimeout } from 'node:timers';
23
23
  import { should } from 'chai';
24
24
  import { stub } from 'sinon';
25
25
 
26
+ import { checkConfig, checkMode } from '../configuration/config.js';
27
+ import { parseStack } from '../lib/stackLib.js';
28
+
26
29
  const s3Mock = mockClient(S3Client);
27
30
  const kinesisMock = mockClient(KinesisClient);
28
31
 
@@ -36,38 +39,30 @@ const TEST_DELAY = 200;
36
39
  should();
37
40
 
38
41
  describe('sumologic-winston-logger Unit Tests', function LoggerTests() {
39
- this.timeout(START_TIMEOUT);
40
- it('Can log an debug message without a correlationId and info', (done) => {
41
- logger.debug('this is an debug statement');
42
- done();
42
+ this.timeout(TEST_START_TIMEOUT);
43
+ it('Can log a debug message without a correlationId and info', () => {
44
+ logger.debug('this is a debug statement');
43
45
  });
44
- it('Can log an error message without a correlationId and info', (done) => {
46
+ it('Can log an error message without a correlationId and info', () => {
45
47
  logger.error('this is an error statement');
46
- done();
47
48
  });
48
- it('Can log an error message without a correlationId', (done) => {
49
+ it('Can log an error message without a correlationId', () => {
49
50
  logger.error('this is an error statement', { error: new Error('this is an error') });
50
- done();
51
51
  });
52
- it('Can log a warning message with a correlationId', (done) => {
52
+ it('Can log a warning message with a correlationId', () => {
53
53
  logger.warn('this is a warning statement', { meta: 'data' }, correlationId);
54
- done();
55
54
  });
56
- it('Can log an info message', (done) => {
55
+ it('Can log an info message', () => {
57
56
  logger.info('this is an info statement', { meta: 'data' });
58
- done();
59
57
  });
60
- it('Can log a verbose message', (done) => {
58
+ it('Can log a verbose message', () => {
61
59
  logger.verbose('this is a verbose statement', 'an extra string', { meta: 'data' });
62
- done();
63
60
  });
64
- it('Can log a debug message with no object and no correlationId', (done) => {
61
+ it('Can log a debug message with no object and no correlationId', () => {
65
62
  logger.debug('this is a debug statement');
66
- done();
67
63
  });
68
- it('can flush logs', (done) => {
64
+ it('can flush logs', () => {
69
65
  logger.flush();
70
- done();
71
66
  });
72
67
  it('Can flush and exit', (done) => {
73
68
  logger.debug('this is a debug statement');
@@ -76,13 +71,14 @@ describe('sumologic-winston-logger Unit Tests', function LoggerTests() {
76
71
  done();
77
72
  });
78
73
  after(done => setTimeout(() => { // adding a delay to make sure that the flush is done
74
+ clearTimeout(logger.safetyTimer);
79
75
  process.exit.restore();
80
76
  done();
81
- }, FLUSH_TIMEOUT));
77
+ }, TEST_FLUSH_TIMEOUT));
82
78
  });
83
79
 
84
80
  describe('Sumologic transport', function SumoTests() {
85
- this.timeout(START_TIMEOUT);
81
+ this.timeout(TEST_START_TIMEOUT);
86
82
  let server;
87
83
  let port;
88
84
  let sumo;
@@ -110,6 +106,7 @@ describe('Sumologic transport', function SumoTests() {
110
106
  after(done => server.close(done));
111
107
 
112
108
  beforeEach(() => {
109
+ sumo.removeAllListeners();
113
110
  sumo.code = 'ok';
114
111
  sumo.endpoint = `http://localhost:${port}/logs/`;
115
112
  });
@@ -186,10 +183,22 @@ describe('Sumologic transport', function SumoTests() {
186
183
  });
187
184
  sumo.log({ level: 'info', message: 'test globalThis' });
188
185
  });
186
+
187
+ it('falls back to unknownServerId when globalThis.serverId is not set', (done) => {
188
+ globalThis.serverType = 'mSumoRemote';
189
+ sumo.code = '401';
190
+ sumo.once('warn', (resp) => {
191
+ resp.data.should.have.property('serverType', 'mSumoRemote');
192
+ resp.data.should.have.property('serverId', 'unknownServerId@clients');
193
+ delete globalThis.serverType;
194
+ done();
195
+ });
196
+ sumo.log({ level: 'info', message: 'test serverId fallback' });
197
+ });
189
198
  });
190
199
 
191
200
  describe('S3 transport', function S3Tests() {
192
- this.timeout(START_TIMEOUT);
201
+ this.timeout(TEST_START_TIMEOUT);
193
202
  beforeEach(() => s3Mock.resetHistory());
194
203
 
195
204
  it('sends info logs to S3', (done) => {
@@ -268,7 +277,7 @@ describe('S3 transport', function S3Tests() {
268
277
  });
269
278
 
270
279
  describe('S3 remote transport', function S3RemoteTests() {
271
- this.timeout(START_TIMEOUT);
280
+ this.timeout(TEST_START_TIMEOUT);
272
281
  beforeEach(() => s3Mock.resetHistory());
273
282
  before(() => {
274
283
  globalThis.serverType = 'mTestRemote';
@@ -319,7 +328,7 @@ describe('S3 remote transport', function S3RemoteTests() {
319
328
  });
320
329
 
321
330
  describe('S3 transport flush', function S3FlushTests() {
322
- this.timeout(START_TIMEOUT);
331
+ this.timeout(TEST_START_TIMEOUT);
323
332
  const HIGH_MAX = 999;
324
333
  let s3Transport;
325
334
  let originalMaxEvents;
@@ -411,7 +420,7 @@ describe('S3 transport flush', function S3FlushTests() {
411
420
  });
412
421
 
413
422
  describe('S3 transport error handling', function S3ErrorTests() {
414
- this.timeout(START_TIMEOUT);
423
+ this.timeout(TEST_START_TIMEOUT);
415
424
 
416
425
  afterEach(() => {
417
426
  s3Mock.reset();
@@ -442,7 +451,7 @@ describe('S3 transport error handling', function S3ErrorTests() {
442
451
  });
443
452
 
444
453
  describe('Circular reference handling', function CircularTests() {
445
- this.timeout(START_TIMEOUT);
454
+ this.timeout(TEST_START_TIMEOUT);
446
455
  beforeEach(() => {
447
456
  s3Mock.resetHistory();
448
457
  kinesisMock.resetHistory();
@@ -464,7 +473,7 @@ describe('Circular reference handling', function CircularTests() {
464
473
  });
465
474
 
466
475
  describe('Kinesis transport', function KinesisTests() {
467
- this.timeout(START_TIMEOUT);
476
+ this.timeout(TEST_START_TIMEOUT);
468
477
  beforeEach(() => kinesisMock.resetHistory());
469
478
 
470
479
  it('sends info logs to the info stream', (done) => {
@@ -499,3 +508,93 @@ describe('Kinesis transport', function KinesisTests() {
499
508
  }, TEST_DELAY);
500
509
  });
501
510
  });
511
+
512
+ describe('Transport close', function CloseTests() {
513
+ this.timeout(TEST_START_TIMEOUT);
514
+
515
+ it('clears the S3 interval timer on close', () => {
516
+ const s3Transport = logger.transports.find(tr => tr.name === 'awsS3');
517
+ (() => s3Transport.close()).should.not.throw();
518
+ });
519
+
520
+ it('clears the Kinesis interval timer on close', () => {
521
+ const kinesisTransport = logger.transports.find(tr => tr.name === 'awsKinesis');
522
+ (() => kinesisTransport.close()).should.not.throw();
523
+ });
524
+ });
525
+
526
+ describe('checkMode validation', function CheckModeTests() {
527
+ this.timeout(TEST_START_TIMEOUT);
528
+
529
+ it('returns null for undefined mode', () => {
530
+ should().equal(checkMode(undefined), null);
531
+ });
532
+
533
+ it('returns null for falsy mode', () => {
534
+ should().equal(checkMode(''), null);
535
+ });
536
+
537
+ it('returns array for a valid single mode', () => {
538
+ checkMode('awsS3').should.deep.equal(['awsS3']);
539
+ });
540
+
541
+ it('parses comma-separated modes', () => {
542
+ checkMode('awsS3, sumologic').should.deep.equal(['awsS3', 'sumologic']);
543
+ });
544
+
545
+ it('expands all mode to sumologic and awsS3', () => {
546
+ checkMode('all').should.deep.equal(['sumologic', 'awsS3']);
547
+ });
548
+
549
+ it('throws when none is combined with other modes', () => {
550
+ (() => checkMode('none, awsS3')).should.throw('Cannot have multiple modes');
551
+ });
552
+
553
+ it('throws for an invalid mode value', () => {
554
+ (() => checkMode('invalid')).should.throw('Invalid items in LOG_MODE');
555
+ });
556
+ });
557
+
558
+ describe('checkConfig validation', function CheckConfigTests() {
559
+ this.timeout(TEST_START_TIMEOUT);
560
+
561
+ it('does not throw for a fully defined config', () => {
562
+ (() => checkConfig({ key: 'value', nested: { count: 1 } })).should.not.throw();
563
+ });
564
+
565
+ it('throws for a config with undefined values', () => {
566
+ (() => checkConfig({ key: undefined })).should.throw('Missing values');
567
+ });
568
+
569
+ it('throws for a nested config with undefined values', () => {
570
+ (() => checkConfig({ nested: { key: undefined } })).should.throw('Missing values');
571
+ });
572
+ });
573
+
574
+ describe('parseStack', function ParseStackTests() {
575
+ this.timeout(TEST_START_TIMEOUT);
576
+
577
+ it('returns a stackInfo object for a valid error', () => {
578
+ const result = parseStack(new Error('test'));
579
+ should().exist(result);
580
+ result.should.have.property('method');
581
+ result.should.have.property('path');
582
+ result.should.have.property('line');
583
+ result.should.have.property('pos');
584
+ result.should.have.property('file');
585
+ result.should.have.property('stack');
586
+ result.should.have.property('hash');
587
+ });
588
+
589
+ it('produces a 64-character hex hash', () => {
590
+ const result = parseStack(new Error('test'));
591
+ should().exist(result);
592
+ result.hash.should.match(/^[a-f0-9]{64}$/u);
593
+ });
594
+
595
+ it('returns null when all stack frames are filtered out', () => {
596
+ const fakeError = { stack: 'Error\n at Object.<anonymous> (node_modules/winston/foo.js:1:1)' };
597
+ const result = parseStack(fakeError);
598
+ should().equal(result, null);
599
+ });
600
+ });
@@ -1,5 +1,5 @@
1
1
  import './testEnvProdFilter.js';
2
- import { FLUSH_TIMEOUT, OK_EXIT, START_TIMEOUT } from '../lib/common.js';
2
+ import { OK_EXIT, TEST_FLUSH_TIMEOUT, TEST_START_TIMEOUT } from '../lib/common.js';
3
3
  import { after, describe, it } from 'mocha';
4
4
  import { getCorrelationId } from '@mimik/request-helper';
5
5
  import logger from '../index.js';
@@ -59,19 +59,16 @@ const user = {
59
59
 
60
60
  should();
61
61
 
62
- describe('sumologic-winston-logger prod Unit Tests', function LoggerTests() {
63
- this.timeout(START_TIMEOUT);
64
- it('Changing the environment to prod to cover filters', (done) => {
62
+ describe('sumologic-winston-logger prod filter tests', function LoggerTests() {
63
+ this.timeout(TEST_START_TIMEOUT);
64
+ it('Changing the environment to prod to cover filters', () => {
65
65
  logger.info('this is an info statement on prod', { meta: 'data' });
66
- done();
67
66
  });
68
- it('Changing the environment to prod to cover filters and see filtered result', (done) => {
67
+ it('Changing the environment to prod to cover filters and see filtered result', () => {
69
68
  logger.info('this is an info statement on prod', { user }, correlationId);
70
- done();
71
69
  });
72
- it('Can log a debug statement without correlationId and info on production', (done) => {
70
+ it('Can log a debug statement without correlationId and info on production', () => {
73
71
  logger.debug('this is a debug statement');
74
- done();
75
72
  });
76
73
  it('Can flush and exit', (done) => {
77
74
  logger.debug('this is a debug statement');
@@ -80,7 +77,8 @@ describe('sumologic-winston-logger prod Unit Tests', function LoggerTests() {
80
77
  done();
81
78
  });
82
79
  after(done => setTimeout(() => { // adding a delay to make sure that the flush is done
80
+ clearTimeout(logger.safetyTimer);
83
81
  process.exit.restore();
84
82
  done();
85
- }, FLUSH_TIMEOUT));
83
+ }, TEST_FLUSH_TIMEOUT));
86
84
  });
package/test/testEnv.js CHANGED
@@ -10,12 +10,12 @@ import process from 'node:process';
10
10
  * | Env variable name | Description | Default | Comments |
11
11
  * | ----------------- | ----------- | ------- | -------- |
12
12
  * | SERVER_TYPE | type of the server that is logged
13
- * | SERVER_ID |id of the servier that is logged
13
+ * | SERVER_ID | id of the server that is logged
14
14
  * | LOG_LEVEL | log level of the running instance
15
15
  * | CONSOLE_LEVEL | log level for the console of the running instance
16
- * | EXIT_DELAY | delay when existing gracefully
17
- * | NO_STACK | indicatior to log th stack on all log message
18
- * | LOG_MODE | loge mode for the running instance
16
+ * | FLUSH_EXIT_DELAY | delay when exiting gracefully
17
+ * | NO_STACK | indicator to log the stack on all log messages
18
+ * | LOG_MODE | log mode for the running instance
19
19
  * | SUMO_LOGIC_ENDPOINT | url of the sumologic collector
20
20
  * | SUMO_LOGIC_COLLECTOR_CODE | code of the sumologic collector
21
21
  * | KINESIS_AWS_STREAM_NAME_INFO | name of the stream for info level logs
@@ -51,7 +51,7 @@ process.env.KINESIS_AWS_STREAM_NAME_ERROR = 'a kinesis stream name for error';
51
51
  process.env.KINESIS_AWS_STREAM_NAME_OTHER = 'a kinesis stream name for other';
52
52
  process.env.S3_AWS_MAX_EVENTS = 1;
53
53
  process.env.KINESIS_AWS_MAX_EVENTS = 1;
54
- process.env.EXIT_DELAY = 1;
54
+ process.env.FLUSH_EXIT_DELAY = 1;
55
55
  process.env.LOG_MODE = 'awsS3, sumologic, awsKinesis';
56
56
  process.env.NO_STACK = 'yes';
57
57
  process.env.LOG_LEVEL = 'info';
@@ -9,12 +9,12 @@ import process from 'node:process';
9
9
  *
10
10
  * | Env variable name | Description | Default | Comments |
11
11
  * | ----------------- | ----------- | ------- | -------- |
12
- * | NODE_ENV | environement of the instance
12
+ * | NODE_ENV | environment of the instance
13
13
  * | LOG_LEVEL | log level of the running instance
14
14
  * | CONSOLE_LEVEL | log level for the console of the running instance
15
15
  * | FILTER_FILE | filename containing filter rules
16
- * | NO_STACK | indicatior to log th stack on all log message
17
- * | LOG_MODE | loge mode for the running instance
16
+ * | NO_STACK | indicator to log the stack on all log messages
17
+ * | LOG_MODE | log mode for the running instance
18
18
  * | SUMO_LOGIC_ENDPOINT | url of the sumologic collector
19
19
  * | SUMO_LOGIC_COLLECTOR_CODE | code of the sumologic collector
20
20
  */