@@ -15,7 +15,8 @@ import * as vscode from "vscode";
1515import * as winston from "winston" ;
1616
1717import configuration from "../configuration" ;
18- import { IS_RUNNING_UNDER_TEST } from "../utilities/utilities" ;
18+ import { IS_RUNNING_IN_DEVELOPMENT_MODE , IS_RUNNING_UNDER_TEST } from "../utilities/utilities" ;
19+ import { FileTransport } from "./FileTransport" ;
1920import { OutputChannelTransport } from "./OutputChannelTransport" ;
2021import { RollingLog } from "./RollingLog" ;
2122import { RollingLogTransport } from "./RollingLogTransport" ;
@@ -31,6 +32,8 @@ export class SwiftLogger implements vscode.Disposable {
3132 private logger : winston . Logger ;
3233 protected rollingLog : RollingLog ;
3334 protected outputChannel : vscode . OutputChannel ;
35+ private fileTransport : FileTransport ;
36+ private cachedOutputChannelLevel : string | undefined ;
3437
3538 constructor (
3639 public readonly name : string ,
@@ -42,16 +45,24 @@ export class SwiftLogger implements vscode.Disposable {
4245 const ouptutChannelTransport = new OutputChannelTransport ( this . outputChannel ) ;
4346 ouptutChannelTransport . level = this . outputChannelLevel ;
4447 const rollingLogTransport = new RollingLogTransport ( this . rollingLog ) ;
48+
49+ // Create file transport
50+ this . fileTransport = new FileTransport ( this . logFilePath ) ;
51+ this . fileTransport . level = "debug" ; // File logging at the 'debug' level always
52+
53+ // Create logger with all transports
54+ const transports = [
55+ ouptutChannelTransport ,
56+ this . fileTransport ,
57+ // Only want to capture the rolling log in memory when testing
58+ ...( IS_RUNNING_UNDER_TEST ? [ rollingLogTransport ] : [ ] ) ,
59+ ...( IS_RUNNING_IN_DEVELOPMENT_MODE
60+ ? [ new winston . transports . Console ( { level : "debug" } ) ]
61+ : [ ] ) ,
62+ ] ;
63+
4564 this . logger = winston . createLogger ( {
46- transports : [
47- new winston . transports . File ( {
48- filename : this . logFilePath ,
49- level : "debug" , // File logging at the 'debug' level always
50- } ) ,
51- ouptutChannelTransport ,
52- // Only want to capture the rolling log in memory when testing
53- ...( IS_RUNNING_UNDER_TEST ? [ rollingLogTransport ] : [ ] ) ,
54- ] ,
65+ transports : transports ,
5566 format : winston . format . combine (
5667 winston . format . errors ( { stack : true } ) ,
5768 winston . format . timestamp ( { format : "YYYY-MM-DD HH:mm:ss.SSS" } ) , // This is the format of `vscode.LogOutputChannel`
@@ -71,37 +82,53 @@ export class SwiftLogger implements vscode.Disposable {
7182 if ( rollingLogTransport . close ) {
7283 rollingLogTransport . close ( ) ;
7384 }
85+ this . fileTransport . close ( ) ;
7486 } ,
7587 } ,
7688 vscode . workspace . onDidChangeConfiguration ( e => {
7789 if (
7890 e . affectsConfiguration ( "swift.outputChannelLogLevel" ) ||
7991 e . affectsConfiguration ( "swift.diagnostics" )
8092 ) {
93+ // Clear cache when configuration changes
94+ this . cachedOutputChannelLevel = undefined ;
8195 ouptutChannelTransport . level = this . outputChannelLevel ;
8296 }
8397 } )
8498 ) ;
8599 }
86100
87101 debug ( message : LoggerMeta , label ?: string , options ?: LogMessageOptions ) {
88- this . logger . debug ( this . normalizeMessage ( message , label ) , options ) ;
102+ const normalizedMessage = this . normalizeMessage ( message , label ) ;
103+ this . logWithBuffer ( "debug" , normalizedMessage , options ) ;
89104 }
90105
91106 info ( message : LoggerMeta , label ?: string , options ?: LogMessageOptions ) {
92- this . logger . info ( this . normalizeMessage ( message , label ) , options ) ;
107+ const normalizedMessage = this . normalizeMessage ( message , label ) ;
108+ this . logWithBuffer ( "info" , normalizedMessage , options ) ;
93109 }
94110
95111 warn ( message : LoggerMeta , label ?: string , options ?: LogMessageOptions ) {
96- this . logger . warn ( this . normalizeMessage ( message , label ) , options ) ;
112+ const normalizedMessage = this . normalizeMessage ( message , label ) ;
113+ this . logWithBuffer ( "warn" , normalizedMessage , options ) ;
97114 }
98115
99116 error ( message : LoggerMeta , label ?: string , options ?: LogMessageOptions ) {
100117 if ( message instanceof Error ) {
101- this . logger . error ( message ) ;
118+ this . logWithBuffer ( "error" , message ) ;
102119 return ;
103120 }
104- this . logger . error ( this . normalizeMessage ( message , label ) , options ) ;
121+ const normalizedMessage = this . normalizeMessage ( message , label ) ;
122+ this . logWithBuffer ( "error" , normalizedMessage , options ) ;
123+ }
124+
125+ private logWithBuffer ( level : string , message : string | Error , meta ?: LoggerMeta ) {
126+ // Log to all transports (output channel, file, console, etc.)
127+ if ( message instanceof Error ) {
128+ this . logger . log ( level , message ) ;
129+ } else {
130+ this . logger . log ( level , message , meta ) ;
131+ }
105132 }
106133
107134 get logs ( ) : string [ ] {
@@ -131,16 +158,22 @@ export class SwiftLogger implements vscode.Disposable {
131158 }
132159
133160 private get outputChannelLevel ( ) : string {
134- const info = vscode . workspace . getConfiguration ( "swift" ) . inspect ( "outputChannelLogLevel" ) ;
135- // If the user has explicitly set `outputChannelLogLevel` then use it, otherwise
136- // check the deprecated `diagnostics` property
137- if ( info ?. globalValue || info ?. workspaceValue || info ?. workspaceFolderValue ) {
138- return configuration . outputChannelLogLevel ;
139- } else if ( configuration . diagnostics ) {
140- return "debug" ;
141- } else {
142- return configuration . outputChannelLogLevel ;
161+ // Cache the configuration lookup to avoid repeated expensive calls during initialization
162+ if ( this . cachedOutputChannelLevel === undefined ) {
163+ const info = vscode . workspace
164+ . getConfiguration ( "swift" )
165+ . inspect ( "outputChannelLogLevel" ) ;
166+ // If the user has explicitly set `outputChannelLogLevel` then use it, otherwise
167+ // check the deprecated `diagnostics` property
168+ if ( info ?. globalValue || info ?. workspaceValue || info ?. workspaceFolderValue ) {
169+ this . cachedOutputChannelLevel = configuration . outputChannelLogLevel ;
170+ } else if ( configuration . diagnostics ) {
171+ this . cachedOutputChannelLevel = "debug" ;
172+ } else {
173+ this . cachedOutputChannelLevel = configuration . outputChannelLogLevel ;
174+ }
143175 }
176+ return this . cachedOutputChannelLevel ;
144177 }
145178
146179 dispose ( ) {
0 commit comments