33
44using System ;
55using System . Text ;
6- using System . Globalization ;
76using System . Diagnostics ;
87using System . Collections . Generic ;
98using Microsoft . Extensions . DependencyInjection ;
@@ -82,6 +81,7 @@ private static ILoggerProvider CreateProvider()
8281 return disposableProvider . Object ;
8382 }
8483
84+
8585 [ Fact ]
8686 public void Dispose_ThrowException_SwallowsException ( )
8787 {
@@ -181,8 +181,10 @@ public void TestActivityIds(ActivityTrackingOptions options)
181181
182182 var logger = loggerFactory . CreateLogger ( "Logger" ) ;
183183
184- Activity a = new Activity ( "ScopeActivity" ) ;
185- a . Start ( ) ;
184+ Activity activity = new Activity ( "ScopeActivity" ) ;
185+ activity . AddBaggage ( "baggageTestKey1" , "baggageTestValue" ) ;
186+ activity . AddTag ( "tagTestKey" , "tagTestValue" ) ;
187+ activity . Start ( ) ;
186188 string activity1String = GetActivityLogString ( options ) ;
187189 string activity2String ;
188190
@@ -199,10 +201,11 @@ public void TestActivityIds(ActivityTrackingOptions options)
199201 }
200202 b . Stop ( ) ;
201203 }
202- a . Stop ( ) ;
204+ activity . Stop ( ) ;
203205
204206 Assert . Equal ( activity1String , loggerProvider . LogText [ 1 ] ) ;
205207 Assert . Equal ( activity2String , loggerProvider . LogText [ 4 ] ) ;
208+ Assert . Equal ( 7 , loggerProvider . LogText . Count ) ; // Ensure that Baggage and Tags aren't added.
206209 }
207210
208211 [ Fact ]
@@ -213,6 +216,195 @@ public void TestInvalidActivityTrackingOptions()
213216 ) ;
214217 }
215218
219+ [ Fact ]
220+ public void TestActivityTrackingOptions_ShouldAddBaggageItemsAsNewScope_WhenBaggageOptionIsSet ( )
221+ {
222+ var loggerProvider = new ExternalScopeLoggerProvider ( ) ;
223+
224+ var loggerFactory = LoggerFactory . Create ( builder =>
225+ {
226+ builder
227+ . Configure ( o => o . ActivityTrackingOptions = ActivityTrackingOptions . Baggage )
228+ . AddProvider ( loggerProvider ) ;
229+ } ) ;
230+
231+ var logger = loggerFactory . CreateLogger ( "Logger" ) ;
232+
233+ Activity activity = new Activity ( "ScopeActivity" ) ;
234+ activity . AddBaggage ( "testKey1" , null ) ;
235+ activity . AddBaggage ( "testKey2" , string . Empty ) ;
236+ activity . AddBaggage ( "testKey3" , "testValue" ) ;
237+ activity . Start ( ) ;
238+
239+ logger . LogInformation ( "Message1" ) ;
240+
241+ activity . Stop ( ) ;
242+
243+ foreach ( string s in loggerProvider . LogText )
244+ {
245+ System . Console . WriteLine ( s ) ;
246+ }
247+
248+ Assert . Equal ( "Message1" , loggerProvider . LogText [ 0 ] ) ;
249+ Assert . Equal ( "testKey3:testValue, testKey2:, testKey1:" , loggerProvider . LogText [ 2 ] ) ;
250+ }
251+
252+ [ Fact ]
253+ public void TestActivityTrackingOptions_ShouldAddTagsAsNewScope_WhenTagsOptionIsSet ( )
254+ {
255+ var loggerProvider = new ExternalScopeLoggerProvider ( ) ;
256+
257+ var loggerFactory = LoggerFactory . Create ( builder =>
258+ {
259+ builder
260+ . Configure ( o => o . ActivityTrackingOptions = ActivityTrackingOptions . TraceId | ActivityTrackingOptions . Tags )
261+ . AddProvider ( loggerProvider ) ;
262+ } ) ;
263+
264+ var logger = loggerFactory . CreateLogger ( "Logger" ) ;
265+
266+ Activity activity = new Activity ( "ScopeActivity" ) ;
267+ activity . AddTag ( "testKey1" , null ) ;
268+ activity . AddTag ( "testKey2" , string . Empty ) ;
269+ activity . AddTag ( "testKey3" , "testValue" ) ;
270+ activity . AddTag ( "testKey4" , new Dummy ( ) ) ;
271+ activity . Start ( ) ;
272+
273+ logger . LogInformation ( "Message1" ) ;
274+
275+ activity . Stop ( ) ;
276+
277+ Assert . Equal ( "Message1" , loggerProvider . LogText [ 0 ] ) ;
278+ Assert . Equal ( "testKey1:, testKey2:, testKey3:testValue, testKey4:DummyToString" , loggerProvider . LogText [ 2 ] ) ;
279+ }
280+
281+ [ Fact ]
282+ public void TestActivityTrackingOptions_ShouldAddTagsAndBaggageAsOneScopeAndTraceIdAsOtherScope_WhenTagsBaggageAndTraceIdOptionAreSet ( )
283+ {
284+ var loggerProvider = new ExternalScopeLoggerProvider ( ) ;
285+
286+ var loggerFactory = LoggerFactory . Create ( builder =>
287+ {
288+ builder
289+ . Configure ( o => o . ActivityTrackingOptions = ActivityTrackingOptions . TraceId | ActivityTrackingOptions . Baggage | ActivityTrackingOptions . Tags )
290+ . AddProvider ( loggerProvider ) ;
291+ } ) ;
292+
293+ var logger = loggerFactory . CreateLogger ( "Logger" ) ;
294+
295+ Activity activity = new Activity ( "ScopeActivity" ) ;
296+ activity . AddTag ( "testTagKey1" , "testTagValue" ) ;
297+ activity . AddBaggage ( "testBaggageKey1" , "testBaggageValue" ) ;
298+ activity . Start ( ) ;
299+ logger . LogInformation ( "Message1" ) ;
300+ string traceIdActivityLogString = GetActivityLogString ( ActivityTrackingOptions . TraceId ) ;
301+ activity . Stop ( ) ;
302+
303+ Assert . Equal ( "Message1" , loggerProvider . LogText [ 0 ] ) ;
304+ Assert . Equal ( traceIdActivityLogString , loggerProvider . LogText [ 1 ] ) ;
305+ Assert . Equal ( "testTagKey1:testTagValue" , loggerProvider . LogText [ 2 ] ) ;
306+ Assert . Equal ( "testBaggageKey1:testBaggageValue" , loggerProvider . LogText [ 3 ] ) ;
307+ }
308+
309+ [ Fact ]
310+ public void TestActivityTrackingOptions_ShouldAddNewTagAndBaggageItemsAtRuntime_WhenTagsAndBaggageOptionAreSetAndWithNestedScopes ( )
311+ {
312+ var loggerProvider = new ExternalScopeLoggerProvider ( ) ;
313+
314+ var loggerFactory = LoggerFactory . Create ( builder =>
315+ {
316+ builder
317+ . Configure ( o => o . ActivityTrackingOptions = ActivityTrackingOptions . Baggage | ActivityTrackingOptions . Tags )
318+ . AddProvider ( loggerProvider ) ;
319+ } ) ;
320+
321+ var logger = loggerFactory . CreateLogger ( "Logger" ) ;
322+
323+ Activity activity = new Activity ( "ScopeActivity" ) ;
324+ activity . Start ( ) ;
325+
326+ // Add baggage and tag items before the first log entry.
327+ activity . AddTag ( "MyTagKey1" , "1" ) ;
328+ activity . AddBaggage ( "MyBaggageKey1" , "1" ) ;
329+
330+ // Log a message, this should create any cached objects.
331+ logger . LogInformation ( "Message1" ) ;
332+
333+ // Start the first scope, add some more items and log.
334+ using ( logger . BeginScope ( "Scope1" ) )
335+ {
336+ activity . AddTag ( "MyTagKey2" , "2" ) ;
337+ activity . AddBaggage ( "MyBaggageKey2" , "2" ) ;
338+ logger . LogInformation ( "Message2" ) ;
339+
340+ // Add two additional scopes and also replace some tag and baggage items.
341+ using ( logger . BeginScope ( "Scope2" ) )
342+ {
343+ activity . AddTag ( "MyTagKey3" , "3" ) ;
344+ activity . AddBaggage ( "MyBaggageKey3" , "3" ) ;
345+
346+ using ( logger . BeginScope ( "Scope3" ) )
347+ {
348+ activity . SetTag ( "MyTagKey3" , "4" ) ;
349+ activity . SetBaggage ( "MyBaggageKey3" , "4" ) ;
350+ logger . LogInformation ( "Message3" ) ;
351+ }
352+ }
353+
354+ // Along with this message we expect all baggage and tags items
355+ // as well as the Scope1 but not the Scope2 and Scope3.
356+ logger . LogInformation ( "Message4" ) ;
357+
358+ activity . Stop ( ) ;
359+ }
360+
361+ Assert . Equal ( "Message1" , loggerProvider . LogText [ 0 ] ) ;
362+ Assert . Equal ( "MyTagKey1:1" , loggerProvider . LogText [ 2 ] ) ;
363+ Assert . Equal ( "MyBaggageKey1:1" , loggerProvider . LogText [ 3 ] ) ;
364+
365+ Assert . Equal ( "Message2" , loggerProvider . LogText [ 4 ] ) ;
366+ Assert . Equal ( "MyTagKey1:1, MyTagKey2:2" , loggerProvider . LogText [ 6 ] ) ;
367+ Assert . Equal ( "MyBaggageKey2:2, MyBaggageKey1:1" , loggerProvider . LogText [ 7 ] ) ;
368+ Assert . Equal ( "Scope1" , loggerProvider . LogText [ 8 ] ) ;
369+
370+ Assert . Equal ( "Message3" , loggerProvider . LogText [ 9 ] ) ;
371+ Assert . Equal ( "MyTagKey1:1, MyTagKey2:2, MyTagKey3:4" , loggerProvider . LogText [ 11 ] ) ;
372+ Assert . Equal ( "MyBaggageKey3:4, MyBaggageKey2:2, MyBaggageKey1:1" , loggerProvider . LogText [ 12 ] ) ;
373+ Assert . Equal ( "Scope1" , loggerProvider . LogText [ 13 ] ) ;
374+ Assert . Equal ( "Scope2" , loggerProvider . LogText [ 14 ] ) ;
375+ Assert . Equal ( "Scope3" , loggerProvider . LogText [ 15 ] ) ;
376+
377+ Assert . Equal ( "Message4" , loggerProvider . LogText [ 16 ] ) ;
378+ Assert . Equal ( "MyTagKey1:1, MyTagKey2:2, MyTagKey3:4" , loggerProvider . LogText [ 18 ] ) ;
379+ Assert . Equal ( "MyBaggageKey3:4, MyBaggageKey2:2, MyBaggageKey1:1" , loggerProvider . LogText [ 19 ] ) ;
380+ Assert . Equal ( "Scope1" , loggerProvider . LogText [ 20 ] ) ;
381+ }
382+
383+ [ Fact ]
384+ public void TestActivityTrackingOptions_ShouldNotAddAdditionalScope_WhenTagsBaggageOptionAreSetButTagsAndBaggageAreEmpty ( )
385+ {
386+ var loggerProvider = new ExternalScopeLoggerProvider ( ) ;
387+
388+ var loggerFactory = LoggerFactory . Create ( builder =>
389+ {
390+ builder
391+ . Configure ( o => o . ActivityTrackingOptions = ActivityTrackingOptions . TraceId | ActivityTrackingOptions . Baggage | ActivityTrackingOptions . Tags )
392+ . AddProvider ( loggerProvider ) ;
393+ } ) ;
394+
395+ var logger = loggerFactory . CreateLogger ( "Logger" ) ;
396+
397+ Activity activity = new Activity ( "ScopeActivity" ) ;
398+ activity . Start ( ) ;
399+ logger . LogInformation ( "Message1" ) ;
400+ string traceIdActivityLogString = GetActivityLogString ( ActivityTrackingOptions . TraceId ) ;
401+ activity . Stop ( ) ;
402+
403+ Assert . Equal ( "Message1" , loggerProvider . LogText [ 0 ] ) ;
404+ Assert . Equal ( traceIdActivityLogString , loggerProvider . LogText [ 1 ] ) ;
405+ Assert . Equal ( 2 , loggerProvider . LogText . Count ) ; // Ensure that the additional scopes for tags and baggage aren't added.
406+ }
407+
216408 [ Fact ]
217409 public void CallsSetScopeProvider_OnSupportedProviders ( )
218410 {
@@ -367,6 +559,10 @@ public ILogger CreateLogger(string categoryName)
367559 public void Log < TState > ( LogLevel logLevel , EventId eventId , TState state , Exception exception , Func < TState , Exception , string > formatter )
368560 {
369561 LogText . Add ( formatter ( state , exception ) ) ;
562+
563+ // Notice that other ILoggers maybe not call "ToString()" on the scope but enumerate it and this isn't covered by this implementation.
564+ // E.g. the SimpleConsoleFormatter calls "ToString()" like it's done here but the "JsonConsoleFormatter" enumerates a scope
565+ // if the Scope is of type IEnumerable<KeyValuePair<string, object>>.
370566 ScopeProvider . ForEachScope ( ( scope , builder ) => builder . Add ( scope . ToString ( ) ) , LogText ) ;
371567 }
372568
@@ -381,6 +577,14 @@ public IDisposable BeginScope<TState>(TState state)
381577 return null ;
382578 }
383579 }
580+
581+ private class Dummy
582+ {
583+ public override string ToString ( )
584+ {
585+ return "DummyToString" ;
586+ }
587+ }
384588 }
385589
386590 internal static class ActivityExtensions
0 commit comments