From ea459749f95bd21ba39c7ca6add074b4b1af9950 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Thu, 29 May 2025 16:18:30 -0400 Subject: [PATCH] refactor(data-schemas): enhance type safety in log formatting functions - Introduced type guards to ensure message and symbol values are strings in redactFormat. - Updated parameter types in truncateLongStrings and condenseArray for better type safety. - Improved type handling in debugTraverse and jsonTruncateFormat to prevent runtime errors. - Ensured proper handling of circular references and object types in logging functions. --- packages/data-schemas/src/config/parsers.ts | 53 +++++++++++++-------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/packages/data-schemas/src/config/parsers.ts b/packages/data-schemas/src/config/parsers.ts index 95a1cf8d67..3064844815 100644 --- a/packages/data-schemas/src/config/parsers.ts +++ b/packages/data-schemas/src/config/parsers.ts @@ -59,9 +59,15 @@ function redactMessage(str: string, trimLength?: number): string { */ const redactFormat = winston.format((info: winston.Logform.TransformableInfo) => { if (info.level === 'error') { - info.message = redactMessage(info.message); - if (info[MESSAGE_SYMBOL]) { - info[MESSAGE_SYMBOL] = redactMessage(info[MESSAGE_SYMBOL]); + // Type guard to ensure message is a string + if (typeof info.message === 'string') { + info.message = redactMessage(info.message); + } + + // Handle MESSAGE_SYMBOL with type safety + const symbolValue = (info as Record)[MESSAGE_SYMBOL]; + if (typeof symbolValue === 'string') { + (info as Record)[MESSAGE_SYMBOL] = redactMessage(symbolValue); } } return info; @@ -74,7 +80,7 @@ const redactFormat = winston.format((info: winston.Logform.TransformableInfo) => * @param length - The length at which to truncate the value. Default: 100. * @returns The truncated or original value. */ -const truncateLongStrings = (value: any, length = 100): any => { +const truncateLongStrings = (value: unknown, length = 100): unknown => { if (typeof value === 'string') { return value.length > length ? value.substring(0, length) + '... [truncated]' : value; } @@ -87,7 +93,7 @@ const truncateLongStrings = (value: any, length = 100): any => { * @param item - The item to be condensed. * @returns The condensed item. */ -const condenseArray = (item: any): any => { +const condenseArray = (item: unknown): string | unknown => { if (typeof item === 'string') { return truncateLongStrings(JSON.stringify(item)); } else if (typeof item === 'object') { @@ -107,12 +113,13 @@ const condenseArray = (item: any): any => { * @returns The formatted log message. */ const debugTraverse = winston.format.printf( - ({ level, message, timestamp, ...metadata }: Record) => { + ({ level, message, timestamp, ...metadata }: Record) => { if (!message) { return `${timestamp} ${level}`; } - if (!message?.trim || typeof message !== 'string') { + // Type-safe version of the CJS logic: !message?.trim || typeof message !== 'string' + if (typeof message !== 'string' || !message.trim) { return `${timestamp} ${level}: ${JSON.stringify(message)}`; } @@ -127,26 +134,29 @@ const debugTraverse = winston.format.printf( return msg; } - const debugValue = metadata[SPLAT_SYMBOL]?.[0]; + // Type-safe access to SPLAT_SYMBOL using bracket notation + const metadataRecord = metadata as Record; + const splatArray = metadataRecord[SPLAT_SYMBOL]; + const debugValue = Array.isArray(splatArray) ? splatArray[0] : undefined; if (!debugValue) { return msg; } - if (Array.isArray(debugValue)) { + if (debugValue && Array.isArray(debugValue)) { msg += `\n${JSON.stringify(debugValue.map(condenseArray))}`; return msg; } if (typeof debugValue !== 'object') { - return `${msg} ${debugValue}`; + return (msg += ` ${debugValue}`); } msg += '\n{'; const copy = klona(metadata); - traverse(copy).forEach(function (this: any, value: any) { + traverse(copy).forEach(function (this: traverse.TraverseContext, value: unknown) { if (typeof this?.key === 'symbol') { return; } @@ -180,8 +190,9 @@ const debugTraverse = winston.format.printf( msg += '\n}'; return msg; - } catch (e: any) { - return `${msg}\n[LOGGER PARSING ERROR] ${e.message}`; + } catch (e: unknown) { + const errorMessage = e instanceof Error ? e.message : 'Unknown error'; + return (msg += `\n[LOGGER PARSING ERROR] ${errorMessage}`); } }, ); @@ -190,18 +201,18 @@ const debugTraverse = winston.format.printf( * Truncates long string values in JSON log objects. * Prevents outputting extremely long values (e.g., base64, blobs). */ -const jsonTruncateFormat = winston.format((info: any) => { +const jsonTruncateFormat = winston.format((info: winston.Logform.TransformableInfo) => { const truncateLongStrings = (str: string, maxLength: number): string => str.length > maxLength ? str.substring(0, maxLength) + '...' : str; - const seen = new WeakSet(); + const seen = new WeakSet(); - const truncateObject = (obj: any): any => { + const truncateObject = (obj: unknown): unknown => { if (typeof obj !== 'object' || obj === null) { return obj; } - // Handle circular references + // Handle circular references - now with proper object type if (seen.has(obj)) { return '[Circular]'; } @@ -211,8 +222,10 @@ const jsonTruncateFormat = winston.format((info: any) => { return obj.map((item) => truncateObject(item)); } - const newObj: Record = {}; - Object.entries(obj).forEach(([key, value]) => { + // We know this is an object at this point + const objectRecord = obj as Record; + const newObj: Record = {}; + Object.entries(objectRecord).forEach(([key, value]) => { if (typeof value === 'string') { newObj[key] = truncateLongStrings(value, CONSOLE_JSON_STRING_LENGTH); } else { @@ -222,7 +235,7 @@ const jsonTruncateFormat = winston.format((info: any) => { return newObj; }; - return truncateObject(info); + return truncateObject(info) as winston.Logform.TransformableInfo; }); export { redactFormat, redactMessage, debugTraverse, jsonTruncateFormat };