changeset 47:b181f7bcb259 interactive logger

refactoring, interactive tarce log almost complete
author cin
date Thu, 17 Apr 2014 18:49:36 +0400
parents 9ce97b262a7a
children d9d794b61bb9
files Implab.Diagnostics.Interactive/Implab.Diagnostics.Interactive.csproj Implab.Diagnostics.Interactive/InteractiveListener.cs Implab.Diagnostics.Interactive/InteractiveTracer.cs Implab.Diagnostics.Interactive/Properties/DataSources/TraceViewItem.datasource Implab.Diagnostics.Interactive/TraceForm.Designer.cs Implab.Diagnostics.Interactive/TraceForm.cs Implab.Diagnostics.Interactive/TraceForm.resx Implab.Diagnostics.Interactive/TraceViewControl.Designer.cs Implab.Diagnostics.Interactive/TraceViewControl.cs Implab.Diagnostics.Interactive/TraceViewControl.resx Implab.Diagnostics.Interactive/TraceViewItem.cs Implab/Diagnostics/TextFileListener.cs Implab/Diagnostics/TextListenerBase.cs
diffstat 13 files changed, 265 insertions(+), 296 deletions(-) [+]
line wrap: on
line diff
--- a/Implab.Diagnostics.Interactive/Implab.Diagnostics.Interactive.csproj	Thu Apr 17 08:49:24 2014 +0400
+++ b/Implab.Diagnostics.Interactive/Implab.Diagnostics.Interactive.csproj	Thu Apr 17 18:49:36 2014 +0400
@@ -41,7 +41,7 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="InteractiveTracer.cs" />
+    <Compile Include="InteractiveListener.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="TextStyle.cs" />
     <Compile Include="TraceForm.cs">
@@ -50,16 +50,10 @@
     <Compile Include="TraceForm.Designer.cs">
       <DependentUpon>TraceForm.cs</DependentUpon>
     </Compile>
-    <Compile Include="TraceViewControl.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="TraceViewControl.Designer.cs">
-      <DependentUpon>TraceViewControl.cs</DependentUpon>
-    </Compile>
     <Compile Include="TraceViewItem.cs" />
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\external\Implab\Implab.csproj">
+    <ProjectReference Include="..\Implab\Implab.csproj">
       <Project>{f550f1f8-8746-4ad0-9614-855f4c4b7f05}</Project>
       <Name>Implab</Name>
     </ProjectReference>
@@ -68,9 +62,9 @@
     <EmbeddedResource Include="TraceForm.resx">
       <DependentUpon>TraceForm.cs</DependentUpon>
     </EmbeddedResource>
