1+ import  logfmt  from  "logfmt" ; 
12import  winston  from  "winston" ; 
23
34import  {  z  }  from  "@blobscan/zod" ; 
@@ -6,19 +7,6 @@ export const logLevelEnum = z.enum(["error", "warn", "info", "http", "debug"]);
67
78export  type  LoggerLevel  =  z . output < typeof  logLevelEnum > ; 
89
9- function  buildErrorCause ( err : Error )  { 
10-   let  msg  =  `\n - Cause: ${ err . message }  ; 
11- 
12-   const  cause  =  err . cause ; 
13-   if  ( cause  instanceof  Error  ||  typeof  cause  ===  "string" )  { 
14-     const  errorCause  =  typeof  cause  ===  "string"  ? new  Error ( cause )  : cause ; 
15- 
16-     msg  +=  buildErrorCause ( errorCause ) ; 
17-   } 
18- 
19-   return  msg ; 
20- } 
21- 
2210const  LOG_LEVELS  =  { 
2311  error : 0 , 
2412  warn : 1 , 
@@ -38,37 +26,59 @@ const colorFormat = winston.format.colorize({
3826  } , 
3927} ) ; 
4028
41- const  format  =  winston . format . combine ( 
29+ // Logfmt formatter for Winston 
30+ const  logfmtFormat  =  winston . format . combine ( 
4231  winston . format . errors ( {  cause : true ,  stack : true  } ) , 
4332  winston . format . timestamp ( {  format : "YYYY-MM-DD HH:mm:ss"  } ) , 
4433  winston . format . printf ( ( info )  =>  { 
45-     const  {  timestamp,  level,  message,  cause,  service }  =  info ; 
46- 
47-     const  formattedLevel  =  colorFormat . colorize ( level ,  level . toUpperCase ( ) ) ; 
48-     const  formattedService  = 
49-       typeof  service  ===  "string" 
50-         ? colorFormat . colorize ( "service" ,  service  ??  "app" ) 
51-         : "" ; 
52-     const  formattedMessage  = 
53-       typeof  message  ===  "string" 
54-         ? colorFormat . colorize ( level ,  message ) 
55-         : message ; 
56- 
57-     let  msg  =  `${ timestamp } ${ formattedLevel } ${ formattedService } ${ formattedMessage }  ; 
34+     const  {  timestamp,  level,  message,  service,  cause,  ...meta  }  =  info ; 
35+ 
36+     const  logData : Record < string ,  string  |  number  |  boolean >  =  { 
37+       ts : String ( timestamp ) , 
38+       level : colorFormat . colorize ( level ,  level ) , 
39+       message : colorFormat . colorize ( 
40+         level , 
41+         typeof  message  ===  "string"  ? message  : JSON . stringify ( message ) 
42+       ) , 
43+     } ; 
44+ 
45+     if  ( typeof  service  ===  "string" )  { 
46+       logData . service  =  colorFormat . colorize ( "service" ,  service ) ; 
47+     } 
5848
49+     // Add any additional metadata 
50+     Object . keys ( meta ) . forEach ( ( key )  =>  { 
51+       const  value  =  meta [ key ] ; 
52+       if  ( value  !==  undefined  &&  key  !==  "cause" )  { 
53+         if  ( 
54+           typeof  value  ===  "string"  || 
55+           typeof  value  ===  "number"  || 
56+           typeof  value  ===  "boolean" 
57+         )  { 
58+           logData [ key ]  =  value ; 
59+         }  else  { 
60+           logData [ key ]  =  JSON . stringify ( value ) ; 
61+         } 
62+       } 
63+     } ) ; 
64+ 
65+     // Handle error causes 
5966    if  ( cause  instanceof  Error )  { 
60-       msg  +=  colorFormat . colorize ( level ,  buildErrorCause ( cause ) ) ; 
67+       logData . error_cause  =  cause . message ; 
68+       if  ( cause . stack )  { 
69+         logData . error_stack  =  cause . stack ; 
70+       } 
6171    } 
6272
63-     return  msg ; 
73+     return  logfmt . stringify ( logData ) ; 
6474  } ) 
6575) ; 
6676
6777export  function  createLogger ( name ?: string ,  opts : winston . LoggerOptions  =  { } )  { 
6878  return  winston . createLogger ( { 
6979    level : process . env . LOG_LEVEL  ??  "info" , 
7080    levels : LOG_LEVELS , 
71-     format, 
81+     format :  logfmtFormat , 
7282    transports : [ new  winston . transports . Console ( ) ] , 
7383    silent : process . env . MODE  ===  "test" , 
7484    ...opts , 
@@ -79,7 +89,7 @@ export function createLogger(name?: string, opts: winston.LoggerOptions = {}) {
7989  } ) ; 
8090} 
8191
82- export  const  logger  =  createLogger ( ) ; 
92+ export  const  logger  =  createLogger ( "rest-api-server" ) ; 
8393
8494export  async  function  perfOperation < T > ( 
8595  operation : ( )  =>  T 
0 commit comments