Skip to content

Commit

Permalink
Handling structured data as logcial operation stack items
Browse files Browse the repository at this point in the history
  • Loading branch information
sgryphon committed Jul 27, 2017
1 parent 3a3029d commit ad4643c
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/Essential.Diagnostics.Core/Version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.1.720.0
2.1.727.0
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class SeqTraceListener : TraceListenerBase
"maxQueueSize", "MaxQueueSize", "maxqueuesize",
"maxRetries", "MaxRetries", "maxretries",
"processDictionaryData", "ProcessDictionaryData", "processdictionarydata",
"processDictionaryLogicalOperationStack", "ProcessDictionaryLogicalOperationStack", "processdictionarylogicaloperationstack",
};

/// <summary>
Expand Down Expand Up @@ -296,6 +297,26 @@ public bool ProcessDictionaryData
}
}

/// <summary>
/// Gets or sets whether logical operation stack items of type IDictionary&lt;string,object&gt; are treated as structured data. Default is true.
/// </summary>
public bool ProcessDictionaryLogicalOperationStack
{
get
{
var processDictionaryLogicalOperationStack = true;
if (Attributes.ContainsKey("processDictionaryLogicalOperationStack"))
{
bool.TryParse(Attributes["processDictionaryLogicalOperationStack"], out processDictionaryLogicalOperationStack);
}
return processDictionaryLogicalOperationStack;
}
set
{
Attributes["processDictionaryLogicalOperationStack"] = value.ToString(CultureInfo.InvariantCulture);
}
}

/// <summary>
/// Allowed attributes for this trace listener.
/// </summary>
Expand Down Expand Up @@ -341,20 +362,6 @@ private void AddAttributeProperties(Dictionary<string, object> properties, Trace
}
}

if (_propertyLogicalOperationStack || (TraceOutputOptions & TraceOptions.LogicalOperationStack) == TraceOptions.LogicalOperationStack)
{
var stack = (eventCache != null ? eventCache.LogicalOperationStack : null) ?? Trace.CorrelationManager.LogicalOperationStack;
var logicalOperationStack = new List<object>();
if (stack != null && stack.Count > 0)
{
foreach (object stackItem in stack)
{
logicalOperationStack.Add(GetRecordedValue(stackItem));
}
properties.Add("LogicalOperationStack", logicalOperationStack.ToArray());
}
}

if (_propertyProcessId || (TraceOutputOptions & TraceOptions.ProcessId) == TraceOptions.ProcessId)
{
var processId = eventCache != null ? eventCache.ProcessId : 0;
Expand Down Expand Up @@ -388,6 +395,45 @@ private void AddAttributeProperties(Dictionary<string, object> properties, Trace
}
}

private void AddLogicalStack(Dictionary<string, object> properties, TraceEventCache eventCache)
{
EnsureAttributesParsed();

var stack = (eventCache != null ? eventCache.LogicalOperationStack : null) ?? Trace.CorrelationManager.LogicalOperationStack;
if (stack != null && stack.Count > 0)
{
var recordStack = _propertyLogicalOperationStack || (TraceOutputOptions & TraceOptions.LogicalOperationStack) == TraceOptions.LogicalOperationStack;
List<object> logicalOperationStack = null;
if (recordStack)
{
logicalOperationStack = new List<object>();
}
foreach (object stackItem in stack)
{
if ((stackItem is IStructuredData) ||
(stackItem is IDictionary<string, object> && ProcessDictionaryLogicalOperationStack))
{
var stackItemDictionary = (IDictionary<string, object>)stackItem;
foreach (var kvp in stackItemDictionary)
{
if (kvp.Key != StructuredData.MessageTemplateProperty)
{
properties[kvp.Key] = kvp.Value;
}
}
}
if (recordStack)
{
logicalOperationStack.Add(GetRecordedValue(stackItem));
}
}
if (recordStack)
{
properties.Add("LogicalOperationStack", logicalOperationStack.ToArray());
}
}
}

