##// END OF EJS Templates
Слияние с interactive logger
cin -
r50:f8cbe84cfdb1 merge default
parent child
Show More
@@ -0,0 +1,77
1 <?xml version="1.0" encoding="utf-8"?>
2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4 <PropertyGroup>
5 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7 <ProjectGuid>{1DB7DB0C-8AA9-484B-A681-33AE94038391}</ProjectGuid>
8 <OutputType>Library</OutputType>
9 <AppDesignerFolder>Properties</AppDesignerFolder>
10 <RootNamespace>Implab.Diagnostics.Interactive</RootNamespace>
11 <AssemblyName>Implab.Diagnostics.Interactive</AssemblyName>
12 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13 <FileAlignment>512</FileAlignment>
14 </PropertyGroup>
15 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16 <DebugSymbols>true</DebugSymbols>
17 <DebugType>full</DebugType>
18 <Optimize>false</Optimize>
19 <OutputPath>bin\Debug\</OutputPath>
20 <DefineConstants>DEBUG;TRACE</DefineConstants>
21 <ErrorReport>prompt</ErrorReport>
22 <WarningLevel>4</WarningLevel>
23 </PropertyGroup>
24 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25 <DebugType>pdbonly</DebugType>
26 <Optimize>true</Optimize>
27 <OutputPath>bin\Release\</OutputPath>
28 <DefineConstants>TRACE</DefineConstants>
29 <ErrorReport>prompt</ErrorReport>
30 <WarningLevel>4</WarningLevel>
31 </PropertyGroup>
32 <ItemGroup>
33 <Reference Include="System" />
34 <Reference Include="System.Core" />
35 <Reference Include="System.Drawing" />
36 <Reference Include="System.Windows.Forms" />
37 <Reference Include="System.Xml.Linq" />
38 <Reference Include="System.Data.DataSetExtensions" />
39 <Reference Include="Microsoft.CSharp" />
40 <Reference Include="System.Data" />
41 <Reference Include="System.Xml" />
42 </ItemGroup>
43 <ItemGroup>
44 <Compile Include="InteractiveListener.cs" />
45 <Compile Include="Properties\AssemblyInfo.cs" />
46 <Compile Include="TextStyle.cs" />
47 <Compile Include="TraceForm.cs">
48 <SubType>Form</SubType>
49 </Compile>
50 <Compile Include="TraceForm.Designer.cs">
51 <DependentUpon>TraceForm.cs</DependentUpon>
52 </Compile>
53 <Compile Include="TraceViewItem.cs" />
54 </ItemGroup>
55 <ItemGroup>
56 <ProjectReference Include="..\Implab\Implab.csproj">
57 <Project>{f550f1f8-8746-4ad0-9614-855f4c4b7f05}</Project>
58 <Name>Implab</Name>
59 </ProjectReference>
60 </ItemGroup>
61 <ItemGroup>
62 <EmbeddedResource Include="TraceForm.resx">
63 <DependentUpon>TraceForm.cs</DependentUpon>
64 </EmbeddedResource>
65 </ItemGroup>
66 <ItemGroup>
67 <None Include="Properties\DataSources\TraceViewItem.datasource" />
68 </ItemGroup>
69 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
70 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
71 Other similar extension points exist, see Microsoft.Common.targets.
72 <Target Name="BeforeBuild">
73 </Target>
74 <Target Name="AfterBuild">
75 </Target>
76 -->
77 </Project> No newline at end of file
@@ -0,0 +1,122
1 using Implab.Parallels;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6 using System.Threading;
7 using System.Threading.Tasks;
8 using System.Windows.Forms;
9
10 namespace Implab.Diagnostics.Interactive
11 {
12 public class InteractiveListener: TextListenerBase
13 {
14 TraceForm m_form;
15
16 SynchronizationContext m_syncGuiThread;
17 readonly Promise<object> m_guiStarted = new Promise<object>();
18
19 readonly IPromiseBase m_guiFinished;
20 readonly IPromiseBase m_workerFinished = new Promise<object>();
21
22 readonly MTQueue<TraceViewItem> m_queue = new MTQueue<TraceViewItem>();
23 readonly AutoResetEvent m_queueEvent = new AutoResetEvent(false);
24
25 int m_queueLength;
26 bool m_exitPending;
27
28 readonly object m_pauseLock = new object();
29 bool m_paused;
30 readonly ManualResetEvent m_pauseEvent = new ManualResetEvent(true);
31
32 public InteractiveListener(bool global) : base(global) {
33 m_guiFinished = AsyncPool.InvokeNewThread(GuiThread);
34 m_workerFinished = AsyncPool.InvokeNewThread(QueueThread);
35
36 m_guiStarted.Join();
37 }
38
39 void GuiThread() {
40 m_form = new TraceForm(); // will create SynchronizationContext
41
42 m_form.PauseEvents += (s,a) => Pause();
43 m_form.ResumeEvents += (s, a) => Resume();
44
45 m_syncGuiThread = SynchronizationContext.Current;
46 m_guiStarted.Resolve();
47 Application.Run();
48 }
49
50 void QueueThread() {
51 while (!m_exitPending) {
52 if (m_paused)
53 m_pauseEvent.WaitOne();
54
55 TraceViewItem item;
56 if (m_queue.TryDequeue(out item)) {
57 Interlocked.Decrement(ref m_queueLength);
58
59 m_syncGuiThread.Send(x => m_form.AddTraceEvent(item),null);
60 } else {
61 m_queueEvent.WaitOne();
62 }
63 }
64 }
65
66 public void Pause() {
67 // for consistency we need to set this properties atomically
68 lock (m_pauseLock) {
69 m_pauseEvent.Reset();
70 m_paused = true;
71 }
72 }
73
74 public void Resume() {
75 // for consistency we need to set this properties atomically
76 lock (m_pauseLock) {
77 m_paused = false;
78 m_pauseEvent.Set();
79 }
80 }
81
82 void Enqueue(TraceViewItem item) {
83 m_queue.Enqueue(item);
84 if (Interlocked.Increment(ref m_queueLength) == 1)
85 m_queueEvent.Set();
86 }
87
88 public void ShowForm() {
89 m_syncGuiThread.Post(x => m_form.Show(), null);
90 }
91
92 public void HideForm() {
93 m_syncGuiThread.Post(x => m_form.Hide(), null);
94 }
95
96 void Terminate() {
97 m_exitPending = true;
98 Resume();
99 m_syncGuiThread.Post(x => Application.ExitThread(), null);
100 }
101
102 protected override void Dispose(bool disposing) {
103 if (disposing) {
104 Terminate();
105 m_guiFinished.Join();
106 }
107 base.Dispose(disposing);
108 }
109
110 protected override void WriteEntry(TraceContext context, EventText text, string channel) {
111 var item = new TraceViewItem {
112 Indent = text.indent,
113 Message = text.content,
114 Thread = context.ThreadId,
115 Channel = channel,
116 Timestamp = Environment.TickCount
117 };
118
119 Enqueue(item);
120 }
121 }
122 }
@@ -0,0 +1,36
1 using System.Reflection;
2 using System.Runtime.CompilerServices;
3 using System.Runtime.InteropServices;
4
5 // General Information about an assembly is controlled through the following
6 // set of attributes. Change these attribute values to modify the information
7 // associated with an assembly.
8 [assembly: AssemblyTitle("Implab.Diagnostics.Interactive")]
9 [assembly: AssemblyDescription("")]
10 [assembly: AssemblyConfiguration("")]
11 [assembly: AssemblyCompany("")]
12 [assembly: AssemblyProduct("Implab.Diagnostics.Interactive")]
13 [assembly: AssemblyCopyright("Copyright © 2014")]
14 [assembly: AssemblyTrademark("")]
15 [assembly: AssemblyCulture("")]
16
17 // Setting ComVisible to false makes the types in this assembly not visible
18 // to COM components. If you need to access a type in this assembly from
19 // COM, set the ComVisible attribute to true on that type.
20 [assembly: ComVisible(false)]
21
22 // The following GUID is for the ID of the typelib if this project is exposed to COM
23 [assembly: Guid("1c156c51-4884-43b2-a823-d86313872e82")]
24
25 // Version information for an assembly consists of the following four values:
26 //
27 // Major Version
28 // Minor Version
29 // Build Number
30 // Revision
31 //
32 // You can specify all the values or you can default the Build and Revision Numbers
33 // by using the '*' as shown below:
34 // [assembly: AssemblyVersion("1.0.*")]
35 [assembly: AssemblyVersion("1.0.0.0")]
36 [assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,10
1 <?xml version="1.0" encoding="utf-8"?>
2 <!--
3 This file is automatically generated by Visual Studio .Net. It is
4 used to store generic object data source configuration information.
5 Renaming the file extension or editing the content of this file may
6 cause the file to be unrecognizable by the program.
7 -->
8 <GenericObjectDataSource DisplayName="TraceViewItem" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
9 <TypeInfo>Implab.Diagnostics.Interactive.TraceViewItem, Implab.Diagnostics.Interactive</TypeInfo>
10 </GenericObjectDataSource> No newline at end of file
@@ -0,0 +1,25
1 using System;
2 using System.Collections.Generic;
3 using System.Drawing;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7
8 namespace Implab.Diagnostics.Interactive {
9 class TextStyle {
10 public Color TextColor {
11 get;
12 set;
13 }
14
15 public FontStyle FontStyle {
16 get;
17 set;
18 }
19
20 public int PaddingLeft {
21 get;
22 set;
23 }
24 }
25 }
@@ -0,0 +1,134
1 namespace Implab.Diagnostics.Interactive {
2 partial class TraceForm {
3 /// <summary>
4 /// Required designer variable.
5 /// </summary>
6 private System.ComponentModel.IContainer components = null;
7
8 /// <summary>
9 /// Clean up any resources being used.
10 /// </summary>
11 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
12 protected override void Dispose(bool disposing) {
13 if (disposing && (components != null)) {
14 components.Dispose();
15 }
16 base.Dispose(disposing);
17 }
18
19 #region Windows Form Designer generated code
20
21 /// <summary>
22 /// Required method for Designer support - do not modify
23 /// the contents of this method with the code editor.
24 /// </summary>
25 private void InitializeComponent() {
26 this.components = new System.ComponentModel.Container();
27 System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
28 System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
29 System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
30 this.eventsDataGrid = new System.Windows.Forms.DataGridView();
31 this.traceViewItemBindingSource = new System.Windows.Forms.BindingSource(this.components);
32 this.threadDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
33 this.Channel = new System.Windows.Forms.DataGridViewTextBoxColumn();
34 this.messageDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
35 ((System.ComponentModel.ISupportInitialize)(this.eventsDataGrid)).BeginInit();
36 ((System.ComponentModel.ISupportInitialize)(this.traceViewItemBindingSource)).BeginInit();
37 this.SuspendLayout();
38 //
39 // eventsDataGrid
40 //
41 this.eventsDataGrid.AllowUserToAddRows = false;
42 this.eventsDataGrid.AllowUserToDeleteRows = false;
43 this.eventsDataGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
44 | System.Windows.Forms.AnchorStyles.Left)
45 | System.Windows.Forms.AnchorStyles.Right)));
46 this.eventsDataGrid.AutoGenerateColumns = false;
47 this.eventsDataGrid.BackgroundColor = System.Drawing.SystemColors.Window;
48 dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
49 dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
50 dataGridViewCellStyle1.Font = new System.Drawing.Font("Lucida Console", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
51 dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
52 dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
53 dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
54 dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
55 this.eventsDataGrid.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
56 this.eventsDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
57 this.eventsDataGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
58 this.threadDataGridViewTextBoxColumn,
59 this.Channel,
60 this.messageDataGridViewTextBoxColumn});
61 this.eventsDataGrid.DataSource = this.traceViewItemBindingSource;
62 dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
63 dataGridViewCellStyle3.BackColor = System.Drawing.SystemColors.Window;
64 dataGridViewCellStyle3.Font = new System.Drawing.Font("Lucida Console", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
65 dataGridViewCellStyle3.ForeColor = System.Drawing.SystemColors.ControlText;
66 dataGridViewCellStyle3.SelectionBackColor = System.Drawing.SystemColors.Highlight;
67 dataGridViewCellStyle3.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
68 dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
69 this.eventsDataGrid.DefaultCellStyle = dataGridViewCellStyle3;
70 this.eventsDataGrid.Location = new System.Drawing.Point(12, 12);
71 this.eventsDataGrid.Name = "eventsDataGrid";
72 this.eventsDataGrid.ReadOnly = true;
73 this.eventsDataGrid.RowHeadersWidth = 17;
74 this.eventsDataGrid.RowTemplate.Resizable = System.Windows.Forms.DataGridViewTriState.False;
75 this.eventsDataGrid.Size = new System.Drawing.Size(939, 480);
76 this.eventsDataGrid.TabIndex = 1;
77 this.eventsDataGrid.CellFormatting += new System.Windows.Forms.DataGridViewCellFormattingEventHandler(this.eventsDataGrid_CellFormatting);
78 //
79 // traceViewItemBindingSource
80 //
81 this.traceViewItemBindingSource.DataSource = typeof(Implab.Diagnostics.Interactive.TraceViewItem);
82 //
83 // threadDataGridViewTextBoxColumn
84 //
85 this.threadDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
86 this.threadDataGridViewTextBoxColumn.DataPropertyName = "Thread";
87 this.threadDataGridViewTextBoxColumn.HeaderText = "TID";
88 this.threadDataGridViewTextBoxColumn.Name = "threadDataGridViewTextBoxColumn";
89 this.threadDataGridViewTextBoxColumn.ReadOnly = true;
90 this.threadDataGridViewTextBoxColumn.Width = 5;
91 //
92 // Channel
93 //
94 this.Channel.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.DisplayedCells;
95 this.Channel.DataPropertyName = "Channel";
96 this.Channel.HeaderText = "Channel";
97 this.Channel.Name = "Channel";
98 this.Channel.ReadOnly = true;
99 this.Channel.Width = 79;
100 //
101 // messageDataGridViewTextBoxColumn
102 //
103 this.messageDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
104 this.messageDataGridViewTextBoxColumn.DataPropertyName = "FormattedMessage";
105 dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
106 this.messageDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle2;
107 this.messageDataGridViewTextBoxColumn.HeaderText = "Message";
108 this.messageDataGridViewTextBoxColumn.Name = "messageDataGridViewTextBoxColumn";
109 this.messageDataGridViewTextBoxColumn.ReadOnly = true;
110 //
111 // TraceForm
112 //
113 this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
114 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
115 this.ClientSize = new System.Drawing.Size(963, 504);
116 this.Controls.Add(this.eventsDataGrid);
117 this.Name = "TraceForm";
118 this.Text = "TraceForm";
119 ((System.ComponentModel.ISupportInitialize)(this.eventsDataGrid)).EndInit();
120 ((System.ComponentModel.ISupportInitialize)(this.traceViewItemBindingSource)).EndInit();
121 this.ResumeLayout(false);
122
123 }
124
125 #endregion
126
127 private System.Windows.Forms.DataGridView eventsDataGrid;
128 private System.Windows.Forms.BindingSource traceViewItemBindingSource;
129 private System.Windows.Forms.DataGridViewTextBoxColumn threadDataGridViewTextBoxColumn;
130 private System.Windows.Forms.DataGridViewTextBoxColumn Channel;
131 private System.Windows.Forms.DataGridViewTextBoxColumn messageDataGridViewTextBoxColumn;
132
133 }
134 } No newline at end of file
@@ -0,0 +1,53
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Linq;
7 using System.Text;
8 using System.Threading.Tasks;
9 using System.Windows.Forms;
10
11 namespace Implab.Diagnostics.Interactive {
12 public partial class TraceForm : Form {
13 readonly Dictionary<int, Color> m_threadColors = new Dictionary<int,Color>();
14 readonly Random m_rand = new Random();
15
16 public event EventHandler PauseEvents;
17
18 public event EventHandler ResumeEvents;
19
20 public TraceForm() {
21 InitializeComponent();
22 }
23
24 protected override void OnFormClosing(FormClosingEventArgs e) {
25 base.OnFormClosing(e);
26 if (!e.Cancel && e.CloseReason == CloseReason.UserClosing) {
27 e.Cancel = true;
28 Hide();
29 }
30 }
31
32 public void AddTraceEvent(TraceViewItem item) {
33 traceViewItemBindingSource.Add(item);
34 eventsDataGrid.FirstDisplayedScrollingRowIndex = eventsDataGrid.RowCount - 1;
35 }
36
37 Color GetThreadColor(int thread) {
38 Color result;
39 if (!m_threadColors.TryGetValue(thread, out result)) {
40 result = Color.FromArgb(m_rand.Next(4)*64, m_rand.Next(4)*64, m_rand.Next(4)*64);
41 m_threadColors[thread] = result;
42 }
43 return result;
44 }
45
46 private void eventsDataGrid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) {
47 var data = (TraceViewItem)traceViewItemBindingSource[e.RowIndex];
48 if (e.ColumnIndex == messageDataGridViewTextBoxColumn.Index)
49 e.CellStyle.Padding = new Padding(data.Indent * 10,0,0,0);
50 e.CellStyle.ForeColor = GetThreadColor(data.Thread);
51 }
52 }
53 }
@@ -0,0 +1,126
1 <?xml version="1.0" encoding="utf-8"?>
2 <root>
3 <!--
4 Microsoft ResX Schema
5
6 Version 2.0
7
8 The primary goals of this format is to allow a simple XML format
9 that is mostly human readable. The generation and parsing of the
10 various data types are done through the TypeConverter classes
11 associated with the data types.
12
13 Example:
14
15 ... ado.net/XML headers & schema ...
16 <resheader name="resmimetype">text/microsoft-resx</resheader>
17 <resheader name="version">2.0</resheader>
18 <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
19 <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
20 <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
21 <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
22 <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
23 <value>[base64 mime encoded serialized .NET Framework object]</value>
24 </data>
25 <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
26 <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
27 <comment>This is a comment</comment>
28 </data>
29
30 There are any number of "resheader" rows that contain simple
31 name/value pairs.
32
33 Each data row contains a name, and value. The row also contains a
34 type or mimetype. Type corresponds to a .NET class that support
35 text/value conversion through the TypeConverter architecture.
36 Classes that don't support this are serialized and stored with the
37 mimetype set.
38
39 The mimetype is used for serialized objects, and tells the
40 ResXResourceReader how to depersist the object. This is currently not
41 extensible. For a given mimetype the value must be set accordingly:
42
43 Note - application/x-microsoft.net.object.binary.base64 is the format
44 that the ResXResourceWriter will generate, however the reader can
45 read any of the formats listed below.
46
47 mimetype: application/x-microsoft.net.object.binary.base64
48 value : The object must be serialized with
49 : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
50 : and then encoded with base64 encoding.
51
52 mimetype: application/x-microsoft.net.object.soap.base64
53 value : The object must be serialized with
54 : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
55 : and then encoded with base64 encoding.
56
57 mimetype: application/x-microsoft.net.object.bytearray.base64
58 value : The object must be serialized into a byte array
59 : using a System.ComponentModel.TypeConverter
60 : and then encoded with base64 encoding.
61 -->
62 <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
63 <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
64 <xsd:element name="root" msdata:IsDataSet="true">
65 <xsd:complexType>
66 <xsd:choice maxOccurs="unbounded">
67 <xsd:element name="metadata">
68 <xsd:complexType>
69 <xsd:sequence>
70 <xsd:element name="value" type="xsd:string" minOccurs="0" />
71 </xsd:sequence>
72 <xsd:attribute name="name" use="required" type="xsd:string" />
73 <xsd:attribute name="type" type="xsd:string" />
74 <xsd:attribute name="mimetype" type="xsd:string" />
75 <xsd:attribute ref="xml:space" />
76 </xsd:complexType>
77 </xsd:element>
78 <xsd:element name="assembly">
79 <xsd:complexType>
80 <xsd:attribute name="alias" type="xsd:string" />
81 <xsd:attribute name="name" type="xsd:string" />
82 </xsd:complexType>
83 </xsd:element>
84 <xsd:element name="data">
85 <xsd:complexType>
86 <xsd:sequence>
87 <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
88 <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
89 </xsd:sequence>
90 <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
91 <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
92 <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
93 <xsd:attribute ref="xml:space" />
94 </xsd:complexType>
95 </xsd:element>
96 <xsd:element name="resheader">
97 <xsd:complexType>
98 <xsd:sequence>
99 <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
100 </xsd:sequence>
101 <xsd:attribute name="name" type="xsd:string" use="required" />
102 </xsd:complexType>
103 </xsd:element>
104 </xsd:choice>
105 </xsd:complexType>
106 </xsd:element>
107 </xsd:schema>
108 <resheader name="resmimetype">
109 <value>text/microsoft-resx</value>
110 </resheader>
111 <resheader name="version">
112 <value>2.0</value>
113 </resheader>
114 <resheader name="reader">
115 <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
116 </resheader>
117 <resheader name="writer">
118 <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119 </resheader>
120 <metadata name="Channel.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
121 <value>True</value>
122 </metadata>
123 <metadata name="traceViewItemBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
124 <value>17, 17</value>
125 </metadata>
126 </root> No newline at end of file
@@ -0,0 +1,26
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Implab.Diagnostics.Interactive {
8 public class TraceViewItem {
9 string m_formattedValue;
10
11 public string Message { get; set; }
12 public int Timestamp { get; set; }
13 public int Indent { get; set; }
14 public int Thread { get; set; }
15 public string Channel { get; set; }
16
17 public string FormattedMessage {
18 get {
19 if (m_formattedValue == null) {
20 m_formattedValue = Message.Replace("\r",String.Empty).Replace("\n", " | ");
21 }
22 return m_formattedValue;
23 }
24 }
25 }
26 }
@@ -11,3 +11,5 Implab.Fx/bin/
11 Implab.Fx.Test/bin/
11 Implab.Fx.Test/bin/
12 Implab.Fx.Test/obj/
12 Implab.Fx.Test/obj/
13 _ReSharper.Implab/
13 _ReSharper.Implab/
14 Implab.Diagnostics.Interactive/bin/
15 Implab.Diagnostics.Interactive/obj/
@@ -13,17 +13,17 namespace Implab.Diagnostics {
13
13
14 }
14 }
15
15
16 public ConsoleTraceListener(bool local)
16 public ConsoleTraceListener(bool global)
17 : base(local) {
17 : base(global) {
18
18
19 }
19 }
20
20
21 protected override void WriteEntry(TraceContext context, EventText text) {
21 protected override void WriteEntry(TraceContext context, EventText text, string channel) {
22 var msg = new StringBuilder();
22 var msg = new StringBuilder();
23
23
24 for (int i = 0; i < text.indent; i++)
24 for (int i = 0; i < text.indent; i++)
25 msg.Append(" ");
25 msg.Append(" ");
26 msg.AppendFormat("[{0}]: {1}", context.ThreadId, text.content);
26 msg.AppendFormat("[{0}]:{1}: {2}", context.ThreadId, channel, text.content);
27
27
28 lock (_consoleLock) {
28 lock (_consoleLock) {
29 Console.ForegroundColor = (ConsoleColor)(context.ThreadId % 15 + 1);
29 Console.ForegroundColor = (ConsoleColor)(context.ThreadId % 15 + 1);
@@ -4,23 +4,74 using System.Linq;
4 using System.Text;
4 using System.Text;
5
5
6 namespace Implab.Diagnostics {
6 namespace Implab.Diagnostics {
7 /// <summary>
8 /// Канал, через который публикуются события журнала.
9 /// </summary>
10 /// <typeparam name="TEvent">Тип событий в канале</typeparam>
11 /// <remarks>
12 /// Событиями журнала могут быть любые типы, например строки, в которых будет передаваться
13 /// информация, или структуры с набором полей, описывающих важность, текст и другую информацию.
14 /// </remarks>
7 public class LogChannel<TEvent> {
15 public class LogChannel<TEvent> {
8 static LogChannel<TEvent> _default = new LogChannel<TEvent>();
16 static LogChannel<TEvent> _default = new LogChannel<TEvent>();
9
17
18 /// <summary>
19 /// Канал по-умолчанию для событий типа <typeparam name="TEvent"/>.
20 /// </summary>
10 public static LogChannel<TEvent> Default {
21 public static LogChannel<TEvent> Default {
11 get {
22 get {
12 return _default;
23 return _default;
13 }
24 }
14 }
25 }
15
26
27 /// <summary>
28 /// Событие появление новой записи в журнале, на это событие подписываются слушатели.
29 /// </summary>
16 public event EventHandler<ValueEventArgs<TEvent>> Events;
30 public event EventHandler<ValueEventArgs<TEvent>> Events;
17
31
32 /// <summary>
33 /// Имя канала, полезно для отображения в журнале
34 /// </summary>
35 public string Name {
36 get;
37 private set;
38 }
39
40 /// <summary>
41 /// Создает журнал, имя типа событий назначается в качетве имени канала.
42 /// </summary>
43 public LogChannel()
44 : this(null) {
45 }
46
47 /// <summary>
48 /// Содает канал с указанным именем.
49 /// </summary>
50 /// <param name="name">Имя канала.</param>
51 public LogChannel(string name) {
52 if (String.IsNullOrEmpty(name))
53 name = typeof(TEvent).Name;
54 Name = name;
55 }
56
57 /// <summary>
58 /// Отправляет запись журнала через канал подписчикам.
59 /// </summary>
60 /// <param name="data">Запись журнала.</param>
61 /// <remarks>
62 /// Контекст трассировки от которого рассылается сообщение определяется автоматически из текущего потока.
63 /// </remarks>
18 public void LogEvent(TEvent data) {
64 public void LogEvent(TEvent data) {
19 var t = Events;
65 var t = Events;
20 if (t!= null)
66 if (t!= null)
21 t(TraceContext.Current,new ValueEventArgs<TEvent>(data));
67 t(TraceContext.Current,new ValueEventArgs<TEvent>(data));
22 }
68 }
23
69
70 /// <summary>
71 /// Отправляет запись журнала через канал подписчикам.
72 /// </summary>
73 /// <param name="data">Запись журнала.</param>
74 /// <param name="context">Контекст трассировки от которого рассылается сообщение/</param>
24 public void LogEvent(TraceContext context,TEvent data) {
75 public void LogEvent(TraceContext context,TEvent data) {
25 var t = Events;
76 var t = Events;
26 if (t != null)
77 if (t != null)
@@ -8,21 +8,23 namespace Implab.Diagnostics {
8 public class TextFileListener: TextListenerBase {
8 public class TextFileListener: TextListenerBase {
9 readonly TextWriter m_textWriter;
9 readonly TextWriter m_textWriter;
10
10
11 public TextFileListener(string fileName, bool local) : base(local) {
11 public TextFileListener(string fileName, bool global)
12 : base(global) {
12 m_textWriter = File.CreateText(fileName);
13 m_textWriter = File.CreateText(fileName);
13
14
14 m_textWriter.WriteLine("LOG {0}", DateTime.Now);
15 m_textWriter.WriteLine("LOG {0}", DateTime.Now);
15 Register(this);
16 Register(this);
16 }
17 }
17
18
18 protected override void WriteEntry(TraceContext context, EventText text) {
19 protected override void WriteEntry(TraceContext context, EventText text, string channel) {
19 var msg = new StringBuilder();
20 var msg = new StringBuilder();
20 for (int i = 0; i < text.indent; i++)
21 for (int i = 0; i < text.indent; i++)
21 msg.Append(" ");
22 msg.Append(" ");
22 msg.AppendFormat("[{0}]: {1}", context.ThreadId, text.content);
23 msg.AppendFormat("[{0}]:{1}: {2}", context.ThreadId, channel, text.content);
23
24
24 lock (m_textWriter) {
25 lock (m_textWriter) {
25 if (!IsDisposed) {
26 if (!IsDisposed) {
27 // тут гарантировано еще не освобожден m_textWriter
26 m_textWriter.WriteLine(msg.ToString());
28 m_textWriter.WriteLine(msg.ToString());
27 m_textWriter.Flush();
29 m_textWriter.Flush();
28 }
30 }
@@ -33,6 +35,7 namespace Implab.Diagnostics {
33 protected override void Dispose(bool disposing) {
35 protected override void Dispose(bool disposing) {
34 base.Dispose(disposing);
36 base.Dispose(disposing);
35 if (disposing) {
37 if (disposing) {
38 // IsDisposed = true
36 lock (m_textWriter) {
39 lock (m_textWriter) {
37 Safe.Dispose(m_textWriter);
40 Safe.Dispose(m_textWriter);
38 }
41 }
@@ -10,9 +10,9 namespace Implab.Diagnostics {
10 readonly LogicalOperation m_boundOperation;
10 readonly LogicalOperation m_boundOperation;
11 readonly int m_baseIndent;
11 readonly int m_baseIndent;
12
12
13 protected TextListenerBase(bool local) {
13 protected TextListenerBase(bool global) {
14 Register(this);
14 Register(this);
15 if (local) {
15 if (!global) {
16 m_boundOperation = TraceContext.Current.CurrentOperation;
16 m_boundOperation = TraceContext.Current.CurrentOperation;
17 m_baseIndent = Math.Max(0, m_boundOperation.Level - 1);
17 m_baseIndent = Math.Max(0, m_boundOperation.Level - 1);
18 }
18 }
@@ -36,6 +36,7 namespace Implab.Diagnostics {
36 AssertNotDisposed();
36 AssertNotDisposed();
37
37
38 var formatter = GetService<IEventTextFormatter<TEvent>>();
38 var formatter = GetService<IEventTextFormatter<TEvent>>();
39 var channelName = channel.Name;
39
40
40 EventHandler<ValueEventArgs<TEvent>> handler = (sender, args) => {
41 EventHandler<ValueEventArgs<TEvent>> handler = (sender, args) => {
41 TraceContext context = (TraceContext)sender;
42 TraceContext context = (TraceContext)sender;
@@ -43,7 +44,7 namespace Implab.Diagnostics {
43 text.indent -= m_baseIndent;
44 text.indent -= m_baseIndent;
44
45
45 if (IsRelated(context.CurrentOperation))
46 if (IsRelated(context.CurrentOperation))
46 WriteEntry(context, text);
47 WriteEntry(context, text, channelName);
47 };
48 };
48
49
49 if (m_subscriptions.ContainsKey(channel))
50 if (m_subscriptions.ContainsKey(channel))
@@ -89,7 +90,16 namespace Implab.Diagnostics {
89 }
90 }
90 }
91 }
91
92
92 protected abstract void WriteEntry(TraceContext context, EventText text);
93 /// <summary>
94 /// Вызывается для записи текста сообщения, в журнал.
95 /// </summary>
96 /// <remarks>
97 /// Данный метод может вызваться из разных потоков одновременно. Возможна ситуация, когда
98 /// данный метод вызывается уже после освобождения ообъекта методом <see cref="Dispose()"/>.
99 /// </remarks>
100 /// <param name="context">Контекст трассировки.</param>
101 /// <param name="text">Текст сообщения.</param>
102 protected abstract void WriteEntry(TraceContext context, EventText text, string channel);
93
103
94 public EventText Format(TraceContext context, object data) {
104 public EventText Format(TraceContext context, object data) {
95 return new EventText {
105 return new EventText {
@@ -110,10 +120,10 namespace Implab.Diagnostics {
110 }
120 }
111
121
112 protected override void Dispose(bool disposing) {
122 protected override void Dispose(bool disposing) {
123 base.Dispose(disposing);
113 if (disposing) {
124 if (disposing) {
114 UnsubscribeAll();
125 UnsubscribeAll();
115 }
126 }
116 base.Dispose(disposing);
117 }
127 }
118 }
128 }
119 }
129 }
@@ -25,18 +25,24 namespace Implab.Diagnostics {
25 /// </summary>
25 /// </summary>
26 public static TraceContext Current {
26 public static TraceContext Current {
27 get {
27 get {
28 if (_current == null)
28 if (_current == null) {
29 _current = new TraceContext();
29 _current = new TraceContext();
30 _current.LogEvent(TraceEventType.Created,"[{0}]", _current.ThreadId);
31 }
30 return _current;
32 return _current;
31 }
33 }
32 }
34 }
33
35
34 TraceContext(TraceContext context) {
36 TraceContext(TraceContext context)
37 : this(context, false) {
38 }
39
40 TraceContext(TraceContext context, bool attach) {
35 if (context == null)
41 if (context == null)
36 throw new ArgumentNullException("context");
42 throw new ArgumentNullException("context");
37
43
38 m_currentOperation = context.CurrentOperation;
44 m_currentOperation = context.CurrentOperation;
39 m_bound = context.CurrentOperation;
45 m_bound = attach ? context.BoundOperation : context.CurrentOperation;
40 m_threadId = Thread.CurrentThread.ManagedThreadId;
46 m_threadId = Thread.CurrentThread.ManagedThreadId;
41 }
47 }
42
48
@@ -57,15 +63,15 namespace Implab.Diagnostics {
57 /// контексте ранее начатые логические операции не могут быть завершены.
63 /// контексте ранее начатые логические операции не могут быть завершены.
58 /// </para>
64 /// </para>
59 /// <para>
65 /// <para>
60 /// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Transfer"/>.
66 /// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Fork"/>.
61 /// </para>
67 /// </para>
62 /// </remarks>
68 /// </remarks>
63 public static void Transfer(TraceContext from) {
69 public static void Fork(TraceContext from) {
64 if (_current == from)
70 if (_current == from)
65 return;
71 return;
66 if (from != null) {
72 if (from != null) {
67 var context = new TraceContext(from);
73 var context = new TraceContext(from);
68 context.LogEvent(TraceEventType.Transfer, "[{0}]-->[{1}]",from.ThreadId, context.ThreadId);
74 context.LogEvent(TraceEventType.Fork, "[{0}]-->[{1}]",from.ThreadId, context.ThreadId);
69 _current = context;
75 _current = context;
70 } else {
76 } else {
71 _current = new TraceContext();
77 _current = new TraceContext();
@@ -73,7 +79,40 namespace Implab.Diagnostics {
73 }
79 }
74
80
75 /// <summary>
81 /// <summary>
76 /// Создает постоянную копию текущего контекста, данную копию можно хранить и использовать для передачи через <see cref="Transfer(TraceContext)"/>
82 /// Задает текущему потоку указанный контекст, текущей поток может заканчивать ранее начатые
83 /// логические операции в указанном контексте.
84 /// </summary>
85 /// <param name="source"></param>
86 public static void Attach(TraceContext source) {
87 if (_current == source)
88 return;
89 if (source != null) {
90 var context = new TraceContext(source, true);
91 context.LogEvent(TraceEventType.Attach, "[{0}]-->[{1}]", source.ThreadId, context.ThreadId);
92 _current = context;
93 } else {
94 _current = new TraceContext();
95 }
96 }
97
98 /// <summary>
99 /// Отсоединяет текущий контекст трассировки от потока, для дальнейшей его передачи другому потоку
100 /// <see cref="Attach(TraceContext)"/>.
101 /// </summary>
102 /// <returns>Контекст трассировки потока</returns>
103 /// <remarks>
104 /// После отсоединения контекста трассировки от потока, при первом обращении к трассировке в этом
105 /// потоке будет создан новый контекст.
106 /// </remarks>
107 public static TraceContext Detach() {
108 var context = Current;
109 context.LogEvent(TraceEventType.Detach, null);
110 _current = null;
111 return context;
112 }
113
114 /// <summary>
115 /// Создает постоянную копию текущего контекста, данную копию можно хранить и использовать для передачи через <see cref="Fork(TraceContext)"/>
77 /// </summary>
116 /// </summary>
78 /// <returns>Копия текущего контекста трассировки.</returns>
117 /// <returns>Копия текущего контекста трассировки.</returns>
79 public static TraceContext Snapshot() {
118 public static TraceContext Snapshot() {
@@ -88,7 +127,7 namespace Implab.Diagnostics {
88 if (action == null)
127 if (action == null)
89 throw new ArgumentNullException("action");
128 throw new ArgumentNullException("action");
90 var old = _current;
129 var old = _current;
91 Transfer(this);
130 Fork(this);
92 try {
131 try {
93 action();
132 action();
94 } finally {
133 } finally {
@@ -11,6 +11,9 namespace Implab.Diagnostics {
11 Error,
11 Error,
12 OperationStarted,
12 OperationStarted,
13 OperationCompleted,
13 OperationCompleted,
14 Transfer
14 Fork,
15 Attach,
16 Detach,
17 Created
15 }
18 }
16 }
19 }
@@ -1,10 +1,14
1 using System;
1 using Implab.Diagnostics;
2 using System;
2 using System.Collections.Generic;
3 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Diagnostics;
4 using System.Linq;
5 using System.Linq;
5 using System.Web;
6 using System.Web;
6
7
7 namespace Implab {
8 namespace Implab {
9 /// <summary>
10 /// Объект, поддерживающий освобождение ресурсов.
11 /// </summary>
8 public class Disposable : IDisposable {
12 public class Disposable : IDisposable {
9
13
10 bool m_disposed;
14 bool m_disposed;
@@ -19,7 +23,16 namespace Implab {
19 if (m_disposed)
23 if (m_disposed)
20 throw new ObjectDisposedException(this.ToString());
24 throw new ObjectDisposedException(this.ToString());
21 }
25 }
22
26 /// <summary>
27 /// Переводит объект в состояние <c>Disposed</c> и вызывает событие <see cref="Disposed"/>
28 /// </summary>
29 /// <param name="disposing">Признак того, что нужно освободить ресурсы, иначе данный метод
30 /// вызван сборщиком мусора и нужно освобождать ТОЛЬКО неуправляемые ресурсы ТОЛЬКО этого
31 /// объекта.</param>
32 /// <remarks>
33 /// Данный метод осуществляет проверку того, что объект уже был освобожден, чтобы не вызывать
34 /// событие <see cref="Disposed"/>. Не поддерживает многопоточность.
35 /// </remarks>
23 protected virtual void Dispose(bool disposing) {
36 protected virtual void Dispose(bool disposing) {
24 if (disposing && !m_disposed) {
37 if (disposing && !m_disposed) {
25 m_disposed = true;
38 m_disposed = true;
@@ -34,8 +47,11 namespace Implab {
34 GC.SuppressFinalize(this);
47 GC.SuppressFinalize(this);
35 }
48 }
36
49
50 /// <summary>
51 /// Записывает сообщение об утечке объекта.
52 /// </summary>
37 protected virtual void ReportObjectLeaks() {
53 protected virtual void ReportObjectLeaks() {
38 Trace.TraceWarning("The object is marked as disposable but isn't disposed properly: {0}", this);
54 TraceLog.TraceWarning("The object is marked as disposable but isn't disposed properly: {0}", this);
39 }
55 }
40
56
41 ~Disposable() {
57 ~Disposable() {
@@ -52,7 +52,6
52 <Compile Include="IPromiseBase.cs" />
52 <Compile Include="IPromiseBase.cs" />
53 <Compile Include="IServiceLocator.cs" />
53 <Compile Include="IServiceLocator.cs" />
54 <Compile Include="ITaskController.cs" />
54 <Compile Include="ITaskController.cs" />
55 <Compile Include="ManagedPromise.cs" />
56 <Compile Include="Parallels\DispatchPool.cs" />
55 <Compile Include="Parallels\DispatchPool.cs" />
57 <Compile Include="Parallels\ArrayTraits.cs" />
56 <Compile Include="Parallels\ArrayTraits.cs" />
58 <Compile Include="Parallels\MTQueue.cs" />
57 <Compile Include="Parallels\MTQueue.cs" />
@@ -42,7 +42,7 namespace Implab.Parallels {
42 }
42 }
43
43
44 protected override void Worker() {
44 protected override void Worker() {
45 TraceContext.Transfer(m_traceContext);
45 TraceContext.Fork(m_traceContext);
46 base.Worker();
46 base.Worker();
47 }
47 }
48
48
@@ -99,7 +99,7 namespace Implab.Parallels {
99 }
99 }
100
100
101 protected override void Worker() {
101 protected override void Worker() {
102 TraceContext.Transfer(m_traceContext);
102 TraceContext.Fork(m_traceContext);
103 base.Worker();
103 base.Worker();
104 }
104 }
105
105
@@ -12,12 +12,12 namespace Implab.Parallels {
12 /// </remarks>
12 /// </remarks>
13 public static class AsyncPool {
13 public static class AsyncPool {
14
14
15 public static Promise<T> Invoke<T>(Func<T> func) {
15 public static IPromise<T> Invoke<T>(Func<T> func) {
16 var p = new Promise<T>();
16 var p = new Promise<T>();
17 var caller = TraceContext.Snapshot();
17 var caller = TraceContext.Snapshot();
18
18
19 ThreadPool.QueueUserWorkItem(param => {
19 ThreadPool.QueueUserWorkItem(param => {
20 TraceContext.Transfer(caller);
20 TraceContext.Fork(caller);
21 try {
21 try {
22 p.Resolve(func());
22 p.Resolve(func());
23 } catch(Exception e) {
23 } catch(Exception e) {
@@ -28,13 +28,13 namespace Implab.Parallels {
28 return p;
28 return p;
29 }
29 }
30
30
31 public static Promise<T> InvokeNewThread<T>(Func<T> func) {
31 public static IPromise<T> InvokeNewThread<T>(Func<T> func) {
32 var p = new Promise<T>();
32 var p = new Promise<T>();
33
33
34 var caller = TraceContext.Snapshot();
34 var caller = TraceContext.Snapshot();
35
35
36 var worker = new Thread(() => {
36 var worker = new Thread(() => {
37 TraceContext.Transfer(caller);
37 TraceContext.Fork(caller);
38 try {
38 try {
39 p.Resolve(func());
39 p.Resolve(func());
40 } catch (Exception e) {
40 } catch (Exception e) {
@@ -46,5 +46,26 namespace Implab.Parallels {
46
46
47 return p;
47 return p;
48 }
48 }
49
50
51 public static IPromiseBase InvokeNewThread(Action func) {
52 var p = new Promise<object>();
53
54 var caller = TraceContext.Snapshot();
55
56 var worker = new Thread(() => {
57 TraceContext.Fork(caller);
58 try {
59 func();
60 p.Resolve();
61 } catch (Exception e) {
62 p.Reject(e);
63 }
64 });
65 worker.IsBackground = true;
66 worker.Start();
67
68 return p;
49 }
69 }
50 }
70 }
71 }
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now