1818#endregion
1919
2020using System ;
21- using System . IO ;
21+ using System . Diagnostics . CodeAnalysis ;
2222using System . Globalization ;
23-
23+ using System . IO ;
24+ using System . Linq ;
25+ using System . Threading ;
2426using log4net . Config ;
2527using log4net . Core ;
2628using log4net . Layout ;
2729using log4net . Layout . Pattern ;
2830using log4net . Repository ;
2931using log4net . Tests . Appender ;
3032using log4net . Util ;
31-
3233using NUnit . Framework ;
33- using System . Diagnostics . CodeAnalysis ;
34- using log4net . Repository . Hierarchy ;
3534
3635namespace log4net . Tests . Layout ;
3736
@@ -51,17 +50,17 @@ public class PatternLayoutTest
5150 public void SetUp ( )
5251 {
5352 // 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 ;
5756 }
5857 [ TearDown ]
5958 public void TearDown ( )
6059 {
6160 Utils . RemovePropertyFromAllContexts ( ) ;
6261 // 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 ! ;
6564 }
6665
6766 protected virtual PatternLayout NewPatternLayout ( ) => new ( ) ;
@@ -79,7 +78,7 @@ public void TestThreadPropertiesPattern()
7978 ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
8079 BasicConfigurator . Configure ( rep , stringAppender ) ;
8180
82- ILog log1 = LogManager . GetLogger ( rep . Name , "TestThreadProperiesPattern" ) ;
81+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( TestThreadPropertiesPattern ) ) ;
8382
8483 log1 . Info ( "TestMessage" ) ;
8584 Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( SystemInfo . NullText ) , "Test no thread properties value set" ) ;
@@ -127,7 +126,7 @@ public void TestGlobalPropertiesPattern()
127126 ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
128127 BasicConfigurator . Configure ( rep , stringAppender ) ;
129128
130- ILog log1 = LogManager . GetLogger ( rep . Name , "TestGlobalProperiesPattern" ) ;
129+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( TestGlobalPropertiesPattern ) ) ;
131130
132131 log1 . Info ( "TestMessage" ) ;
133132 Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( SystemInfo . NullText ) , "Test no global properties value set" ) ;
@@ -152,16 +151,16 @@ public void TestAddingCustomPattern()
152151 StringAppender stringAppender = new ( ) ;
153152 PatternLayout layout = NewPatternLayout ( ) ;
154153
155- layout . AddConverter ( " TestAddingCustomPattern" , typeof ( TestMessagePatternConverter ) ) ;
156- layout . ConversionPattern = "%TestAddingCustomPattern" ;
154+ layout . AddConverter ( nameof ( TestAddingCustomPattern ) , typeof ( TestMessagePatternConverter ) ) ;
155+ layout . ConversionPattern = "%" + nameof ( TestAddingCustomPattern ) ;
157156 layout . ActivateOptions ( ) ;
158157
159158 stringAppender . Layout = layout ;
160159
161160 ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
162161 BasicConfigurator . Configure ( rep , stringAppender ) ;
163162
164- ILog log1 = LogManager . GetLogger ( rep . Name , " TestAddingCustomPattern" ) ;
163+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( TestAddingCustomPattern ) ) ;
165164
166165 log1 . Info ( "TestMessage" ) ;
167166 Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( "TestMessage" ) , "%TestAddingCustomPattern not registered" ) ;
@@ -179,7 +178,7 @@ public void NamedPatternConverterWithoutPrecisionShouldReturnFullName()
179178 stringAppender . Layout = layout ;
180179 ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
181180 BasicConfigurator . Configure ( rep , stringAppender ) ;
182- ILog log1 = LogManager . GetLogger ( rep . Name , "TestAddingCustomPattern" ) ;
181+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( NamedPatternConverterWithoutPrecisionShouldReturnFullName ) ) ;
183182
184183 log1 . Info ( "NoDots" ) ;
185184 Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( "NoDots" ) , "%message-as-name not registered" ) ;
@@ -226,7 +225,7 @@ public void NamedPatternConverterWithPrecision1ShouldStripLeadingStuffIfPresent(
226225 stringAppender . Layout = layout ;
227226 ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
228227 BasicConfigurator . Configure ( rep , stringAppender ) ;
229- ILog log1 = LogManager . GetLogger ( rep . Name , "TestAddingCustomPattern" ) ;
228+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( NamedPatternConverterWithPrecision1ShouldStripLeadingStuffIfPresent ) ) ;
230229
231230 log1 . Info ( "NoDots" ) ;
232231 Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( "NoDots" ) , "%message-as-name not registered" ) ;
@@ -273,7 +272,7 @@ public void NamedPatternConverterWithPrecision2ShouldStripLessLeadingStuffIfPres
273272 stringAppender . Layout = layout ;
274273 ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
275274 BasicConfigurator . Configure ( rep , stringAppender ) ;
276- ILog log1 = LogManager . GetLogger ( rep . Name , "TestAddingCustomPattern" ) ;
275+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( NamedPatternConverterWithPrecision2ShouldStripLessLeadingStuffIfPresent ) ) ;
277276
278277 log1 . Info ( "NoDots" ) ;
279278 Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( "NoDots" ) , "%message-as-name not registered" ) ;
@@ -334,7 +333,7 @@ public void TestExceptionPattern()
334333 ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
335334 BasicConfigurator . Configure ( rep , stringAppender ) ;
336335
337- ILog log1 = LogManager . GetLogger ( rep . Name , " TestExceptionPattern" ) ;
336+ ILog log1 = LogManager . GetLogger ( rep . Name , nameof ( TestExceptionPattern ) ) ;
338337
339338 InvalidOperationException exception = new ( "Oh no!" ) ;
340339 log1 . Info ( "TestMessage" , exception ) ;
@@ -355,11 +354,33 @@ public void ConvertMicrosecondsPatternTest()
355354 ILoggerRepository rep = LogManager . CreateRepository ( Guid . NewGuid ( ) . ToString ( ) ) ;
356355 BasicConfigurator . Configure ( rep , stringAppender ) ;
357356
358- ILog logger = LogManager . GetLogger ( rep . Name , "TestThreadProperiesPattern" ) ;
357+ ILog logger = LogManager . GetLogger ( rep . Name , nameof ( ConvertMicrosecondsPatternTest ) ) ;
359358
360359 logger . Logger . Log ( new ( new ( ) { TimeStampUtc = new ( 2025 , 02 , 10 , 13 , 01 , 02 , 123 , 456 , DateTimeKind . Utc ) , Message = "test" , Level = Level . Info } ) ) ;
361360 Assert . That ( stringAppender . GetString ( ) , Is . EqualTo ( "20250210 13:01:02.123456" ) ) ;
362361 }
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+ }
363384#endif
364385
365386 [ SuppressMessage ( "Microsoft.Performance" , "CA1812:AvoidUninstantiatedInternalClasses" , Justification = "Reflection" ) ]
0 commit comments