@@ -206,20 +206,43 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
206206 if ( ! IsEnabled ( logLevel ) )
207207 return ;
208208
209- var message = new Dictionary < string , object > ( StringComparer . Ordinal ) ;
209+ var timestamp = DateTime . UtcNow ;
210+ var message = CustomFormatter ( state , exception , out var customMessage ) && customMessage is not null
211+ ? customMessage
212+ : formatter ( state , exception ) ;
213+
214+ var logFormatter = Logger . GetFormatter ( ) ;
215+ var logEntry = logFormatter is null ?
216+ GetLogEntry ( logLevel , timestamp , message , exception ) :
217+ GetFormattedLogEntry ( logLevel , timestamp , message , exception , logFormatter ) ;
218+
219+ _systemWrapper . LogLine ( JsonSerializer . Serialize ( logEntry , JsonSerializerOptions ) ) ;
220+ }
221+
222+ /// <summary>
223+ /// Gets a log entry.
224+ /// </summary>
225+ /// <param name="logLevel">Entry will be written on this level.</param>
226+ /// <param name="timestamp">Entry timestamp.</param>
227+ /// <param name="message">The message to be written. Can be also an object.</param>
228+ /// <param name="exception">The exception related to this entry.</param>
229+ private Dictionary < string , object > GetLogEntry ( LogLevel logLevel , DateTime timestamp , object message ,
230+ Exception exception )
231+ {
232+ var logEntry = new Dictionary < string , object > ( StringComparer . Ordinal ) ;
210233
211234 // Add Custom Keys
212235 foreach ( var ( key , value ) in Logger . GetAllKeys ( ) )
213- message . TryAdd ( key , value ) ;
236+ logEntry . TryAdd ( key , value ) ;
214237
215238 // Add Lambda Context Keys
216239 if ( PowertoolsLambdaContext . Instance is not null )
217240 {
218- message . TryAdd ( LoggingConstants . KeyFunctionName , PowertoolsLambdaContext . Instance . FunctionName ) ;
219- message . TryAdd ( LoggingConstants . KeyFunctionVersion , PowertoolsLambdaContext . Instance . FunctionVersion ) ;
220- message . TryAdd ( LoggingConstants . KeyFunctionMemorySize , PowertoolsLambdaContext . Instance . MemoryLimitInMB ) ;
221- message . TryAdd ( LoggingConstants . KeyFunctionArn , PowertoolsLambdaContext . Instance . InvokedFunctionArn ) ;
222- message . TryAdd ( LoggingConstants . KeyFunctionRequestId , PowertoolsLambdaContext . Instance . AwsRequestId ) ;
241+ logEntry . TryAdd ( LoggingConstants . KeyFunctionName , PowertoolsLambdaContext . Instance . FunctionName ) ;
242+ logEntry . TryAdd ( LoggingConstants . KeyFunctionVersion , PowertoolsLambdaContext . Instance . FunctionVersion ) ;
243+ logEntry . TryAdd ( LoggingConstants . KeyFunctionMemorySize , PowertoolsLambdaContext . Instance . MemoryLimitInMB ) ;
244+ logEntry . TryAdd ( LoggingConstants . KeyFunctionArn , PowertoolsLambdaContext . Instance . InvokedFunctionArn ) ;
245+ logEntry . TryAdd ( LoggingConstants . KeyFunctionRequestId , PowertoolsLambdaContext . Instance . AwsRequestId ) ;
223246 }
224247
225248 // Add Extra Fields
@@ -228,24 +251,109 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
228251 foreach ( var ( key , value ) in CurrentScope . ExtraKeys )
229252 {
230253 if ( ! string . IsNullOrWhiteSpace ( key ) )
231- message . TryAdd ( key , value ) ;
254+ logEntry . TryAdd ( key , value ) ;
232255 }
233256 }
234257
235- message . TryAdd ( LoggingConstants . KeyTimestamp , DateTime . UtcNow . ToString ( "o" ) ) ;
236- message . TryAdd ( LoggingConstants . KeyLogLevel , logLevel . ToString ( ) ) ;
237- message . TryAdd ( LoggingConstants . KeyService , Service ) ;
238- message . TryAdd ( LoggingConstants . KeyLoggerName , _name ) ;
239- message . TryAdd ( LoggingConstants . KeyMessage ,
240- CustomFormatter ( state , exception , out var customMessage ) && customMessage is not null
241- ? customMessage
242- : formatter ( state , exception ) ) ;
258+ logEntry . TryAdd ( LoggingConstants . KeyTimestamp , timestamp . ToString ( "o" ) ) ;
259+ logEntry . TryAdd ( LoggingConstants . KeyLogLevel , logLevel . ToString ( ) ) ;
260+ logEntry . TryAdd ( LoggingConstants . KeyService , Service ) ;
261+ logEntry . TryAdd ( LoggingConstants . KeyLoggerName , _name ) ;
262+ logEntry . TryAdd ( LoggingConstants . KeyMessage , message ) ;
263+
243264 if ( CurrentConfig . SamplingRate . HasValue )
244- message . TryAdd ( LoggingConstants . KeySamplingRate , CurrentConfig . SamplingRate . Value ) ;
265+ logEntry . TryAdd ( LoggingConstants . KeySamplingRate , CurrentConfig . SamplingRate . Value ) ;
245266 if ( exception != null )
246- message . TryAdd ( LoggingConstants . KeyException , exception ) ;
267+ logEntry . TryAdd ( LoggingConstants . KeyException , exception ) ;
247268
248- _systemWrapper . LogLine ( JsonSerializer . Serialize ( message , JsonSerializerOptions ) ) ;
269+ return logEntry ;
270+ }
271+
272+ /// <summary>
273+ /// Gets a formatted log entry.
274+ /// </summary>
275+ /// <param name="logLevel">Entry will be written on this level.</param>
276+ /// <param name="timestamp">Entry timestamp.</param>
277+ /// <param name="message">The message to be written. Can be also an object.</param>
278+ /// <param name="exception">The exception related to this entry.</param>
279+ /// <param name="logFormatter">The custom log entry formatter.</param>
280+ private object GetFormattedLogEntry ( LogLevel logLevel , DateTime timestamp , object message ,
281+ Exception exception , ILogFormatter logFormatter )
282+ {
283+ if ( logFormatter is null )
284+ return null ;
285+
286+ var logEntry = new LogEntry
287+ {
288+ Timestamp = timestamp ,
289+ Level = logLevel ,
290+ Service = Service ,
291+ Name = _name ,
292+ Message = message ,
293+ Exception = exception ,
294+ SamplingRate = CurrentConfig . SamplingRate ,
295+ } ;
296+
297+ var extraKeys = new Dictionary < string , object > ( ) ;
298+
299+ // Add Custom Keys
300+ foreach ( var ( key , value ) in Logger . GetAllKeys ( ) )
301+ {
302+ switch ( key )
303+ {
304+ case LoggingConstants . KeyColdStart :
305+ logEntry . ColdStart = ( bool ) value ;
306+ break ;
307+ case LoggingConstants . KeyXRayTraceId :
308+ logEntry . XRayTraceId = value as string ;
309+ break ;
310+ case LoggingConstants . KeyCorrelationId :
311+ logEntry . CorrelationId = value as string ;
312+ break ;
313+ default :
314+ extraKeys . TryAdd ( key , value ) ;
315+ break ;
316+ }
317+ }
318+
319+ // Add Extra Fields
320+ if ( CurrentScope ? . ExtraKeys is not null )
321+ {
322+ foreach ( var ( key , value ) in CurrentScope . ExtraKeys )
323+ {
324+ if ( ! string . IsNullOrWhiteSpace ( key ) )
325+ extraKeys . TryAdd ( key , value ) ;
326+ }
327+ }
328+
329+ if ( extraKeys . Any ( ) )
330+ logEntry . ExtraKeys = extraKeys ;
331+
332+ // Add Lambda Context Keys
333+ if ( PowertoolsLambdaContext . Instance is not null )
334+ {
335+ logEntry . LambdaContext = new LogEntryLambdaContext
336+ {
337+ FunctionName = PowertoolsLambdaContext . Instance . FunctionName ,
338+ FunctionVersion = PowertoolsLambdaContext . Instance . FunctionVersion ,
339+ MemoryLimitInMB = PowertoolsLambdaContext . Instance . MemoryLimitInMB ,
340+ InvokedFunctionArn = PowertoolsLambdaContext . Instance . InvokedFunctionArn ,
341+ AwsRequestId = PowertoolsLambdaContext . Instance . AwsRequestId ,
342+ } ;
343+ }
344+
345+ try
346+ {
347+ var logObject = logFormatter . FormatLogEntry ( logEntry ) ;
348+ if ( logObject is null )
349+ throw new LogFormatException ( $ "{ logFormatter . GetType ( ) . FullName } returned Null value.") ;
350+ return logObject ;
351+ }
352+ catch ( Exception e )
353+ {
354+ throw new LogFormatException (
355+ $ "{ logFormatter . GetType ( ) . FullName } raised an exception: { e . Message } .", e ) ;
356+ }
249357 }
250358
251359 /// <summary>
0 commit comments