1
1
import { LoggerService , Injectable } from '@nestjs/common' ;
2
2
import { WinstonModule , WinstonModuleOptions } from 'nest-winston' ;
3
+ import { isString } from 'lodash' ;
4
+ import { ClientMetadata , SessionMetadata } from 'src/common/models' ;
3
5
4
6
type LogMeta = object ;
5
7
6
8
type LogObject = {
7
9
[ key : string ] : unknown ;
8
10
} ;
9
11
10
- type ErrorOrMeta = Error | LogMeta | string ;
12
+ type ErrorOrMeta = Error | LogMeta | string | ClientMetadata | SessionMetadata ;
11
13
12
14
@Injectable ( )
13
15
export class AppLogger implements LoggerService {
@@ -25,89 +27,132 @@ export class AppLogger implements LoggerService {
25
27
this . logger = WinstonModule . createLogger ( loggerConfig ) ;
26
28
}
27
29
28
- private isException ( error ?: unknown ) {
29
- return ! ! (
30
- error instanceof Error
31
- || ( ( error as Error ) ?. stack && ( error as Error ) ?. message )
32
- ) ;
30
+ /**
31
+ * Get context from optional arguments
32
+ * If the last argument is a string - it will be handled like a context
33
+ * since nest passes the logger context as the last argument
34
+ * Note: args array might be mutated
35
+ * @param args
36
+ */
37
+ static getContext ( args : ErrorOrMeta [ ] = [ ] ) : string {
38
+ const lastArg = args ?. [ args . length - 1 ] ;
39
+
40
+ if ( isString ( lastArg ) ) {
41
+ return args . pop ( ) as string ;
42
+ }
43
+
44
+ return 'TODO: generic name or null?' ;
45
+ }
46
+
47
+ /**
48
+ * Get an error from the optional arguments
49
+ * Will find first entry which is error type
50
+ * Note: args array might be mutated
51
+ * @param args
52
+ */
53
+ static getError ( args : ErrorOrMeta [ ] = [ ] ) : void | { } {
54
+ let error = null ;
55
+ const index = args . findIndex ( ( arg ) => ( arg instanceof Error ) ) ;
56
+ if ( index > - 1 ) {
57
+ [ error ] = args . splice ( index , 1 ) ;
58
+ }
59
+
60
+ if ( error ) {
61
+ return {
62
+ message : error . message ,
63
+ stack : error . stack ,
64
+ response : error . response ,
65
+ } ;
66
+ }
67
+
68
+ return undefined ;
69
+ }
70
+
71
+ /**
72
+ * Get clientMetadata and/or sessionMetadata object(s) from args
73
+ * Will find first entry of ClientMetadata and get SessionMetadata, from it and return both
74
+ * otherwise will find SessionMetadata and return only it
75
+ * otherwise will return empty object
76
+ * Note: args array might be mutated
77
+ * @param args
78
+ */
79
+ static getUserMetadata ( args : ErrorOrMeta [ ] = [ ] ) : {
80
+ clientMetadata ?: Partial < ClientMetadata > ,
81
+ sessionMetadata ?: SessionMetadata ,
82
+ } {
83
+ // check for client metadata in args
84
+ const clientMetadataIndex = args . findIndex ( ( arg ) => ( arg instanceof ClientMetadata ) ) ;
85
+ if ( clientMetadataIndex > - 1 ) {
86
+ const [ clientMetadata ] = args . splice ( clientMetadataIndex , 1 ) as ClientMetadata [ ] ;
87
+ return {
88
+ clientMetadata : {
89
+ ...clientMetadata ,
90
+ sessionMetadata : undefined ,
91
+ } ,
92
+ sessionMetadata : clientMetadata . sessionMetadata ,
93
+ } ;
94
+ }
95
+
96
+ // check for session metadata in args
97
+ const sessionMetadataIndex = args . findIndex ( ( arg ) => ( arg instanceof SessionMetadata ) ) ;
98
+ if ( sessionMetadataIndex > - 1 ) {
99
+ const [ sessionMetadata ] = args . splice ( sessionMetadataIndex , 1 ) as SessionMetadata [ ] ;
100
+ return {
101
+ sessionMetadata,
102
+ } ;
103
+ }
104
+
105
+ // by default will return empty object
106
+ return { } ;
33
107
}
34
108
35
109
private parseLoggerArgs (
36
110
message : string | LogObject ,
37
- optionalParams : ErrorOrMeta [ ] ,
38
- isErrorLevel = false ,
111
+ optionalParams : ErrorOrMeta [ ] = [ ] ,
39
112
) {
40
113
const messageObj : LogObject = (
41
114
typeof message === 'object' ? message : { message }
42
115
) as LogObject ;
43
- const meta = [ ] ;
44
- let errorMessage : string ;
45
- let errorStack : string ;
46
-
47
- // nest passes the logger context as the last argument
48
- const contextArg = optionalParams ?. [ optionalParams . length - 1 ] ;
49
-
50
- // the global exception filter converts the error object to strings
51
- if (
52
- isErrorLevel
53
- && typeof optionalParams [ 0 ] === 'string'
54
- && optionalParams . length > 1
55
- ) {
56
- errorStack = optionalParams . shift ( ) as string ;
57
- }
58
116
59
- for ( const k in optionalParams ) {
60
- if ( this . isException ( optionalParams [ k ] ) ) {
61
- errorMessage = ( optionalParams [ k ] as Error ) . message ;
62
- errorStack = ( optionalParams [ k ] as Error ) . stack ;
63
- } else if ( optionalParams [ k ] !== contextArg ) {
64
- meta . push ( optionalParams [ k ] ) ;
65
- }
66
- }
67
- const metaObj = meta . length > 1 ? meta : meta [ 0 ] ;
117
+ const context = AppLogger . getContext ( optionalParams ) ;
118
+ const error = AppLogger . getError ( optionalParams ) ;
119
+ const userMetadata = AppLogger . getUserMetadata ( optionalParams ) ;
68
120
69
121
return {
70
- context : contextArg && typeof contextArg === 'string' ? contextArg : null ,
71
- ...metaObj ,
72
- ...( messageObj || { } ) ,
73
- ...( errorMessage || errorStack
74
- ? {
75
- error : errorMessage ,
76
- stack : [ errorStack ] ,
77
- }
78
- : { } ) ,
122
+ ...messageObj ,
123
+ context,
124
+ error,
125
+ ...userMetadata ,
126
+ data : optionalParams ?. length ? optionalParams : undefined ,
79
127
} ;
80
128
}
81
129
82
130
/**
83
131
* Write a 'log' level log.
84
132
*/
85
133
log ( message : string | LogObject , ...optionalParams : ErrorOrMeta [ ] ) {
86
- const parsedArgs = this . parseLoggerArgs ( message , optionalParams ) ;
87
- if ( ! AppLogger . startupContexts . includes ( parsedArgs . context ) ) {
88
- this . logger . log ( parsedArgs ) ;
89
- }
134
+ this . logger . log ( this . parseLoggerArgs ( message , optionalParams ) ) ;
90
135
}
91
136
92
137
/**
93
138
* Write a 'fatal' level log.
94
139
*/
95
140
fatal ( message : string | LogObject , ...optionalParams : ErrorOrMeta [ ] ) {
96
- this . logger . fatal ( this . parseLoggerArgs ( message , optionalParams , true ) ) ;
141
+ this . logger . fatal ( this . parseLoggerArgs ( message , optionalParams ) ) ;
97
142
}
98
143
99
144
/**
100
145
* Write an 'error' level log.
101
146
*/
102
147
error ( message : string | LogObject , ...optionalParams : ErrorOrMeta [ ] ) {
103
- this . logger . error ( this . parseLoggerArgs ( message , optionalParams , true ) ) ;
148
+ this . logger . error ( this . parseLoggerArgs ( message , optionalParams ) ) ;
104
149
}
105
150
106
151
/**
107
152
* Write a 'warn' level log.
108
153
*/
109
154
warn ( message : string | LogObject , ...optionalParams : ErrorOrMeta [ ] ) {
110
- this . logger . warn ( this . parseLoggerArgs ( message , optionalParams , true ) ) ;
155
+ this . logger . warn ( this . parseLoggerArgs ( message , optionalParams ) ) ;
111
156
}
112
157
113
158
/**
0 commit comments