Skip to content

Commit 8de856c

Browse files
committed
logging: truncate long field names
1 parent c6c07a9 commit 8de856c

File tree

3 files changed

+107
-13
lines changed

3 files changed

+107
-13
lines changed

src/shared/clients/codecatalystClient.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
ListSourceRepositoriesItem,
3030
ListSourceRepositoriesItems,
3131
} from 'aws-sdk/clients/codecatalyst'
32-
import { truncate } from '../utilities/textUtilities'
32+
import { truncateProps } from '../utilities/textUtilities'
3333

3434
interface CodeCatalystConfig {
3535
readonly region: string
@@ -267,12 +267,17 @@ class CodeCatalystClientInternal {
267267
'API request failed (time: %dms): %s\nparams: %O\nerror: %O\nheaders: %O',
268268
timecost,
269269
r.operation,
270-
r.params,
270+
truncateProps(r.params, 20, ['nextToken']),
271271
errNoStack,
272272
logHeaders
273273
)
274274
} else {
275-
log.error('API request failed (time: %dms):%O\nheaders: %O', timecost, req, logHeaders)
275+
log.error(
276+
'API request failed (time: %dms):%O\nheaders: %O',
277+
timecost,
278+
truncateProps(req, 20, ['nextToken']),
279+
logHeaders
280+
)
276281
}
277282
if (silent) {
278283
if (defaultVal === undefined) {
@@ -285,19 +290,12 @@ class CodeCatalystClientInternal {
285290
return
286291
}
287292
if (log.logLevelEnabled('verbose')) {
288-
const truncatedData = {
289-
...data,
290-
nextToken: (data as any)?.nextToken ?? '',
291-
}
292-
if (truncatedData.nextToken && typeof truncatedData.nextToken === 'string') {
293-
truncatedData.nextToken = truncate(truncatedData.nextToken, 20)
294-
}
295293
log.verbose(
296294
'API request (time: %dms): %s\nparams: %O\nresponse: %O',
297295
timecost,
298296
r.operation ?? '?',
299-
r.params ?? '?',
300-
truncatedData
297+
r.params ? truncateProps(r.params, 20, ['nextToken']) : '?',
298+
truncateProps(data as object, 20, ['nextToken'])
301299
)
302300
}
303301
resolve(data)

src/shared/utilities/textUtilities.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,63 @@ import { default as stripAnsi } from 'strip-ansi'
1010
import { isCloud9 } from '../extensionUtilities'
1111
import { getLogger } from '../logger'
1212

13+
/**
14+
* Truncates string `s` if it exceeds `len` chars.
15+
*
16+
* @param s String to truncate
17+
* @param len Truncate top-level string properties exceeding this length
18+
* @param suffix String appended to truncated value (default: "…")
19+
*/
20+
export function truncate(s: string, len: number, suffix?: string): string {
21+
suffix = suffix ?? '…'
22+
if (len <= 0) {
23+
throw Error(`invalid len: ${len}`)
24+
}
25+
if (s === undefined || s.length <= len) {
26+
return s
27+
}
28+
return `${s.substring(0, len)}${suffix}`
29+
}
30+
31+
/**
32+
* Creates a (shallow) clone of `obj` and truncates its top-level string properties.
33+
*
34+
* @param obj Object to copy and truncate
35+
* @param len Truncate top-level string properties exceeding this length
36+
* @param propNames Only truncate properties in this list
37+
* @param suffix String appended to truncated values (default: "…")
38+
*/
39+
export function truncateProps(obj: object, len: number, propNames?: string[], suffix?: string): object {
40+
if (len <= 0) {
41+
throw Error(`invalid len: ${len}`)
42+
}
43+
// Shallow-copy to avoid modifying the original object.
44+
const r = { ...obj }
45+
46+
if (propNames) {
47+
for (const propName of propNames) {
48+
try {
49+
const val = (r as any)[propName]
50+
if (val !== undefined && typeof val === 'string') {
51+
;(r as any)[propName] = truncate(val, len, suffix)
52+
}
53+
} catch {
54+
// Do nothing ("best effort").
55+
}
56+
}
57+
} else {
58+
for (const propName of Object.getOwnPropertyNames(r)) {
59+
try {
60+
;(r as any)[propName] = truncate((r as any)[propName], len, suffix)
61+
} catch {
62+
// Do nothing ("best effort").
63+
}
64+
}
65+
}
66+
67+
return r
68+
}
69+
1370
export function removeAnsi(text: string): string {
1471
try {
1572
return stripAnsi(text)

src/test/shared/utilities/textUtilities.test.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,46 @@
44
*/
55

66
import * as assert from 'assert'
7-
import { getRelativeDate, getStringHash, removeAnsi } from '../../../shared/utilities/textUtilities'
7+
import { getRelativeDate, getStringHash, removeAnsi, truncateProps } from '../../../shared/utilities/textUtilities'
8+
9+
describe('textUtilities', async function () {
10+
it('truncateProps()', async function () {
11+
const testObj = {
12+
a: 34234234234,
13+
b: '123456789',
14+
c: new Date(2023, 1, 1),
15+
d: '123456789_abcdefg_ABCDEFG',
16+
e: {
17+
e1: [4, 3, 7],
18+
e2: 'loooooooooo \n nnnnnnnnnnn \n gggggggg \n string',
19+
},
20+
f: () => {
21+
throw Error()
22+
},
23+
}
24+
const expected = {
25+
...testObj,
26+
e: {
27+
e1: [...testObj.e.e1],
28+
e2: testObj.e.e2,
29+
},
30+
}
31+
32+
assert.deepStrictEqual(truncateProps(testObj, 25), expected)
33+
assert.deepStrictEqual(truncateProps(testObj, 3, ['b']), {
34+
...expected,
35+
b: '123…',
36+
})
37+
// Assert that original object didn't change.
38+
assert.deepStrictEqual(truncateProps(testObj, 25), expected)
39+
40+
assert.deepStrictEqual(truncateProps(testObj, 3, ['a', 'b', 'd', 'f']), {
41+
...expected,
42+
b: '123…',
43+
d: '123…',
44+
})
45+
})
46+
})
847

948
describe('removeAnsi', async function () {
1049
it('removes ansi code from text', async function () {

0 commit comments

Comments
 (0)