Skip to content

Commit 11f8839

Browse files
committed
fixup! feat(logging): support logger instances
1 parent 541b952 commit 11f8839

File tree

10 files changed

+46
-78
lines changed

10 files changed

+46
-78
lines changed

packages/core/src/codewhisperer/activation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export async function activate(context: ExtContext): Promise<void> {
114114

115115
// TODO: this is already done in packages/core/src/extensionCommon.ts, why doesn't amazonq use that?
116116
registerWebviewErrorHandler((error: unknown, webviewId: string, command: string) => {
117-
logAndShowWebviewError(localize, error, webviewId, command)
117+
return logAndShowWebviewError(localize, error, webviewId, command)
118118
})
119119

120120
/**

packages/core/src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export async function activateCommon(
8383
})
8484

8585
registerWebviewErrorHandler((error: unknown, webviewId: string, command: string) => {
86-
logAndShowWebviewError(localize, error, webviewId, command)
86+
return logAndShowWebviewError(localize, error, webviewId, command)
8787
})
8888

8989
// Setup the logger

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ export async function logAndShowError(
5252
* @param err The error that was thrown in the backend
5353
* @param webviewId Arbitrary value that identifies which webview had the error
5454
* @param command The high level command/function that was run which triggered the error
55+
*
56+
* @returns user-facing error
5557
*/
5658
export function logAndShowWebviewError(localize: nls.LocalizeFunc, err: unknown, webviewId: string, command: string) {
5759
// HACK: The following implementation is a hack, influenced by the implementation of handleError().
@@ -62,4 +64,6 @@ export function logAndShowWebviewError(localize: nls.LocalizeFunc, err: unknown,
6264
logAndShowError(localize, userFacingError, `webviewId="${webviewId}"`, 'Webview error').catch((e) => {
6365
getLogger().error('logAndShowError failed: %s', (e as Error).message)
6466
})
67+
68+
return userFacingError
6569
}

packages/core/src/test/codewhisperer/commands/basicCommands.test.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import { stub } from '../../utilities/stubber'
2828
import { AuthUtil } from '../../../codewhisperer/util/authUtil'
2929
import { getTestWindow } from '../../shared/vscode/window'
3030
import { ExtContext } from '../../../shared/extensions'
31-
import { getLogger } from '../../../shared/logger/logger'
3231
import {
3332
createAutoScans,
3433
createAutoSuggestions,
@@ -57,6 +56,7 @@ import * as diagnosticsProvider from '../../../codewhisperer/service/diagnostics
5756
import { SecurityIssueHoverProvider } from '../../../codewhisperer/service/securityIssueHoverProvider'
5857
import { SecurityIssueCodeActionProvider } from '../../../codewhisperer/service/securityIssueCodeActionProvider'
5958
import { randomUUID } from '../../../shared/crypto'
59+
import { assertLogsContain } from '../../globalSetup.test'
6060

6161
describe('CodeWhisperer-basicCommands', function () {
6262
let targetCommand: Command<any> & vscode.Disposable
@@ -636,7 +636,6 @@ describe('CodeWhisperer-basicCommands', function () {
636636
openTextDocumentMock.resolves(textDocumentMock)
637637

638638
sandbox.stub(vscode.workspace, 'openTextDocument').value(openTextDocumentMock)
639-
const loggerStub = sinon.stub(getLogger(), 'error')
640639

641640
sinon.stub(vscode.WorkspaceEdit.prototype, 'replace').value(replaceMock)
642641
applyEditMock.resolves(false)
@@ -652,9 +651,7 @@ describe('CodeWhisperer-basicCommands', function () {
652651
await targetCommand.execute(codeScanIssue, fileName, 'quickfix')
653652

654653
assert.ok(replaceMock.calledOnce)
655-
assert.ok(loggerStub.calledOnce)
656-
const actual = loggerStub.getCall(0).args[0]
657-
assert.strictEqual(actual, 'Apply fix command failed. Error: Failed to apply edit to the workspace.')
654+
assertLogsContain('Apply fix command failed. Error: Failed to apply edit to the workspace.', true, 'error')
658655
assertTelemetry('codewhisperer_codeScanIssueApplyFix', {
659656
detectorId: codeScanIssue.detectorId,
660657
findingId: codeScanIssue.findingId,

packages/core/src/test/globalSetup.test.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -169,18 +169,17 @@ async function writeLogsToFile(testName: string) {
169169

170170
// TODO: merge this with `toolkitLogger.test.ts:checkFile`
171171
export function assertLogsContain(text: string, exactMatch: boolean, severity: LogLevel) {
172+
const logs = getTestLogger().getLoggedEntries(severity)
172173
assert.ok(
173-
getTestLogger()
174-
.getLoggedEntries(severity)
175-
.some((e) =>
176-
e instanceof Error
177-
? exactMatch
178-
? e.message === text
179-
: e.message.includes(text)
180-
: exactMatch
181-
? e === text
182-
: e.includes(text)
183-
),
174+
logs.some((e) =>
175+
e instanceof Error
176+
? exactMatch
177+
? e.message === text
178+
: e.message.includes(text)
179+
: exactMatch
180+
? e === text
181+
: e.includes(text)
182+
),
184183
`Expected to find "${text}" in the logs as type "${severity}"`
185184
)
186185
}

packages/core/src/test/lambda/vue/remoteInvoke/invokeLambda.test.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ import { getTestWindow } from '../../../shared/vscode/window'
1616
import { LambdaFunctionNode } from '../../../../lambda/explorer/lambdaFunctionNode'
1717
import * as utils from '../../../../lambda/utils'
1818
import { HttpResourceFetcher } from '../../../../shared/resourcefetcher/httpResourceFetcher'
19-
import { getLogger } from '../../../../shared/logger'
2019
import { ExtContext } from '../../../../shared/extensions'
2120
import { FakeExtensionContext } from '../../../fakeExtensionContext'
2221
import * as samCliRemoteTestEvent from '../../../../shared/sam/cli/samCliRemoteTestEvent'
2322
import { TestEventsOperation, SamCliRemoteTestEventsParameters } from '../../../../shared/sam/cli/samCliRemoteTestEvent'
23+
import { assertLogsContain } from '../../../globalSetup.test'
2424

2525
describe('RemoteInvokeWebview', () => {
2626
let outputChannel: vscode.OutputChannel
@@ -190,20 +190,11 @@ describe('RemoteInvokeWebview', () => {
190190

191191
getTestWindow().onDidShowDialog((d) => d.selectItem(fileUri))
192192

193-
const loggerErrorStub = sinon.stub(getLogger(), 'error')
194-
195-
try {
196-
await assert.rejects(
197-
async () => await remoteInvokeWebview.promptFile(),
198-
new Error('Failed to read selected file')
199-
)
200-
assert.strictEqual(loggerErrorStub.calledOnce, true)
201-
assert.strictEqual(loggerErrorStub.firstCall.args[0], 'readFileSync: Failed to read file at path %s %O')
202-
assert.strictEqual(loggerErrorStub.firstCall.args[1], fileUri.fsPath)
203-
assert(loggerErrorStub.firstCall.args[2] instanceof Error)
204-
} finally {
205-
loggerErrorStub.restore()
206-
}
193+
await assert.rejects(
194+
async () => await remoteInvokeWebview.promptFile(),
195+
new Error('Failed to read selected file')
196+
)
197+
assertLogsContain('readFileSync: Failed to read file at path %s %O', true, 'error')
207198
})
208199
})
209200

packages/core/src/test/lambda/vue/samInvokeBackend.test.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ import path from 'path'
2222
import { addCodiconToString, fs, makeTemporaryToolkitFolder } from '../../../shared'
2323
import { LaunchConfiguration } from '../../../shared/debug/launchConfiguration'
2424
import { getTestWindow } from '../..'
25-
import { getLogger } from '../../../shared/logger'
2625
import * as extensionUtilities from '../../../shared/extensionUtilities'
2726
import * as samInvokeBackend from '../../../lambda/vue/configEditor/samInvokeBackend'
2827
import { SamDebugConfigProvider } from '../../../shared/sam/debugger/awsSamDebugger'
2928
import sinon from 'sinon'
3029
import * as nls from 'vscode-nls'
30+
import { assertLogsContain } from '../../../test/globalSetup.test'
3131

3232
const localize = nls.loadMessageBundle()
3333

@@ -438,19 +438,13 @@ describe('SamInvokeWebview', () => {
438438

439439
getTestWindow().onDidShowDialog((window) => window.selectItem(fileUri))
440440

441-
const loggerErrorStub = sinon.stub(getLogger(), 'error')
442-
443441
try {
444442
await assert.rejects(
445443
async () => await samInvokeWebview.promptFile(),
446444
new Error('Failed to read selected file')
447445
)
448-
assert.strictEqual(loggerErrorStub.calledOnce, true)
449-
assert.strictEqual(loggerErrorStub.firstCall.args[0], 'readFileSync: Failed to read file at path %s %O')
450-
assert.strictEqual(loggerErrorStub.firstCall.args[1], fileUri.fsPath)
451-
assert(loggerErrorStub.firstCall.args[2] instanceof Error)
446+
assertLogsContain('readFileSync: Failed to read file at path %s %O', true, 'error')
452447
} finally {
453-
loggerErrorStub.restore()
454448
await fs.delete(tempFolder, { recursive: true })
455449
}
456450
})

packages/core/src/test/shared/applicationBuilder/explorer/nodes/deployedNode.test.ts

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,19 @@ import { LambdaFunctionNode } from '../../../../../lambda/explorer/lambdaFunctio
1919
import { RestApiNode } from '../../../../../awsService/apigateway/explorer/apiNodes'
2020
import { S3BucketNode } from '../../../../../awsService/s3/explorer/s3BucketNode'
2121
import * as LambdaNodeModule from '../../../../../lambda/explorer/lambdaNodes'
22-
import { getLogger } from '../../../../../shared/logger/logger'
2322
import { getIcon } from '../../../../../shared/icons'
2423
import _ from 'lodash'
2524
import { isTreeNode } from '../../../../../shared/treeview/resourceTreeDataProvider'
2625
import { Any } from '../../../../../shared/utilities/typeConstructors'
2726
import { IamConnection, ProfileMetadata } from '../../../../../auth/connection'
2827
import * as AuthUtils from '../../../../../auth/utils'
28+
import { assertLogsContain } from '../../../../../test/globalSetup.test'
2929

3030
describe('DeployedResourceNode', () => {
3131
const expectedStackName = 'myStack'
3232
const expectedRegionCode = 'us-west-2'
33-
let loggerWarnStub: sinon.SinonStub<[message: string | Error, ...meta: any[]], number>
3433

35-
beforeEach(() => {
36-
// Create a stub for the entire logger module
37-
loggerWarnStub = sinon.stub(getLogger(), 'warn')
38-
})
34+
beforeEach(() => {})
3935

4036
afterEach(() => {
4137
// Restore the original function after each test
@@ -87,8 +83,7 @@ describe('DeployedResourceNode', () => {
8783
assert.strictEqual(deployedLambdaNode.id, '')
8884
assert.strictEqual(deployedLambdaNode.contextValue, '')
8985
assert.deepStrictEqual(deployedLambdaNode.resource, emptyArnDeployedResource)
90-
assert(loggerWarnStub.calledOnce)
91-
assert(loggerWarnStub.calledWith('Cannot create DeployedResourceNode, the ARN does not exist.'))
86+
assertLogsContain('Cannot create DeployedResourceNode, the ARN does not exist.', false, 'warn')
9287
})
9388
})
9489
})
@@ -121,17 +116,13 @@ describe('DeployedResourceNode', () => {
121116
describe('generateDeployedNode', () => {
122117
const expectedStackName = 'myStack'
123118
const expectedRegionCode = 'us-west-2'
124-
let loggerErrorStub: sinon.SinonStub<[message: string | Error, ...meta: any[]], number>
125-
let loggerInfoStub: sinon.SinonStub<[message: string | Error, ...meta: any[]], number>
126119

127120
let sandbox: sinon.SinonSandbox
128121

129122
beforeEach(() => {
130123
// Initiate stub sanbox
131124
sandbox = sinon.createSandbox()
132125
// Create a stub for the entire logger module
133-
loggerErrorStub = sandbox.stub(getLogger(), 'error')
134-
loggerInfoStub = sandbox.stub(getLogger(), 'info')
135126
})
136127
afterEach(async () => {
137128
sandbox.restore()
@@ -223,8 +214,7 @@ describe('generateDeployedNode', () => {
223214
lambdaDeployedNodeInput.resourceTreeEntity
224215
)
225216

226-
assert(loggerErrorStub.calledOnceWith('Error getting Lambda configuration %O'))
227-
assert(loggerErrorStub.neverCalledWith('Error getting Lambda V3 configuration %O'))
217+
assertLogsContain('Error getting Lambda configuration %O', true, 'error')
228218
assert(deployedResourceNodes.length === 1)
229219

230220
// Check placeholder propertries
@@ -375,10 +365,7 @@ describe('generateDeployedNode', () => {
375365
unsupportTypeInput.resourceTreeEntity
376366
)
377367

378-
assert(loggerInfoStub.calledOnceWith('Details are missing or are incomplete for: %O'))
379-
380-
// Check deployedResourceNodes array propertries
381-
assert(loggerErrorStub.neverCalledWith('Error getting Lambda V3 configuration %O'))
368+
assertLogsContain('Details are missing or are incomplete for:', false, 'info')
382369

383370
// Check deployedResourceNodes array propertries
384371
assert(deployedResourceNodes.length === 1)

packages/core/src/test/webview/server.test.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,34 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { SinonStub, stub } from 'sinon'
7-
import { Logger, setLogger } from '../../shared/logger/logger'
86
import assert from 'assert'
97
import { ToolkitError } from '../../shared/errors'
108
import { handleWebviewError } from '../../webviews/server'
9+
import { assertLogsContain } from '../globalSetup.test'
1110

1211
describe('logAndShowWebviewError()', function () {
13-
let logError: SinonStub<[message: string, ...meta: any[]], number>
1412
const myWebviewId = 'myWebviewId'
1513
const myCommand = 'myCommand'
1614

17-
beforeEach(function () {
18-
logError = stub()
19-
const logger = { error: logError } as unknown as Logger
20-
setLogger(logger, 'main')
21-
})
15+
beforeEach(function () {})
2216

23-
afterEach(function () {
24-
setLogger(undefined, 'main')
25-
})
17+
afterEach(function () {})
2618

2719
it('logs the provided error, but is wrapped in ToolkitErrors for more context', function () {
2820
// The method is being tested due to its fragile implementation. This test
2921
// protects against changes in the underlying logAndShowError() implementation.
3022

3123
const inputError = new Error('Random Error')
3224

33-
handleWebviewError(inputError, myWebviewId, myCommand)
25+
const err = handleWebviewError(inputError, myWebviewId, myCommand)
3426

35-
assert.strictEqual(logError.callCount, 1)
27+
// assertLogsContain('Random Error', false, 'error')
3628

3729
// A shortened error is shown to the user
38-
const userFacingError = logError.getCall(0).args[1]
39-
assert(userFacingError instanceof ToolkitError)
40-
assert.strictEqual(userFacingError.message, 'Webview error')
30+
assertLogsContain('Webview error', false, 'error')
4131

4232
// A higher level context of what caused the error
43-
const detailedError = userFacingError.cause
33+
const detailedError = err.cause
4434
assert(detailedError instanceof ToolkitError)
4535
assert.strictEqual(detailedError.message, `Webview backend command failed: "${myCommand}()"`)
4636

packages/core/src/webviews/server.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as vscode from 'vscode'
77
import { getLogger } from '../shared/logger'
88
import { Message } from './client'
99
import { AsyncResource } from 'async_hooks'
10+
import { ToolkitError } from '../shared/errors'
1011

1112
interface Command<T extends any[] = any, R = any> {
1213
(...args: T): R | never
@@ -90,7 +91,12 @@ export function registerWebviewServer(
9091
return { dispose: () => (messageListener.dispose(), disposeListeners()) }
9192
}
9293

93-
let errorHandler: (error: unknown, webviewId: string, command: string) => void
94+
/**
95+
* Logs and handles an error.
96+
*
97+
* @returns final, chained, user-facing error
98+
*/
99+
let errorHandler: (error: unknown, webviewId: string, command: string) => ToolkitError
94100
/**
95101
* Registers the handler for errors thrown by the webview backend/server code.
96102
*/
@@ -104,7 +110,7 @@ export function registerWebviewErrorHandler(handler: typeof errorHandler): void
104110
/**
105111
* Invokes the registered webview error handler.
106112
*/
107-
export function handleWebviewError(error: unknown, webviewId: string, command: string): void {
113+
export function handleWebviewError(error: unknown, webviewId: string, command: string): ToolkitError {
108114
if (errorHandler === undefined) {
109115
throw new Error('Webview error handler not registered')
110116
}

0 commit comments

Comments
 (0)