Skip to content

Commit b753e82

Browse files
authored
refactor(logger): log some objects at higher depth #5984
## Problem Deeply nested objects fail to show up in the logger due to use of `%O` instead of `JSON.stringify`. Some customers use this information for debugging or other purposes. Ex. ``` 2024-11-12 13:23:39.682 [info] request from tab: tab-1 conversationID: 619df9a2-3ab2-4676-9896-9eb608d80582 request: { conversationState: { currentMessage: { userInputMessage: [Object] }, chatTriggerType: 'MANUAL', customizationArn: undefined } } ``` ## Solution - Change codewhisper chat request/response log messages (which are very deeply nested) back to `JSON.stringify`.
1 parent b173d6c commit b753e82

File tree

4 files changed

+55
-7
lines changed

4 files changed

+55
-7
lines changed

packages/core/src/codewhispererChat/controllers/chat/controller.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import { globals, waitUntil } from '../../../shared'
5353
import { telemetry } from '../../../shared/telemetry'
5454
import { Auth } from '../../../auth'
5555
import { isSsoConnection } from '../../../auth/connection'
56+
import { inspect } from '../../../shared/utilities/collectionUtils'
5657

5758
export interface ChatControllerMessagePublishers {
5859
readonly processPromptChatMessage: MessagePublisher<PromptMessage>
@@ -656,7 +657,11 @@ export class ChatController {
656657

657658
const request = triggerPayloadToChatRequest(triggerPayload)
658659
const session = this.sessionStorage.getSession(tabID)
659-
getLogger().info(`request from tab: ${tabID} conversationID: ${session.sessionIdentifier} request: %O`, request)
660+
getLogger().info(
661+
`request from tab: ${tabID} conversationID: ${session.sessionIdentifier} request: ${inspect(request, {
662+
depth: 12,
663+
})}`
664+
)
660665
let response: MessengerResponseType | undefined = undefined
661666
session.createNewTokenSource()
662667
try {
@@ -681,8 +686,7 @@ export class ChatController {
681686
getLogger().info(
682687
`response to tab: ${tabID} conversationID: ${session.sessionIdentifier} requestID: ${
683688
response.$metadata.requestId
684-
} metadata: %O`,
685-
response.$metadata
689+
} metadata: ${inspect(response.$metadata, { depth: 12 })}`
686690
)
687691
await this.messenger.sendAIResponse(response, session, tabID, triggerID, triggerPayload)
688692
} catch (e: any) {

packages/core/src/shared/utilities/collectionUtils.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6+
import { isWeb } from '../extensionGlobals'
7+
import { inspect as nodeInspect } from 'util'
68
import { AsyncCollection, toCollection } from './asyncCollection'
79
import { SharedProp, AccumulableKeys, Coalesce, isNonNullable } from './tsUtils'
810

@@ -297,7 +299,6 @@ export function assign<T extends Record<any, any>, U extends Partial<T>>(data: T
297299
* - depth=2 returns `obj` with its children and their children.
298300
* - and so on...
299301
*
300-
* TODO: node's `util.inspect()` function is better, but doesn't work in web browser?
301302
*
302303
* @param obj Object to clone.
303304
* @param depth
@@ -329,6 +330,18 @@ export function partialClone(obj: any, depth: number = 3, omitKeys: string[] = [
329330
return clonedObj
330331
}
331332

333+
/**
334+
* Wrapper around nodes inspect function that works on web. Defaults to JSON.stringify on web.
335+
* @param obj object to show
336+
* @param opt options for showing (ex. depth, omitting keys)
337+
*/
338+
export function inspect(obj: any, opt?: { depth: number }): string {
339+
const options = {
340+
depth: opt?.depth ?? 3,
341+
}
342+
return isWeb() ? JSON.stringify(partialClone(obj, options.depth), undefined, 2) : nodeInspect(obj, options)
343+
}
344+
332345
/** Recursively delete undefined key/value pairs */
333346
export function stripUndefined<T extends Record<string, any>>(
334347
obj: T

packages/core/src/test/shared/utilities/collectionUtils.test.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
joinAll,
3232
isPresent,
3333
partialClone,
34+
inspect,
3435
} from '../../../shared/utilities/collectionUtils'
3536

3637
import { asyncGenerator } from '../../../shared/utilities/collectionUtils'
@@ -511,7 +512,7 @@ describe('CollectionUtils', async function () {
511512
const requester = async (request: { next?: string }) => pages[request.next ?? 'page1']
512513

513514
it('creates a new AsyncCollection', async function () {
514-
const collection = pageableToCollection(requester, {}, 'next', 'data')
515+
const collection = pageableToCollection(requester, {}, 'next' as never, 'data')
515516
assert.deepStrictEqual(await collection.promise(), [[0, 1, 2], [3, 4], [5], []])
516517
})
517518

@@ -540,7 +541,7 @@ describe('CollectionUtils', async function () {
540541

541542
describe('last', function () {
542543
it('it persists last element when mapped', async function () {
543-
const collection = pageableToCollection(requester, {}, 'next', 'data')
544+
const collection = pageableToCollection(requester, {}, 'next' as never, 'data')
544545
const mapped = collection.map((i) => i[0] ?? -1)
545546
assert.strictEqual(await last(mapped), -1)
546547
})
@@ -679,6 +680,36 @@ describe('CollectionUtils', async function () {
679680
})
680681
})
681682

683+
describe('inspect', function () {
684+
let testData: any
685+
before(function () {
686+
testData = {
687+
root: {
688+
A: {
689+
B: {
690+
C: {
691+
D: {
692+
E: 'data',
693+
},
694+
},
695+
},
696+
},
697+
},
698+
}
699+
})
700+
701+
it('defaults to a depth of 3', function () {
702+
assert.strictEqual(inspect(testData), '{\n root: { A: { B: { C: [Object] } } }\n}')
703+
})
704+
705+
it('allows depth to be set manually', function () {
706+
assert.strictEqual(
707+
inspect(testData, { depth: 6 }),
708+
"{\n root: {\n A: {\n B: { C: { D: { E: 'data' } } }\n }\n }\n}"
709+
)
710+
})
711+
})
712+
682713
describe('partialClone', function () {
683714
it('omits properties by depth', function () {
684715
const testObj = {

plugins/eslint-plugin-aws-toolkits/lib/rules/no-json-stringify-in-log.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { AST_NODE_TYPES, ESLintUtils, TSESTree } from '@typescript-eslint/utils'
77
import { Rule } from 'eslint'
88

99
export const errMsg =
10-
'Avoid using JSON.stringify within logging and error messages, prefer %O. Note: %O has a depth limit of 2'
10+
'Avoid using JSON.stringify within logging and error messages, prefer %O in general or inspect from collectionUtils for custom depth formatting'
1111

1212
/**
1313
* Check if a given expression is a JSON.stringify call.

0 commit comments

Comments
 (0)