Skip to content

Commit 3bb2ace

Browse files
committed
Console log buffer - experiment with no waiting if buffer is full
1 parent 38efb41 commit 3bb2ace

File tree

2 files changed

+10
-36
lines changed

2 files changed

+10
-36
lines changed

src/WebJobs.Script.WebHost/Diagnostics/ConsoleWriter.cs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System;
55
using System.Text;
6-
using System.Threading;
76
using System.Threading.Channels;
87
using System.Threading.Tasks;
98

@@ -80,30 +79,8 @@ public void WriteHandler(string evt)
8079

8180
private void WriteToConsoleBuffer(string evt)
8281
{
83-
try
82+
if (_consoleBuffer.Writer.TryWrite(evt) == false)
8483
{
85-
if (_consoleBuffer.Writer.TryWrite(evt) == false)
86-
{
87-
// Buffer is currently full, wait until writing is permitted.
88-
using var source = new CancellationTokenSource(_consoleBufferTimeout);
89-
var writeTask = _consoleBuffer.Writer.WriteAsync(evt, source.Token);
90-
91-
// This is the downside of using channels, we are on a sync code path and so we have to block on this task if we want to wait for the buffer to clear.
92-
if (writeTask.IsCompleted)
93-
{
94-
writeTask.GetAwaiter().GetResult();
95-
}
96-
else
97-
{
98-
writeTask.AsTask().GetAwaiter().GetResult();
99-
}
100-
}
101-
}
102-
catch (Exception ex)
103-
{
104-
// Most likely a task cancellation exception from the timeout expiring, but regardless we use the handler
105-
// dump the raw exception and write the event to the console directly
106-
_exceptionhandler(ex);
10784
Console.WriteLine(evt);
10885
}
10986
}

test/WebJobs.Script.Tests/Diagnostics/LinuxContainerEventGeneratorWithConsoleOutputTests.cs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,12 @@ public void MultipleEventsWithTinyBuffer_WritesDirectlyToConsoleOnTimeout(bool b
152152
var output = sr.ReadToEnd().Trim().SplitLines();
153153

154154
// The first two messages are still stuck in the buffer. The third message will have been written to the console.
155-
// We should also have a log for the timeout exception that occurred while waiting for the buffer to become available.
156-
Assert.Equal(2, output.Length);
157-
Assert.StartsWith("MS_FUNCTION_LOGS 2,,,,,LogUnhandledException,\"System.OperationCanceledException: The operation was canceled.", output[0]);
158-
Assert.Equal($"MS_FUNCTION_LOGS 4,C37E3412-86D1-4B93-BC5A-A2AE09D26C2D,TestApp,TestFunction3,TestEvent,TestSource,\"These are the details, lots of details\",\"This is the summary, a great summary\",{ScriptHost.Version},{timestamp.ToString("O")},TestExceptionType,\"Test exception message, with details\",E2D5A6ED-4CE3-4CFD-8878-FD4814F0A1F3,3AD41658-1C4E-4C9D-B0B9-24F2BDAE2829,F0AAA9AD-C3A6-48B9-A75E-57BB280EBB53,TEST-CONTAINER,test-stamp,test-tenant,TestRuntimeSiteName,TestSlotName", output[1]);
155+
Assert.Equal(1, output.Length);
156+
Assert.Equal($"MS_FUNCTION_LOGS 4,C37E3412-86D1-4B93-BC5A-A2AE09D26C2D,TestApp,TestFunction3,TestEvent,TestSource,\"These are the details, lots of details\",\"This is the summary, a great summary\",{ScriptHost.Version},{timestamp.ToString("O")},TestExceptionType,\"Test exception message, with details\",E2D5A6ED-4CE3-4CFD-8878-FD4814F0A1F3,3AD41658-1C4E-4C9D-B0B9-24F2BDAE2829,F0AAA9AD-C3A6-48B9-A75E-57BB280EBB53,TEST-CONTAINER,test-stamp,test-tenant,TestRuntimeSiteName,TestSlotName", output[0]);
159157
}
160158

