##// END OF EJS Templates
Improved logging
cin -
r134:04d4c92d0f28 v2
parent child
Show More
@@ -0,0 +1,8
1 using System;
2
3 namespace Implab.Diagnostics {
4 public interface ILogWriter<in TEvent> {
5 void Write(LogEventArgs args, TEvent entry);
6 }
7 }
8
@@ -0,0 +1,87
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace Implab.Diagnostics {
7 public abstract class ListenerBase : ServiceLocator, ILogWriter<object>, ILogWriter<TraceEvent> {
8
9 readonly Dictionary<object, Action> m_subscriptions = new Dictionary<object, Action>();
10
11 protected ListenerBase() {
12 Register(this);
13 }
14
15 public void Subscribe(Type eventType) {
16 if (eventType == null)
17 throw new ArgumentNullException("eventType");
18 GetType().GetMethod("Subscribe", new Type[0]).MakeGenericMethod(eventType).Invoke(this, null);
19 }
20
21 public void Subscribe<TEvent>() {
22 Subscribe<TEvent>(LogChannel<TEvent>.Default);
23 }
24
25 public void Subscribe<TEvent>(LogChannel<TEvent> channel) {
26 if (channel == null)
27 throw new ArgumentNullException("channel");
28
29 lock (m_subscriptions) {
30 AssertNotDisposed();
31 if (m_subscriptions.ContainsKey(channel))
32 return;
33
34 var writer = GetService<ILogWriter<TEvent>>();
35
36 EventHandler<LogEventArgs<TEvent>> handler = (sender, args) => writer.Write(args,args.Value);
37
38 channel.Events += handler;
39
40 Action unsubscribe = () => {
41 channel.Events -= handler;
42 };
43
44 m_subscriptions.Add(channel, unsubscribe);
45 }
46 }
47
48 public void Unsubscribe<TEvent>(LogChannel<TEvent> channel) {
49 if (channel == null)
50 throw new ArgumentNullException("channel");
51
52 lock (m_subscriptions) {
53 Action subscription;
54 if (m_subscriptions.TryGetValue(channel, out subscription)) {
55 subscription();
56 m_subscriptions.Remove(channel);
57 }
58 }
59 }
60
61 public void UnsubscribeAll() {
62 lock (m_subscriptions) {
63 foreach (var subscription in m_subscriptions.Values)
64 subscription();
65 m_subscriptions.Clear();
66 }
67 }
68
69 #region ILogWriter implementation
70 public abstract void Write(LogEventArgs args, object entry);
71 #endregion
72
73 #region ILogWriter implementation
74 public virtual void Write(LogEventArgs args, TraceEvent entry) {
75 Write(args, (object)entry);
76 }
77 #endregion
78
79
80 protected override void Dispose(bool disposing) {
81 base.Dispose(disposing);
82 if (disposing) {
83 UnsubscribeAll();
84 }
85 }
86 }
87 }
@@ -9,7 +9,7 using System.Windows.Forms;
9 9
10 10 namespace Implab.Diagnostics.Interactive
11 11 {
12 public class InteractiveListener: TextListenerBase
12 public class InteractiveListener: ListenerBase
13 13 {
14 14 TraceForm m_form;
15 15
@@ -29,7 +29,7 namespace Implab.Diagnostics.Interactive
29 29 bool m_paused;
30 30 readonly ManualResetEvent m_pauseEvent = new ManualResetEvent(true);
31 31
32 public InteractiveListener(bool global) : base(global) {
32 public InteractiveListener() {
33 33 m_guiFinished = AsyncPool.RunThread(GuiThread);
34 34 /*m_workerFinished = */AsyncPool.RunThread(QueueThread);
35 35
@@ -107,12 +107,12 namespace Implab.Diagnostics.Interactive
107 107 base.Dispose(disposing);
108 108 }
109 109
110 protected override void WriteEntry(LogEventArgs args, EventText text, string channel) {
110 public override void Write(LogEventArgs args, object entry) {
111 111 var item = new TraceViewItem {
112 Indent = text.indent,
113 Message = text.content,
112 Indent = args.Operation.Level,
113 Message = entry.ToString(),
114 114 Thread = args.ThreadId,
115 Channel = channel,
115 Channel = args.ChannelName,
116 116 Timestamp = Environment.TickCount
117 117 };
118 118
@@ -1,29 +1,17
1 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 2 using System.Text;
5 3
6 4 namespace Implab.Diagnostics {
7 public class ConsoleTraceListener: TextListenerBase {
5 public class ConsoleTraceListener: ListenerBase {
8 6
9 7 static readonly object _consoleLock = new object();
10 8
11 public ConsoleTraceListener()
12 : base(true) {
13
14 }
15
16 public ConsoleTraceListener(bool global)
17 : base(global) {
18
19 }
20
21 protected override void WriteEntry(LogEventArgs args, EventText text, string channel) {
9 public override void Write(LogEventArgs args, object entry) {
22 10 var msg = new StringBuilder();
23 11
24 for (int i = 0; i < text.indent; i++)
12 for (int i = 0; i < args.Operation.Level; i++)
25 13 msg.Append(" ");
26 msg.AppendFormat("[{0}]: {1}", args.ThreadId, text.content);
14 msg.AppendFormat("[{0}]: {1}", args.ThreadId, entry);
27 15
28 16 lock (_consoleLock) {
29 17 Console.ForegroundColor = (ConsoleColor)(args.ThreadId % 15 + 1);
@@ -1,6 +1,4
1 using System;
2
3 namespace Implab.Diagnostics {
1 namespace Implab.Diagnostics {
4 2 public static class Extensions {
5 3 public static IPromise<T> EndLogicalOperation<T>(this IPromise<T> promise) {
6 4 Safe.ArgumentNotNull(promise, "promise");
@@ -69,6 +69,7 namespace Implab.Diagnostics {
69 69 this,
70 70 new LogEventArgs<TEvent>(
71 71 data,
72 Name,
72 73 traceContext.ThreadId,
73 74 traceContext.CurrentOperation,
74 75 traceContext.CurrentOperation.Duration
@@ -2,6 +2,10
2 2
3 3 namespace Implab.Diagnostics {
4 4 public class LogEventArgs : EventArgs {
5 public string ChannelName {
6 get;
7 private set;
8 }
5 9 public int ThreadId {
6 10 get;
7 11 private set;
@@ -14,7 +18,8 namespace Implab.Diagnostics {
14 18 get;
15 19 private set;
16 20 }
17 public LogEventArgs(int threadId, LogicalOperation operation, int timeOffset) {
21 public LogEventArgs(string channelName, int threadId, LogicalOperation operation, int timeOffset) {
22 ChannelName = channelName;
18 23 ThreadId = threadId;
19 24 Operation = operation;
20 25 OperationTimeOffset = timeOffset;
@@ -5,7 +5,7
5 5 private set;
6 6 }
7 7
8 public LogEventArgs(TEvent value, int threadId, LogicalOperation operation, int timeOffset) : base(threadId, operation, timeOffset) {
8 public LogEventArgs(TEvent value,string channelName, int threadId, LogicalOperation operation, int timeOffset) : base(channelName, threadId, operation, timeOffset) {
9 9 Value = value;
10 10 }
11 11 }
@@ -1,9 +1,10
1 1 namespace Implab.Diagnostics {
2 2 struct OperationContext {
3 readonly LogicalOperation m_initial;
4 3 public readonly static OperationContext EMPTY = new OperationContext(LogicalOperation.EMPTY, false);
4
5 LogicalOperation m_initial;
5 6 LogicalOperation m_current;
6 readonly bool m_ownership;
7 bool m_ownership;
7 8
8 9 public OperationContext(LogicalOperation operation, bool ownership) {
9 10 Safe.ArgumentNotNull(operation, "operation");
@@ -39,14 +40,19
39 40 return detached;
40 41 }
41 42
42 public void EndLogicalOperation() {
43 if (m_current != m_initial) {
43 public LogicalOperation EndLogicalOperation() {
44 var current = m_current;
45 if (m_current != LogicalOperation.EMPTY && (m_current != m_initial || m_ownership)) {
44 46 m_current = m_current.Parent;
45 } else if (m_current != LogicalOperation.EMPTY && m_ownership) {
46 m_current = LogicalOperation.EMPTY;
47 if (current == m_initial) {
48 // we have complete the owned operation
49 m_initial = m_current;
50 m_ownership = false;
51 }
47 52 } else {
48 53 TraceLog.TraceWarning("EndLogicalOperation can't be applied in the current context");
49 54 }
55 return current;
50 56 }
51 57
52 58 public void Leave() {
@@ -3,22 +3,22 using System.IO;
3 3 using System.Text;
4 4
5 5 namespace Implab.Diagnostics {
6 public class TextFileListener: TextListenerBase {
6 public class TextFileListener: ListenerBase {
7 7 readonly TextWriter m_textWriter;
8 8
9 public TextFileListener(string fileName, bool global)
10 : base(global) {
9 public TextFileListener(string fileName) {
11 10 m_textWriter = File.CreateText(fileName);
12 11
13 12 m_textWriter.WriteLine("LOG {0}", DateTime.Now);
14 Register(this);
15 13 }
16 14
17 protected override void WriteEntry(LogEventArgs args, EventText text, string channel) {
15 #region implemented abstract members of ListenerBase
16
17 public override void Write(LogEventArgs args, object entry) {
18 18 var msg = new StringBuilder();
19 for (int i = 0; i < text.indent; i++)
19 for (int i = 0; i < args.Operation.Level; i++)
20 20 msg.Append(" ");
21 msg.AppendFormat("[{0}]:{1}: {2}", args.ThreadId, channel, text.content);
21 msg.AppendFormat("[{0}]:{1}: {2}", args.ThreadId, args.ChannelName, entry);
22 22
23 23 lock (m_textWriter) {
24 24 if (!IsDisposed) {
@@ -29,7 +29,8 namespace Implab.Diagnostics {
29 29 }
30 30 }
31 31
32
32 #endregion
33
33 34 protected override void Dispose(bool disposing) {
34 35 base.Dispose(disposing);
35 36 if (disposing) {
@@ -42,14 +42,14 namespace Implab.Diagnostics {
42 42
43 43 public void EnterLogicalOperation(LogicalOperation operation, bool takeOwnership) {
44 44 //var prev = CurrentOperation;
45 //LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(takeOwnership ? TraceEventType.Attach : TraceEventType.Enter, String.Format("{0} -> {1}",prev.Name, operation.Name)));
45 46 m_stack.Push(m_current);
46 47 m_current = new OperationContext(operation, takeOwnership);
47 //LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(takeOwnership ? TraceEventType.Attach : TraceEventType.Enter, String.Format("{0} -> {1}",prev.Name, operation.Name)));
48 48 }
49 49
50 50 public void StartLogicalOperation(string name) {
51 LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationStarted, name));
51 52 m_current.BeginLogicalOperation(name);
52 LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationStarted, String.Format("+{0}",CurrentOperation.Name)));
53 53 }
54 54
55 55 public void StartLogicalOperation() {
@@ -57,8 +57,8 namespace Implab.Diagnostics {
57 57 }
58 58
59 59 public void EndLogicalOperation() {
60 LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationCompleted, String.Format("-{0} : {1}ms",CurrentOperation.Name, CurrentOperation.Duration)));
61 m_current.EndLogicalOperation();
60 var op = m_current.EndLogicalOperation();
61 LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationCompleted, String.Format("-{0} : {1}ms",op.Name, op.Duration)));
62 62 }
63 63
64 64 public LogicalOperation DetachLogicalOperation() {
@@ -74,11 +74,9
74 74 <Compile Include="CustomEqualityComparer.cs" />
75 75 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
76 76 <Compile Include="Diagnostics\EventText.cs" />
77 <Compile Include="Diagnostics\IEventTextFormatter.cs" />
78 77 <Compile Include="Diagnostics\LogChannel.cs" />
79 78 <Compile Include="Diagnostics\LogicalOperation.cs" />
80 79 <Compile Include="Diagnostics\TextFileListener.cs" />
81 <Compile Include="Diagnostics\TextListenerBase.cs" />
82 80 <Compile Include="Diagnostics\TraceLog.cs" />
83 81 <Compile Include="Diagnostics\TraceEvent.cs" />
84 82 <Compile Include="Diagnostics\TraceEventType.cs" />
@@ -155,6 +153,8
155 153 <Compile Include="PromiseTransientException.cs" />
156 154 <Compile Include="Parallels\Signal.cs" />
157 155 <Compile Include="Parallels\SharedLock.cs" />
156 <Compile Include="Diagnostics\ILogWriter.cs" />
157 <Compile Include="Diagnostics\ListenerBase.cs" />
158 158 </ItemGroup>
159 159 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
160 160 <ItemGroup />
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now