@webex/plugin-logger 2.59.2 → 2.59.3-next.1

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/src/logger.js CHANGED
@@ -1,427 +1,427 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import {inBrowser, patterns} from '@webex/common';
6
- import {WebexHttpError, WebexPlugin} from '@webex/webex-core';
7
- import {cloneDeep, has, isArray, isObject, isString} from 'lodash';
8
-
9
- const precedence = {
10
- silent: 0,
11
- group: 1,
12
- groupEnd: 2,
13
- error: 3,
14
- warn: 4,
15
- log: 5,
16
- info: 6,
17
- debug: 7,
18
- trace: 8,
19
- };
20
-
21
- export const levels = Object.keys(precedence).filter((level) => level !== 'silent');
22
-
23
- const fallbacks = {
24
- error: ['log'],
25
- warn: ['error', 'log'],
26
- info: ['log'],
27
- debug: ['info', 'log'],
28
- trace: ['debug', 'info', 'log'],
29
- };
30
-
31
- const LOG_TYPES = {
32
- SDK: 'sdk',
33
- CLIENT: 'client',
34
- };
35
-
36
- const SDK_LOG_TYPE_NAME = 'wx-js-sdk';
37
-
38
- const authTokenKeyPattern = /[Aa]uthorization/;
39
-
40
- /**
41
- * Recursively strips "authorization" fields from the specified object
42
- * @param {Object} object
43
- * @param {Array<mixed>} [visited]
44
- * @private
45
- * @returns {Object}
46
- */
47
- function walkAndFilter(object, visited = []) {
48
- if (visited.includes(object)) {
49
- // Prevent circular references
50
- return object;
51
- }
52
-
53
- visited.push(object);
54
-
55
- if (isArray(object)) {
56
- return object.map((o) => walkAndFilter(o, visited));
57
- }
58
- if (!isObject(object)) {
59
- if (isString(object)) {
60
- if (patterns.containsEmails.test(object)) {
61
- return object.replace(patterns.containsEmails, '[REDACTED]');
62
- }
63
- }
64
-
65
- return object;
66
- }
67
-
68
- for (const [key, value] of Object.entries(object)) {
69
- if (authTokenKeyPattern.test(key)) {
70
- Reflect.deleteProperty(object, key);
71
- } else {
72
- object[key] = walkAndFilter(value, visited);
73
- }
74
- }
75
-
76
- return object;
77
- }
78
-
79
- /**
80
- * @class
81
- */
82
- const Logger = WebexPlugin.extend({
83
- namespace: 'Logger',
84
-
85
- derived: {
86
- level: {
87
- cache: false,
88
- fn() {
89
- return this.getCurrentLevel();
90
- },
91
- },
92
- client_level: {
93
- cache: false,
94
- fn() {
95
- return this.getCurrentClientLevel();
96
- },
97
- },
98
- },
99
- session: {
100
- // for when configured to use single buffer
101
- buffer: {
102
- type: 'array',
103
- default() {
104
- return [];
105
- },
106
- },
107
- groupLevel: {
108
- type: 'number',
109
- default() {
110
- return 0;
111
- },
112
- },
113
- // for when configured to use separate buffers
114
- sdkBuffer: {
115
- type: 'array',
116
- default() {
117
- return [];
118
- },
119
- },
120
- clientBuffer: {
121
- type: 'array',
122
- default() {
123
- return [];
124
- },
125
- },
126
- },
127
-
128
- /**
129
- * Ensures auth headers don't get printed in logs
130
- * @param {Array<mixed>} args
131
- * @private
132
- * @memberof Logger
133
- * @returns {Array<mixed>}
134
- */
135
- filter(...args) {
136
- return args.map((arg) => {
137
- // WebexHttpError already ensures auth tokens don't get printed, so, no
138
- // need to alter it here.
139
- if (arg instanceof Error) {
140
- // karma logs won't print subclassed errors correctly, so we need
141
- // explicitly call their tostring methods.
142
- if (process.env.NODE_ENV === 'test' && inBrowser) {
143
- let ret = arg.toString();
144
-
145
- ret += 'BEGIN STACK';
146
- ret += arg.stack;
147
- ret += 'END STACK';
148
-
149
- return ret;
150
- }
151
-
152
- return arg;
153
- }
154
-
155
- arg = cloneDeep(arg);
156
-
157
- return walkAndFilter(arg);
158
- });
159
- },
160
-
161
- /**
162
- * Determines if the current level allows logs at the specified level to be
163
- * printed
164
- * @param {string} level
165
- * @param {string} type type of log, SDK or client
166
- * @private
167
- * @memberof Logger
168
- * @returns {boolean}
169
- */
170
- shouldPrint(level, type = LOG_TYPES.SDK) {
171
- return (
172
- precedence[level] <=
173
- precedence[type === LOG_TYPES.SDK ? this.getCurrentLevel() : this.getCurrentClientLevel()]
174
- );
175
- },
176
-
177
- /**
178
- * Determines if the current level allows logs at the specified level to be
179
- * put into the log buffer. We're configuring it omit trace and debug logs
180
- * because there are *a lot* of debug logs that really don't provide value at
181
- * runtime (they're helpful for debugging locally, but really just pollute the
182
- * uploaded logs and push useful info out).
183
- * @param {string} level
184
- * @param {string} type type of log, SDK or client
185
- * @private
186
- * @memberof Logger
187
- * @returns {boolean}
188
- */
189
- shouldBuffer(level) {
190
- return (
191
- precedence[level] <=
192
- (this.config.bufferLogLevel ? precedence[this.config.bufferLogLevel] : precedence.info)
193
- );
194
- },
195
-
196
- /**
197
- * Indicates the current SDK log level based on env vars, feature toggles, and
198
- * user type.
199
- * @instance
200
- * @memberof Logger
201
- * @private
202
- * @memberof Logger
203
- * @returns {string}
204
- */
205
- // eslint-disable-next-line complexity
206
- getCurrentLevel() {
207
- // If a level has been explicitly set via config, alway use it.
208
- if (this.config.level) {
209
- return this.config.level;
210
- }
211
-
212
- if (levels.includes(process.env.WEBEX_LOG_LEVEL)) {
213
- return process.env.WEBEX_LOG_LEVEL;
214
- }
215
-
216
- // Always use debug-level logging in test mode;
217
- if (process.env.NODE_ENV === 'test') {
218
- return 'trace';
219
- }
220
-
221
- // Use server-side-feature toggles to configure log levels
222
- const level =
223
- this.webex.internal.device && this.webex.internal.device.features.developer.get('log-level');
224
-
225
- if (level) {
226
- if (levels.includes(level)) {
227
- return level;
228
- }
229
- }
230
-
231
- return 'error';
232
- },
233
-
234
- /**
235
- * Indicates the current client log level based on config, defaults to SDK level
236
- * @instance
237
- * @memberof Logger
238
- * @private
239
- * @memberof Logger
240
- * @returns {string}
241
- */
242
- getCurrentClientLevel() {
243
- // If a client log level has been explicitly set via config, alway use it.
244
- if (this.config.clientLevel) {
245
- return this.config.clientLevel;
246
- }
247
-
248
- // otherwise default to SDK level
249
- return this.getCurrentLevel();
250
- },
251
-
252
- /**
253
- * Format logs (for upload)
254
- *
255
- * If separate client, SDK buffers is configured, merge the buffers, if configured
256
- *
257
- * @instance
258
- * @memberof Logger
259
- * @public
260
- * @memberof Logger
261
- * @returns {string} formatted buffer
262
- */
263
- formatLogs() {
264
- function getDate(log) {
265
- return log[1];
266
- }
267
- let buffer = [];
268
- let clientIndex = 0;
269
- let sdkIndex = 0;
270
-
271
- if (this.config.separateLogBuffers) {
272
- // merge the client and sdk buffers
273
- // while we have entries in either buffer
274
- while (clientIndex < this.clientBuffer.length || sdkIndex < this.sdkBuffer.length) {
275
- // if we have remaining entries in the SDK buffer
276
- if (
277
- sdkIndex < this.sdkBuffer.length &&
278
- // and we haven't exhausted all the client buffer entries, or SDK date is before client date
279
- (clientIndex >= this.clientBuffer.length ||
280
- new Date(getDate(this.sdkBuffer[sdkIndex])) <=
281
- new Date(getDate(this.clientBuffer[clientIndex])))
282
- ) {
283
- // then add to the SDK buffer
284
- buffer.push(this.sdkBuffer[sdkIndex]);
285
- sdkIndex += 1;
286
- }
287
- // otherwise if we haven't exhausted all the client buffer entries, add client entry, whether it was because
288
- // it was the only remaining entries or date was later (the above if)
289
- else if (clientIndex < this.clientBuffer.length) {
290
- buffer.push(this.clientBuffer[clientIndex]);
291
- clientIndex += 1;
292
- }
293
- }
294
- } else {
295
- buffer = this.buffer;
296
- }
297
-
298
- return buffer.join('\n');
299
- },
300
- });
301
-
302
- /**
303
- * Creates a logger method
304
- *
305
- *
306
- * @param {string} level level to create (info, error, warn, etc.)
307
- * @param {string} impl the level to use when writing to console
308
- * @param {string} type type of log, SDK or client
309
- * @param {bool} neverPrint function never prints to console
310
- * @param {bool} alwaysBuffer function always logs to log buffer
311
- * @instance
312
- * @memberof Logger
313
- * @private
314
- * @memberof Logger
315
- * @returns {function} logger method with specified params
316
- */
317
- function makeLoggerMethod(level, impl, type, neverPrint = false, alwaysBuffer = false) {
318
- // Much of the complexity in the following function is due to a test-mode-only
319
- // helper
320
- return function wrappedConsoleMethod(...args) {
321
- // it would be easier to just pass in the name and buffer here, but the config isn't completely initialized
322
- // in Ampersand, even if the initialize method is used to set this up. so we keep the type to achieve
323
- // a sort of late binding to allow retrieving a name from config.
324
- const logType = type;
325
- const clientName =
326
- logType === LOG_TYPES.SDK ? SDK_LOG_TYPE_NAME : this.config.clientName || logType;
327
-
328
- let buffer;
329
- let historyLength;
330
-
331
- if (this.config.separateLogBuffers) {
332
- historyLength = this.config.clientHistoryLength
333
- ? this.config.clientHistoryLength
334
- : this.config.historyLength;
335
- buffer = logType === LOG_TYPES.SDK ? this.sdkBuffer : this.clientBuffer;
336
- } else {
337
- buffer = this.buffer;
338
- historyLength = this.config.historyLength;
339
- }
340
-
341
- try {
342
- const shouldPrint = !neverPrint && this.shouldPrint(level, logType);
343
- const shouldBuffer = alwaysBuffer || this.shouldBuffer(level);
344
-
345
- if (!shouldBuffer && !shouldPrint) {
346
- return;
347
- }
348
-
349
- const filtered = [clientName, ...this.filter(...args)];
350
- const stringified = filtered.map((item) => {
351
- if (item instanceof WebexHttpError) {
352
- return item.toString();
353
- }
354
-
355
- return item;
356
- });
357
-
358
- if (shouldPrint) {
359
- // when logging an object in browsers, we tend to get a dynamic
360
- // reference, thus going back to look at the logged value doesn't
361
- // necessarily show the state at log time, thus we print the stringified
362
- // value.
363
- const toPrint = inBrowser ? stringified : filtered;
364
-
365
- /* istanbul ignore if */
366
- if (process.env.NODE_ENV === 'test' && has(this, 'webex.internal.device.url')) {
367
- toPrint.unshift(this.webex.internal.device.url.slice(-3));
368
- }
369
- // eslint-disable-next-line no-console
370
- console[impl](...toPrint);
371
- }
372
-
373
- if (shouldBuffer) {
374
- const logDate = new Date();
375
-
376
- stringified.unshift(logDate.toISOString());
377
- stringified.unshift('| '.repeat(this.groupLevel));
378
- buffer.push(stringified);
379
- if (buffer.length > historyLength) {
380
- buffer.shift();
381
- }
382
- if (level === 'group') this.groupLevel += 1;
383
- if (level === 'groupEnd' && this.groupLevel > 0) this.groupLevel -= 1;
384
- }
385
- } catch (reason) {
386
- if (!neverPrint) {
387
- /* istanbul ignore next */
388
- // eslint-disable-next-line no-console
389
- console.warn(`failed to execute Logger#${level}`, reason);
390
- }
391
- }
392
- };
393
- }
394
-
395
- levels.forEach((level) => {
396
- let impls = fallbacks[level];
397
- let impl = level;
398
-
399
- if (impls) {
400
- impls = impls.slice();
401
- // eslint-disable-next-line no-console
402
- while (!console[impl]) {
403
- impl = impls.pop();
404
- }
405
- }
406
-
407
- // eslint-disable-next-line complexity
408
- Logger.prototype[`client_${level}`] = makeLoggerMethod(level, impl, LOG_TYPES.CLIENT);
409
- Logger.prototype[level] = makeLoggerMethod(level, impl, LOG_TYPES.SDK);
410
- });
411
-
412
- Logger.prototype.client_logToBuffer = makeLoggerMethod(
413
- levels.info,
414
- levels.info,
415
- LOG_TYPES.CLIENT,
416
- true,
417
- true
418
- );
419
- Logger.prototype.logToBuffer = makeLoggerMethod(
420
- levels.info,
421
- levels.info,
422
- LOG_TYPES.SDK,
423
- true,
424
- true
425
- );
426
-
427
- export default Logger;
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {inBrowser, patterns} from '@webex/common';
6
+ import {WebexHttpError, WebexPlugin} from '@webex/webex-core';
7
+ import {cloneDeep, has, isArray, isObject, isString} from 'lodash';
8
+
9
+ const precedence = {
10
+ silent: 0,
11
+ group: 1,
12
+ groupEnd: 2,
13
+ error: 3,
14
+ warn: 4,
15
+ log: 5,
16
+ info: 6,
17
+ debug: 7,
18
+ trace: 8,
19
+ };
20
+
21
+ export const levels = Object.keys(precedence).filter((level) => level !== 'silent');
22
+
23
+ const fallbacks = {
24
+ error: ['log'],
25
+ warn: ['error', 'log'],
26
+ info: ['log'],
27
+ debug: ['info', 'log'],
28
+ trace: ['debug', 'info', 'log'],
29
+ };
30
+
31
+ const LOG_TYPES = {
32
+ SDK: 'sdk',
33
+ CLIENT: 'client',
34
+ };
35
+
36
+ const SDK_LOG_TYPE_NAME = 'wx-js-sdk';
37
+
38
+ const authTokenKeyPattern = /[Aa]uthorization/;
39
+
40
+ /**
41
+ * Recursively strips "authorization" fields from the specified object
42
+ * @param {Object} object
43
+ * @param {Array<mixed>} [visited]
44
+ * @private
45
+ * @returns {Object}
46
+ */
47
+ function walkAndFilter(object, visited = []) {
48
+ if (visited.includes(object)) {
49
+ // Prevent circular references
50
+ return object;
51
+ }
52
+
53
+ visited.push(object);
54
+
55
+ if (isArray(object)) {
56
+ return object.map((o) => walkAndFilter(o, visited));
57
+ }
58
+ if (!isObject(object)) {
59
+ if (isString(object)) {
60
+ if (patterns.containsEmails.test(object)) {
61
+ return object.replace(patterns.containsEmails, '[REDACTED]');
62
+ }
63
+ }
64
+
65
+ return object;
66
+ }
67
+
68
+ for (const [key, value] of Object.entries(object)) {
69
+ if (authTokenKeyPattern.test(key)) {
70
+ Reflect.deleteProperty(object, key);
71
+ } else {
72
+ object[key] = walkAndFilter(value, visited);
73
+ }
74
+ }
75
+
76
+ return object;
77
+ }
78
+
79
+ /**
80
+ * @class
81
+ */
82
+ const Logger = WebexPlugin.extend({
83
+ namespace: 'Logger',
84
+
85
+ derived: {
86
+ level: {
87
+ cache: false,
88
+ fn() {
89
+ return this.getCurrentLevel();
90
+ },
91
+ },
92
+ client_level: {
93
+ cache: false,
94
+ fn() {
95
+ return this.getCurrentClientLevel();
96
+ },
97
+ },
98
+ },
99
+ session: {
100
+ // for when configured to use single buffer
101
+ buffer: {
102
+ type: 'array',
103
+ default() {
104
+ return [];
105
+ },
106
+ },
107
+ groupLevel: {
108
+ type: 'number',
109
+ default() {
110
+ return 0;
111
+ },
112
+ },
113
+ // for when configured to use separate buffers
114
+ sdkBuffer: {
115
+ type: 'array',
116
+ default() {
117
+ return [];
118
+ },
119
+ },
120
+ clientBuffer: {
121
+ type: 'array',
122
+ default() {
123
+ return [];
124
+ },
125
+ },
126
+ },
127
+
128
+ /**
129
+ * Ensures auth headers don't get printed in logs
130
+ * @param {Array<mixed>} args
131
+ * @private
132
+ * @memberof Logger
133
+ * @returns {Array<mixed>}
134
+ */
135
+ filter(...args) {
136
+ return args.map((arg) => {
137
+ // WebexHttpError already ensures auth tokens don't get printed, so, no
138
+ // need to alter it here.
139
+ if (arg instanceof Error) {
140
+ // karma logs won't print subclassed errors correctly, so we need
141
+ // explicitly call their tostring methods.
142
+ if (process.env.NODE_ENV === 'test' && inBrowser) {
143
+ let ret = arg.toString();
144
+
145
+ ret += 'BEGIN STACK';
146
+ ret += arg.stack;
147
+ ret += 'END STACK';
148
+
149
+ return ret;
150
+ }
151
+
152
+ return arg;
153
+ }
154
+
155
+ arg = cloneDeep(arg);
156
+
157
+ return walkAndFilter(arg);
158
+ });
159
+ },
160
+
161
+ /**
162
+ * Determines if the current level allows logs at the specified level to be
163
+ * printed
164
+ * @param {string} level
165
+ * @param {string} type type of log, SDK or client
166
+ * @private
167
+ * @memberof Logger
168
+ * @returns {boolean}
169
+ */
170
+ shouldPrint(level, type = LOG_TYPES.SDK) {
171
+ return (
172
+ precedence[level] <=
173
+ precedence[type === LOG_TYPES.SDK ? this.getCurrentLevel() : this.getCurrentClientLevel()]
174
+ );
175
+ },
176
+
177
+ /**
178
+ * Determines if the current level allows logs at the specified level to be
179
+ * put into the log buffer. We're configuring it omit trace and debug logs
180
+ * because there are *a lot* of debug logs that really don't provide value at
181
+ * runtime (they're helpful for debugging locally, but really just pollute the
182
+ * uploaded logs and push useful info out).
183
+ * @param {string} level
184
+ * @param {string} type type of log, SDK or client
185
+ * @private
186
+ * @memberof Logger
187
+ * @returns {boolean}
188
+ */
189
+ shouldBuffer(level) {
190
+ return (
191
+ precedence[level] <=
192
+ (this.config.bufferLogLevel ? precedence[this.config.bufferLogLevel] : precedence.info)
193
+ );
194
+ },
195
+
196
+ /**
197
+ * Indicates the current SDK log level based on env vars, feature toggles, and
198
+ * user type.
199
+ * @instance
200
+ * @memberof Logger
201
+ * @private
202
+ * @memberof Logger
203
+ * @returns {string}
204
+ */
205
+ // eslint-disable-next-line complexity
206
+ getCurrentLevel() {
207
+ // If a level has been explicitly set via config, alway use it.
208
+ if (this.config.level) {
209
+ return this.config.level;
210
+ }
211
+
212
+ if (levels.includes(process.env.WEBEX_LOG_LEVEL)) {
213
+ return process.env.WEBEX_LOG_LEVEL;
214
+ }
215
+
216
+ // Always use debug-level logging in test mode;
217
+ if (process.env.NODE_ENV === 'test') {
218
+ return 'trace';
219
+ }
220
+
221
+ // Use server-side-feature toggles to configure log levels
222
+ const level =
223
+ this.webex.internal.device && this.webex.internal.device.features.developer.get('log-level');
224
+
225
+ if (level) {
226
+ if (levels.includes(level)) {
227
+ return level;
228
+ }
229
+ }
230
+
231
+ return 'error';
232
+ },
233
+
234
+ /**
235
+ * Indicates the current client log level based on config, defaults to SDK level
236
+ * @instance
237
+ * @memberof Logger
238
+ * @private
239
+ * @memberof Logger
240
+ * @returns {string}
241
+ */
242
+ getCurrentClientLevel() {
243
+ // If a client log level has been explicitly set via config, alway use it.
244
+ if (this.config.clientLevel) {
245
+ return this.config.clientLevel;
246
+ }
247
+
248
+ // otherwise default to SDK level
249
+ return this.getCurrentLevel();
250
+ },
251
+
252
+ /**
253
+ * Format logs (for upload)
254
+ *
255
+ * If separate client, SDK buffers is configured, merge the buffers, if configured
256
+ *
257
+ * @instance
258
+ * @memberof Logger
259
+ * @public
260
+ * @memberof Logger
261
+ * @returns {string} formatted buffer
262
+ */
263
+ formatLogs() {
264
+ function getDate(log) {
265
+ return log[1];
266
+ }
267
+ let buffer = [];
268
+ let clientIndex = 0;
269
+ let sdkIndex = 0;
270
+
271
+ if (this.config.separateLogBuffers) {
272
+ // merge the client and sdk buffers
273
+ // while we have entries in either buffer
274
+ while (clientIndex < this.clientBuffer.length || sdkIndex < this.sdkBuffer.length) {
275
+ // if we have remaining entries in the SDK buffer
276
+ if (
277
+ sdkIndex < this.sdkBuffer.length &&
278
+ // and we haven't exhausted all the client buffer entries, or SDK date is before client date
279
+ (clientIndex >= this.clientBuffer.length ||
280
+ new Date(getDate(this.sdkBuffer[sdkIndex])) <=
281
+ new Date(getDate(this.clientBuffer[clientIndex])))
282
+ ) {
283
+ // then add to the SDK buffer
284
+ buffer.push(this.sdkBuffer[sdkIndex]);
285
+ sdkIndex += 1;
286
+ }
287
+ // otherwise if we haven't exhausted all the client buffer entries, add client entry, whether it was because
288
+ // it was the only remaining entries or date was later (the above if)
289
+ else if (clientIndex < this.clientBuffer.length) {
290
+ buffer.push(this.clientBuffer[clientIndex]);
291
+ clientIndex += 1;
292
+ }
293
+ }
294
+ } else {
295
+ buffer = this.buffer;
296
+ }
297
+
298
+ return buffer.join('\n');
299
+ },
300
+ });
301
+
302
+ /**
303
+ * Creates a logger method
304
+ *
305
+ *
306
+ * @param {string} level level to create (info, error, warn, etc.)
307
+ * @param {string} impl the level to use when writing to console
308
+ * @param {string} type type of log, SDK or client
309
+ * @param {bool} neverPrint function never prints to console
310
+ * @param {bool} alwaysBuffer function always logs to log buffer
311
+ * @instance
312
+ * @memberof Logger
313
+ * @private
314
+ * @memberof Logger
315
+ * @returns {function} logger method with specified params
316
+ */
317
+ function makeLoggerMethod(level, impl, type, neverPrint = false, alwaysBuffer = false) {
318
+ // Much of the complexity in the following function is due to a test-mode-only
319
+ // helper
320
+ return function wrappedConsoleMethod(...args) {
321
+ // it would be easier to just pass in the name and buffer here, but the config isn't completely initialized
322
+ // in Ampersand, even if the initialize method is used to set this up. so we keep the type to achieve
323
+ // a sort of late binding to allow retrieving a name from config.
324
+ const logType = type;
325
+ const clientName =
326
+ logType === LOG_TYPES.SDK ? SDK_LOG_TYPE_NAME : this.config.clientName || logType;
327
+
328
+ let buffer;
329
+ let historyLength;
330
+
331
+ if (this.config.separateLogBuffers) {
332
+ historyLength = this.config.clientHistoryLength
333
+ ? this.config.clientHistoryLength
334
+ : this.config.historyLength;
335
+ buffer = logType === LOG_TYPES.SDK ? this.sdkBuffer : this.clientBuffer;
336
+ } else {
337
+ buffer = this.buffer;
338
+ historyLength = this.config.historyLength;
339
+ }
340
+
341
+ try {
342
+ const shouldPrint = !neverPrint && this.shouldPrint(level, logType);
343
+ const shouldBuffer = alwaysBuffer || this.shouldBuffer(level);
344
+
345
+ if (!shouldBuffer && !shouldPrint) {
346
+ return;
347
+ }
348
+
349
+ const filtered = [clientName, ...this.filter(...args)];
350
+ const stringified = filtered.map((item) => {
351
+ if (item instanceof WebexHttpError) {
352
+ return item.toString();
353
+ }
354
+
355
+ return item;
356
+ });
357
+
358
+ if (shouldPrint) {
359
+ // when logging an object in browsers, we tend to get a dynamic
360
+ // reference, thus going back to look at the logged value doesn't
361
+ // necessarily show the state at log time, thus we print the stringified
362
+ // value.
363
+ const toPrint = inBrowser ? stringified : filtered;
364
+
365
+ /* istanbul ignore if */
366
+ if (process.env.NODE_ENV === 'test' && has(this, 'webex.internal.device.url')) {
367
+ toPrint.unshift(this.webex.internal.device.url.slice(-3));
368
+ }
369
+ // eslint-disable-next-line no-console
370
+ console[impl](...toPrint);
371
+ }
372
+
373
+ if (shouldBuffer) {
374
+ const logDate = new Date();
375
+
376
+ stringified.unshift(logDate.toISOString());
377
+ stringified.unshift('| '.repeat(this.groupLevel));
378
+ buffer.push(stringified);
379
+ if (buffer.length > historyLength) {
380
+ buffer.shift();
381
+ }
382
+ if (level === 'group') this.groupLevel += 1;
383
+ if (level === 'groupEnd' && this.groupLevel > 0) this.groupLevel -= 1;
384
+ }
385
+ } catch (reason) {
386
+ if (!neverPrint) {
387
+ /* istanbul ignore next */
388
+ // eslint-disable-next-line no-console
389
+ console.warn(`failed to execute Logger#${level}`, reason);
390
+ }
391
+ }
392
+ };
393
+ }
394
+
395
+ levels.forEach((level) => {
396
+ let impls = fallbacks[level];
397
+ let impl = level;
398
+
399
+ if (impls) {
400
+ impls = impls.slice();
401
+ // eslint-disable-next-line no-console
402
+ while (!console[impl]) {
403
+ impl = impls.pop();
404
+ }
405
+ }
406
+
407
+ // eslint-disable-next-line complexity
408
+ Logger.prototype[`client_${level}`] = makeLoggerMethod(level, impl, LOG_TYPES.CLIENT);
409
+ Logger.prototype[level] = makeLoggerMethod(level, impl, LOG_TYPES.SDK);
410
+ });
411
+
412
+ Logger.prototype.client_logToBuffer = makeLoggerMethod(
413
+ levels.info,
414
+ levels.info,
415
+ LOG_TYPES.CLIENT,
416
+ true,
417
+ true
418
+ );
419
+ Logger.prototype.logToBuffer = makeLoggerMethod(
420
+ levels.info,
421
+ levels.info,
422
+ LOG_TYPES.SDK,
423
+ true,
424
+ true
425
+ );
426
+
427
+ export default Logger;