Mercurial > pub > ImplabNet
changeset 134:04d4c92d0f28 v2
Improved logging
author | cin |
---|---|
date | Wed, 11 Feb 2015 02:12:15 +0300 |
parents | 6c49d02a9a05 |
children | 656815cb7147 |
files | Implab.Diagnostics.Interactive/InteractiveListener.cs Implab/Diagnostics/ConsoleTraceListener.cs Implab/Diagnostics/Extensions.cs Implab/Diagnostics/IEventTextFormatter.cs Implab/Diagnostics/ILogWriter.cs Implab/Diagnostics/ListenerBase.cs Implab/Diagnostics/LogChannel.cs Implab/Diagnostics/LogEventArgs.cs Implab/Diagnostics/LogEventArgsT.cs Implab/Diagnostics/OperationContext.cs Implab/Diagnostics/TextFileListener.cs Implab/Diagnostics/TextListenerBase.cs Implab/Diagnostics/TraceContext.cs Implab/Implab.csproj |
diffstat | 14 files changed, 141 insertions(+), 180 deletions(-) [+] |
line wrap: on
line diff
--- a/Implab.Diagnostics.Interactive/InteractiveListener.cs Mon Feb 09 00:28:13 2015 +0300 +++ b/Implab.Diagnostics.Interactive/InteractiveListener.cs Wed Feb 11 02:12:15 2015 +0300 @@ -9,7 +9,7 @@ namespace Implab.Diagnostics.Interactive { - public class InteractiveListener: TextListenerBase + public class InteractiveListener: ListenerBase { TraceForm m_form; @@ -29,7 +29,7 @@ bool m_paused; readonly ManualResetEvent m_pauseEvent = new ManualResetEvent(true); - public InteractiveListener(bool global) : base(global) { + public InteractiveListener() { m_guiFinished = AsyncPool.RunThread(GuiThread); /*m_workerFinished = */AsyncPool.RunThread(QueueThread); @@ -107,12 +107,12 @@ base.Dispose(disposing); } - protected override void WriteEntry(LogEventArgs args, EventText text, string channel) { + public override void Write(LogEventArgs args, object entry) { var item = new TraceViewItem { - Indent = text.indent, - Message = text.content, + Indent = args.Operation.Level, + Message = entry.ToString(), Thread = args.ThreadId, - Channel = channel, + Channel = args.ChannelName, Timestamp = Environment.TickCount };
--- a/Implab/Diagnostics/ConsoleTraceListener.cs Mon Feb 09 00:28:13 2015 +0300 +++ b/Implab/Diagnostics/ConsoleTraceListener.cs Wed Feb 11 02:12:15 2015 +0300 @@ -1,29 +1,17 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Text; namespace Implab.Diagnostics { - public class ConsoleTraceListener: TextListenerBase { + public class ConsoleTraceListener: ListenerBase { static readonly object _consoleLock = new object(); - public ConsoleTraceListener() - : base(true) { - - } - - public ConsoleTraceListener(bool global) - : base(global) { - - } - - protected override void WriteEntry(LogEventArgs args, EventText text, string channel) { + public override void Write(LogEventArgs args, object entry) { var msg = new StringBuilder(); - for (int i = 0; i < text.indent; i++) + for (int i = 0; i < args.Operation.Level; i++) msg.Append(" "); - msg.AppendFormat("[{0}]: {1}", args.ThreadId, text.content); + msg.AppendFormat("[{0}]: {1}", args.ThreadId, entry); lock (_consoleLock) { Console.ForegroundColor = (ConsoleColor)(args.ThreadId % 15 + 1);
--- a/Implab/Diagnostics/Extensions.cs Mon Feb 09 00:28:13 2015 +0300 +++ b/Implab/Diagnostics/Extensions.cs Wed Feb 11 02:12:15 2015 +0300 @@ -1,6 +1,4 @@ -using System; - -namespace Implab.Diagnostics { +namespace Implab.Diagnostics { public static class Extensions { public static IPromise<T> EndLogicalOperation<T>(this IPromise<T> promise) { Safe.ArgumentNotNull(promise, "promise");
--- a/Implab/Diagnostics/IEventTextFormatter.cs Mon Feb 09 00:28:13 2015 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -namespace Implab.Diagnostics { - public interface IEventTextFormatter<in TEvent> { - EventText Format(LogEventArgs args, TEvent data); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/Diagnostics/ILogWriter.cs Wed Feb 11 02:12:15 2015 +0300 @@ -0,0 +1,8 @@ +using System; + +namespace Implab.Diagnostics { + public interface ILogWriter<in TEvent> { + void Write(LogEventArgs args, TEvent entry); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/Diagnostics/ListenerBase.cs Wed Feb 11 02:12:15 2015 +0300 @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Implab.Diagnostics { + public abstract class ListenerBase : ServiceLocator, ILogWriter<object>, ILogWriter<TraceEvent> { + + readonly Dictionary<object, Action> m_subscriptions = new Dictionary<object, Action>(); + + protected ListenerBase() { + Register(this); + } + + public void Subscribe(Type eventType) { + if (eventType == null) + throw new ArgumentNullException("eventType"); + GetType().GetMethod("Subscribe", new Type[0]).MakeGenericMethod(eventType).Invoke(this, null); + } + + public void Subscribe<TEvent>() { + Subscribe<TEvent>(LogChannel<TEvent>.Default); + } + + public void Subscribe<TEvent>(LogChannel<TEvent> channel) { + if (channel == null) + throw new ArgumentNullException("channel"); + + lock (m_subscriptions) { + AssertNotDisposed(); + if (m_subscriptions.ContainsKey(channel)) + return; + + var writer = GetService<ILogWriter<TEvent>>(); + + EventHandler<LogEventArgs<TEvent>> handler = (sender, args) => writer.Write(args,args.Value); + + channel.Events += handler; + + Action unsubscribe = () => { + channel.Events -= handler; + }; + + m_subscriptions.Add(channel, unsubscribe); + } + } + + public void Unsubscribe<TEvent>(LogChannel<TEvent> channel) { + if (channel == null) + throw new ArgumentNullException("channel"); + + lock (m_subscriptions) { + Action subscription; + if (m_subscriptions.TryGetValue(channel, out subscription)) { + subscription(); + m_subscriptions.Remove(channel); + } + } + } + + public void UnsubscribeAll() { + lock (m_subscriptions) { + foreach (var subscription in m_subscriptions.Values) + subscription(); + m_subscriptions.Clear(); + } + } + + #region ILogWriter implementation + public abstract void Write(LogEventArgs args, object entry); + #endregion + + #region ILogWriter implementation + public virtual void Write(LogEventArgs args, TraceEvent entry) { + Write(args, (object)entry); + } + #endregion + + + protected override void Dispose(bool disposing) { + base.Dispose(disposing); + if (disposing) { + UnsubscribeAll(); + } + } + } +}
--- a/Implab/Diagnostics/LogChannel.cs Mon Feb 09 00:28:13 2015 +0300 +++ b/Implab/Diagnostics/LogChannel.cs Wed Feb 11 02:12:15 2015 +0300 @@ -69,6 +69,7 @@ this, new LogEventArgs<TEvent>( data, + Name, traceContext.ThreadId, traceContext.CurrentOperation, traceContext.CurrentOperation.Duration
--- a/Implab/Diagnostics/LogEventArgs.cs Mon Feb 09 00:28:13 2015 +0300 +++ b/Implab/Diagnostics/LogEventArgs.cs Wed Feb 11 02:12:15 2015 +0300 @@ -2,6 +2,10 @@ namespace Implab.Diagnostics { public class LogEventArgs : EventArgs { + public string ChannelName { + get; + private set; + } public int ThreadId { get; private set; @@ -14,7 +18,8 @@ get; private set; } - public LogEventArgs(int threadId, LogicalOperation operation, int timeOffset) { + public LogEventArgs(string channelName, int threadId, LogicalOperation operation, int timeOffset) { + ChannelName = channelName; ThreadId = threadId; Operation = operation; OperationTimeOffset = timeOffset;
--- a/Implab/Diagnostics/LogEventArgsT.cs Mon Feb 09 00:28:13 2015 +0300 +++ b/Implab/Diagnostics/LogEventArgsT.cs Wed Feb 11 02:12:15 2015 +0300 @@ -5,7 +5,7 @@ private set; } - public LogEventArgs(TEvent value, int threadId, LogicalOperation operation, int timeOffset) : base(threadId, operation, timeOffset) { + public LogEventArgs(TEvent value,string channelName, int threadId, LogicalOperation operation, int timeOffset) : base(channelName, threadId, operation, timeOffset) { Value = value; } }
--- a/Implab/Diagnostics/OperationContext.cs Mon Feb 09 00:28:13 2015 +0300 +++ b/Implab/Diagnostics/OperationContext.cs Wed Feb 11 02:12:15 2015 +0300 @@ -1,9 +1,10 @@ namespace Implab.Diagnostics { struct OperationContext { - readonly LogicalOperation m_initial; public readonly static OperationContext EMPTY = new OperationContext(LogicalOperation.EMPTY, false); + + LogicalOperation m_initial; LogicalOperation m_current; - readonly bool m_ownership; + bool m_ownership; public OperationContext(LogicalOperation operation, bool ownership) { Safe.ArgumentNotNull(operation, "operation"); @@ -39,14 +40,19 @@ return detached; } - public void EndLogicalOperation() { - if (m_current != m_initial) { + public LogicalOperation EndLogicalOperation() { + var current = m_current; + if (m_current != LogicalOperation.EMPTY && (m_current != m_initial || m_ownership)) { m_current = m_current.Parent; - } else if (m_current != LogicalOperation.EMPTY && m_ownership) { - m_current = LogicalOperation.EMPTY; + if (current == m_initial) { + // we have complete the owned operation + m_initial = m_current; + m_ownership = false; + } } else { TraceLog.TraceWarning("EndLogicalOperation can't be applied in the current context"); } + return current; } public void Leave() {
--- a/Implab/Diagnostics/TextFileListener.cs Mon Feb 09 00:28:13 2015 +0300 +++ b/Implab/Diagnostics/TextFileListener.cs Wed Feb 11 02:12:15 2015 +0300 @@ -3,22 +3,22 @@ using System.Text; namespace Implab.Diagnostics { - public class TextFileListener: TextListenerBase { + public class TextFileListener: ListenerBase { readonly TextWriter m_textWriter; - public TextFileListener(string fileName, bool global) - : base(global) { + public TextFileListener(string fileName) { m_textWriter = File.CreateText(fileName); m_textWriter.WriteLine("LOG {0}", DateTime.Now); - Register(this); } - protected override void WriteEntry(LogEventArgs args, EventText text, string channel) { + #region implemented abstract members of ListenerBase + + public override void Write(LogEventArgs args, object entry) { var msg = new StringBuilder(); - for (int i = 0; i < text.indent; i++) + for (int i = 0; i < args.Operation.Level; i++) msg.Append(" "); - msg.AppendFormat("[{0}]:{1}: {2}", args.ThreadId, channel, text.content); + msg.AppendFormat("[{0}]:{1}: {2}", args.ThreadId, args.ChannelName, entry); lock (m_textWriter) { if (!IsDisposed) { @@ -29,7 +29,8 @@ } } - + #endregion + protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) {
--- a/Implab/Diagnostics/TextListenerBase.cs Mon Feb 09 00:28:13 2015 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Implab.Diagnostics { - public abstract class TextListenerBase : ServiceLocator, IEventTextFormatter<object>, IEventTextFormatter<TraceEvent> { - - readonly Dictionary<object, Action> m_subscriptions = new Dictionary<object, Action>(); - readonly LogicalOperation m_boundOperation; - readonly int m_baseIndent; - - protected TextListenerBase(bool global) { - Register(this); - if (!global) { - m_boundOperation = TraceContext.Instance.CurrentOperation; - m_baseIndent = Math.Max(0, m_boundOperation.Level - 1); - } - } - - public void Subscribe(Type eventType) { - if (eventType == null) - throw new ArgumentNullException("eventType"); - GetType().GetMethod("Subscribe", new Type[0]).MakeGenericMethod(eventType).Invoke(this, null); - } - - public void Subscribe<TEvent>() { - Subscribe<TEvent>(LogChannel<TEvent>.Default); - } - - public void Subscribe<TEvent>(LogChannel<TEvent> channel) { - if (channel == null) - throw new ArgumentNullException("channel"); - - lock (m_subscriptions) { - AssertNotDisposed(); - - var formatter = GetService<IEventTextFormatter<TEvent>>(); - var channelName = channel.Name; - - EventHandler<LogEventArgs<TEvent>> handler = (sender, args) => { - var text = formatter.Format(args, args.Value); - text.indent -= m_baseIndent; - - if (IsRelated(args.Operation)) - WriteEntry(args, text, channelName); - }; - - if (m_subscriptions.ContainsKey(channel)) - return; - - channel.Events += handler; - - Action unsubscribe = () => { - channel.Events -= handler; - }; - - m_subscriptions.Add(channel, unsubscribe); - } - } - - public bool IsRelated(LogicalOperation op) { - if (m_boundOperation == null) - return true; - - while (op != m_boundOperation && op.Level > m_boundOperation.Level) - op = op.Parent; - return op == m_boundOperation; - } - - public void Unsubscribe<TEvent>(LogChannel<TEvent> channel) { - if (channel == null) - throw new ArgumentNullException("channel"); - - lock (m_subscriptions) { - Action subscription; - if (m_subscriptions.TryGetValue(channel, out subscription)) { - subscription(); - m_subscriptions.Remove(channel); - } - } - } - - public void UnsubscribeAll() { - lock (m_subscriptions) { - foreach (var subscription in m_subscriptions.Values) - subscription(); - m_subscriptions.Clear(); - } - } - - /// <summary> - /// Вызывается для записи текста сообщения, в журнал. - /// </summary> - /// <remarks> - /// Данный метод может вызваться из разных потоков одновременно. Возможна ситуация, когда - /// данный метод вызывается уже после освобождения ообъекта методом <see cref="Dispose()"/>. - /// </remarks> - /// <param name="text">Текст сообщения.</param> - /// <param name = "channel"></param> - protected abstract void WriteEntry(LogEventArgs args, EventText text, string channel); - - public EventText Format(LogEventArgs args, object data) { - return new EventText { - indent = args.Operation.Level, - content = data.ToString() - }; - } - - public EventText Format(LogEventArgs args, TraceEvent data) { - var level = args.Operation.Level; - if (data.EventType == TraceEventType.OperationCompleted || data.EventType == TraceEventType.OperationStarted) - level--; - - return new EventText { - indent = level, - content = data.ToString() - }; - } - - protected override void Dispose(bool disposing) { - base.Dispose(disposing); - if (disposing) { - UnsubscribeAll(); - } - } - } -}
--- a/Implab/Diagnostics/TraceContext.cs Mon Feb 09 00:28:13 2015 +0300 +++ b/Implab/Diagnostics/TraceContext.cs Wed Feb 11 02:12:15 2015 +0300 @@ -42,14 +42,14 @@ public void EnterLogicalOperation(LogicalOperation operation, bool takeOwnership) { //var prev = CurrentOperation; + //LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(takeOwnership ? TraceEventType.Attach : TraceEventType.Enter, String.Format("{0} -> {1}",prev.Name, operation.Name))); m_stack.Push(m_current); m_current = new OperationContext(operation, takeOwnership); - //LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(takeOwnership ? TraceEventType.Attach : TraceEventType.Enter, String.Format("{0} -> {1}",prev.Name, operation.Name))); } public void StartLogicalOperation(string name) { + LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationStarted, name)); m_current.BeginLogicalOperation(name); - LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationStarted, String.Format("+{0}",CurrentOperation.Name))); } public void StartLogicalOperation() { @@ -57,8 +57,8 @@ } public void EndLogicalOperation() { - LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationCompleted, String.Format("-{0} : {1}ms",CurrentOperation.Name, CurrentOperation.Duration))); - m_current.EndLogicalOperation(); + var op = m_current.EndLogicalOperation(); + LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationCompleted, String.Format("-{0} : {1}ms",op.Name, op.Duration))); } public LogicalOperation DetachLogicalOperation() {
--- a/Implab/Implab.csproj Mon Feb 09 00:28:13 2015 +0300 +++ b/Implab/Implab.csproj Wed Feb 11 02:12:15 2015 +0300 @@ -74,11 +74,9 @@ <Compile Include="CustomEqualityComparer.cs" /> <Compile Include="Diagnostics\ConsoleTraceListener.cs" /> <Compile Include="Diagnostics\EventText.cs" /> - <Compile Include="Diagnostics\IEventTextFormatter.cs" /> <Compile Include="Diagnostics\LogChannel.cs" /> <Compile Include="Diagnostics\LogicalOperation.cs" /> <Compile Include="Diagnostics\TextFileListener.cs" /> - <Compile Include="Diagnostics\TextListenerBase.cs" /> <Compile Include="Diagnostics\TraceLog.cs" /> <Compile Include="Diagnostics\TraceEvent.cs" /> <Compile Include="Diagnostics\TraceEventType.cs" /> @@ -155,6 +153,8 @@ <Compile Include="PromiseTransientException.cs" /> <Compile Include="Parallels\Signal.cs" /> <Compile Include="Parallels\SharedLock.cs" /> + <Compile Include="Diagnostics\ILogWriter.cs" /> + <Compile Include="Diagnostics\ListenerBase.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup />