1- import * as vscode from 'vscode' ;
21import { LogLevel , type ILogger } from '../types' ;
2+ import { createConsoleLogger } from '../utils' ;
3+ import type * as vscode from 'vscode' ;
34
4- export const disallowedLogKeys = [ 'password' , 'secret' , 'token' , 'apiKey' , 'apiSecret' , 'content' ] ;
5+ export const disallowedLogKeys : Set < string > = new Set ( [
6+ 'password' ,
7+ 'secret' ,
8+ 'token' ,
9+ 'apikey' ,
10+ 'apisecret' ,
11+ 'content' ,
12+ ] ) ;
513
614function removePromptsFromData < T > ( dictionary : T | undefined | null ) : T | undefined {
715 if ( dictionary === null || dictionary === undefined ) {
@@ -15,12 +23,10 @@ function removePromptsFromData<T>(dictionary: T | undefined | null): T | undefin
1523 return dictionary ;
1624 }
1725
18- const clone = structuredClone ( dictionary ) as Record < string , unknown > ;
19-
2026 try {
21- for ( const key in clone ) {
22- const value = clone [ key ] ;
23- if ( disallowedLogKeys . includes ( key ) ) {
27+ const clone = structuredClone ( dictionary ) as Record < string , unknown > ;
28+ for ( const [ key , value ] of Object . entries ( clone ) ) {
29+ if ( disallowedLogKeys . has ( key . toLowerCase ( ) ) ) {
2430 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
2531 delete clone [ key ] ;
2632 continue ;
@@ -32,21 +38,21 @@ function removePromptsFromData<T>(dictionary: T | undefined | null): T | undefin
3238 clone [ key ] = removePromptsFromData ( value as Record < string , unknown > ) as unknown ;
3339 }
3440 }
41+ return clone as unknown as T ;
3542 } catch ( error ) {
3643 console . error ( 'Error processing log data:' , error ) ;
3744 return { } as T ;
3845 }
39-
40- return clone as unknown as T ;
4146}
4247
4348/**
4449 * Static logger class for extension-wide logging
4550 */
4651// eslint-disable-next-line @typescript-eslint/no-extraneous-class
4752class LoggerImpl {
48- private static readonly outputChannel : vscode . OutputChannel =
49- vscode . window . createOutputChannel ( 'IPC' ) ;
53+ // eslint-disable-next-line sonarjs/public-static-readonly
54+ static outputChannel : vscode . OutputChannel | undefined = undefined ;
55+ private static readonly consoleLogger = createConsoleLogger ( 'RVW' ) ;
5056
5157 public static debug ( message : string , data : Record < string , unknown > | undefined = undefined ) {
5258 this . log ( LogLevel . DEBUG , message , data ) ;
@@ -65,33 +71,64 @@ class LoggerImpl {
6571 }
6672
6773 public static dispose ( ) {
68- this . outputChannel . dispose ( ) ;
74+ this . outputChannel ?. dispose ( ) ;
75+ this . outputChannel = undefined ;
6976 }
7077
7178 private static log ( level : LogLevel , message : string , data : Record < string , unknown > | undefined ) {
7279 const timestamp = new Date ( ) . toISOString ( ) . split ( 'T' ) [ 1 ] ;
73- const levelStr = LogLevel [ level ] || 'UNKNOWN' ;
7480 const cleanedData = removePromptsFromData ( data ) ;
75- const line = `[${ timestamp } ] [${ levelStr } ] ${ message } ` ;
76- if ( cleanedData === undefined ) {
77- this . outputChannel . appendLine ( line ) ;
81+ if ( this . outputChannel === undefined ) {
82+ const methodName = LogLevel [ level ] . toLowerCase ( ) as
83+ | undefined
84+ | keyof Omit < ILogger , 'dispose' > ;
85+ if ( methodName !== undefined && typeof this . consoleLogger [ methodName ] === 'function' ) {
86+ if ( cleanedData === undefined ) {
87+ this . consoleLogger [ methodName ] ( `[${ timestamp } ] ${ message } ` ) ;
88+ } else {
89+ this . consoleLogger [ methodName ] ( `[${ timestamp } ] ${ message } ` , cleanedData ) ;
90+ }
91+ }
7892 } else {
79- try {
80- this . outputChannel . appendLine ( `${ line } : ${ JSON . stringify ( cleanedData ) } ` ) ;
81- } catch {
82- this . outputChannel . appendLine ( `${ line } : unserializable data` ) ;
93+ const levelStr = LogLevel [ level ] || 'UNKNOWN' ;
94+ const line = `[${ timestamp } ] [${ levelStr } ] ${ message } ` ;
95+
96+ if ( cleanedData === undefined ) {
97+ this . outputChannel . appendLine ( line ) ;
98+ } else {
99+ try {
100+ this . outputChannel . appendLine ( `${ line } : ${ JSON . stringify ( cleanedData ) } ` ) ;
101+ } catch {
102+ this . outputChannel . appendLine ( `${ line } : unserializable data` ) ;
103+ }
83104 }
84105 }
85106 }
86107}
87108
88- export const Logger : ILogger = {
89- debug : ( message : string , data ?: Record < string , unknown > ) => LoggerImpl . debug ( message , data ) ,
90- info : ( message : string , data ?: Record < string , unknown > ) => LoggerImpl . info ( message , data ) ,
91- warn : ( message : string , data ?: Record < string , unknown > ) => LoggerImpl . warn ( message , data ) ,
92- error : ( message : string , data ?: Record < string , unknown > ) => LoggerImpl . error ( message , data ) ,
93- dispose : ( ) => LoggerImpl . dispose ( ) ,
94- } ;
109+ export const Logger : ILogger & {
110+ setOutputChannel : ( outputChannel : vscode . OutputChannel | undefined ) => void ;
111+ } =
112+ /**
113+ * Sets the VS Code output channel for the logger.
114+ * The logger takes ownership of the channel and will dispose it
115+ * when `Logger.dispose()` is called or when a new channel is set.
116+ * @param outputChannel The output channel to use for logging.
117+ */
118+ {
119+ setOutputChannel : ( outputChannel : vscode . OutputChannel | undefined ) => {
120+ if ( LoggerImpl . outputChannel === outputChannel ) {
121+ return ;
122+ }
123+ LoggerImpl . dispose ( ) ;
124+ LoggerImpl . outputChannel = outputChannel ;
125+ } ,
126+ debug : ( message : string , data ?: Record < string , unknown > ) => LoggerImpl . debug ( message , data ) ,
127+ info : ( message : string , data ?: Record < string , unknown > ) => LoggerImpl . info ( message , data ) ,
128+ warn : ( message : string , data ?: Record < string , unknown > ) => LoggerImpl . warn ( message , data ) ,
129+ error : ( message : string , data ?: Record < string , unknown > ) => LoggerImpl . error ( message , data ) ,
130+ dispose : ( ) => LoggerImpl . dispose ( ) ,
131+ } ;
95132
96133export const getLogger = ( tag : string ) : ILogger => ( {
97134 debug : ( message : string , data ?: Record < string , unknown > ) =>
0 commit comments