-    <EmbeddedResource Include="TraceViewControl.resx">
-      <DependentUpon>TraceViewControl.cs</DependentUpon>
-    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Properties\DataSources\TraceViewItem.datasource" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.Diagnostics.Interactive/InteractiveListener.cs	Thu Apr 17 18:49:36 2014 +0400
@@ -0,0 +1,107 @@
+using Implab.Parallels;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace Implab.Diagnostics.Interactive
+{
+    public class InteractiveListener: Disposable
+    {
+        TraceForm m_form;
+        
+        SynchronizationContext m_syncGuiThread;
+        
+        readonly IPromiseBase m_guiFinished;
+        readonly Promise<object> m_guiStarted = new Promise<object>();
+
+        readonly IPromiseBase m_workerFinished = new Promise<object>();
+        
+        readonly MTQueue<TraceViewItem> m_queue = new MTQueue<TraceViewItem>();
+        readonly AutoResetEvent m_queueEvent = new AutoResetEvent(false);
+        
+        int m_queueLength;
+        bool m_exitPending;
+
+        readonly object m_pauseLock = new object();
+        bool m_paused;
+        readonly ManualResetEvent m_pauseEvent = new ManualResetEvent(true);
+
+        public InteractiveListener() {
+            m_guiFinished = AsyncPool.InvokeNewThread(() => {
+                GuiThread();
+                return 0;
+            });
+
+            m_guiStarted.Join();
+        }
+
+        void GuiThread() {
+            m_form = new TraceForm(); // will create SynchronizationContext
+            m_syncGuiThread = SynchronizationContext.Current;
+            m_guiStarted.Resolve();
+            Application.Run();
+        }
+
+        void QueueThread() {
+            while (!m_exitPending) {
+                if (m_paused)
+                    m_pauseEvent.WaitOne();
+                
+                TraceViewItem item;
+                if (m_queue.TryDequeue(out item)) {
+                    Interlocked.Decrement(ref m_queueLength);
+
+                    m_syncGuiThread.Send(x => m_form.AddTraceEvent(item),null);
+                } else {
+                    m_queueEvent.WaitOne();
+                }
+            }
+        }
+
+        public void Pause() {
+            // for consistency we need to set this properties atomically
+            lock (m_pauseLock) {
+                m_pauseEvent.Reset();
+                m_paused = true;
+            }
+        }
+
+        public void Resume() {
+            // for consistency we need to set this properties atomically
+            lock (m_pauseLock) {
+                m_paused = false;
+                m_pauseEvent.Set();
+            }
+        }
+
+        void Enqueue(TraceViewItem item) {
+            m_queue.Enqueue(item);
+            if (Interlocked.Increment(ref m_queueLength) == 1)
+                m_queueEvent.Set();
+        }
+
+        public void ShowForm() {
+            m_syncGuiThread.Post(x => m_form.Show(), null);
+        }
+
+        public void HideForm() {
+            m_syncGuiThread.Post(x => m_form.Hide(), null);
+        }
+
+        void Terminate() {
+            m_syncGuiThread.Post(x => Application.ExitThread(), null);
+        }
+
+        protected override void Dispose(bool disposing) {
+            if (disposing) {
+                Terminate();
+                m_guiFinished.Join();
+            }
+            base.Dispose(disposing);
+        }
+    }
+}
--- a/Implab.Diagnostics.Interactive/InteractiveTracer.cs	Thu Apr 17 08:49:24 2014 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-using Implab.Parallels;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-
-namespace Implab.Diagnostics.Interactive
-{
-    public class InteractiveTracer: Disposable
-    {
-        TraceForm m_form;
-        SynchronizationContext m_syncGuiThread;
-        readonly IPromiseBase m_completed;
-        readonly Promise<object> m_started = new Promise<object>();
-
-        public InteractiveTracer() {
-            m_completed = AsyncPool.InvokeNewThread(() => {
-                GuiThread();
-                return 0;
-            });
-
-            m_started.Join();
-        }
-
-        void GuiThread() {
-            m_form = new TraceForm(); // will create SynchronizationContext
-            m_syncGuiThread = SynchronizationContext.Current;
-            m_started.Resolve();
-            Application.Run();
-        }
-
-        public void ShowForm() {
-            m_syncGuiThread.Post(x => m_form.Show(), null);
-        }
-
-        public void HideForm() {
-            m_syncGuiThread.Post(x => m_form.Hide(), null);
-        }
-
-        void Terminate() {
-            m_syncGuiThread.Post(x => Application.ExitThread(), null);
-        }
-
-        protected override void Dispose(bool disposing) {
-            if (disposing) {
-                Terminate();
-                m_completed.Join();
-            }
-            base.Dispose(disposing);
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.Diagnostics.Interactive/Properties/DataSources/TraceViewItem.datasource	Thu Apr 17 18:49:36 2014 +0400
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    This file is automatically generated by Visual Studio .Net. It is 
+    used to store generic object data source configuration information.  
+    Renaming the file extension or editing the content of this file may   
+    cause the file to be unrecognizable by the program.
+-->
+<GenericObjectDataSource DisplayName="TraceViewItem" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
+   <TypeInfo>Implab.Diagnostics.Interactive.TraceViewItem, Implab.Diagnostics.Interactive</TypeInfo>
+</GenericObjectDataSource>
\ No newline at end of file
--- a/Implab.Diagnostics.Interactive/TraceForm.Designer.cs	Thu Apr 17 08:49:24 2014 +0400
+++ b/Implab.Diagnostics.Interactive/TraceForm.Designer.cs	Thu Apr 17 18:49:36 2014 +0400
@@ -23,30 +23,100 @@
         /// the contents of this method with the code editor.
         /// </summary>
         private void InitializeComponent() {
-            this.traceViewControl1 = new Implab.Diagnostics.Interactive.TraceViewControl();
+            this.components = new System.ComponentModel.Container();
+            System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
+            System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
+            System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
+            this.eventsDataGrid = new System.Windows.Forms.DataGridView();
+            this.traceViewItemBindingSource = new System.Windows.Forms.BindingSource(this.components);
+            this.threadDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
+            this.messageDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
+            ((System.ComponentModel.ISupportInitialize)(this.eventsDataGrid)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.traceViewItemBindingSource)).BeginInit();
             this.SuspendLayout();
             // 
-            // traceViewControl1
+            // eventsDataGrid
             // 
-            this.traceViewControl1.Location = new System.Drawing.Point(13, 13);
-            this.traceViewControl1.Name = "traceViewControl1";
-            this.traceViewControl1.Size = new System.Drawing.Size(267, 248);
-            this.traceViewControl1.TabIndex = 0;
+            this.eventsDataGrid.AllowUserToAddRows = false;
+            this.eventsDataGrid.AllowUserToDeleteRows = false;
+            this.eventsDataGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.eventsDataGrid.AutoGenerateColumns = false;
+            this.eventsDataGrid.BackgroundColor = System.Drawing.SystemColors.Window;
+            dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+            dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+            dataGridViewCellStyle1.Font = new System.Drawing.Font("Lucida Console", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
+            dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
+            dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+            dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+            dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
+            this.eventsDataGrid.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
+            this.eventsDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+            this.eventsDataGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
+            this.threadDataGridViewTextBoxColumn,
+            this.messageDataGridViewTextBoxColumn});
+            this.eventsDataGrid.DataSource = this.traceViewItemBindingSource;
+            dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+            dataGridViewCellStyle3.BackColor = System.Drawing.SystemColors.Window;
+            dataGridViewCellStyle3.Font = new System.Drawing.Font("Lucida Console", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
+            dataGridViewCellStyle3.ForeColor = System.Drawing.SystemColors.ControlText;
+            dataGridViewCellStyle3.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+            dataGridViewCellStyle3.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+            dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+            this.eventsDataGrid.DefaultCellStyle = dataGridViewCellStyle3;
+            this.eventsDataGrid.Location = new System.Drawing.Point(12, 12);
+            this.eventsDataGrid.Name = "eventsDataGrid";
+            this.eventsDataGrid.ReadOnly = true;
+            this.eventsDataGrid.RowHeadersWidth = 17;
+            this.eventsDataGrid.RowTemplate.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+            this.eventsDataGrid.Size = new System.Drawing.Size(939, 480);
+            this.eventsDataGrid.TabIndex = 1;
+            this.eventsDataGrid.CellFormatting += new System.Windows.Forms.DataGridViewCellFormattingEventHandler(this.eventsDataGrid_CellFormatting);
+            // 
+            // traceViewItemBindingSource
+            // 
+            this.traceViewItemBindingSource.DataSource = typeof(Implab.Diagnostics.Interactive.TraceViewItem);
+            // 
+            // threadDataGridViewTextBoxColumn
+            // 
+            this.threadDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
+            this.threadDataGridViewTextBoxColumn.DataPropertyName = "Thread";
+            this.threadDataGridViewTextBoxColumn.HeaderText = "TID";
+            this.threadDataGridViewTextBoxColumn.Name = "threadDataGridViewTextBoxColumn";
+            this.threadDataGridViewTextBoxColumn.ReadOnly = true;
+            this.threadDataGridViewTextBoxColumn.Width = 5;
+            // 
+            // messageDataGridViewTextBoxColumn
+            // 
+            this.messageDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+            this.messageDataGridViewTextBoxColumn.DataPropertyName = "FormattedMessage";
+            dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+            this.messageDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle2;
+            this.messageDataGridViewTextBoxColumn.HeaderText = "Message";
+            this.messageDataGridViewTextBoxColumn.Name = "messageDataGridViewTextBoxColumn";
+            this.messageDataGridViewTextBoxColumn.ReadOnly = true;
             // 
             // TraceForm
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.ClientSize = new System.Drawing.Size(292, 273);
-            this.Controls.Add(this.traceViewControl1);
+            this.ClientSize = new System.Drawing.Size(963, 504);
+            this.Controls.Add(this.eventsDataGrid);
             this.Name = "TraceForm";
             this.Text = "TraceForm";
+            ((System.ComponentModel.ISupportInitialize)(this.eventsDataGrid)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.traceViewItemBindingSource)).EndInit();
             this.ResumeLayout(false);
 
         }
 
         #endregion
 
-        private TraceViewControl traceViewControl1;
+        private System.Windows.Forms.DataGridView eventsDataGrid;
+        private System.Windows.Forms.BindingSource traceViewItemBindingSource;
+        private System.Windows.Forms.DataGridViewTextBoxColumn threadDataGridViewTextBoxColumn;
+        private System.Windows.Forms.DataGridViewTextBoxColumn messageDataGridViewTextBoxColumn;
+
     }
 }