private void AddStructuredData(Dictionary<string, object> properties, IDictionary<string, object> structuredData, ref Exception exception, ref string messageFormat)
{
foreach (var kvp in structuredData)
Expand Down Expand Up @@ -470,8 +516,8 @@ private TraceData CreateTraceData(TraceEventCache eventCache, string source, Tra

// Properties
var properties = new Dictionary<string, object>();

AddAttributeProperties(properties, eventCache);
AddLogicalStack(properties, eventCache);

object[] recordedArgsArray = null;
var exception = default(Exception);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,98 @@ public void SeqIgnoresStructuredDictionaryWhenTurnedOff()
StringAssert.Matches(requestBody, regexData);
}

[TestMethod]
public void SeqHandlesStructuredOperationAsTraceOutput()
{
var mockRequestFactory = new MockHttpWebRequestFactory();
mockRequestFactory.ResponseQueue.Enqueue(
new MockHttpWebResponse(HttpStatusCode.OK, null)
);

var listener = new SeqTraceListener("http://testuri");
listener.BatchSize = 0;
listener.BatchSender.HttpWebRequestFactory = mockRequestFactory;
listener.TraceOutputOptions = TraceOptions.LogicalOperationStack;

var structuredData = new StructuredData(new Dictionary<string, object>() { { "a", 1 } });
Trace.CorrelationManager.StartLogicalOperation(structuredData);
listener.TraceEvent(null, "TestSource", TraceEventType.Warning, 1, "x{0}", "y");
Trace.CorrelationManager.StopLogicalOperation();

Assert.AreEqual(1, mockRequestFactory.RequestsCreated.Count);

var request = mockRequestFactory.RequestsCreated[0];
var requestBody = request.RequestBody;
Console.WriteLine(requestBody);
StringAssert.Contains(requestBody, "\"MessageTemplate\":\"x{0}\"");
StringAssert.Contains(requestBody, "\"0\":\"y\"");
StringAssert.Contains(requestBody, "\"LogicalOperationStack\":[{\"a\":1}]");
var regexData = new Regex("\"Data\":");
StringAssert.DoesNotMatch(requestBody, regexData);
}

[TestMethod]
public void SeqHandlesStructuredOperationAsPropertiesOnly()
{
var mockRequestFactory = new MockHttpWebRequestFactory();
mockRequestFactory.ResponseQueue.Enqueue(
new MockHttpWebResponse(HttpStatusCode.OK, null)
);

var listener = new SeqTraceListener("http://testuri");
listener.BatchSize = 0;
listener.BatchSender.HttpWebRequestFactory = mockRequestFactory;

var structuredData = new StructuredData(new Dictionary<string, object>() { { "a", 1 } });
Trace.CorrelationManager.StartLogicalOperation(structuredData);
listener.TraceEvent(null, "TestSource", TraceEventType.Warning, 1, "x{0}", "y");
Trace.CorrelationManager.StopLogicalOperation();

Assert.AreEqual(1, mockRequestFactory.RequestsCreated.Count);

var request = mockRequestFactory.RequestsCreated[0];
var requestBody = request.RequestBody;
Console.WriteLine(requestBody);
StringAssert.Contains(requestBody, "\"MessageTemplate\":\"x{0}\"");
StringAssert.Contains(requestBody, "\"0\":\"y\"");
StringAssert.Contains(requestBody, "\"a\":1");
var regexData = new Regex("\"Data\":");
StringAssert.DoesNotMatch(requestBody, regexData);
var regexStack = new Regex("\"LogicalOperationStack\":");
StringAssert.DoesNotMatch(requestBody, regexStack);
}

[TestMethod]
public void SeqHandlesDictionaryOperationAsProperties()
{
var mockRequestFactory = new MockHttpWebRequestFactory();
mockRequestFactory.ResponseQueue.Enqueue(
new MockHttpWebResponse(HttpStatusCode.OK, null)
);

var listener = new SeqTraceListener("http://testuri");
listener.BatchSize = 0;
listener.BatchSender.HttpWebRequestFactory = mockRequestFactory;

var dictionaryData = new Dictionary<string, object>() { { "a", 1 } };
Trace.CorrelationManager.StartLogicalOperation(dictionaryData);
listener.TraceEvent(null, "TestSource", TraceEventType.Warning, 1, "x{0}", "y");
Trace.CorrelationManager.StopLogicalOperation();

Assert.AreEqual(1, mockRequestFactory.RequestsCreated.Count);

var request = mockRequestFactory.RequestsCreated[0];
var requestBody = request.RequestBody;
Console.WriteLine(requestBody);
StringAssert.Contains(requestBody, "\"MessageTemplate\":\"x{0}\"");
StringAssert.Contains(requestBody, "\"0\":\"y\"");
StringAssert.Contains(requestBody, "\"a\":1");
var regexData = new Regex("\"Data\":");
StringAssert.DoesNotMatch(requestBody, regexData);
var regexStack = new Regex("\"LogicalOperationStack\":");
StringAssert.DoesNotMatch(requestBody, regexStack);
}

[TestMethod]
public void SeqStructuredCustomObject()
{
Expand Down

0 comments on commit ad4643c

Please sign in to comment.