From 0d78afc4e7d18168a0efcab994ec14e9445a05ee Mon Sep 17 00:00:00 2001 From: Momo Kornher Date: Thu, 23 Jan 2025 19:56:56 +0000 Subject: [PATCH] fix(cli): trace output (-vv) is useless when files are uploaded --- .../aws-cdk/lib/api/aws-auth/sdk-logger.ts | 3 +- packages/aws-cdk/lib/serialize.ts | 33 +++++++++++++++++++ packages/aws-cdk/lib/util/bytes.ts | 21 ++++++++++++ packages/aws-cdk/test/util/bytes.test.ts | 18 ++++++++++ packages/aws-cdk/test/util/serialize.test.ts | 7 ++++ 5 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 packages/aws-cdk/lib/util/bytes.ts create mode 100644 packages/aws-cdk/test/util/bytes.test.ts create mode 100644 packages/aws-cdk/test/util/serialize.test.ts diff --git a/packages/aws-cdk/lib/api/aws-auth/sdk-logger.ts b/packages/aws-cdk/lib/api/aws-auth/sdk-logger.ts index ce1b981bab0d1..9a05d10283f31 100644 --- a/packages/aws-cdk/lib/api/aws-auth/sdk-logger.ts +++ b/packages/aws-cdk/lib/api/aws-auth/sdk-logger.ts @@ -1,6 +1,7 @@ import { inspect } from 'util'; import { Logger } from '@smithy/types'; import { trace } from '../../logging'; +import { replacerBufferWithInfo } from '../../serialize'; export class SdkToCliLogger implements Logger { public trace(..._content: any[]) { @@ -105,7 +106,7 @@ function formatApiCall(content: any): string | undefined { parts.push(`[${content.metadata?.attempts} attempts, ${content.metadata?.totalRetryDelay}ms retry]`); } - parts.push(`${service}.${api}(${JSON.stringify(content.input)})`); + parts.push(`${service}.${api}(${JSON.stringify(content.input, replacerBufferWithInfo)})`); if (isSdkApiCallSuccess(content)) { parts.push('-> OK'); diff --git a/packages/aws-cdk/lib/serialize.ts b/packages/aws-cdk/lib/serialize.ts index 9f310c95b3f78..7a6e836268036 100644 --- a/packages/aws-cdk/lib/serialize.ts +++ b/packages/aws-cdk/lib/serialize.ts @@ -1,4 +1,5 @@ import * as fs from 'fs-extra'; +import { formatBytes } from './util/bytes'; import * as yaml_cfn from './util/yaml-cfn'; /** @@ -51,3 +52,35 @@ export function obscureTemplate(template: any = {}) { return template; } + +/** + * Detects a buffer that has been converted to a JSON-like object + * In Node, `Buffer`s have `toJSON()` method that converts the buffer + * into a JS object that can be JSON stringified. + * Unfortunately this conversion happens before the replacer is called, + * so normal means of detecting a `Buffer` objet don't work anymore. + * @see https://github.com/nodejs/node-v0.x-archive/issues/5110 + */ +function isJsonBuffer(value: any): value is { + type: 'Buffer'; + data: number[]; +} { + return typeof value === 'object' + && 'type' in value + && value.type === 'Buffer' + && 'data' in value + && Array.isArray(value.data); +} + +/** + * A JSON.stringify() replacer that converts Buffers into a string with information + * Use this if you plan to print out JSON stringified objects that may contain a Buffer. + * Without this, large buffers (think: Megabytes) will completely fill up the output + * and even crash the system. + */ +export function replacerBufferWithInfo(_key: any, value: any): any { + if (isJsonBuffer(value)) { + return ``; + } + return value; +} diff --git a/packages/aws-cdk/lib/util/bytes.ts b/packages/aws-cdk/lib/util/bytes.ts new file mode 100644 index 0000000000000..22226d049b05d --- /dev/null +++ b/packages/aws-cdk/lib/util/bytes.ts @@ -0,0 +1,21 @@ +/** + * Format bytes as a human readable string + * + * @param bytes Number of bytes to format + * @param decimals Number of decimal places to show (default 2) + * @returns Formatted string with appropriate unit suffix + */ +export function formatBytes(bytes: number, decimals: number = 2): string { + decimals = decimals < 0 ? 0 : decimals; + + if (bytes === 0) { + return '0 Bytes'; + } + + const k = 1024; + const sizes = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']; + + const i = Math.floor(Math.log(bytes) / Math.log(k)); + + return `${parseFloat((bytes / Math.pow(k, i)).toFixed(decimals))} ${sizes[i]}`; +} diff --git a/packages/aws-cdk/test/util/bytes.test.ts b/packages/aws-cdk/test/util/bytes.test.ts new file mode 100644 index 0000000000000..9292af4f338ff --- /dev/null +++ b/packages/aws-cdk/test/util/bytes.test.ts @@ -0,0 +1,18 @@ +import { formatBytes } from '../../lib/util/bytes'; + +test.each([ + [0, '0 Bytes'], + [10, '10 Bytes'], + [1024, '1 KiB'], + [10.5 * 1024 * 1024, '10.5 MiB'], +])('converts %s bytes to %s', (bytes: number, expected: string) => { + expect(formatBytes(bytes)).toEqual(expected); +}); + +test('can format many decimals', () => { + expect(formatBytes(10.51234 * 1024 * 1024, 5)).toEqual('10.51234 MiB'); +}); + +test('can deal with negative decimals', () => { + expect(formatBytes(10.5 * 1024 * 1024, -1)).toEqual('11 MiB'); +}); diff --git a/packages/aws-cdk/test/util/serialize.test.ts b/packages/aws-cdk/test/util/serialize.test.ts new file mode 100644 index 0000000000000..65eab98b00cb4 --- /dev/null +++ b/packages/aws-cdk/test/util/serialize.test.ts @@ -0,0 +1,7 @@ +import { replacerBufferWithInfo } from '../../lib/serialize'; + +test('converts buffer to information', () => { + const res = JSON.stringify({ data: Buffer.from('test data') }, replacerBufferWithInfo); + + expect(res).toEqual('{"data":""}'); +});