TextListenerBase.cs
128 lines
| 4.6 KiB
| text/x-csharp
|
CSharpLexer
|
|
r40 | 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>(); | ||||
|
|
r43 | readonly LogicalOperation m_boundOperation; | ||
| readonly int m_baseIndent; | ||||
|
|
r40 | |||
|
|
r48 | protected TextListenerBase(bool global) { | ||
|
|
r40 | Register(this); | ||
|
|
r48 | if (!global) { | ||
|
|
r92 | m_boundOperation = TraceContext.Instance.CurrentOperation; | ||
|
|
r43 | m_baseIndent = Math.Max(0, m_boundOperation.Level - 1); | ||
| } | ||||
|
|
r40 | } | ||
| 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>>(); | ||||
|
|
r48 | var channelName = channel.Name; | ||
|
|
r40 | |||
|
|
r92 | EventHandler<LogEventArgs<TEvent>> handler = (sender, args) => { | ||
| var text = formatter.Format(args, args.Value); | ||||
|
|
r43 | text.indent -= m_baseIndent; | ||
|
|
r92 | if (IsRelated(args.Operation)) | ||
| WriteEntry(args, text, channelName); | ||||
|
|
r40 | }; | ||
| if (m_subscriptions.ContainsKey(channel)) | ||||
| return; | ||||
| channel.Events += handler; | ||||
| Action unsubscribe = () => { | ||||
| channel.Events -= handler; | ||||
| }; | ||||
| m_subscriptions.Add(channel, unsubscribe); | ||||
| } | ||||
| } | ||||
|
|
r43 | 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; | ||||
| } | ||||
|
|
r40 | 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(); | ||||
| } | ||||
| } | ||||
|
|
r47 | /// <summary> | ||
| /// Вызывается для записи текста сообщения, в журнал. | ||||
| /// </summary> | ||||
| /// <remarks> | ||||
| /// Данный метод может вызваться из разных потоков одновременно. Возможна ситуация, когда | ||||
| /// данный метод вызывается уже после освобождения ообъекта методом <see cref="Dispose()"/>. | ||||
| /// </remarks> | ||||
| /// <param name="text">Текст сообщения.</param> | ||||
|
|
r92 | /// <param name = "channel"></param> | ||
| protected abstract void WriteEntry(LogEventArgs args, EventText text, string channel); | ||||
|
|
r40 | |||
|
|
r92 | public EventText Format(LogEventArgs args, object data) { | ||
|
|
r40 | return new EventText { | ||
|
|
r92 | indent = args.Operation.Level, | ||
|
|
r40 | content = data.ToString() | ||
| }; | ||||
| } | ||||
|
|
r92 | public EventText Format(LogEventArgs args, TraceEvent data) { | ||
| var level = args.Operation.Level; | ||||
|
|
r40 | if (data.EventType == TraceEventType.OperationCompleted || data.EventType == TraceEventType.OperationStarted) | ||
| level--; | ||||
| return new EventText { | ||||
| indent = level, | ||||
| content = data.ToString() | ||||
| }; | ||||
| } | ||||
| protected override void Dispose(bool disposing) { | ||||
|
|
r47 | base.Dispose(disposing); | ||
|
|
r40 | if (disposing) { | ||
| UnsubscribeAll(); | ||||
| } | ||||
| } | ||||
| } | ||||
| } | ||||
