1
1
using System ;
2
+ using System . Diagnostics ;
2
3
using System . Net ;
3
4
using System . Net . Sockets ;
4
5
using System . Threading . Tasks ;
5
6
using FluentAssertions ;
7
+ using Serilog . Core ;
8
+ using Serilog . Core . Enrichers ;
9
+ using Serilog . Events ;
6
10
using Serilog . Formatting ;
7
11
using Serilog . Sinks . Network . Formatters ;
8
12
using Xunit ;
@@ -11,15 +15,22 @@ namespace Serilog.Sinks.Network.Test
11
15
{
12
16
public class JsonFormatter
13
17
{
14
- private static LoggerAndSocket ConfigureTestLogger ( ITextFormatter ? formatter = null )
18
+ private static LoggerAndSocket ConfigureTestLogger (
19
+ ITextFormatter ? formatter = null ,
20
+ ILogEventEnricher [ ] enrichers = null
21
+ )
15
22
{
16
23
var socket = new Socket ( AddressFamily . InterNetwork , SocketType . Stream , ProtocolType . Tcp ) ;
17
24
socket . Bind ( new IPEndPoint ( IPAddress . Loopback , 0 ) ) ;
18
25
socket . Listen ( ) ;
19
26
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 ( ) ;
23
34
24
35
return new LoggerAndSocket { Logger = logger , Socket = socket } ;
25
36
}
@@ -51,5 +62,81 @@ public async Task CanStillLogMessagesWithExceptions()
51
62
52
63
receivedData . Should ( ) . Contain ( "\" exception\" :\" System.Exception: exploding\" }" ) ;
53
64
}
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
+ }
54
141
}
55
142
}
0 commit comments