161159
[Fact]
162-
public async Task MultipleEventsBatchedWithTinyBuffer_BlocksOnWriteOnBufferFull_IfTimeoutNotReached()
160+
public async Task WritesLogsDirectlyWhenBufferIsFull()
163161
{
164162
// setup in a state where the buffer isn't being processed and can only hold two messages
165163
var env = CreateEnvironment(bufferSize: 2, batched: true);
@@ -170,24 +168,23 @@ public async Task MultipleEventsBatchedWithTinyBuffer_BlocksOnWriteOnBufferFull_
170168
generator.LogFunctionTraceEvent(LogLevel.Information, "C37E3412-86D1-4B93-BC5A-A2AE09D26C2D", "TestApp", "TestFunction1", "TestEvent", "TestSource", "These are the details, lots of details", "This is the summary, a great summary", "TestExceptionType", "Test exception message, with details", "E2D5A6ED-4CE3-4CFD-8878-FD4814F0A1F3", "3AD41658-1C4E-4C9D-B0B9-24F2BDAE2829", "F0AAA9AD-C3A6-48B9-A75E-57BB280EBB53", "TestRuntimeSiteName", "TestSlotName", timestamp);
171169
generator.LogFunctionTraceEvent(LogLevel.Information, "C37E3412-86D1-4B93-BC5A-A2AE09D26C2D", "TestApp", "TestFunction2", "TestEvent", "TestSource", "These are the details, lots of details", "This is the summary, a great summary", "TestExceptionType", "Test exception message, with details", "E2D5A6ED-4CE3-4CFD-8878-FD4814F0A1F3", "3AD41658-1C4E-4C9D-B0B9-24F2BDAE2829", "F0AAA9AD-C3A6-48B9-A75E-57BB280EBB53", "TestRuntimeSiteName", "TestSlotName", timestamp);
172170

173-
// The third write will block until the first two are flushed.
174-
var logTask = Task.Run(() => generator.LogFunctionTraceEvent(LogLevel.Information, "C37E3412-86D1-4B93-BC5A-A2AE09D26C2D", "TestApp", "TestFunction3", "TestEvent", "TestSource", "These are the details, lots of details", "This is the summary, a great summary", "TestExceptionType", "Test exception message, with details", "E2D5A6ED-4CE3-4CFD-8878-FD4814F0A1F3", "3AD41658-1C4E-4C9D-B0B9-24F2BDAE2829", "F0AAA9AD-C3A6-48B9-A75E-57BB280EBB53", "TestRuntimeSiteName", "TestSlotName", timestamp));
171+
// The third write will go direct to console
172+
generator.LogFunctionTraceEvent(LogLevel.Information, "C37E3412-86D1-4B93-BC5A-A2AE09D26C2D", "TestApp", "TestFunction3", "TestEvent", "TestSource", "These are the details, lots of details", "This is the summary, a great summary", "TestExceptionType", "Test exception message, with details", "E2D5A6ED-4CE3-4CFD-8878-FD4814F0A1F3", "3AD41658-1C4E-4C9D-B0B9-24F2BDAE2829", "F0AAA9AD-C3A6-48B9-A75E-57BB280EBB53", "TestRuntimeSiteName", "TestSlotName", timestamp);
175173
await Task.Delay(TimeSpan.FromMilliseconds(10));
176-
Assert.False(logTask.IsCompleted);
177174

178175
consoleWriter.StartProcessingBuffer(batched: true);
179176
await Task.Delay(TimeSpan.FromMilliseconds(50));
180-
Assert.True(logTask.IsCompleted);
181177

182178
using var sr = new StreamReader(_consoleOut);
183179
_consoleOut.Position = 0;
184180
var output = sr.ReadToEnd().Trim().SplitLines();
185181

186182
Assert.Equal(3, output.Length);
187183

188-
Assert.Equal($"MS_FUNCTION_LOGS 4,C37E3412-86D1-4B93-BC5A-A2AE09D26C2D,TestApp,TestFunction1,TestEvent,TestSource,\"These are the details, lots of details\",\"This is the summary, a great summary\",{ScriptHost.Version},{timestamp.ToString("O")},TestExceptionType,\"Test exception message, with details\",E2D5A6ED-4CE3-4CFD-8878-FD4814F0A1F3,3AD41658-1C4E-4C9D-B0B9-24F2BDAE2829,F0AAA9AD-C3A6-48B9-A75E-57BB280EBB53,TEST-CONTAINER,test-stamp,test-tenant,TestRuntimeSiteName,TestSlotName", output[0]);
189-
Assert.Equal($"MS_FUNCTION_LOGS 4,C37E3412-86D1-4B93-BC5A-A2AE09D26C2D,TestApp,TestFunction2,TestEvent,TestSource,\"These are the details, lots of details\",\"This is the summary, a great summary\",{ScriptHost.Version},{timestamp.ToString("O")},TestExceptionType,\"Test exception message, with details\",E2D5A6ED-4CE3-4CFD-8878-FD4814F0A1F3,3AD41658-1C4E-4C9D-B0B9-24F2BDAE2829,F0AAA9AD-C3A6-48B9-A75E-57BB280EBB53,TEST-CONTAINER,test-stamp,test-tenant,TestRuntimeSiteName,TestSlotName", output[1]);
190-
Assert.Equal($"MS_FUNCTION_LOGS 4,C37E3412-86D1-4B93-BC5A-A2AE09D26C2D,TestApp,TestFunction3,TestEvent,TestSource,\"These are the details, lots of details\",\"This is the summary, a great summary\",{ScriptHost.Version},{timestamp.ToString("O")},TestExceptionType,\"Test exception message, with details\",E2D5A6ED-4CE3-4CFD-8878-FD4814F0A1F3,3AD41658-1C4E-4C9D-B0B9-24F2BDAE2829,F0AAA9AD-C3A6-48B9-A75E-57BB280EBB53,TEST-CONTAINER,test-stamp,test-tenant,TestRuntimeSiteName,TestSlotName", output[2]);
184+
// the log from TestFunction3 will be first because it was written directly to the console
185+
Assert.Equal($"MS_FUNCTION_LOGS 4,C37E3412-86D1-4B93-BC5A-A2AE09D26C2D,TestApp,TestFunction3,TestEvent,TestSource,\"These are the details, lots of details\",\"This is the summary, a great summary\",{ScriptHost.Version},{timestamp.ToString("O")},TestExceptionType,\"Test exception message, with details\",E2D5A6ED-4CE3-4CFD-8878-FD4814F0A1F3,3AD41658-1C4E-4C9D-B0B9-24F2BDAE2829,F0AAA9AD-C3A6-48B9-A75E-57BB280EBB53,TEST-CONTAINER,test-stamp,test-tenant,TestRuntimeSiteName,TestSlotName", output[0]);
186+
Assert.Equal($"MS_FUNCTION_LOGS 4,C37E3412-86D1-4B93-BC5A-A2AE09D26C2D,TestApp,TestFunction1,TestEvent,TestSource,\"These are the details, lots of details\",\"This is the summary, a great summary\",{ScriptHost.Version},{timestamp.ToString("O")},TestExceptionType,\"Test exception message, with details\",E2D5A6ED-4CE3-4CFD-8878-FD4814F0A1F3,3AD41658-1C4E-4C9D-B0B9-24F2BDAE2829,F0AAA9AD-C3A6-48B9-A75E-57BB280EBB53,TEST-CONTAINER,test-stamp,test-tenant,TestRuntimeSiteName,TestSlotName", output[1]);
187+
Assert.Equal($"MS_FUNCTION_LOGS 4,C37E3412-86D1-4B93-BC5A-A2AE09D26C2D,TestApp,TestFunction2,TestEvent,TestSource,\"These are the details, lots of details\",\"This is the summary, a great summary\",{ScriptHost.Version},{timestamp.ToString("O")},TestExceptionType,\"Test exception message, with details\",E2D5A6ED-4CE3-4CFD-8878-FD4814F0A1F3,3AD41658-1C4E-4C9D-B0B9-24F2BDAE2829,F0AAA9AD-C3A6-48B9-A75E-57BB280EBB53,TEST-CONTAINER,test-stamp,test-tenant,TestRuntimeSiteName,TestSlotName", output[2]);
191188
}
192189

193190
[Fact]

0 commit comments

Comments
 (0)