diff --git a/Implab/Component.cs b/Implab/Component.cs
new file mode 100644
--- /dev/null
+++ b/Implab/Component.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace Implab {
+ ///
+ /// Компоненты являются состовными объектами, имеют детерминированный период жизни, автоматически освобождают ресурсы входящие в них.
+ ///
+ /// Компонента управляет временем жизни включенных в нее компонент
+ public class Component: Disposable {
+ LinkedList m_components = new LinkedList();
+
+ ///
+ /// Коллекция компонент, из которых состоит текущая компонента.
+ ///
+ public ICollection Components {
+ get {
+ AssertNotDisposed();
+ return m_components;
+ }
+ }
+
+ ///
+ /// Освобождает компоненты, входящие в состав текущей компоненты.
+ ///
+ /// Признак того, что происходит освобождение ресурсов.
+ protected override void Dispose(bool disposing) {
+ if (disposing) {
+ foreach (var item in m_components)
+ item.Dispose();
+ m_components.Clear();
+ }
+ base.Dispose(disposing);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Implab/Diagnostics/ConsoleTraceListener.cs b/Implab/Diagnostics/ConsoleTraceListener.cs
--- a/Implab/Diagnostics/ConsoleTraceListener.cs
+++ b/Implab/Diagnostics/ConsoleTraceListener.cs
@@ -4,29 +4,16 @@ using System.Linq;
using System.Text;
namespace Implab.Diagnostics {
- public class ConsoleTraceListener {
+ public class ConsoleTraceListener: TextListenerBase {
static readonly object _consoleLock = new object();
- public void Subscribe() {
- LogChannel.Default.Events += Default_Events;
- }
-
- public void Unsubscribe() {
- LogChannel.Default.Events -= Default_Events;
- }
+ protected override void WriteEntry(TraceContext context, EventText text) {
+ var msg = new StringBuilder();
- void Default_Events(object sender, ValueEventArgs e) {
- LogEvent((TraceContext)sender, e.Value);
- }
-
- void LogEvent(TraceContext context, TraceEvent evt) {
- var msg = new StringBuilder();
- for (int i = 0; i < context.CurrentOperation.Level; i++)
+ for (int i = 0; i < text.indent; i++)
msg.Append(" ");
- msg.Append(evt.EventType);
- msg.AppendFormat("[{0}]: ",context.ThreadId);
- msg.Append(evt.Message);
+ msg.AppendFormat("[{0}]: {1}", context.ThreadId, text.content);
lock (_consoleLock) {
Console.ForegroundColor = (ConsoleColor)(context.ThreadId % 15 + 1);
diff --git a/Implab/Diagnostics/EventText.cs b/Implab/Diagnostics/EventText.cs
new file mode 100644
--- /dev/null
+++ b/Implab/Diagnostics/EventText.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Implab.Diagnostics {
+ public struct EventText {
+ public int indent;
+
+ public string content;
+ }
+}
diff --git a/Implab/Diagnostics/IEventTextFormatter.cs b/Implab/Diagnostics/IEventTextFormatter.cs
new file mode 100644
--- /dev/null
+++ b/Implab/Diagnostics/IEventTextFormatter.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Implab.Diagnostics {
+ public interface IEventTextFormatter {
+ EventText Format(TraceContext context, TEvent data);
+ }
+}
diff --git a/Implab/Diagnostics/TextFileListener.cs b/Implab/Diagnostics/TextFileListener.cs
new file mode 100644
--- /dev/null
+++ b/Implab/Diagnostics/TextFileListener.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Implab.Diagnostics {
+ public class TextFileListener: TextListenerBase {
+ readonly TextWriter m_textWriter;
+
+ public TextFileListener(string fileName) {
+ m_textWriter = File.CreateText(fileName);
+
+ m_textWriter.WriteLine("LOG {0}", DateTime.Now);
+ Register(this);
+ }
+
+ protected override void WriteEntry(TraceContext context, EventText text) {
+ var msg = new StringBuilder();
+ for (int i = 0; i < text.indent; i++)
+ msg.Append(" ");
+ msg.AppendFormat("[{0}]: {1}", context.ThreadId, text.content);
+
+ lock (m_textWriter) {
+ if (!IsDisposed) {
+ m_textWriter.WriteLine(msg.ToString());
+ m_textWriter.Flush();
+ }
+ }
+ }
+
+
+ protected override void Dispose(bool disposing) {
+ base.Dispose(disposing);
+ if (disposing) {
+ lock (m_textWriter) {
+ Safe.Dispose(m_textWriter);
+ }
+ }
+ }
+
+
+ }
+}
diff --git a/Implab/Diagnostics/TextListenerBase.cs b/Implab/Diagnostics/TextListenerBase.cs
new file mode 100644
--- /dev/null
+++ b/Implab/Diagnostics/TextListenerBase.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Implab.Diagnostics {
+ public abstract class TextListenerBase : ServiceLocator, IEventTextFormatter