18
18
#endregion
19
19
20
20
using System ;
21
- using System . IO ;
21
+ using System . Diagnostics . CodeAnalysis ;
22
22
using System . Globalization ;
23
-
23
+ using System . IO ;
24
+ using System . Linq ;
25
+ using System . Threading ;
24
26
using log4net . Config ;
25
27
using log4net . Core ;
26
28
using log4net . Layout ;
27
29
using log4net . Layout . Pattern ;
28
30
using log4net . Repository ;
29
31
using log4net . Tests . Appender ;
30
32
using log4net . Util ;
31
-
32
33
using NUnit . Framework ;
33
- using System . Diagnostics . CodeAnalysis ;
34
- using log4net . Repository . Hierarchy ;
35
34
36
35
namespace log4net . Tests . Layout ;
37
36
@@ -51,17 +50,17 @@ public class PatternLayoutTest
51
50
public void SetUp ( )
52
51
{
53
52
// set correct thread culture
54
- _currentCulture = System . Threading . Thread . CurrentThread . CurrentCulture ;
55
- _currentUiCulture = System . Threading . Thread . CurrentThread . CurrentUICulture ;
56
- System . Threading . Thread . CurrentThread . CurrentCulture = System . Threading . Thread . CurrentThread . CurrentUICulture = System . Globalization . CultureInfo . InvariantCulture ;
53
+ _currentCulture = Thread . CurrentThread . CurrentCulture ;
54
+ _currentUiCulture = Thread . CurrentThread . CurrentUICulture ;
55
+ Thread . CurrentThread . CurrentCulture = Thread . CurrentThread . CurrentUICulture = CultureInfo . InvariantCulture ;
57
56
}
58
57
[ TearDown ]
59
58
public void TearDown ( )
60
59
{
61
60
Utils . RemovePropertyFromAllContexts ( ) ;
62
61
// restore previous culture
63
- System . Threading . Thread . CurrentThread . CurrentCulture = _currentCulture ! ;
64
- System . Threading . Thread . CurrentThread . CurrentUICulture = _currentUiCulture ! ;
62
+ Thread . CurrentThread . CurrentCulture = _currentCulture ! ;
63
+ Thread . CurrentThread . CurrentUICulture = _currentUiCulture ! ;
65
64
}
66
65
67
66
protected virtual PatternLayout NewPatternLayout ( ) => new ( ) ;
@@ -79,7 +78,7 @@ public void TestThreadPropertiesPattern()
79
78
ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
80
79
BasicConfigurator . Configure ( rep , stringAppender ) ;
81
80
82
- ILog log1 = LogManager . GetLogger ( rep . Name , "TestThreadProperiesPattern" ) ;
81
+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( TestThreadPropertiesPattern ) ) ;
83
82
84
83
log1 . Info ( "TestMessage" ) ;
85
84
Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( SystemInfo . NullText ) , "Test no thread properties value set" ) ;
@@ -127,7 +126,7 @@ public void TestGlobalPropertiesPattern()
127
126
ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
128
127
BasicConfigurator . Configure ( rep , stringAppender ) ;
129
128
130
- ILog log1 = LogManager . GetLogger ( rep . Name , "TestGlobalProperiesPattern" ) ;
129
+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( TestGlobalPropertiesPattern ) ) ;
131
130
132
131
log1 . Info ( "TestMessage" ) ;
133
132
Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( SystemInfo . NullText ) , "Test no global properties value set" ) ;
@@ -152,16 +151,16 @@ public void TestAddingCustomPattern()
152
151
StringAppender stringAppender = new ( ) ;
153
152
PatternLayout layout = NewPatternLayout ( ) ;
154
153
155
- layout . AddConverter ( " TestAddingCustomPattern" , typeof ( TestMessagePatternConverter ) ) ;
156
- layout . ConversionPattern = "%TestAddingCustomPattern" ;
154
+ layout . AddConverter ( nameof ( TestAddingCustomPattern ) , typeof ( TestMessagePatternConverter ) ) ;
155
+ layout . ConversionPattern = "%" + nameof ( TestAddingCustomPattern ) ;
157
156
layout . ActivateOptions ( ) ;
158
157
159
158
stringAppender . Layout = layout ;
160
159
161
160
ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
162
161
BasicConfigurator . Configure ( rep , stringAppender ) ;
163
162
164
- ILog log1 = LogManager . GetLogger ( rep . Name , " TestAddingCustomPattern" ) ;
163
+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( TestAddingCustomPattern ) ) ;
165
164
166
165
log1 . Info ( "TestMessage" ) ;
167
166
Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( "TestMessage" ) , "%TestAddingCustomPattern not registered" ) ;
@@ -179,7 +178,7 @@ public void NamedPatternConverterWithoutPrecisionShouldReturnFullName()
179
178
stringAppender . Layout = layout ;
180
179
ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
181
180
BasicConfigurator . Configure ( rep , stringAppender ) ;
182
- ILog log1 = LogManager . GetLogger ( rep . Name , "TestAddingCustomPattern" ) ;
181
+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( NamedPatternConverterWithoutPrecisionShouldReturnFullName ) ) ;
183
182
184
183
log1 . Info ( "NoDots" ) ;
185
184
Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( "NoDots" ) , "%message-as-name not registered" ) ;
@@ -226,7 +225,7 @@ public void NamedPatternConverterWithPrecision1ShouldStripLeadingStuffIfPresent(
226
225
stringAppender . Layout = layout ;
227
226
ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
228
227
BasicConfigurator . Configure ( rep , stringAppender ) ;
229
- ILog log1 = LogManager . GetLogger ( rep . Name , "TestAddingCustomPattern" ) ;
228
+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( NamedPatternConverterWithPrecision1ShouldStripLeadingStuffIfPresent ) ) ;
230
229
231
230
log1 . Info ( "NoDots" ) ;
232
231
Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( "NoDots" ) , "%message-as-name not registered" ) ;
@@ -273,7 +272,7 @@ public void NamedPatternConverterWithPrecision2ShouldStripLessLeadingStuffIfPres
273
272
stringAppender . Layout = layout ;
274
273
ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
275
274
BasicConfigurator . Configure ( rep , stringAppender ) ;
276
- ILog log1 = LogManager . GetLogger ( rep . Name , "TestAddingCustomPattern" ) ;
275
+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( NamedPatternConverterWithPrecision2ShouldStripLessLeadingStuffIfPresent ) ) ;
277
276
278
277
log1 . Info ( "NoDots" ) ;
279
278
Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( "NoDots" ) , "%message-as-name not registered" ) ;
@@ -334,7 +333,7 @@ public void TestExceptionPattern()
334
333
ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
335
334
BasicConfigurator . Configure ( rep , stringAppender ) ;
336
335
337
- ILog log1 = LogManager . GetLogger ( rep . Name , " TestExceptionPattern" ) ;
336
+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( TestExceptionPattern ) ) ;
338
337
339
338
InvalidOperationException exception = new ( "Oh no!" ) ;
340
339
log1 . Info ( "TestMessage" , exception ) ;
@@ -355,11 +354,33 @@ public void ConvertMicrosecondsPatternTest()
355
354
ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
356
355
BasicConfigurator . Configure ( rep , stringAppender ) ;
357
356
358
- ILog logger = LogManager . GetLogger ( rep . Name , "TestThreadProperiesPattern" ) ;
357
+ ILog logger = LogManager . GetLogger ( rep . Name , nameof ( ConvertMicrosecondsPatternTest ) ) ;
359
358
360
359
logger . Logger . Log ( new ( new ( ) { TimeStampUtc = new ( 2025 , 02 , 10 , 13 , 01 , 02 , 123 , 456 , DateTimeKind . Utc ) , Message = "test" , Level = Level . Info } ) ) ;
361
360
Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( "20250210 13:01:02.123456" ) ) ;
362
361
}
362
+
363
+ [ Test ]
364
+ public void ConvertMultipleMicrosecondsPatternTest ( )
365
+ {
366
+ StringAppender stringAppender = new ( )
367
+ {
368
+ Layout = NewPatternLayout ( "[%date{yyyyMMdd HH:mm:ss.ffffff}] [%-5level] [%thread] - %message%newline" )
369
+ } ;
370
+
371
+ ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
372
+ BasicConfigurator . Configure ( rep , stringAppender ) ;
373
+
374
+ ILog logger = LogManager . GetLogger ( rep . Name , nameof ( ConvertMultipleMicrosecondsPatternTest ) ) ;
375
+
376
+ for ( int i = 0 ; i < 100 ; i ++ )
377
+ {
378
+ logger . Info ( null ) ;
379
+ Thread . Sleep ( 1 ) ;
380
+ }
381
+ string [ ] lines = stringAppender . GetString ( ) . Split ( '\n ' ) ;
382
+ Assert . That ( lines , Has . Length . EqualTo ( lines . Distinct ( ) . Count ( ) ) , "no duplicate timestamps allowed" ) ;
383
+ }
363
384
#endif
364
385
365
386
[ SuppressMessage ( "Microsoft.Performance" , "CA1812:AvoidUninstantiatedInternalClasses" , Justification = "Reflection" ) ]
0 commit comments