4
4
using System ;
5
5
using System . Collections . Generic ;
6
6
using System . Diagnostics ;
7
- using Microsoft . Extensions . Logging ;
7
+ using Microsoft . Extensions . Logging . Abstractions ;
8
8
using Microsoft . Shared . Pools ;
9
9
10
10
namespace Microsoft . Extensions . Logging ;
@@ -15,7 +15,7 @@ namespace Microsoft.Extensions.Logging;
15
15
// redactor code calls recursively back into the logger. Don't do that.
16
16
//
17
17
// NOTE: Unlike the original logger in dotnet/runtime, this logger eats exceptions thrown from invoked loggers, enrichers,
18
- // and redactors, rather than forwarding the exceptions to the caller. The fact an exception occured is recorded in
18
+ // and redactors, rather than forwarding the exceptions to the caller. The fact an exception occurred is recorded in
19
19
// the event log instead. The idea is that failures in the telemetry stack should not lead to failures in the
20
20
// application. It's better to keep running with missing telemetry rather than crashing the process completely.
21
21
@@ -49,7 +49,7 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
49
49
}
50
50
}
51
51
52
- LegacyPath < TState > ( logLevel , eventId , state , exception , formatter ) ;
52
+ LegacyPath ( logLevel , eventId , state , exception , formatter ) ;
53
53
}
54
54
55
55
public IDisposable ? BeginScope < TState > ( TState state )
@@ -261,16 +261,33 @@ private void ModernPath(LogLevel logLevel, EventId eventId, LoggerMessageState m
261
261
RecordException ( exception , joiner . EnrichmentTagCollector , config ) ;
262
262
}
263
263
264
+ bool ? samplingDecision = null ;
264
265
for ( int i = 0 ; i < loggers . Length ; i ++ )
265
266
{
266
267
ref readonly MessageLogger loggerInfo = ref loggers [ i ] ;
267
268
if ( loggerInfo . IsNotFilteredOut ( logLevel ) )
268
269
{
270
+ if ( samplingDecision is null && config . Sampler is not null )
271
+ {
272
+ var logEntry = new LogEntry < ModernTagJoiner > ( logLevel , loggerInfo . Category , eventId , joiner , exception , static ( s , e ) =>
273
+ {
274
+ Func < LoggerMessageState , Exception ? , string > fmt = s . Formatter ! ;
275
+ return fmt ( s . State ! , e ) ;
276
+ } ) ;
277
+ samplingDecision = config . Sampler . ShouldSample ( in logEntry ) ;
278
+ }
279
+
280
+ if ( samplingDecision is false )
281
+ {
282
+ // the record was not selected for being sampled in, so we drop it.
283
+ break ;
284
+ }
285
+
269
286
try
270
287
{
271
288
loggerInfo . LoggerLog ( logLevel , eventId , joiner , exception , static ( s , e ) =>
272
289
{
273
- var fmt = s . Formatter ! ;
290
+ Func < LoggerMessageState , Exception ? , string > ? fmt = s . Formatter ! ;
274
291
return fmt ( s . State ! , e ) ;
275
292
} ) ;
276
293
}
@@ -345,11 +362,28 @@ private void LegacyPath<TState>(LogLevel logLevel, EventId eventId, TState state
345
362
RecordException ( exception , joiner . EnrichmentTagCollector , config ) ;
346
363
}
347
364
365
+ bool ? samplingDecision = null ;
348
366
for ( int i = 0 ; i < loggers . Length ; i ++ )
349
367
{
350
368
ref readonly MessageLogger loggerInfo = ref loggers [ i ] ;
351
369
if ( loggerInfo . IsNotFilteredOut ( logLevel ) )
352
370
{
371
+ if ( samplingDecision is null && config . Sampler is not null )
372
+ {
373
+ var logEntry = new LogEntry < LegacyTagJoiner > ( logLevel , loggerInfo . Category , eventId , joiner , exception , static ( s , e ) =>
374
+ {
375
+ var fmt = ( Func < TState , Exception ? , string > ) s . Formatter ! ;
376
+ return fmt ( ( TState ) s . State ! , e ) ;
377
+ } ) ;
378
+ samplingDecision = config . Sampler . ShouldSample ( in logEntry ) ;
379
+ }
380
+
381
+ if ( samplingDecision is false )
382
+ {
383
+ // the record was not selected for being sampled in, so we drop it.
384
+ break ;
385
+ }
386
+
353
387
try
354
388
{
355
389
loggerInfo . Logger . Log ( logLevel , eventId , joiner , exception , static ( s , e ) =>
0 commit comments