\ No newline at end of file
--- a/Implab.Diagnostics.Interactive/TraceForm.cs	Thu Apr 17 08:49:24 2014 +0400
+++ b/Implab.Diagnostics.Interactive/TraceForm.cs	Thu Apr 17 18:49:36 2014 +0400
@@ -10,8 +10,12 @@
 
 namespace Implab.Diagnostics.Interactive {
     public partial class TraceForm : Form {
+        readonly Dictionary<int, Color> m_threadColors = new Dictionary<int,Color>();
+        readonly Random m_rand = new Random();
+
         public TraceForm() {
             InitializeComponent();
+
         }
 
         protected override void OnFormClosing(FormClosingEventArgs e) {
@@ -21,5 +25,34 @@
                 Hide();
             }
         }
+
+        public void AddTraceEvent(int indent, int thread, string message) {
+            traceViewItemBindingSource.Add(new TraceViewItem {
+                Indent = indent,
+                Thread = thread,
+                Message = message,
+                Timestamp = Environment.TickCount
+            });
+
+        }
+
+        public void AddTraceEvent(TraceViewItem item) {
+            traceViewItemBindingSource.Add(item);
+        }
+
+        Color GetThreadColor(int thread) {
+            Color result;
+            if (!m_threadColors.TryGetValue(thread, out result)) {
+                result = Color.FromArgb(m_rand.Next(4)*64, m_rand.Next(4)*64, m_rand.Next(4)*64);
+                m_threadColors[thread] = result;
+            }
+            return result;
+        }
+
+        private void eventsDataGrid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) {
+            var data = (TraceViewItem)traceViewItemBindingSource[e.RowIndex];
+            e.CellStyle.Padding = new Padding(data.Indent * 10,0,0,0);
+            e.CellStyle.ForeColor = GetThreadColor(data.Thread);
+        }
     }
 }
