@@ -44,45 +44,47 @@ const sanitizeKeys = (sanitizedKeys = []) => winston.format(info => {
4444} ) ;
4545
4646// Custom console format that mimics the old formatter behavior
47- const consoleFormat = ( logName , logLevelConsole ) => winston . format . printf ( ( { level, message, timestamp, ...meta } ) => {
48- // Get da prefixes
49- const element = ( logName === 'lando' ) ? 'lando' : logName ;
50- const elementColor = ( logName === 'lando' ) ? 'lando' : 'app' ;
51- // Set the leftmost column width
52- fcw = _ . max ( [ fcw , _ . size ( element ) ] ) ;
53-
54- // Extract the splat array (format arguments) if available
55- const splat = meta [ Symbol . for ( 'splat' ) ] || [ ] ;
56-
57- // Format the message with splat arguments using util.format
58- const formattedMessage = splat . length > 0 ?
59- util . format ( message , ...splat ) :
60- message ;
61-
62- // Remove splat from meta before serializing
63- const metaWithoutSplat = { ...meta } ;
64- delete metaWithoutSplat [ Symbol . for ( 'splat' ) ] ;
65-
66- // Serialize remaining metadata
67- const serializedMeta = Object . keys ( metaWithoutSplat ) . length ?
68- ' ' + JSON . stringify ( metaWithoutSplat ) :
69- '' ;
70-
71- // Default output
72- const output = [
73- winston . format . colorize ( { colors : logColors } ) . colorize ( elementColor , _ . padEnd ( element . toLowerCase ( ) , fcw ) ) ,
74- winston . format . colorize ( { colors : logColors } ) . colorize ( 'timestamp' , timestamp ) ,
75- winston . format . colorize ( ) . colorize ( level , level . toUpperCase ( ) ) ,
76- '==>' ,
77- formattedMessage + serializedMeta ,
78- ] ;
79-
80- // If this is a warning or error and we aren't verbose then omit prefixes
81- if ( _ . includes ( userLevels , level ) && _ . includes ( userLevels , logLevelConsole ) ) {
82- return _ . drop ( output , 2 ) . join ( ' ' ) ;
83- }
84- return output . join ( ' ' ) ;
85- } ) ;
47+ const consoleFormat = ( logLevelConsole , defaultLogName ) =>
48+ winston . format . printf ( ( { level, message, timestamp, logName, ...meta } ) => {
49+ // Get da prefixes
50+ const resolvedLogName = logName || defaultLogName ;
51+ const element = ( resolvedLogName === 'lando' ) ? 'lando' : resolvedLogName ;
52+ const elementColor = ( resolvedLogName === 'lando' ) ? 'lando' : 'app' ;
53+ // Set the leftmost column width
54+ fcw = _ . max ( [ fcw , _ . size ( element ) ] ) ;
55+
56+ // Extract the splat array (format arguments) if available
57+ const splat = meta [ Symbol . for ( 'splat' ) ] || [ ] ;
58+
59+ // Format the message with splat arguments using util.format
60+ const formattedMessage = splat . length > 0 ?
61+ util . format ( message , ...splat ) :
62+ message ;
63+
64+ // Remove splat from meta before serializing
65+ const metaWithoutSplat = { ...meta } ;
66+ delete metaWithoutSplat [ Symbol . for ( 'splat' ) ] ;
67+
68+ // Serialize remaining metadata
69+ const serializedMeta = Object . keys ( metaWithoutSplat ) . length ?
70+ ' ' + JSON . stringify ( metaWithoutSplat ) :
71+ '' ;
72+
73+ // Default output
74+ const output = [
75+ winston . format . colorize ( { colors : logColors } ) . colorize ( elementColor , _ . padEnd ( element . toLowerCase ( ) , fcw ) ) ,
76+ winston . format . colorize ( { colors : logColors } ) . colorize ( 'timestamp' , timestamp ) ,
77+ winston . format . colorize ( ) . colorize ( level , level . toUpperCase ( ) ) ,
78+ '==>' ,
79+ formattedMessage + serializedMeta ,
80+ ] ;
81+
82+ // If this is a warning or error and we aren't verbose then omit prefixes
83+ if ( _ . includes ( userLevels , level ) && _ . includes ( userLevels , logLevelConsole ) ) {
84+ return _ . drop ( output , 2 ) . join ( ' ' ) ;
85+ }
86+ return output . join ( ' ' ) ;
87+ } ) ;
8688
8789/**
8890 * Logs a debug message.
@@ -178,43 +180,52 @@ const consoleFormat = (logName, logLevelConsole) => winston.format.printf(({leve
178180 * // Log a warning message
179181 * lando.log.warning('Something is up with app %s in directory %s', appName, dir);
180182 */
181- module . exports = class Log extends EventEmitter {
182- constructor ( { logDir, logLevelConsole = 'warn' , logLevel = 'debug' , logName = 'lando' } = { } ) {
183+ class Log extends EventEmitter {
184+ constructor ( { logDir, logFile , logLevelConsole = 'warn' , logLevel = 'debug' , logName = 'lando' , logger } = { } ) {
183185 super ( ) ;
184186
187+ if ( process . env . DEBUG ) {
188+ try {
189+ const debugLib = require ( 'debug' ) ;
190+ debugLib . disable ( 'winston:*' ) ;
191+ } catch {
192+ // Ignore if debug is unavailable.
193+ }
194+ }
195+
185196 // If loglevelconsole is numeric lets map it!
186197 if ( _ . isInteger ( logLevelConsole ) ) logLevelConsole = logLevels [ logLevelConsole ] ;
187198
188199 // Initialize sanitized keys
189200 this . sanitizedKeys = [ 'auth' , 'token' , 'password' , 'key' , 'api_key' , 'secret' , 'machine_token' ] ;
190201
191- // Create formats
192- const formats = [
193- winston . format . timestamp ( { format : ( ) => new Date ( ) . toISOString ( ) . slice ( 11 , 19 ) } ) ,
194- sanitizeKeys ( this . sanitizedKeys ) ( ) ,
195- ] ;
196-
197- // The default console transport
198- const transports = [
199- new winston . transports . Console ( {
200- format : winston . format . combine (
201- ...formats ,
202- consoleFormat ( logName , logLevelConsole ) ,
203- ) ,
204- level : logLevelConsole ,
205- } ) ,
206- ] ;
202+ if ( logger ) {
203+ this . sanitizedKeys = logger . sanitizedKeys || this . sanitizedKeys ;
204+ logger . sanitizedKeys = this . sanitizedKeys ;
205+ this . logger = logName ? logger . child ( { logName} ) : logger ;
206+ } else {
207+ // Create formats
208+ const formats = [
209+ winston . format . timestamp ( { format : ( ) => new Date ( ) . toISOString ( ) . slice ( 11 , 19 ) } ) ,
210+ sanitizeKeys ( this . sanitizedKeys ) ( ) ,
211+ ] ;
207212
208- // If we have a log path then let's add in some file transports
209- if ( logDir ) {
210- // Ensure the log dir actually exists
211- fs . mkdirSync ( logDir , { recursive : true } ) ;
213+ // The default console transport
214+ const transports = [
215+ new winston . transports . Console ( {
216+ format : winston . format . combine (
217+ ...formats ,
218+ consoleFormat ( logLevelConsole , logName ) ,
219+ ) ,
220+ level : logLevelConsole ,
221+ } ) ,
222+ ] ;
212223
213224 // File format without colorization
214225 const fileFormat = winston . format . combine (
215226 winston . format . timestamp ( ) ,
216227 sanitizeKeys ( this . sanitizedKeys ) ( ) ,
217- winston . format . printf ( ( { timestamp, level, message, ...meta } ) => {
228+ winston . format . printf ( ( { timestamp, level, message, logName , ...meta } ) => {
218229 // Extract the splat array (format arguments) if available
219230 const splat = meta [ Symbol . for ( 'splat' ) ] || [ ] ;
220231
@@ -232,35 +243,55 @@ module.exports = class Log extends EventEmitter {
232243 ' ' + JSON . stringify ( metaWithoutSplat ) :
233244 '' ;
234245
235- return `${ timestamp } [${ logName } ] ${ level . toUpperCase ( ) } : ${ formattedMessage } ${ serializedMeta } ` ;
246+ const resolvedLogName = logName || 'lando' ;
247+ return `${ timestamp } [${ resolvedLogName } ] ${ level . toUpperCase ( ) } : ${ formattedMessage } ${ serializedMeta } ` ;
236248 } ) ,
237249 ) ;
238250
239- // Add in our generic and error logs
240- transports . push ( new winston . transports . File ( {
241- format : fileFormat ,
242- level : 'warn' ,
243- maxsize : 500000 ,
244- maxFiles : 2 ,
245- filename : path . join ( logDir , `${ logName } -error.log` ) ,
246- } ) ) ;
247- transports . push ( new winston . transports . File ( {
248- format : fileFormat ,
249- level : logLevel ,
250- maxsize : 500000 ,
251- maxFiles : 3 ,
252- filename : path . join ( logDir , `${ logName } .log` ) ,
253- } ) ) ;
254- }
251+ if ( logFile ) {
252+ const resolvedLogFile = path . isAbsolute ( logFile ) ?
253+ logFile :
254+ path . join ( logDir || '' , logFile ) ;
255+ fs . mkdirSync ( path . dirname ( resolvedLogFile ) , { recursive : true } ) ;
256+ transports . push ( new winston . transports . File ( {
257+ format : fileFormat ,
258+ level : logLevel ,
259+ maxsize : 500000 ,
260+ maxFiles : 3 ,
261+ filename : resolvedLogFile ,
262+ } ) ) ;
263+ } else if ( logDir ) {
264+ // Ensure the log dir actually exists
265+ fs . mkdirSync ( logDir , { recursive : true } ) ;
255266
256- // Add custom colors to winston
257- winston . addColors ( logColors ) ;
267+ // Add in our generic and error logs
268+ transports . push ( new winston . transports . File ( {
269+ format : fileFormat ,
270+ level : 'warn' ,
271+ maxsize : 500000 ,
272+ maxFiles : 2 ,
273+ filename : path . join ( logDir , `${ logName } -error.log` ) ,
274+ } ) ) ;
275+ transports . push ( new winston . transports . File ( {
276+ format : fileFormat ,
277+ level : logLevel ,
278+ maxsize : 500000 ,
279+ maxFiles : 3 ,
280+ filename : path . join ( logDir , `${ logName } .log` ) ,
281+ } ) ) ;
282+ }
258283
259- // Create the winston logger
260- this . logger = winston . createLogger ( {
261- transports : transports ,
262- exitOnError : true ,
263- } ) ;
284+ // Add custom colors to winston
285+ winston . addColors ( logColors ) ;
286+
287+ // Create the winston logger
288+ this . logger = winston . createLogger ( {
289+ transports : transports ,
290+ exitOnError : true ,
291+ defaultMeta : { logName} ,
292+ } ) ;
293+ this . logger . sanitizedKeys = this . sanitizedKeys ;
294+ }
264295
265296 // Create aliases for winston methods to maintain compatibility
266297 [ 'error' , 'warn' , 'info' , 'verbose' , 'debug' , 'silly' ] . forEach ( level => {
@@ -269,15 +300,12 @@ module.exports = class Log extends EventEmitter {
269300
270301 // Expose transports for compatibility with tests
271302 this . transports = [ ] ;
272- transports . forEach ( ( transport , index ) => {
303+ const loggerTransports = this . logger && this . logger . transports ? this . logger . transports : [ ] ;
304+ loggerTransports . forEach ( transport => {
273305 if ( transport instanceof winston . transports . Console ) {
274306 this . transports . push ( transport ) ;
275307 } else if ( transport instanceof winston . transports . File ) {
276- if ( transport . filename && transport . filename . includes ( '-error.log' ) ) {
277- this . transports . push ( transport ) ;
278- } else if ( transport . filename ) {
279- this . transports . push ( transport ) ;
280- }
308+ if ( transport . filename ) this . transports . push ( transport ) ;
281309 }
282310 } ) ;
283311
@@ -288,7 +316,14 @@ module.exports = class Log extends EventEmitter {
288316 // Method to help other things add sanitizations
289317 alsoSanitize ( key ) {
290318 this . sanitizedKeys . push ( key ) ;
319+ if ( this . logger ) this . logger . sanitizedKeys = this . sanitizedKeys ;
291320 // We need to recreate the format with the updated keys
292321 // For simplicity, we'll just add to the array and it will be used in next log call
293322 }
294- } ;
323+
324+ child ( logName ) {
325+ return new Log ( { logger : this . logger , logName} ) ;
326+ }
327+ }
328+
329+ module . exports = Log ;
0 commit comments