Skip to content

Commit

Permalink
Add back TraceListener handling for Callstack/LogicalOperationStack (d…
Browse files Browse the repository at this point in the history
  • Loading branch information
stephentoub authored Oct 17, 2019
1 parent 9b88ca1 commit c8ea7bd
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ private void WriteFooter(TraceEventCache eventCache)
if (IsEnabled(TraceOptions.Timestamp))
Write(eventCache.Timestamp.ToString(CultureInfo.InvariantCulture));
Write(Delimiter); // Use get_Delimiter

if (IsEnabled(TraceOptions.Callstack))
WriteEscaped(eventCache.Callstack);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ private static void AppendTraceEventCache(this StringBuilder builder, TraceEvent
builder.Append(delimiter);
builder.Append(cache.Timestamp.ToString(CultureInfo.InvariantCulture));
builder.Append(delimiter);
builder.Append(EscapedString(cache.Callstack));
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public void TraceEvent_FormatString_Test(TraceFilter filter, TraceEventCache eve
using (var target = GetListener())
{
target.Filter = filter;
target.TraceOutputOptions = TraceOptions.ProcessId | TraceOptions.ThreadId | TraceOptions.DateTime | TraceOptions.Timestamp | TraceOptions.LogicalOperationStack;
target.TraceOutputOptions = TraceOptions.ProcessId | TraceOptions.ThreadId | TraceOptions.DateTime | TraceOptions.Timestamp | TraceOptions.LogicalOperationStack | TraceOptions.Callstack;
target.TraceEvent(eventCache, source, eventType, id, format, args);
}

Expand All @@ -102,7 +102,7 @@ public void TraceEvent_String_Test(TraceFilter filter, TraceEventCache eventCach
using (var target = GetListener())
{
target.Filter = filter;
target.TraceOutputOptions = TraceOptions.ProcessId | TraceOptions.ThreadId | TraceOptions.DateTime | TraceOptions.Timestamp | TraceOptions.LogicalOperationStack;
target.TraceOutputOptions = TraceOptions.ProcessId | TraceOptions.ThreadId | TraceOptions.DateTime | TraceOptions.Timestamp | TraceOptions.LogicalOperationStack | TraceOptions.Callstack;
target.TraceEvent(eventCache, source, eventType, id, message);
}

Expand Down Expand Up @@ -138,7 +138,7 @@ public void TraceData_Object_Test(TraceFilter filter, TraceEventCache eventCache
using (var target = GetListener())
{
target.Filter = filter;
target.TraceOutputOptions = TraceOptions.ProcessId | TraceOptions.ThreadId | TraceOptions.DateTime | TraceOptions.Timestamp | TraceOptions.LogicalOperationStack;
target.TraceOutputOptions = TraceOptions.ProcessId | TraceOptions.ThreadId | TraceOptions.DateTime | TraceOptions.Timestamp | TraceOptions.LogicalOperationStack | TraceOptions.Callstack;
target.TraceData(eventCache, source, eventType, id, data);
}

Expand Down Expand Up @@ -174,7 +174,7 @@ public void TraceData_ObjectArray_Test(string delimiter, TraceFilter filter, Tra
{
target.Delimiter = delimiter;
target.Filter = filter;
target.TraceOutputOptions = TraceOptions.ProcessId | TraceOptions.ThreadId | TraceOptions.DateTime | TraceOptions.Timestamp | TraceOptions.LogicalOperationStack;
target.TraceOutputOptions = TraceOptions.ProcessId | TraceOptions.ThreadId | TraceOptions.DateTime | TraceOptions.Timestamp | TraceOptions.LogicalOperationStack | TraceOptions.Callstack;
target.TraceData(eventCache, source, eventType, id, data);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,9 +418,32 @@ private void WriteFooter(TraceEventCache eventCache)
return;

_indentLevel++;

if (IsEnabled(TraceOptions.ProcessId))
WriteLine("ProcessId=" + eventCache.ProcessId);

if (IsEnabled(TraceOptions.LogicalOperationStack))
{
Write("LogicalOperationStack=");
Stack operationStack = eventCache.LogicalOperationStack;
bool first = true;
foreach (object obj in operationStack)
{
if (!first)
{
Write(", ");
}
else
{
first = false;
}

Write(obj.ToString());
}

WriteLine(string.Empty);
}

if (IsEnabled(TraceOptions.ThreadId))
WriteLine("ThreadId=" + eventCache.ThreadId);

Expand All @@ -430,6 +453,9 @@ private void WriteFooter(TraceEventCache eventCache)
if (IsEnabled(TraceOptions.Timestamp))
WriteLine("Timestamp=" + eventCache.Timestamp);

if (IsEnabled(TraceOptions.Callstack))
WriteLine("Callstack=" + eventCache.Callstack);

_indentLevel--;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Xunit;

namespace System.Diagnostics.TraceSourceTests
Expand Down Expand Up @@ -49,23 +52,27 @@ public void FilterTest()
Assert.NotNull(listener.Filter);
}

[Fact]
public void TraceOutputOptionsTest()
[Theory]
[InlineData(TraceOptions.Callstack)]
[InlineData(TraceOptions.DateTime)]
[InlineData(TraceOptions.LogicalOperationStack)]
[InlineData(TraceOptions.None)]
[InlineData(TraceOptions.ProcessId)]
[InlineData(TraceOptions.ThreadId)]
[InlineData(TraceOptions.Timestamp)]
public void TraceOutputOptionsTest_Valid(TraceOptions options)
{
var listener = new TestTraceListener();
listener.TraceOutputOptions = TraceOptions.None;

// NOTE: TraceOptions includes values for 0x01 and 0x20 in .NET Framework 4.5, but not in CoreFX
// These assertions test for those missing values, and the exceptional condition that
// maintains compatibility with 4.5
var missingValue = (TraceOptions)0x01;
listener.TraceOutputOptions = missingValue;

missingValue = (TraceOptions)0x20;
listener.TraceOutputOptions = missingValue;
listener.TraceOutputOptions = options;
Assert.Equal(options, listener.TraceOutputOptions);
}

var badValue = (TraceOptions)0x80;
Assert.Throws<ArgumentOutOfRangeException>(() => listener.TraceOutputOptions = badValue);
[Theory]
[InlineData((TraceOptions)0x80)]
public void TraceOutputOptionsTest_Invalid(TraceOptions options)
{
var listener = new TestTraceListener();
Assert.Throws<ArgumentOutOfRangeException>(() => listener.TraceOutputOptions = options);
}

[Fact]
Expand Down Expand Up @@ -280,6 +287,7 @@ public void TraceEventTest2()
[InlineData(TraceOptions.Timestamp, 1)]
[InlineData(TraceOptions.ProcessId | TraceOptions.ThreadId, 2)]
[InlineData(TraceOptions.DateTime | TraceOptions.Timestamp, 2)]
[InlineData(TraceOptions.DateTime | TraceOptions.Timestamp | TraceOptions.Callstack, 3)]
public void WriteFooterTest(TraceOptions opts, int flagCount)
{
var cache = new TraceEventCache();
Expand All @@ -304,5 +312,99 @@ public void WriteFooterTest(TraceOptions opts, int flagCount)
listener.TraceEvent(cache, "Source", TraceEventType.Critical, 1);
Assert.Equal(expected, listener.WriteCount);
}

[Fact]
[MethodImpl(MethodImplOptions.NoInlining)]
public void WriteFooterTest_Callstack()
{
var cache = new TraceEventCache();
var listener = new TestTextTraceListener() { TraceOutputOptions = TraceOptions.Callstack };
listener.TraceEvent(cache, "Source", TraceEventType.Critical, 42);
listener.Flush();

Assert.Contains("Callstack=", listener.Output);
Assert.Contains(nameof(WriteFooterTest_Callstack), listener.Output);
}

[Fact]
public void WriteFooterTest_DateTime()
{
var cache = new TraceEventCache();
var listener = new TestTextTraceListener() { TraceOutputOptions = TraceOptions.DateTime };
listener.TraceEvent(cache, "Source", TraceEventType.Critical, 42);
listener.Flush();

Assert.Contains("DateTime=", listener.Output);
Assert.Contains(cache.DateTime.ToString("o"), listener.Output);
}

[Fact]
public void WriteFooterTest_LogicalOperationStack()
{
for (int i = 0; i <= 3; i++)
{
int[] items = Enumerable.Range(42, i).ToArray();

foreach (int item in items)
{
Trace.CorrelationManager.LogicalOperationStack.Push(item.ToString());
}

try
{
var cache = new TraceEventCache();
var listener = new TestTextTraceListener() { TraceOutputOptions = TraceOptions.LogicalOperationStack };
listener.TraceEvent(cache, "Source", TraceEventType.Critical, 42);
listener.Flush();

Assert.Contains("LogicalOperationStack=", listener.Output);
Assert.Contains(string.Join(", ", items.Reverse()), listener.Output);
}
finally
{
foreach (int _ in items)
{
Trace.CorrelationManager.LogicalOperationStack.Pop();
}
}
}
}

[Fact]
public void WriteFooterTest_ProcessId()
{
var cache = new TraceEventCache();
var listener = new TestTextTraceListener() { TraceOutputOptions = TraceOptions.ProcessId };
listener.TraceOutputOptions = TraceOptions.ProcessId;
listener.TraceEvent(cache, "Source", TraceEventType.Critical, 42);
listener.Flush();

Assert.Contains("ProcessId=", listener.Output);
Assert.Contains(cache.ProcessId.ToString(), listener.Output);
}

[Fact]
public void WriteFooterTest_ThreadId()
{
var cache = new TraceEventCache();
var listener = new TestTextTraceListener() { TraceOutputOptions = TraceOptions.ThreadId };
listener.TraceEvent(cache, "Source", TraceEventType.Critical, 42);
listener.Flush();

Assert.Contains("ThreadId=", listener.Output);
Assert.Contains(cache.ThreadId.ToString(), listener.Output);
}

[Fact]
public void WriteFooterTest_Timestamp()
{
var cache = new TraceEventCache();
var listener = new TestTextTraceListener() { TraceOutputOptions = TraceOptions.Timestamp };
listener.TraceEvent(cache, "Source", TraceEventType.Critical, 42);
listener.Flush();

Assert.Contains("Timestamp=", listener.Output);
Assert.Contains(cache.Timestamp.ToString(), listener.Output);
}
}
}

0 comments on commit c8ea7bd

Please sign in to comment.