Skip to content

Commit 52e575f

Browse files
committed
ensure log lines are written in correct order
1 parent faa4fca commit 52e575f

1 file changed

Lines changed: 54 additions & 1 deletion

File tree

CodeStats/Logger.cs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using Kbg.NppPluginNET.PluginInfrastructure;
22
using System;
3+
using System.Collections.Concurrent;
4+
using System.Diagnostics;
35
using System.IO;
46
using System.Text;
57
using 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

Comments
 (0)