using System; using System.Diagnostics; using System.IO; namespace Implab.Diagnostics { public class SimpleTraceListener : TextWriterTraceListener { public SimpleTraceListener() { } public SimpleTraceListener(Stream stream) : base(stream) { } public SimpleTraceListener(TextWriter writer) : base(writer) { } public SimpleTraceListener(string fileName) : base(fileName) { } public SimpleTraceListener(Stream stream, string name) : base(stream, name) { } public SimpleTraceListener(TextWriter writer, string name) : base(writer, name) { } public SimpleTraceListener(string fileName, string name) : base(fileName, name) { } public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data) { switch (id) { case TraceEventCodes.StartLogicalOperation: TraceEvent(eventCache, source, eventType, id, "+{0}", data); break; case TraceEventCodes.StopLogicalOperation: TraceEvent(eventCache, source, eventType, id, FormatStopLogicalOperation(data)); break; default: TraceEvent(eventCache, source, eventType, id, data?.ToString()); break; } } string FormatStopLogicalOperation(object data) { if (data is LogicalOperation op) { return string.Format("-{0} ({1})", op, FormatTimespan(op.Elapsed)); } else { return data?.ToString(); } } string FormatTimespan(TimeSpan value) { if (value.TotalSeconds < 10) { return value.Milliseconds.ToString() + "ms"; } else if (value.TotalSeconds < 30) { return string.Format("{0:0.###}s", value.TotalSeconds); } else { return value.ToString(); } } public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, params object[] data) { var prev = IndentLevel; IndentLevel += eventCache.LogicalOperationStack.Count; try { base.TraceData(eventCache, source, eventType, id, data); } finally { IndentLevel = prev; } } public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id) { var prev = IndentLevel; IndentLevel += eventCache.LogicalOperationStack.Count; try { base.TraceEvent(eventCache, source, eventType, id); } finally { IndentLevel = prev; } } public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args) { TraceEvent(eventCache, source, eventType, id, String.Format(format, args)); } public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message) { var prev = IndentLevel; IndentLevel += eventCache.LogicalOperationStack.Count; try { LogicalOperation operation = null; if (eventCache.LogicalOperationStack.Count > 0) operation = eventCache.LogicalOperationStack.Peek() as LogicalOperation; if (operation != null) { base.TraceData(eventCache, source, eventType, id, FormatTimespan(operation.Elapsed) + ": " + message); } else { base.TraceData(eventCache, source, eventType, id, message); } } finally { IndentLevel = prev; } } public override void TraceTransfer(TraceEventCache eventCache, string source, int id, string message, Guid relatedActivityId) { var prev = IndentLevel; IndentLevel += eventCache.LogicalOperationStack.Count; try { base.TraceTransfer(eventCache, source, id, message, relatedActivityId); } finally { IndentLevel = prev; } } } }