Skip to content

Commit bc3b392

Browse files
committed
feat: generalize performance logging into utility
1 parent e90c374 commit bc3b392

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

packages/core/src/shared/clients/clientWrapper.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { AwsClient, AwsClientConstructor, AwsCommand, AwsCommandConstructor } fr
88
import { PaginationConfiguration, Paginator } from '@aws-sdk/types'
99
import { AsyncCollection, toCollection } from '../utilities/asyncCollection'
1010
import { isDefined } from '../utilities/tsUtils'
11+
import { withPerfLogOnFail } from '../logger/perfLogger'
12+
import { truncateProps } from '../utilities/textUtilities'
1113

1214
type SDKPaginator<C, CommandInput extends object, CommandOutput extends object> = (
1315
config: Omit<PaginationConfiguration, 'client'> & { client: C },
@@ -35,7 +37,14 @@ export abstract class ClientWrapper<C extends AwsClient> implements vscode.Dispo
3537
CommandOptions extends CommandInput,
3638
Command extends AwsCommand<CommandInput, CommandOutput>,
3739
>(command: AwsCommandConstructor<CommandInput, Command>, commandOptions: CommandOptions): Promise<CommandOutput> {
38-
return await this.getClient().send(new command(commandOptions))
40+
const makeRequest = withPerfLogOnFail(
41+
'API Request',
42+
() => this.getClient().send(new command(commandOptions)),
43+
truncateProps(commandOptions, 20, ['nextToken']),
44+
mapNameToCode
45+
)
46+
47+
return makeRequest()
3948
}
4049

4150
protected makePaginatedRequest<CommandInput extends object, CommandOutput extends object, Output extends object>(
@@ -65,3 +74,7 @@ export abstract class ClientWrapper<C extends AwsClient> implements vscode.Dispo
6574
this.client?.destroy()
6675
}
6776
}
77+
78+
function mapNameToCode<E extends Error>(e: E): E & { code: string } {
79+
return { ...e, message: e.message, name: e.name, stack: e.stack, code: e.message }
80+
}

packages/core/src/shared/logger/perfLogger.ts

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

6+
import { ToolkitError } from '../errors'
67
import { getLogger } from './logger'
78

89
export class PerfLog {
@@ -27,3 +28,39 @@ export class PerfLog {
2728
this.log.verbose('%s took %dms', this.topic, elapsed.toFixed(1))
2829
}
2930
}
31+
32+
/**
33+
* Call a function f and if it fails, log the error with performance information included.
34+
* @param action label of action in the error log.
35+
* @param f action to attempt.
36+
* @param params params that were passed to f.
37+
* @param errMap optional mapping to apply to error to potentially add information.
38+
* @returns result of f
39+
*/
40+
export function withPerfLogOnFail<Result, E extends Error = never>(
41+
action: string,
42+
f: () => Result | Promise<Result>,
43+
params: object = {},
44+
errMap?: (e: Error) => E
45+
) {
46+
return async function () {
47+
const perflog = new PerfLog(action)
48+
try {
49+
return await f()
50+
} catch (e) {
51+
if (e instanceof Error) {
52+
const errWithoutStack = errMap ? errMap(e) : { ...e }
53+
delete errWithoutStack['stack']
54+
const timecost = perflog.elapsed().toFixed(1)
55+
getLogger().error(
56+
`${action} failed (time: %dms) \nparams: %O\nerror: %O`,
57+
timecost,
58+
params,
59+
errWithoutStack
60+
)
61+
throw new ToolkitError(`${action}: ${e.message}`, { code: e.message, cause: e })
62+
}
63+
throw e
64+
}
65+
}
66+
}

0 commit comments

Comments
 (0)