|
| 1 | +import { |
| 2 | + HandlerExecutionContext, |
| 3 | + InitializeHandler, |
| 4 | + InitializeHandlerArguments, |
| 5 | + MiddlewareStack, |
| 6 | + SerializeHandler, |
| 7 | + SerializeHandlerArguments, |
| 8 | +} from "@smithy/types"; |
| 9 | + |
| 10 | +/** |
| 11 | + * FOR DEBUG USE ONLY. |
| 12 | + * This plugin logs or records the timings of the middleware named in options.middlewareNames. |
| 13 | + * |
| 14 | + * @param options.middlewareNames - names of the middleware to measure. |
| 15 | + * @param options.storage - a container for the data. If none is provided, metrics will be logged to console. |
| 16 | + * |
| 17 | + * @beta |
| 18 | + */ |
| 19 | +export function getMiddlewareTimerPlugin( |
| 20 | + options: { |
| 21 | + middlewareNames?: string[]; |
| 22 | + storage?: Record<string, number[]>; |
| 23 | + } = {} |
| 24 | +) { |
| 25 | + const middlewareNames = |
| 26 | + options.middlewareNames ?? |
| 27 | + (["serializerMiddleware", "deserializerMiddleware", "httpSigningMiddleware", "retryMiddleware"] as string[]); |
| 28 | + |
| 29 | + return { |
| 30 | + applyToStack(middlewareStack: MiddlewareStack<any, any>) { |
| 31 | + for (const mw of middlewareNames) { |
| 32 | + middlewareStack.addRelativeTo( |
| 33 | + (next: SerializeHandler<any, any>, context: HandlerExecutionContext) => |
| 34 | + async (args: SerializeHandlerArguments<any>) => { |
| 35 | + context.middlewareTimings[mw].leaderPreNext = performance.now(); |
| 36 | + const handlerOutput = await next(args); |
| 37 | + context.middlewareTimings[mw].leaderPostNext = performance.now(); |
| 38 | + return handlerOutput; |
| 39 | + }, |
| 40 | + { |
| 41 | + name: mw + "-before", |
| 42 | + override: true, |
| 43 | + toMiddleware: mw, |
| 44 | + relation: "before", |
| 45 | + } |
| 46 | + ); |
| 47 | + |
| 48 | + middlewareStack.addRelativeTo( |
| 49 | + (next: SerializeHandler<any, any>, context: HandlerExecutionContext) => |
| 50 | + async (args: SerializeHandlerArguments<any>) => { |
| 51 | + context.middlewareTimings[mw].trailerPreNext = performance.now(); |
| 52 | + const handlerOutput = await next(args); |
| 53 | + context.middlewareTimings[mw].trailerPostNext = performance.now(); |
| 54 | + return handlerOutput; |
| 55 | + }, |
| 56 | + { |
| 57 | + name: mw + "-after", |
| 58 | + override: true, |
| 59 | + toMiddleware: mw, |
| 60 | + relation: "after", |
| 61 | + } |
| 62 | + ); |
| 63 | + } |
| 64 | + |
| 65 | + middlewareStack.add( |
| 66 | + (next: InitializeHandler<any, any>, context: HandlerExecutionContext) => |
| 67 | + async (args: InitializeHandlerArguments<any>) => { |
| 68 | + context.middlewareTimings = context.middlewareTimings ?? ({} as Record<string, Record<string, number>>); |
| 69 | + for (const mw of middlewareNames) { |
| 70 | + context.middlewareTimings[mw] = {} as Record<string, number>; |
| 71 | + } |
| 72 | + |
| 73 | + const handlerOutput = await next(args); |
| 74 | + |
| 75 | + for (const [mw, timings] of Object.entries( |
| 76 | + context.middlewareTimings as Record<string, Record<string, number>> |
| 77 | + )) { |
| 78 | + const { leaderPreNext, trailerPreNext, trailerPostNext, leaderPostNext } = timings; |
| 79 | + /** |
| 80 | + * Formula note: |
| 81 | + * |
| 82 | + * Let M be the middleware we are measuring. |
| 83 | + * Let L be the middleware prior to the measured middleware, |
| 84 | + * and T be the middleware after the measured middleware. |
| 85 | + * |
| 86 | + * We take timings before L calls next, after L calls next, |
| 87 | + * before T calls next, and after T calls next. |
| 88 | + * |
| 89 | + * The own-time of M is therefore the period from: |
| 90 | + * L-pre-next (before entering M from L) -> T-pre-next (after exiting M to T) |
| 91 | + * plus |
| 92 | + * T-post-next (return to M from T) -> L-post-next (exiting M to L) |
| 93 | + */ |
| 94 | + const middlewareOwnTime = trailerPreNext - leaderPreNext + leaderPostNext - trailerPostNext; |
| 95 | + |
| 96 | + if (options.storage) { |
| 97 | + options.storage[mw] = options.storage[mw] ?? []; |
| 98 | + options.storage[mw].push(middlewareOwnTime); |
| 99 | + } else { |
| 100 | + console.log({ |
| 101 | + [mw]: middlewareOwnTime, |
| 102 | + }); |
| 103 | + } |
| 104 | + } |
| 105 | + return handlerOutput; |
| 106 | + }, |
| 107 | + { |
| 108 | + name: "middleware-timing-logger-middleware", |
| 109 | + override: true, |
| 110 | + step: "initialize", |
| 111 | + } |
| 112 | + ); |
| 113 | + }, |
| 114 | + }; |
| 115 | +} |
0 commit comments