11using System ;
2+ using System . Diagnostics ;
23using System . Net ;
34using System . Net . Sockets ;
45using System . Threading . Tasks ;
56using FluentAssertions ;
7+ using Serilog . Core ;
8+ using Serilog . Core . Enrichers ;
9+ using Serilog . Events ;
610using Serilog . Formatting ;
711using Serilog . Sinks . Network . Formatters ;
812using Xunit ;
@@ -11,15 +15,22 @@ namespace Serilog.Sinks.Network.Test
1115{
1216 public class JsonFormatter
1317 {
14- private static LoggerAndSocket ConfigureTestLogger ( ITextFormatter ? formatter = null )
18+ private static LoggerAndSocket ConfigureTestLogger (
19+ ITextFormatter ? formatter = null ,
20+ ILogEventEnricher [ ] enrichers = null
21+ )
1522 {
1623 var socket = new Socket ( AddressFamily . InterNetwork , SocketType . Stream , ProtocolType . Tcp ) ;
1724 socket . Bind ( new IPEndPoint ( IPAddress . Loopback , 0 ) ) ;
1825 socket . Listen ( ) ;
1926
20- var logger = new LoggerConfiguration ( )
21- . WriteTo . TCPSink ( IPAddress . Loopback , ( ( IPEndPoint ) socket . LocalEndPoint ! ) . Port , null , null , formatter )
22- . CreateLogger ( ) ;
27+ var loggerConfiguration = new LoggerConfiguration ( )
28+ . WriteTo . TCPSink ( IPAddress . Loopback , ( ( IPEndPoint ) socket . LocalEndPoint ! ) . Port , null , null , formatter ) ;
29+ if ( enrichers != null )
30+ {
31+ loggerConfiguration . Enrich . With ( enrichers ) ;
32+ }
33+ var logger = loggerConfiguration . CreateLogger ( ) ;
2334
2435 return new LoggerAndSocket { Logger = logger , Socket = socket } ;
2536 }
@@ -51,5 +62,81 @@ public async Task CanStillLogMessagesWithExceptions()
5162
5263 receivedData . Should ( ) . Contain ( "\" exception\" :\" System.Exception: exploding\" }" ) ;
5364 }
65+
66+ [ Fact ]
67+ public async Task IncludesCurrentActivityTraceAndSpanIds ( )
68+ {
69+ // Create an ActivitySource, add a listener, and start an activity.
70+ // StartActivity() would return null if there were no listeners.
71+ using var activitySource = new ActivitySource ( "TestSource" ) ;
72+ using var activityListener = CreateAndAddActivityListener ( activitySource . Name ) ;
73+ using var activity = activitySource . StartActivity ( ) ;
74+ Assert . NotNull ( activity ) ;
75+
76+ using var fixture = ConfigureTestLogger ( new LogstashJsonFormatter ( ) ) ;
77+
78+ fixture . Logger . Information ( "arbitraryMessage" ) ;
79+
80+ var receivedData = await ServerPoller . PollForReceivedData ( fixture . Socket ) ;
81+
82+ receivedData . Should ( ) . Contain ( $ "\" traceId\" :\" { activity . TraceId } \" ") ;
83+ receivedData . Should ( ) . Contain ( $ "\" spanId\" :\" { activity . SpanId } \" ") ;
84+ }
85+
86+ [ Fact ]
87+ public async Task OmitsTraceAndSpanIdsWhenThereIsNoActivity ( )
88+ {
89+ using var fixture = ConfigureTestLogger ( new LogstashJsonFormatter ( ) ) ;
90+
91+ fixture . Logger . Information ( "arbitraryMessage" ) ;
92+
93+ var receivedData = await ServerPoller . PollForReceivedData ( fixture . Socket ) ;
94+
95+ receivedData . Should ( ) . NotContain ( "\" traceId\" " ) ;
96+ receivedData . Should ( ) . NotContain ( "\" spanId\" " ) ;
97+ }
98+
99+ // The following test documents and validates the current behavior, but this could change
100+ // depending on how https://github.com/serilog-contrib/Serilog.Sinks.Network/issues/39 is
101+ // resolved.
102+ [ Fact ]
103+ public async Task WritesTraceAndSpanIdsBeforeDuplicatePropertiesFromEnrichers ( )
104+ {
105+ using var activitySource = new ActivitySource ( "TestSource" ) ;
106+ using var activityListener = CreateAndAddActivityListener ( activitySource . Name ) ;
107+ using var activity = activitySource . StartActivity ( ) ;
108+ Assert . NotNull ( activity ) ;
109+
110+ using var fixture = ConfigureTestLogger (
111+ new LogstashJsonFormatter ( ) ,
112+ [
113+ new PropertyEnricher ( "traceId" , "traceId-from-enricher" ) ,
114+ new PropertyEnricher ( "spanId" , "spanId-from-enricher" )
115+ ]
116+ ) ;
117+
118+ fixture . Logger . Information ( "arbitraryMessage" ) ;
119+
120+ var receivedData = await ServerPoller . PollForReceivedData ( fixture . Socket ) ;
121+
122+ var indexOfTraceId = receivedData . IndexOf ( $ "\" traceId\" :\" { activity . TraceId } \" ") ;
123+ var indexOfTraceIdFromEnricher = receivedData . IndexOf ( "\" traceId\" :\" traceId-from-enricher\" " ) ;
124+ indexOfTraceId . Should ( ) . BePositive ( ) . And . BeLessThan ( indexOfTraceIdFromEnricher ) ;
125+
126+ var indexOfSpanId = receivedData . IndexOf ( $ "\" spanId\" :\" { activity . SpanId } \" ") ;
127+ var indexOfSpanIdFromEnricher = receivedData . IndexOf ( "\" spanId\" :\" spanId-from-enricher\" " ) ;
128+ indexOfSpanId . Should ( ) . BePositive ( ) . And . BeLessThan ( indexOfSpanIdFromEnricher ) ;
129+ }
130+
131+ private static ActivityListener CreateAndAddActivityListener ( string sourceName )
132+ {
133+ var activityListener = new ActivityListener
134+ {
135+ ShouldListenTo = source => source . Name == sourceName ,
136+ Sample = ( ref ActivityCreationOptions < ActivityContext > _ ) => ActivitySamplingResult . AllData ,
137+ } ;
138+ ActivitySource . AddActivityListener ( activityListener ) ;
139+ return activityListener ;
140+ }
54141 }
55142}
0 commit comments