@elisra-devops/docgen-data-provider 1.142.0 → 1.143.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/bin/helpers/requestContext.d.ts +15 -0
- package/bin/helpers/requestContext.js +39 -2
- package/bin/helpers/requestContext.js.map +1 -1
- package/bin/helpers/tfs.js +9 -2
- package/bin/helpers/tfs.js.map +1 -1
- package/bin/modules/GitDataProvider.js +1 -1
- package/bin/modules/GitDataProvider.js.map +1 -1
- package/bin/modules/JfrogDataProvider.js +1 -1
- package/bin/modules/JfrogDataProvider.js.map +1 -1
- package/bin/modules/PipelinesDataProvider.js +3 -3
- package/bin/modules/PipelinesDataProvider.js.map +1 -1
- package/bin/modules/ResultDataProvider.js +10 -10
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/modules/TestDataProvider.js +3 -3
- package/bin/modules/TestDataProvider.js.map +1 -1
- package/bin/modules/TicketsDataProvider.js +11 -11
- package/bin/modules/TicketsDataProvider.js.map +1 -1
- package/bin/tests/helpers/requestContext.test.js +39 -0
- package/bin/tests/helpers/requestContext.test.js.map +1 -1
- package/bin/tests/helpers/tfs.test.js +21 -2
- package/bin/tests/helpers/tfs.test.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +1 -0
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/bin/tests/utils/logger.test.js +26 -0
- package/bin/tests/utils/logger.test.js.map +1 -1
- package/bin/utils/logger.d.ts +2 -0
- package/bin/utils/logger.js +48 -9
- package/bin/utils/logger.js.map +1 -1
- package/package.json +1 -1
- package/src/helpers/requestContext.ts +39 -3
- package/src/helpers/tfs.ts +11 -3
- package/src/modules/GitDataProvider.ts +2 -2
- package/src/modules/JfrogDataProvider.ts +2 -2
- package/src/modules/PipelinesDataProvider.ts +4 -4
- package/src/modules/ResultDataProvider.ts +11 -11
- package/src/modules/TestDataProvider.ts +4 -4
- package/src/modules/TicketsDataProvider.ts +12 -12
- package/src/tests/helpers/requestContext.test.ts +50 -0
- package/src/tests/helpers/tfs.test.ts +23 -2
- package/src/tests/modules/ResultDataProvider.test.ts +1 -0
- package/src/tests/utils/logger.test.ts +35 -1
- package/src/utils/logger.ts +42 -4
|
@@ -10,7 +10,7 @@ import { TestSteps } from '../models/tfs-data';
|
|
|
10
10
|
import TestStepParserHelper from '../utils/testStepParserHelper';
|
|
11
11
|
|
|
12
12
|
import logger from '../utils/logger';
|
|
13
|
-
import { describeError } from '../helpers/requestContext';
|
|
13
|
+
import { describeError, logCaughtError } from '../helpers/requestContext';
|
|
14
14
|
const pLimit = require('p-limit');
|
|
15
15
|
|
|
16
16
|
type FallbackFetchOutcome = {
|
|
@@ -492,7 +492,7 @@ export default class TicketsDataProvider {
|
|
|
492
492
|
break;
|
|
493
493
|
}
|
|
494
494
|
} catch (err: any) {
|
|
495
|
-
|
|
495
|
+
logCaughtError('Error occurred during fetching shared queries:', err);
|
|
496
496
|
throw err;
|
|
497
497
|
}
|
|
498
498
|
}
|
|
@@ -528,7 +528,7 @@ export default class TicketsDataProvider {
|
|
|
528
528
|
})
|
|
529
529
|
);
|
|
530
530
|
} catch (err: any) {
|
|
531
|
-
|
|
531
|
+
logCaughtError('Error occurred during fetching fields by type:', err);
|
|
532
532
|
throw err;
|
|
533
533
|
}
|
|
534
534
|
}
|
|
@@ -559,7 +559,7 @@ export default class TicketsDataProvider {
|
|
|
559
559
|
}
|
|
560
560
|
return { types, states: Array.from(stateSet) };
|
|
561
561
|
} catch (err: any) {
|
|
562
|
-
|
|
562
|
+
logCaughtError('Error fetching work item type states:', err);
|
|
563
563
|
throw err;
|
|
564
564
|
}
|
|
565
565
|
}
|
|
@@ -1287,7 +1287,7 @@ export default class TicketsDataProvider {
|
|
|
1287
1287
|
break;
|
|
1288
1288
|
}
|
|
1289
1289
|
} catch (err: any) {
|
|
1290
|
-
|
|
1290
|
+
logCaughtError(`Could not fetch query results for ${wiqlHref}:`, err);
|
|
1291
1291
|
}
|
|
1292
1292
|
}
|
|
1293
1293
|
|
|
@@ -1663,7 +1663,7 @@ export default class TicketsDataProvider {
|
|
|
1663
1663
|
}
|
|
1664
1664
|
return [...workItemsResultMap.values()];
|
|
1665
1665
|
} catch (error: any) {
|
|
1666
|
-
|
|
1666
|
+
logCaughtError('could not parse requested flat query:', error);
|
|
1667
1667
|
}
|
|
1668
1668
|
}
|
|
1669
1669
|
|
|
@@ -3563,7 +3563,7 @@ export default class TicketsDataProvider {
|
|
|
3563
3563
|
|
|
3564
3564
|
item.fields = { ...parsedFields };
|
|
3565
3565
|
} catch (err: any) {
|
|
3566
|
-
|
|
3566
|
+
logCaughtError('Cannot filter columns:', err);
|
|
3567
3567
|
throw err;
|
|
3568
3568
|
}
|
|
3569
3569
|
}
|
|
@@ -3618,7 +3618,7 @@ export default class TicketsDataProvider {
|
|
|
3618
3618
|
|
|
3619
3619
|
return workItemTypesWithIcons;
|
|
3620
3620
|
} catch (err: any) {
|
|
3621
|
-
|
|
3621
|
+
logCaughtError('Error occurred during fetching work item types:', err);
|
|
3622
3622
|
throw err;
|
|
3623
3623
|
}
|
|
3624
3624
|
}
|
|
@@ -3793,7 +3793,7 @@ export default class TicketsDataProvider {
|
|
|
3793
3793
|
totalCount: workItemIds.length,
|
|
3794
3794
|
};
|
|
3795
3795
|
} catch (err: any) {
|
|
3796
|
-
|
|
3796
|
+
logCaughtError('Could not fetch categorized requirements:', err);
|
|
3797
3797
|
throw err;
|
|
3798
3798
|
}
|
|
3799
3799
|
}
|
|
@@ -3888,7 +3888,7 @@ export default class TicketsDataProvider {
|
|
|
3888
3888
|
const relations = qr?.workItemRelations || [];
|
|
3889
3889
|
result['req-test'] = await resolveQuerySides(cols, relations, true);
|
|
3890
3890
|
} catch (err: any) {
|
|
3891
|
-
|
|
3891
|
+
logCaughtError('GetTraceColumnsByType[req-test] failed:', err);
|
|
3892
3892
|
result['req-test'] = { Requirement: [], 'Test Case': [] };
|
|
3893
3893
|
}
|
|
3894
3894
|
}
|
|
@@ -3900,14 +3900,14 @@ export default class TicketsDataProvider {
|
|
|
3900
3900
|
const relations = qr?.workItemRelations || [];
|
|
3901
3901
|
result['test-req'] = await resolveQuerySides(cols, relations, false);
|
|
3902
3902
|
} catch (err: any) {
|
|
3903
|
-
|
|
3903
|
+
logCaughtError('GetTraceColumnsByType[test-req] failed:', err);
|
|
3904
3904
|
result['test-req'] = { Requirement: [], 'Test Case': [] };
|
|
3905
3905
|
}
|
|
3906
3906
|
}
|
|
3907
3907
|
|
|
3908
3908
|
return result;
|
|
3909
3909
|
} catch (err: any) {
|
|
3910
|
-
|
|
3910
|
+
logCaughtError('GetTraceColumnsByType failed:', err);
|
|
3911
3911
|
return {};
|
|
3912
3912
|
}
|
|
3913
3913
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logger from '../../utils/logger';
|
|
1
2
|
import {
|
|
2
3
|
sanitizeUrl,
|
|
3
4
|
summarizeBody,
|
|
@@ -5,6 +6,9 @@ import {
|
|
|
5
6
|
buildAdoRequestContext,
|
|
6
7
|
annotateAdoError,
|
|
7
8
|
maskWiqlLiterals,
|
|
9
|
+
templatePath,
|
|
10
|
+
describeError,
|
|
11
|
+
logCaughtError,
|
|
8
12
|
} from '../../helpers/requestContext';
|
|
9
13
|
|
|
10
14
|
describe('maskWiqlLiterals', () => {
|
|
@@ -200,3 +204,49 @@ describe('annotateAdoError', () => {
|
|
|
200
204
|
expect(() => annotateAdoError(undefined as any, { url: 'u' })).not.toThrow();
|
|
201
205
|
});
|
|
202
206
|
});
|
|
207
|
+
|
|
208
|
+
describe('templatePath', () => {
|
|
209
|
+
it('drops origin and query and collapses numeric / guid segments', () => {
|
|
210
|
+
expect(templatePath('https://dev.azure.com/org/p/_apis/wit/workitems/123?api-version=7')).toBe(
|
|
211
|
+
'/org/p/_apis/wit/workitems/{id}'
|
|
212
|
+
);
|
|
213
|
+
expect(templatePath('https://h/a/3f2504e0-4f89-11d3-9a0c-0305e82c3301/b')).toBe('/a/{id}/b');
|
|
214
|
+
});
|
|
215
|
+
it('copes with a relative or missing url', () => {
|
|
216
|
+
expect(templatePath('/rel/42?x=1')).toBe('/rel/{id}');
|
|
217
|
+
expect(templatePath(undefined)).toBe('(unknown url)');
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
describe('describeError', () => {
|
|
222
|
+
it('carries the original message separately so the dashboard err.message is not the combined line', () => {
|
|
223
|
+
expect(describeError(new Error('boom'))).toMatchObject({ message: 'boom', errMessage: 'boom' });
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
describe('logCaughtError', () => {
|
|
228
|
+
beforeEach(() => {
|
|
229
|
+
jest.spyOn(logger, 'warn').mockImplementation((() => logger) as any);
|
|
230
|
+
jest.spyOn(logger, 'error').mockImplementation((() => logger) as any);
|
|
231
|
+
});
|
|
232
|
+
afterEach(() => jest.restoreAllMocks());
|
|
233
|
+
|
|
234
|
+
it('logs at warn when TFSServices already reported the error', () => {
|
|
235
|
+
const err = annotateAdoError(new Error('x'), { method: 'GET', url: 'https://h/y', reported: true });
|
|
236
|
+
logCaughtError('Could not fetch Y:', err);
|
|
237
|
+
expect(logger.warn).toHaveBeenCalledWith('Could not fetch Y:', expect.objectContaining({ message: 'x' }));
|
|
238
|
+
expect(logger.error).not.toHaveBeenCalled();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('stays at error when the error was annotated but not reported (printError=false)', () => {
|
|
242
|
+
const err = annotateAdoError(new Error('x'), { method: 'GET', url: 'https://h/y', reported: false });
|
|
243
|
+
logCaughtError('Could not fetch Y:', err);
|
|
244
|
+
expect(logger.error).toHaveBeenCalledTimes(1);
|
|
245
|
+
expect(logger.warn).not.toHaveBeenCalled();
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('stays at error for a non-ADO error', () => {
|
|
249
|
+
logCaughtError('Could not fetch Y:', new Error('plain'));
|
|
250
|
+
expect(logger.error).toHaveBeenCalledTimes(1);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
@@ -1115,6 +1115,7 @@ describe('TFSServices request-context annotation', () => {
|
|
|
1115
1115
|
url: 'https://dev.azure.com/org/_apis/wit/queries/q1',
|
|
1116
1116
|
status: 404,
|
|
1117
1117
|
attempt: 1,
|
|
1118
|
+
reported: false,
|
|
1118
1119
|
responseExcerpt: 'TF401232: Work item 5 does not exist',
|
|
1119
1120
|
});
|
|
1120
1121
|
expect(logger.error).not.toHaveBeenCalled();
|
|
@@ -1127,13 +1128,33 @@ describe('TFSServices request-context annotation', () => {
|
|
|
1127
1128
|
|
|
1128
1129
|
expect(logger.error).toHaveBeenCalledTimes(1);
|
|
1129
1130
|
expect(logger.error).toHaveBeenCalledWith(
|
|
1130
|
-
'ADO request failed',
|
|
1131
|
+
'ADO request failed: GET /org/_apis/x -> 404',
|
|
1131
1132
|
expect.objectContaining({
|
|
1132
|
-
adoRequest: expect.objectContaining({
|
|
1133
|
+
adoRequest: expect.objectContaining({
|
|
1134
|
+
method: 'GET',
|
|
1135
|
+
url: 'https://dev.azure.com/org/_apis/x',
|
|
1136
|
+
status: 404,
|
|
1137
|
+
reported: true,
|
|
1138
|
+
}),
|
|
1133
1139
|
})
|
|
1134
1140
|
);
|
|
1135
1141
|
});
|
|
1136
1142
|
|
|
1143
|
+
it('puts status and templated path in the message so 401 and 404 group separately', async () => {
|
|
1144
|
+
const e401: any = new Error('Request failed with status code 401');
|
|
1145
|
+
e401.response = { status: 401, data: {} };
|
|
1146
|
+
mockAxiosInstance.request.mockRejectedValueOnce(e401);
|
|
1147
|
+
await TFSServices.getItemContent('https://dev.azure.com/org/p/_apis/wit/workitems/123', 'pat').catch(() => undefined);
|
|
1148
|
+
mockAxiosInstance.request.mockRejectedValueOnce(notFound());
|
|
1149
|
+
await TFSServices.getItemContent('https://dev.azure.com/org/p/_apis/wit/workitems/456', 'pat').catch(() => undefined);
|
|
1150
|
+
|
|
1151
|
+
const messages = (logger.error as jest.Mock).mock.calls.map((c) => c[0]);
|
|
1152
|
+
expect(messages).toEqual([
|
|
1153
|
+
'ADO request failed: GET /org/p/_apis/wit/workitems/{id} -> 401',
|
|
1154
|
+
'ADO request failed: GET /org/p/_apis/wit/workitems/{id} -> 404',
|
|
1155
|
+
]);
|
|
1156
|
+
});
|
|
1157
|
+
|
|
1137
1158
|
it('never leaks the PAT: credentials are applied to the axios config, not the description', async () => {
|
|
1138
1159
|
mockAxiosInstance.request.mockRejectedValue(notFound());
|
|
1139
1160
|
|
|
@@ -6032,6 +6032,7 @@ describe('ResultDataProvider', () => {
|
|
|
6032
6032
|
// record with the response summary as meta (docgen-log-redaction / Phase 2/4).
|
|
6033
6033
|
expect(logger.error).toHaveBeenCalledWith('Error during getCombinedResultsSummary:', {
|
|
6034
6034
|
message: 'boom',
|
|
6035
|
+
errMessage: 'boom',
|
|
6035
6036
|
stack: expect.any(String),
|
|
6036
6037
|
responseSummary: '{"detail":"bad"}',
|
|
6037
6038
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as winston from 'winston';
|
|
2
2
|
import Transport = require('winston-transport');
|
|
3
|
-
import { redact, DiagnosticsTransport } from '../../utils/logger';
|
|
3
|
+
import { redact, DiagnosticsTransport, isSensitiveKey, skipUncaptured } from '../../utils/logger';
|
|
4
4
|
import { installLogSink, LogSink, DiagnosticEvent } from '../../utils/logSink';
|
|
5
5
|
import { runContextStore } from '../../utils/runContext';
|
|
6
6
|
|
|
@@ -379,3 +379,37 @@ describe('DiagnosticsTransport capture policy (Phase 6b)', () => {
|
|
|
379
379
|
expect(events[0].message).toBe('verbose debug');
|
|
380
380
|
});
|
|
381
381
|
});
|
|
382
|
+
|
|
383
|
+
describe('isSensitiveKey', () => {
|
|
384
|
+
it.each(['token', 'accessToken', 'x-docgen-ingest-token', 'PAT', 'pat', 'password', 'DB_PASSWORD', 'Authorization', 'minioSecretKey', 'minioAccessKey', 'apiKey', 'clientSecret', 'cookie'])(
|
|
385
|
+
'redacts %s',
|
|
386
|
+
(key) => expect(isSensitiveKey(key)).toBe(true)
|
|
387
|
+
);
|
|
388
|
+
it.each(['areaPath', 'IterationPath', 'path', 'filePath', 'patch', 'dispatch', 'compatibility', 'tokenCount', 'System.AreaPath', 'url'])(
|
|
389
|
+
'keeps %s',
|
|
390
|
+
(key) => expect(isSensitiveKey(key)).toBe(false)
|
|
391
|
+
);
|
|
392
|
+
it('redact() leaves areaPath visible but scrubs a token', () => {
|
|
393
|
+
const out = applyRedact({ message: 'm', areaPath: 'P\\Area', accessToken: 'abc' });
|
|
394
|
+
expect(out.areaPath).toBe('P\\Area');
|
|
395
|
+
expect(out.accessToken).toBe('[REDACTED]');
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
describe('skipUncaptured', () => {
|
|
400
|
+
const run = (level: string) => (skipUncaptured() as any).transform({ level, message: 'm' });
|
|
401
|
+
it('keeps what stdout prints and always keeps warn/error', () => {
|
|
402
|
+
expect(run('error')).toBeTruthy();
|
|
403
|
+
expect(run('warn')).toBeTruthy();
|
|
404
|
+
expect(run('info')).toBeTruthy();
|
|
405
|
+
});
|
|
406
|
+
it('drops debug in normal mode', () => {
|
|
407
|
+
expect(run('debug')).toBe(false);
|
|
408
|
+
});
|
|
409
|
+
it('keeps debug inside a verbose run', () => {
|
|
410
|
+
const { runContextStore } = require('../../utils/runContext');
|
|
411
|
+
runContextStore.run({ runId: 'r1', captureMode: 'verbose' }, () => {
|
|
412
|
+
expect(run('debug')).toBeTruthy();
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
});
|
package/src/utils/logger.ts
CHANGED
|
@@ -29,7 +29,24 @@ export const withRunContext = winston.format((info) => {
|
|
|
29
29
|
// "accesskey" (not just "minioaccesskey") so this also catches an *AccessKeyId-style field —
|
|
30
30
|
// a real gap found in api-gate's copy during the Phase 5 manifest work: only the *SecretKey
|
|
31
31
|
// sibling was covered before, via "secret". Applied here too to keep the four copies in sync.
|
|
32
|
-
|
|
32
|
+
// Word-based, not substring: the key is split into lower-case words (camelCase, kebab-case and
|
|
33
|
+
// snake_case alike) and judged by how it *ends*. A substring test matched "pat" inside
|
|
34
|
+
// "areaPath" / "path" / "patch" and blanked ordinary ADO fields; this keeps `accessToken`,
|
|
35
|
+
// `x-docgen-ingest-token`, `minioSecretKey`, `PAT`, `password` redacted while `areaPath` stays.
|
|
36
|
+
const SENSITIVE_TAILS = ['token', 'password', 'secret', 'authorization', 'accesskey', 'secretkey', 'apikey'];
|
|
37
|
+
const SENSITIVE_LAST_WORDS = new Set(['pat', 'pwd', 'cookie', 'tokens', 'passwords', 'secrets']);
|
|
38
|
+
export function isSensitiveKey(key: string): boolean {
|
|
39
|
+
const words = key
|
|
40
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
41
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
|
|
42
|
+
.toLowerCase()
|
|
43
|
+
.split(/[^a-z0-9]+/)
|
|
44
|
+
.filter(Boolean);
|
|
45
|
+
if (words.length === 0) return false;
|
|
46
|
+
if (SENSITIVE_LAST_WORDS.has(words[words.length - 1])) return true;
|
|
47
|
+
const tail = words.slice(-2).join('');
|
|
48
|
+
return SENSITIVE_TAILS.some((t) => tail.endsWith(t));
|
|
49
|
+
}
|
|
33
50
|
|
|
34
51
|
// A per-key try/catch on the *read*, not just around the whole loop: a getter that throws
|
|
35
52
|
// (e.g. `{ get boom() { throw ... } }`) would otherwise abort redaction for every remaining
|
|
@@ -56,7 +73,7 @@ export function redactValue(value: unknown, depth = 0, seen = new WeakSet<object
|
|
|
56
73
|
out[key] = '[Unreadable property]';
|
|
57
74
|
continue;
|
|
58
75
|
}
|
|
59
|
-
out[key] =
|
|
76
|
+
out[key] = isSensitiveKey(key) ? '[REDACTED]' : redactValue(read.value, depth + 1, seen);
|
|
60
77
|
}
|
|
61
78
|
return out;
|
|
62
79
|
}
|
|
@@ -75,7 +92,7 @@ export const redact = winston.format((info) => {
|
|
|
75
92
|
? '[Unreadable property]'
|
|
76
93
|
: // A top-level primitive (e.g. token: "abc") has no children for redactValue to walk into —
|
|
77
94
|
// the key itself has to be checked here too, not just inside the recursive object walk.
|
|
78
|
-
|
|
95
|
+
isSensitiveKey(key)
|
|
79
96
|
? '[REDACTED]'
|
|
80
97
|
: redactValue(read.value);
|
|
81
98
|
try {
|
|
@@ -216,7 +233,9 @@ export class DiagnosticsTransport extends Transport {
|
|
|
216
233
|
message,
|
|
217
234
|
err: hasErr
|
|
218
235
|
? {
|
|
219
|
-
message
|
|
236
|
+
// The error's own message when the call site supplied it (describeError); else
|
|
237
|
+
// the combined winston message, which is all a bare logger.error(err) leaves.
|
|
238
|
+
message: clamp(info.errMessage, MAX_MESSAGE_LEN) ?? message,
|
|
220
239
|
code: typeof info.code === 'string' ? info.code : undefined,
|
|
221
240
|
stack: clamp(info.stack, MAX_STACK_LEN),
|
|
222
241
|
}
|
|
@@ -248,11 +267,29 @@ const useJson = (process.env.LOG_FORMAT || 'text').toLowerCase() === 'json';
|
|
|
248
267
|
// for free; info/warn/error volume (Phase 4's focus) is unaffected either way.
|
|
249
268
|
const CONSOLE_LOG_LEVEL = process.env.LOG_LEVEL || 'info';
|
|
250
269
|
|
|
270
|
+
// Drops a record before the (comparatively expensive) redact/splat/format work when nothing
|
|
271
|
+
// would consume it: stdout wouldn't print it, and DiagnosticsTransport wouldn't persist it
|
|
272
|
+
// (only debug/info under a verbose/retain-on-failure run are captured below warn). The logger's
|
|
273
|
+
// own level gate must stay 'debug' for that capture, so this is the cheap early exit instead.
|
|
274
|
+
const LEVEL_RANK: Record<string, number> = { error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6 };
|
|
275
|
+
export const skipUncaptured = winston.format((info) => {
|
|
276
|
+
const printRank = LEVEL_RANK[CONSOLE_LOG_LEVEL];
|
|
277
|
+
const rank = LEVEL_RANK[String(info.level)];
|
|
278
|
+
if (printRank === undefined || rank === undefined || rank <= printRank) return info;
|
|
279
|
+
const mode = runContextStore.getStore()?.captureMode;
|
|
280
|
+
const captured =
|
|
281
|
+
DIAGNOSTICS_CAPTURE_ENABLED &&
|
|
282
|
+
(info.level === 'debug' || info.level === 'info') &&
|
|
283
|
+
(mode === 'verbose' || mode === 'retain-on-failure');
|
|
284
|
+
return captured ? info : false;
|
|
285
|
+
});
|
|
286
|
+
|
|
251
287
|
logger = winston.createLogger({
|
|
252
288
|
level: 'debug',
|
|
253
289
|
defaultMeta: { service: '@elisra-devops/docgen-data-provider', version: readOwnVersion() },
|
|
254
290
|
format: useJson
|
|
255
291
|
? winston.format.combine(
|
|
292
|
+
skipUncaptured(),
|
|
256
293
|
winston.format.errors({ stack: true }),
|
|
257
294
|
winston.format.timestamp(),
|
|
258
295
|
withRunContext(),
|
|
@@ -261,6 +298,7 @@ logger = winston.createLogger({
|
|
|
261
298
|
winston.format.json()
|
|
262
299
|
)
|
|
263
300
|
: winston.format.combine(
|
|
301
|
+
skipUncaptured(),
|
|
264
302
|
winston.format.errors({ stack: true }),
|
|
265
303
|
winston.format.timestamp(),
|
|
266
304
|
withRunContext(),
|