1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . Linq ;
4
+ using System . Text ;
4
5
using NLog . Config ;
5
6
using NLog . Layouts ;
6
7
@@ -20,7 +21,7 @@ public class MicrosoftConsoleJsonLayout : JsonLayout
20
21
/// </summary>
21
22
public MicrosoftConsoleJsonLayout ( )
22
23
{
23
- Attributes . Add ( new JsonAttribute ( "Timestamp" , "${date:format=O:universalTime=true}" ) ) ;
24
+ Attributes . Add ( new JsonAttribute ( "Timestamp" , new TimestampLayout ( ) ) ) ;
24
25
Attributes . Add ( new JsonAttribute ( "EventId" , Layout . FromMethod ( evt => LookupEventId ( evt ) , LayoutRenderOptions . ThreadAgnostic ) ) { Encode = false } ) ;
25
26
Attributes . Add ( new JsonAttribute ( "LogLevel" , Layout . FromMethod ( evt => ConvertLogLevel ( evt . Level ) , LayoutRenderOptions . ThreadAgnostic ) ) ) ;
26
27
Attributes . Add ( new JsonAttribute ( "Category" , "${logger}" ) ) ;
@@ -75,7 +76,7 @@ public string TimestampFormat
75
76
get
76
77
{
77
78
var index = LookupNamedAttributeIndex ( "Timestamp" ) ;
78
- return index >= 0 ? ( ( Attributes [ index ] . Layout as SimpleLayout ) ? . LayoutRenderers ? . FirstOrDefault ( ) as NLog . LayoutRenderers . DateLayoutRenderer ) ? . Format : null ;
79
+ return index >= 0 ? ( Attributes [ index ] . Layout as TimestampLayout ) ? . TimestampFormat : null ;
79
80
}
80
81
set
81
82
{
@@ -87,7 +88,7 @@ public string TimestampFormat
87
88
88
89
if ( ! string . IsNullOrEmpty ( value ) )
89
90
{
90
- Attributes . Insert ( 0 , new JsonAttribute ( "Timestamp" , $ "${{date:format= { value } :universalTime=true}}" ) ) ;
91
+ Attributes . Insert ( 0 , new JsonAttribute ( "Timestamp" , new TimestampLayout ( ) { TimestampFormat = value } ) ) ;
91
92
}
92
93
}
93
94
}
@@ -150,5 +151,86 @@ private static string ConvertLogLevel(LogLevel logLevel)
150
151
else
151
152
return nameof ( Microsoft . Extensions . Logging . LogLevel . Critical ) ;
152
153
}
154
+
155
+ [ ThreadAgnostic ]
156
+ private sealed class TimestampLayout : Layout
157
+ {
158
+ public string TimestampFormat
159
+ {
160
+ get => _timestampFormat ;
161
+ set
162
+ {
163
+ if ( "o" . Equals ( value ) )
164
+ value = "O" ;
165
+ _timestampFormat = value ;
166
+ _timestampFormatString = string . IsNullOrEmpty ( value ) ? null : $ "{{0:{ value } }}";
167
+ }
168
+ }
169
+ private string _timestampFormat ;
170
+ private string _timestampFormatString ;
171
+
172
+ public TimestampLayout ( )
173
+ {
174
+ TimestampFormat = "O" ; // Round-trip - ISO8601 - yyyy-MM-ddTHH:mm:ss.fffffffZ
175
+ }
176
+
177
+ protected override string GetFormattedMessage ( LogEventInfo logEvent )
178
+ {
179
+ return _timestampFormatString != null ? logEvent . TimeStamp . ToUniversalTime ( ) . ToString ( TimestampFormat , System . Globalization . CultureInfo . InvariantCulture ) : String . Empty ;
180
+ }
181
+
182
+ protected override void RenderFormattedMessage ( LogEventInfo logEvent , StringBuilder target )
183
+ {
184
+ var utcTimestamp = logEvent . TimeStamp . ToUniversalTime ( ) ;
185
+ if ( "O" . Equals ( TimestampFormat ) )
186
+ {
187
+ // yyyy-MM-ddTHH:mm:ss.fffffffZ
188
+ Append4DigitsZeroPadded ( target , utcTimestamp . Year ) ;
189
+ target . Append ( '-' ) ;
190
+ Append2DigitsZeroPadded ( target , utcTimestamp . Month ) ;
191
+ target . Append ( '-' ) ;
192
+ Append2DigitsZeroPadded ( target , utcTimestamp . Day ) ;
193
+ target . Append ( 'T' ) ;
194
+ Append2DigitsZeroPadded ( target , utcTimestamp . Hour ) ;
195
+ target . Append ( ':' ) ;
196
+ Append2DigitsZeroPadded ( target , utcTimestamp . Minute ) ;
197
+ target . Append ( ':' ) ;
198
+ Append2DigitsZeroPadded ( target , utcTimestamp . Second ) ;
199
+ target . Append ( '.' ) ;
200
+ var ticks = ( int ) ( utcTimestamp . Ticks % 10000000 ) ;
201
+ Append7DigitsZeroPadded ( target , ticks ) ;
202
+ target . Append ( 'Z' ) ;
203
+ }
204
+ else if ( _timestampFormatString != null )
205
+ {
206
+ target . AppendFormat ( System . Globalization . CultureInfo . InvariantCulture , _timestampFormatString , utcTimestamp ) ;
207
+ }
208
+ }
209
+
210
+ internal static void Append2DigitsZeroPadded ( StringBuilder builder , int number )
211
+ {
212
+ builder . Append ( ( char ) ( ( number / 10 ) + '0' ) ) ;
213
+ builder . Append ( ( char ) ( ( number % 10 ) + '0' ) ) ;
214
+ }
215
+
216
+ internal static void Append4DigitsZeroPadded ( StringBuilder builder , int number )
217
+ {
218
+ builder . Append ( ( char ) ( ( ( number / 1000 ) % 10 ) + '0' ) ) ;
219
+ builder . Append ( ( char ) ( ( ( number / 100 ) % 10 ) + '0' ) ) ;
220
+ builder . Append ( ( char ) ( ( ( number / 10 ) % 10 ) + '0' ) ) ;
221
+ builder . Append ( ( char ) ( ( number % 10 ) + '0' ) ) ;
222
+ }
223
+
224
+ internal static void Append7DigitsZeroPadded ( StringBuilder builder , int number )
225
+ {
226
+ builder . Append ( ( char ) ( ( ( number / 1000000 ) % 10 ) + '0' ) ) ;
227
+ builder . Append ( ( char ) ( ( ( number / 100000 ) % 10 ) + '0' ) ) ;
228
+ builder . Append ( ( char ) ( ( ( number / 10000 ) % 10 ) + '0' ) ) ;
229
+ builder . Append ( ( char ) ( ( ( number / 1000 ) % 10 ) + '0' ) ) ;
230
+ builder . Append ( ( char ) ( ( ( number / 100 ) % 10 ) + '0' ) ) ;
231
+ builder . Append ( ( char ) ( ( ( number / 10 ) % 10 ) + '0' ) ) ;
232
+ builder . Append ( ( char ) ( ( number % 10 ) + '0' ) ) ;
233
+ }
234
+ }
153
235
}
154
236
}
0 commit comments