--- a/Implab.Diagnostics.Interactive/TraceForm.resx	Thu Apr 17 08:49:24 2014 +0400
+++ b/Implab.Diagnostics.Interactive/TraceForm.resx	Thu Apr 17 18:49:36 2014 +0400
@@ -117,4 +117,7 @@
   <resheader name="writer">
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
+  <metadata name="traceViewItemBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
 </root>
\ No newline at end of file
--- a/Implab.Diagnostics.Interactive/TraceViewControl.Designer.cs	Thu Apr 17 08:49:24 2014 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-namespace Implab.Diagnostics.Interactive {
-    partial class TraceViewControl {
-        /// <summary> 
-        /// Required designer variable.
-        /// </summary>
-        private System.ComponentModel.IContainer components = null;
-
-        /// <summary> 
-        /// Clean up any resources being used.
-        /// </summary>
-        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-        protected override void Dispose(bool disposing) {
-            if (disposing && (components != null)) {
-                components.Dispose();
-            }
-            base.Dispose(disposing);
-        }
-
-        #region Component Designer generated code
-
-        /// <summary> 
-        /// Required method for Designer support - do not modify 
-        /// the contents of this method with the code editor.
-        /// </summary>
-        private void InitializeComponent() {
-            this.SuspendLayout();
-            // 
-            // TraceViewControl
-            // 
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.BackColor = System.Drawing.SystemColors.Window;
-            this.Name = "TraceViewControl";
-            this.ResumeLayout(false);
-
-        }
-
-        #endregion
-    }
-}
--- a/Implab.Diagnostics.Interactive/TraceViewControl.cs	Thu Apr 17 08:49:24 2014 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Drawing;
-using System.Data;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-
-namespace Implab.Diagnostics.Interactive {
-    public partial class TraceViewControl : UserControl {
-        int m_maxEvents = 1000;
-
-        string m_status = "ready";
-        
-        readonly LinkedList<TraceViewItem> m_events = new LinkedList<TraceViewItem>();
-        public TraceViewControl() {
-            InitializeComponent();
-
-            var ticks = Environment.TickCount;
-
-            for (int i = 0; i < 1333; i++) {
-                AddViewItem(new TraceViewItem {
-                    indent = i % 4,
-                    message = String.Format("Auto generated {0}", i),
-                    thread = 2,
-                    timestamp = ticks + i*10
-                });
-            }
-        }
-
-        public void AddViewItem(TraceViewItem item) {
-            m_events.AddLast(item);
-            if (m_events.Count > m_maxEvents)
-                m_events.RemoveFirst();
-        }
-
-        protected override void OnPaint(PaintEventArgs e) {
-            base.OnPaint(e);
-
-            if (m_status != null)
-                e.Graphics.DrawString(m_status, DefaultFont, Brushes.Black, 0, 0);
-            
-        }
-
-        protected override void OnMouseMove(MouseEventArgs e) {
-            base.OnMouseMove(e);
-
-            m_status = String.Format("({0},{1})", e.X, e.Y);
-            Invalidate();
-        }
-        
-    }
-}
--- a/Implab.Diagnostics.Interactive/TraceViewControl.resx	Thu Apr 17 08:49:24 2014 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
-  <!-- 
-    Microsoft ResX Schema 
-    
-    Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
-    associated with the data types.
-    
-    Example:
-    
-    ... ado.net/XML headers & schema ...
-    <resheader name="resmimetype">text/microsoft-resx</resheader>
-    <resheader name="version">2.0</resheader>
-    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
-    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
-    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
-    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
-    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
-        <value>[base64 mime encoded serialized .NET Framework object]</value>
-    </data>
-    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
-        <comment>This is a comment</comment>
-    </data>
-                
-    There are any number of "resheader" rows that contain simple 
-    name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
-    mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
-    extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
-    read any of the formats listed below.
-    
-    mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
-            : and then encoded with base64 encoding.
-    
-    mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
-            : and then encoded with base64 encoding.
-
-    mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
-            : using a System.ComponentModel.TypeConverter
-            : and then encoded with base64 encoding.
-    -->
-  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
-    <xsd:element name="root" msdata:IsDataSet="true">
-      <xsd:complexType>
-        <xsd:choice maxOccurs="unbounded">
-          <xsd:element name="metadata">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" />
-              </xsd:sequence>
-              <xsd:attribute name="name" use="required" type="xsd:string" />
-              <xsd:attribute name="type" type="xsd:string" />
-              <xsd:attribute name="mimetype" type="xsd:string" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="assembly">
-            <xsd:complexType>
-              <xsd:attribute name="alias" type="xsd:string" />
-              <xsd:attribute name="name" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="data">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
-              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
-              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="resheader">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" />
-            </xsd:complexType>
-          </xsd:element>
-        </xsd:choice>
-      </xsd:complexType>
-    </xsd:element>
-  </xsd:schema>
-  <resheader name="resmimetype">
-    <value>text/microsoft-resx</value>
-  </resheader>
-  <resheader name="version">
-    <value>2.0</value>
-  </resheader>
-  <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-</root>
\ No newline at end of file
--- a/Implab.Diagnostics.Interactive/TraceViewItem.cs	Thu Apr 17 08:49:24 2014 +0400
+++ b/Implab.Diagnostics.Interactive/TraceViewItem.cs	Thu Apr 17 18:49:36 2014 +0400
@@ -5,10 +5,21 @@
 using System.Threading.Tasks;
 
 namespace Implab.Diagnostics.Interactive {
-    public struct TraceViewItem {
-        public string message;
-        public int timestamp;
-        public int indent;
-        public int thread;
+    public class TraceViewItem {
+        string m_formattedValue;
+
+        public string Message { get; set; }
+        public int Timestamp { get; set; }
+        public int Indent { get; set; }
+        public int Thread { get; set; }
+
+        public string FormattedMessage {
+            get {
+                if (m_formattedValue == null) {
+                    m_formattedValue = Message.Replace("\r",String.Empty).Replace("\n", " | ");
+                }
+                return m_formattedValue;
+            }
+        }
     }
 }
--- a/Implab/Diagnostics/TextFileListener.cs	Thu Apr 17 08:49:24 2014 +0400
+++ b/Implab/Diagnostics/TextFileListener.cs	Thu Apr 17 18:49:36 2014 +0400
@@ -23,6 +23,7 @@
 
             lock (m_textWriter) {
                 if (!IsDisposed) {
+                    // тут гарантировано еще не освобожден m_textWriter
                     m_textWriter.WriteLine(msg.ToString());
                     m_textWriter.Flush();
                 }
@@ -33,6 +34,7 @@
         protected override void Dispose(bool disposing) {
             base.Dispose(disposing);
             if (disposing) {
+                // IsDisposed = true
                 lock (m_textWriter) {
                     Safe.Dispose(m_textWriter);
                 }
--- a/Implab/Diagnostics/TextListenerBase.cs	Thu Apr 17 08:49:24 2014 +0400
+++ b/Implab/Diagnostics/TextListenerBase.cs	Thu Apr 17 18:49:36 2014 +0400
@@ -89,6 +89,15 @@
             }
         }
 
+        /// <summary>
+        /// Вызывается для записи текста сообщения, в журнал.
+        /// </summary>
+        /// <remarks>
+        /// Данный метод может вызваться из разных потоков одновременно. Возможна ситуация, когда
+        /// данный метод вызывается уже после освобождения ообъекта методом <see cref="Dispose()"/>.
+        /// </remarks>
+        /// <param name="context">Контекст трассировки.</param>
+        /// <param name="text">Текст сообщения.</param>
         protected abstract void WriteEntry(TraceContext context, EventText text);
         
         public EventText Format(TraceContext context, object data) {
@@ -110,10 +119,10 @@
         }
 
         protected override void Dispose(bool disposing) {
+            base.Dispose(disposing);
             if (disposing) {
                 UnsubscribeAll();
             }
-            base.Dispose(disposing);
         }
     }
 }