11using Kbg . NppPluginNET . PluginInfrastructure ;
22using System ;
3+ using System . Collections . Concurrent ;
4+ using System . Diagnostics ;
35using System . IO ;
46using System . Text ;
57using System . Threading ;
@@ -22,6 +24,7 @@ static class Logger
2224 internal static bool hasAlreadyShownErrorBox = false ;
2325 private static StreamWriter writer ;
2426 private static SemaphoreSlim semaphore = new SemaphoreSlim ( 1 , 1 ) ;
27+ private static ConcurrentQueue < Func < Task > > funcTaskQueue = new ConcurrentQueue < Func < Task > > ( ) ;
2528
2629 internal static void Debug ( string msg )
2730 {
@@ -48,9 +51,33 @@ internal static void Error(string msg, Exception ex = null)
4851 Log ( LogLevel . HandledException , exceptionMessage ) ;
4952 }
5053
54+ private static bool RunNextLogTask ( )
55+ {
56+ Func < Task > result ;
57+ // first only peek without removing, so that EnqueueLogTask won't call another out-of-chain RunNextLogTask
58+ if ( funcTaskQueue . TryPeek ( out result ) )
59+ {
60+ Task . Run ( result ) . ContinueWith ( task => {
61+ // dequeue current log line only now
62+ funcTaskQueue . TryDequeue ( out result ) ;
63+ RunNextLogTask ( ) ;
64+ } ) ;
65+ return true ;
66+ }
67+ return false ; // nothing remained
68+ }
69+
70+ private static void EnqueueLogTask ( Func < Task > taskFunc )
71+ {
72+ bool wasEmpty = funcTaskQueue . IsEmpty ;
73+ funcTaskQueue . Enqueue ( taskFunc ) ;
74+ if ( wasEmpty )
75+ RunNextLogTask ( ) ;
76+ }
77+
5178 internal static void Log ( LogLevel level , string msg )
5279 {
53- Task . Run ( async ( ) =>
80+ EnqueueLogTask ( async ( ) =>
5481 {
5582 try
5683 {
@@ -78,6 +105,32 @@ internal static void Log(LogLevel level, string msg)
78105 } ) ;
79106 }
80107
108+ // called on shutdown to ensure everything is flushed synchronously
109+ public static void FlushEverything ( )
110+ {
111+ if ( writer == null )
112+ return ;
113+
114+ // let all log lines be written first
115+ /*while (true)
116+ {
117+ if (!RunNextLogTask())
118+ break;
119+ }*/
120+ Stopwatch stopwatch = new Stopwatch ( ) ;
121+ stopwatch . Start ( ) ;
122+ while ( ! funcTaskQueue . IsEmpty && stopwatch . ElapsedMilliseconds < 1000 ) // wait for max 1 second
123+ {
124+ semaphore . Wait ( ) ;
125+ semaphore . Release ( ) ;
126+ }
127+ stopwatch . Stop ( ) ;
128+
129+ semaphore . Wait ( ) ;
130+ writer . Flush ( ) ;
131+ semaphore . Release ( ) ;
132+ }
133+
81134 private static StreamWriter Setup ( )
82135 {
83136 if ( String . IsNullOrWhiteSpace ( configDir ) )
0 commit comments