##// END OF EJS Templates
Interactive tracing...
cin -
r48:d9d794b61bb9 interactive logger
parent child
Show More
@@ -1,107 +1,122
1 1 using Implab.Parallels;
2 2 using System;
3 3 using System.Collections.Generic;
4 4 using System.Linq;
5 5 using System.Text;
6 6 using System.Threading;
7 7 using System.Threading.Tasks;
8 8 using System.Windows.Forms;
9 9
10 10 namespace Implab.Diagnostics.Interactive
11 11 {
12 public class InteractiveListener: Disposable
12 public class InteractiveListener: TextListenerBase
13 13 {
14 14 TraceForm m_form;
15 15
16 16 SynchronizationContext m_syncGuiThread;
17 readonly Promise<object> m_guiStarted = new Promise<object>();
17 18
18 19 readonly IPromiseBase m_guiFinished;
19 readonly Promise<object> m_guiStarted = new Promise<object>();
20
21 20 readonly IPromiseBase m_workerFinished = new Promise<object>();
22 21
23 22 readonly MTQueue<TraceViewItem> m_queue = new MTQueue<TraceViewItem>();
24 23 readonly AutoResetEvent m_queueEvent = new AutoResetEvent(false);
25 24
26 25 int m_queueLength;
27 26 bool m_exitPending;
28 27
29 28 readonly object m_pauseLock = new object();
30 29 bool m_paused;
31 30 readonly ManualResetEvent m_pauseEvent = new ManualResetEvent(true);
32 31
33 public InteractiveListener() {
34 m_guiFinished = AsyncPool.InvokeNewThread(() => {
35 GuiThread();
36 return 0;
37 });
32 public InteractiveListener(bool global) : base(global) {
33 m_guiFinished = AsyncPool.InvokeNewThread(GuiThread);
34 m_workerFinished = AsyncPool.InvokeNewThread(QueueThread);
38 35
39 36 m_guiStarted.Join();
40 37 }
41 38
42 39 void GuiThread() {
43 40 m_form = new TraceForm(); // will create SynchronizationContext
41
42 m_form.PauseEvents += (s,a) => Pause();
43 m_form.ResumeEvents += (s, a) => Resume();
44
44 45 m_syncGuiThread = SynchronizationContext.Current;
45 46 m_guiStarted.Resolve();
46 47 Application.Run();
47 48 }
48 49
49 50 void QueueThread() {
50 51 while (!m_exitPending) {
51 52 if (m_paused)
52 53 m_pauseEvent.WaitOne();
53 54
54 55 TraceViewItem item;
55 56 if (m_queue.TryDequeue(out item)) {
56 57 Interlocked.Decrement(ref m_queueLength);
57 58
58 59 m_syncGuiThread.Send(x => m_form.AddTraceEvent(item),null);
59 60 } else {
60 61 m_queueEvent.WaitOne();
61 62 }
62 63 }
63 64 }
64 65
65 66 public void Pause() {
66 67 // for consistency we need to set this properties atomically
67 68 lock (m_pauseLock) {
68 69 m_pauseEvent.Reset();
69 70 m_paused = true;
70 71 }
71 72 }
72 73
73 74 public void Resume() {
74 75 // for consistency we need to set this properties atomically
75 76 lock (m_pauseLock) {
76 77 m_paused = false;
77 78 m_pauseEvent.Set();
78 79 }
79 80 }
80 81
81 82 void Enqueue(TraceViewItem item) {
82 83 m_queue.Enqueue(item);
83 84 if (Interlocked.Increment(ref m_queueLength) == 1)
84 85 m_queueEvent.Set();
85 86 }
86 87
87 88 public void ShowForm() {
88 89 m_syncGuiThread.Post(x => m_form.Show(), null);
89 90 }
90 91
91 92 public void HideForm() {
92 93 m_syncGuiThread.Post(x => m_form.Hide(), null);
93 94 }
94 95
95 96 void Terminate() {
97 m_exitPending = true;
98 Resume();
96 99 m_syncGuiThread.Post(x => Application.ExitThread(), null);
97 100 }
98 101
99 102 protected override void Dispose(bool disposing) {
100 103 if (disposing) {
101 104 Terminate();
102 105 m_guiFinished.Join();
103 106 }
104 107 base.Dispose(disposing);
105 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 }
106 121 }
107 122 }
@@ -1,122 +1,134
1 1 namespace Implab.Diagnostics.Interactive {
2 2 partial class TraceForm {
3 3 /// <summary>
4 4 /// Required designer variable.
5 5 /// </summary>
6 6 private System.ComponentModel.IContainer components = null;
7 7
8 8 /// <summary>
9 9 /// Clean up any resources being used.
10 10 /// </summary>
11 11 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
12 12 protected override void Dispose(bool disposing) {
13 13 if (disposing && (components != null)) {
14 14 components.Dispose();
15 15 }
16 16 base.Dispose(disposing);
17 17 }
18 18
19 19 #region Windows Form Designer generated code
20 20
21 21 /// <summary>
22 22 /// Required method for Designer support - do not modify
23 23 /// the contents of this method with the code editor.
24 24 /// </summary>
25 25 private void InitializeComponent() {
26 26 this.components = new System.ComponentModel.Container();
27 27 System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
28 28 System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
29 29 System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
30 30 this.eventsDataGrid = new System.Windows.Forms.DataGridView();
31 31 this.traceViewItemBindingSource = new System.Windows.Forms.BindingSource(this.components);
32 32 this.threadDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
33 this.Channel = new System.Windows.Forms.DataGridViewTextBoxColumn();
33 34 this.messageDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
34 35 ((System.ComponentModel.ISupportInitialize)(this.eventsDataGrid)).BeginInit();
35 36 ((System.ComponentModel.ISupportInitialize)(this.traceViewItemBindingSource)).BeginInit();
36 37 this.SuspendLayout();
37 38 //
38 39 // eventsDataGrid
39 40 //
40 41 this.eventsDataGrid.AllowUserToAddRows = false;
41 42 this.eventsDataGrid.AllowUserToDeleteRows = false;
42 43 this.eventsDataGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
43 44 | System.Windows.Forms.AnchorStyles.Left)
44 45 | System.Windows.Forms.AnchorStyles.Right)));
45 46 this.eventsDataGrid.AutoGenerateColumns = false;
46 47 this.eventsDataGrid.BackgroundColor = System.Drawing.SystemColors.Window;
47 48 dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
48 49 dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
49 50 dataGridViewCellStyle1.Font = new System.Drawing.Font("Lucida Console", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
50 51 dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
51 52 dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
52 53 dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
53 54 dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
54 55 this.eventsDataGrid.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
55 56 this.eventsDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
56 57 this.eventsDataGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
57 58 this.threadDataGridViewTextBoxColumn,
59 this.Channel,
58 60 this.messageDataGridViewTextBoxColumn});
59 61 this.eventsDataGrid.DataSource = this.traceViewItemBindingSource;
60 62 dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
61 63 dataGridViewCellStyle3.BackColor = System.Drawing.SystemColors.Window;
62 64 dataGridViewCellStyle3.Font = new System.Drawing.Font("Lucida Console", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
63 65 dataGridViewCellStyle3.ForeColor = System.Drawing.SystemColors.ControlText;
64 66 dataGridViewCellStyle3.SelectionBackColor = System.Drawing.SystemColors.Highlight;
65 67 dataGridViewCellStyle3.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
66 68 dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
67 69 this.eventsDataGrid.DefaultCellStyle = dataGridViewCellStyle3;
68 70 this.eventsDataGrid.Location = new System.Drawing.Point(12, 12);
69 71 this.eventsDataGrid.Name = "eventsDataGrid";
70 72 this.eventsDataGrid.ReadOnly = true;
71 73 this.eventsDataGrid.RowHeadersWidth = 17;
72 74 this.eventsDataGrid.RowTemplate.Resizable = System.Windows.Forms.DataGridViewTriState.False;
73 75 this.eventsDataGrid.Size = new System.Drawing.Size(939, 480);
74 76 this.eventsDataGrid.TabIndex = 1;
75 77 this.eventsDataGrid.CellFormatting += new System.Windows.Forms.DataGridViewCellFormattingEventHandler(this.eventsDataGrid_CellFormatting);
76 78 //
77 79 // traceViewItemBindingSource
78 80 //
79 81 this.traceViewItemBindingSource.DataSource = typeof(Implab.Diagnostics.Interactive.TraceViewItem);
80 82 //
81 83 // threadDataGridViewTextBoxColumn
82 84 //
83 85 this.threadDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
84 86 this.threadDataGridViewTextBoxColumn.DataPropertyName = "Thread";
85 87 this.threadDataGridViewTextBoxColumn.HeaderText = "TID";
86 88 this.threadDataGridViewTextBoxColumn.Name = "threadDataGridViewTextBoxColumn";
87 89 this.threadDataGridViewTextBoxColumn.ReadOnly = true;
88 90 this.threadDataGridViewTextBoxColumn.Width = 5;
89 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 //
90 101 // messageDataGridViewTextBoxColumn
91 102 //
92 103 this.messageDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
93 104 this.messageDataGridViewTextBoxColumn.DataPropertyName = "FormattedMessage";
94 105 dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
95 106 this.messageDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle2;
96 107 this.messageDataGridViewTextBoxColumn.HeaderText = "Message";
97 108 this.messageDataGridViewTextBoxColumn.Name = "messageDataGridViewTextBoxColumn";
98 109 this.messageDataGridViewTextBoxColumn.ReadOnly = true;
99 110 //
100 111 // TraceForm
101 112 //
102 113 this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
103 114 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
104 115 this.ClientSize = new System.Drawing.Size(963, 504);
105 116 this.Controls.Add(this.eventsDataGrid);
106 117 this.Name = "TraceForm";
107 118 this.Text = "TraceForm";
108 119 ((System.ComponentModel.ISupportInitialize)(this.eventsDataGrid)).EndInit();
109 120 ((System.ComponentModel.ISupportInitialize)(this.traceViewItemBindingSource)).EndInit();
110 121 this.ResumeLayout(false);
111 122
112 123 }
113 124
114 125 #endregion
115 126
116 127 private System.Windows.Forms.DataGridView eventsDataGrid;
117 128 private System.Windows.Forms.BindingSource traceViewItemBindingSource;
118 129 private System.Windows.Forms.DataGridViewTextBoxColumn threadDataGridViewTextBoxColumn;
130 private System.Windows.Forms.DataGridViewTextBoxColumn Channel;
119 131 private System.Windows.Forms.DataGridViewTextBoxColumn messageDataGridViewTextBoxColumn;
120 132
121 133 }
122 134 } No newline at end of file
@@ -1,58 +1,53
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.ComponentModel;
4 4 using System.Data;
5 5 using System.Drawing;
6 6 using System.Linq;
7 7 using System.Text;
8 8 using System.Threading.Tasks;
9 9 using System.Windows.Forms;
10 10
11 11 namespace Implab.Diagnostics.Interactive {
12 12 public partial class TraceForm : Form {
13 13 readonly Dictionary<int, Color> m_threadColors = new Dictionary<int,Color>();
14 14 readonly Random m_rand = new Random();
15 15
16 public event EventHandler PauseEvents;
17
18 public event EventHandler ResumeEvents;
19
16 20 public TraceForm() {
17 21 InitializeComponent();
18
19 22 }
20 23
21 24 protected override void OnFormClosing(FormClosingEventArgs e) {
22 25 base.OnFormClosing(e);
23 26 if (!e.Cancel && e.CloseReason == CloseReason.UserClosing) {
24 27 e.Cancel = true;
25 28 Hide();
26 29 }
27 30 }
28 31
29 public void AddTraceEvent(int indent, int thread, string message) {
30 traceViewItemBindingSource.Add(new TraceViewItem {
31 Indent = indent,
32 Thread = thread,
33 Message = message,
34 Timestamp = Environment.TickCount
35 });
36
37 }
38
39 32 public void AddTraceEvent(TraceViewItem item) {
40 33 traceViewItemBindingSource.Add(item);
34 eventsDataGrid.FirstDisplayedScrollingRowIndex = eventsDataGrid.RowCount - 1;
41 35 }
42 36
43 37 Color GetThreadColor(int thread) {
44 38 Color result;
45 39 if (!m_threadColors.TryGetValue(thread, out result)) {
46 40 result = Color.FromArgb(m_rand.Next(4)*64, m_rand.Next(4)*64, m_rand.Next(4)*64);
47 41 m_threadColors[thread] = result;
48 42 }
49 43 return result;
50 44 }
51 45
52 46 private void eventsDataGrid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) {
53 47 var data = (TraceViewItem)traceViewItemBindingSource[e.RowIndex];
54 e.CellStyle.Padding = new Padding(data.Indent * 10,0,0,0);
48 if (e.ColumnIndex == messageDataGridViewTextBoxColumn.Index)
49 e.CellStyle.Padding = new Padding(data.Indent * 10,0,0,0);
55 50 e.CellStyle.ForeColor = GetThreadColor(data.Thread);
56 51 }
57 52 }
58 53 }
@@ -1,123 +1,126
1 1 ο»Ώ<?xml version="1.0" encoding="utf-8"?>
2 2 <root>
3 3 <!--
4 4 Microsoft ResX Schema
5 5
6 6 Version 2.0
7 7
8 8 The primary goals of this format is to allow a simple XML format
9 9 that is mostly human readable. The generation and parsing of the
10 10 various data types are done through the TypeConverter classes
11 11 associated with the data types.
12 12
13 13 Example:
14 14
15 15 ... ado.net/XML headers & schema ...
16 16 <resheader name="resmimetype">text/microsoft-resx</resheader>
17 17 <resheader name="version">2.0</resheader>
18 18 <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
19 19 <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
20 20 <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
21 21 <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
22 22 <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
23 23 <value>[base64 mime encoded serialized .NET Framework object]</value>
24 24 </data>
25 25 <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
26 26 <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
27 27 <comment>This is a comment</comment>
28 28 </data>
29 29
30 30 There are any number of "resheader" rows that contain simple
31 31 name/value pairs.
32 32
33 33 Each data row contains a name, and value. The row also contains a
34 34 type or mimetype. Type corresponds to a .NET class that support
35 35 text/value conversion through the TypeConverter architecture.
36 36 Classes that don't support this are serialized and stored with the
37 37 mimetype set.
38 38
39 39 The mimetype is used for serialized objects, and tells the
40 40 ResXResourceReader how to depersist the object. This is currently not
41 41 extensible. For a given mimetype the value must be set accordingly:
42 42
43 43 Note - application/x-microsoft.net.object.binary.base64 is the format
44 44 that the ResXResourceWriter will generate, however the reader can
45 45 read any of the formats listed below.
46 46
47 47 mimetype: application/x-microsoft.net.object.binary.base64
48 48 value : The object must be serialized with
49 49 : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
50 50 : and then encoded with base64 encoding.
51 51
52 52 mimetype: application/x-microsoft.net.object.soap.base64
53 53 value : The object must be serialized with
54 54 : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
55 55 : and then encoded with base64 encoding.
56 56
57 57 mimetype: application/x-microsoft.net.object.bytearray.base64
58 58 value : The object must be serialized into a byte array
59 59 : using a System.ComponentModel.TypeConverter
60 60 : and then encoded with base64 encoding.
61 61 -->
62 62 <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
63 63 <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
64 64 <xsd:element name="root" msdata:IsDataSet="true">
65 65 <xsd:complexType>
66 66 <xsd:choice maxOccurs="unbounded">
67 67 <xsd:element name="metadata">
68 68 <xsd:complexType>
69 69 <xsd:sequence>
70 70 <xsd:element name="value" type="xsd:string" minOccurs="0" />
71 71 </xsd:sequence>
72 72 <xsd:attribute name="name" use="required" type="xsd:string" />
73 73 <xsd:attribute name="type" type="xsd:string" />
74 74 <xsd:attribute name="mimetype" type="xsd:string" />
75 75 <xsd:attribute ref="xml:space" />
76 76 </xsd:complexType>
77 77 </xsd:element>
78 78 <xsd:element name="assembly">
79 79 <xsd:complexType>
80 80 <xsd:attribute name="alias" type="xsd:string" />
81 81 <xsd:attribute name="name" type="xsd:string" />
82 82 </xsd:complexType>
83 83 </xsd:element>
84 84 <xsd:element name="data">
85 85 <xsd:complexType>
86 86 <xsd:sequence>
87 87 <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
88 88 <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
89 89 </xsd:sequence>
90 90 <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
91 91 <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
92 92 <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
93 93 <xsd:attribute ref="xml:space" />
94 94 </xsd:complexType>
95 95 </xsd:element>
96 96 <xsd:element name="resheader">
97 97 <xsd:complexType>
98 98 <xsd:sequence>
99 99 <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
100 100 </xsd:sequence>
101 101 <xsd:attribute name="name" type="xsd:string" use="required" />
102 102 </xsd:complexType>
103 103 </xsd:element>
104 104 </xsd:choice>
105 105 </xsd:complexType>
106 106 </xsd:element>
107 107 </xsd:schema>
108 108 <resheader name="resmimetype">
109 109 <value>text/microsoft-resx</value>
110 110 </resheader>
111 111 <resheader name="version">
112 112 <value>2.0</value>
113 113 </resheader>
114 114 <resheader name="reader">
115 115 <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
116 116 </resheader>
117 117 <resheader name="writer">
118 118 <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119 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>
120 123 <metadata name="traceViewItemBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
121 124 <value>17, 17</value>
122 125 </metadata>
123 126 </root> No newline at end of file
@@ -1,25 +1,26
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Threading.Tasks;
6 6
7 7 namespace Implab.Diagnostics.Interactive {
8 8 public class TraceViewItem {
9 9 string m_formattedValue;
10 10
11 11 public string Message { get; set; }
12 12 public int Timestamp { get; set; }
13 13 public int Indent { get; set; }
14 14 public int Thread { get; set; }
15 public string Channel { get; set; }
15 16
16 17 public string FormattedMessage {
17 18 get {
18 19 if (m_formattedValue == null) {
19 20 m_formattedValue = Message.Replace("\r",String.Empty).Replace("\n", " | ");
20 21 }
21 22 return m_formattedValue;
22 23 }
23 24 }
24 25 }
25 26 }
@@ -1,34 +1,34
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5
6 6 namespace Implab.Diagnostics {
7 7 public class ConsoleTraceListener: TextListenerBase {
8 8
9 9 static readonly object _consoleLock = new object();
10 10
11 11 public ConsoleTraceListener()
12 12 : base(true) {
13 13
14 14 }
15 15
16 public ConsoleTraceListener(bool local)
17 : base(local) {
16 public ConsoleTraceListener(bool global)
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 22 var msg = new StringBuilder();
23 23
24 24 for (int i = 0; i < text.indent; i++)
25 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 28 lock (_consoleLock) {
29 29 Console.ForegroundColor = (ConsoleColor)(context.ThreadId % 15 + 1);
30 30 Console.WriteLine(msg.ToString());
31 31 }
32 32 }
33 33 }
34 34 }
@@ -1,30 +1,81
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5
6 6 namespace Implab.Diagnostics {
7 /// <summary>
8 /// Канал, Ρ‡Π΅Ρ€Π΅Π· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΡƒΠ±Π»ΠΈΠΊΡƒΡŽΡ‚ΡΡ события ΠΆΡƒΡ€Π½Π°Π»Π°.
9 /// </summary>
10 /// <typeparam name="TEvent">Π’ΠΈΠΏ событий Π² ΠΊΠ°Π½Π°Π»Π΅</typeparam>
11 /// <remarks>
12 /// Бобытиями ΠΆΡƒΡ€Π½Π°Π»Π° ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Π»ΡŽΠ±Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ строки, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒΡΡ
13 /// информация, ΠΈΠ»ΠΈ структуры с Π½Π°Π±ΠΎΡ€ΠΎΠΌ ΠΏΠΎΠ»Π΅ΠΉ, ΠΎΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‰ΠΈΡ… Π²Π°ΠΆΠ½ΠΎΡΡ‚ΡŒ, тСкст ΠΈ Π΄Ρ€ΡƒΠ³ΡƒΡŽ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ.
14 /// </remarks>
7 15 public class LogChannel<TEvent> {
8 16 static LogChannel<TEvent> _default = new LogChannel<TEvent>();
9 17
18 /// <summary>
19 /// Канал ΠΏΠΎ-ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ для событий Ρ‚ΠΈΠΏΠ° <typeparam name="TEvent"/>.
20 /// </summary>
10 21 public static LogChannel<TEvent> Default {
11 22 get {
12 23 return _default;
13 24 }
14 25 }
15 26
27 /// <summary>
28 /// Π‘ΠΎΠ±Ρ‹Ρ‚ΠΈΠ΅ появлСниС Π½ΠΎΠ²ΠΎΠΉ записи Π² ΠΆΡƒΡ€Π½Π°Π»Π΅, Π½Π° это событиС ΠΏΠΎΠ΄ΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‚ΡΡ ΡΠ»ΡƒΡˆΠ°Ρ‚Π΅Π»ΠΈ.
29 /// </summary>
16 30 public event EventHandler<ValueEventArgs<TEvent>> Events;
31
32 /// <summary>
33 /// Имя ΠΊΠ°Π½Π°Π»Π°, ΠΏΠΎΠ»Π΅Π·Π½ΠΎ для отобраТСния Π² ΠΆΡƒΡ€Π½Π°Π»Π΅
34 /// </summary>
35 public string Name {
36 get;
37 private set;
38 }
17 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 64 public void LogEvent(TEvent data) {
19 65 var t = Events;
20 66 if (t!= null)
21 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 75 public void LogEvent(TraceContext context,TEvent data) {
25 76 var t = Events;
26 77 if (t != null)
27 78 t(context, new ValueEventArgs<TEvent>(data));
28 79 }
29 80 }
30 81 }
@@ -1,46 +1,47
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.IO;
4 4 using System.Linq;
5 5 using System.Text;
6 6
7 7 namespace Implab.Diagnostics {
8 8 public class TextFileListener: TextListenerBase {
9 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 13 m_textWriter = File.CreateText(fileName);
13 14
14 15 m_textWriter.WriteLine("LOG {0}", DateTime.Now);
15 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 20 var msg = new StringBuilder();
20 21 for (int i = 0; i < text.indent; i++)
21 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 25 lock (m_textWriter) {
25 26 if (!IsDisposed) {
26 27 // Ρ‚ΡƒΡ‚ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ Π΅Ρ‰Π΅ Π½Π΅ освобоТдСн m_textWriter
27 28 m_textWriter.WriteLine(msg.ToString());
28 29 m_textWriter.Flush();
29 30 }
30 31 }
31 32 }
32 33
33 34
34 35 protected override void Dispose(bool disposing) {
35 36 base.Dispose(disposing);
36 37 if (disposing) {
37 38 // IsDisposed = true
38 39 lock (m_textWriter) {
39 40 Safe.Dispose(m_textWriter);
40 41 }
41 42 }
42 43 }
43 44
44 45
45 46 }
46 47 }
@@ -1,128 +1,129
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5
6 6 namespace Implab.Diagnostics {
7 7 public abstract class TextListenerBase : ServiceLocator, IEventTextFormatter<object>, IEventTextFormatter<TraceEvent> {
8 8
9 9 readonly Dictionary<object, Action> m_subscriptions = new Dictionary<object, Action>();
10 10 readonly LogicalOperation m_boundOperation;
11 11 readonly int m_baseIndent;
12 12
13 protected TextListenerBase(bool local) {
13 protected TextListenerBase(bool global) {
14 14 Register(this);
15 if (local) {
15 if (!global) {
16 16 m_boundOperation = TraceContext.Current.CurrentOperation;
17 17 m_baseIndent = Math.Max(0, m_boundOperation.Level - 1);
18 18 }
19 19 }
20 20
21 21 public void Subscribe(Type eventType) {
22 22 if (eventType == null)
23 23 throw new ArgumentNullException("eventType");
24 24 GetType().GetMethod("Subscribe", new Type[0]).MakeGenericMethod(eventType).Invoke(this, null);
25 25 }
26 26
27 27 public void Subscribe<TEvent>() {
28 28 Subscribe<TEvent>(LogChannel<TEvent>.Default);
29 29 }
30 30
31 31 public void Subscribe<TEvent>(LogChannel<TEvent> channel) {
32 32 if (channel == null)
33 33 throw new ArgumentNullException("channel");
34 34
35 35 lock (m_subscriptions) {
36 36 AssertNotDisposed();
37 37
38 38 var formatter = GetService<IEventTextFormatter<TEvent>>();
39 var channelName = channel.Name;
39 40
40 41 EventHandler<ValueEventArgs<TEvent>> handler = (sender, args) => {
41 42 TraceContext context = (TraceContext)sender;
42 43 var text = formatter.Format(context, args.Value);
43 44 text.indent -= m_baseIndent;
44 45
45 46 if (IsRelated(context.CurrentOperation))
46 WriteEntry(context, text);
47 WriteEntry(context, text, channelName);
47 48 };
48 49
49 50 if (m_subscriptions.ContainsKey(channel))
50 51 return;
51 52
52 53 channel.Events += handler;
53 54
54 55 Action unsubscribe = () => {
55 56 channel.Events -= handler;
56 57 };
57 58
58 59 m_subscriptions.Add(channel, unsubscribe);
59 60 }
60 61 }
61 62
62 63 public bool IsRelated(LogicalOperation op) {
63 64 if (m_boundOperation == null)
64 65 return true;
65 66
66 67 while (op != m_boundOperation && op.Level > m_boundOperation.Level)
67 68 op = op.Parent;
68 69 return op == m_boundOperation;
69 70 }
70 71
71 72 public void Unsubscribe<TEvent>(LogChannel<TEvent> channel) {
72 73 if (channel == null)
73 74 throw new ArgumentNullException("channel");
74 75
75 76 lock (m_subscriptions) {
76 77 Action subscription;
77 78 if (m_subscriptions.TryGetValue(channel, out subscription)) {
78 79 subscription();
79 80 m_subscriptions.Remove(channel);
80 81 }
81 82 }
82 83 }
83 84
84 85 public void UnsubscribeAll() {
85 86 lock (m_subscriptions) {
86 87 foreach (var subscription in m_subscriptions.Values)
87 88 subscription();
88 89 m_subscriptions.Clear();
89 90 }
90 91 }
91 92
92 93 /// <summary>
93 94 /// ВызываСтся для записи тСкста сообщСния, Π² ΠΆΡƒΡ€Π½Π°Π».
94 95 /// </summary>
95 96 /// <remarks>
96 97 /// Π”Π°Π½Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒΡΡ ΠΈΠ· Ρ€Π°Π·Π½Ρ‹Ρ… ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ. Π’ΠΎΠ·ΠΌΠΎΠΆΠ½Π° ситуация, ΠΊΠΎΠ³Π΄Π°
97 98 /// Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ вызываСтся ΡƒΠΆΠ΅ послС освобоТдСния ΠΎΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠΌ <see cref="Dispose()"/>.
98 99 /// </remarks>
99 100 /// <param name="context">ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ трассировки.</param>
100 101 /// <param name="text">ВСкст сообщСния.</param>
101 protected abstract void WriteEntry(TraceContext context, EventText text);
102 protected abstract void WriteEntry(TraceContext context, EventText text, string channel);
102 103
103 104 public EventText Format(TraceContext context, object data) {
104 105 return new EventText {
105 106 indent = context.CurrentOperation.Level,
106 107 content = data.ToString()
107 108 };
108 109 }
109 110
110 111 public EventText Format(TraceContext context, TraceEvent data) {
111 112 var level = context.CurrentOperation.Level;
112 113 if (data.EventType == TraceEventType.OperationCompleted || data.EventType == TraceEventType.OperationStarted)
113 114 level--;
114 115
115 116 return new EventText {
116 117 indent = level,
117 118 content = data.ToString()
118 119 };
119 120 }
120 121
121 122 protected override void Dispose(bool disposing) {
122 123 base.Dispose(disposing);
123 124 if (disposing) {
124 125 UnsubscribeAll();
125 126 }
126 127 }
127 128 }
128 129 }
@@ -1,172 +1,211
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Threading;
6 6 using System.Threading.Tasks;
7 7
8 8 namespace Implab.Diagnostics {
9 9 /// <summary>
10 10 /// ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ трассировки, привязываСтся ΠΊ ΠΏΠΎΡ‚ΠΎΠΊΡƒ ΠΈ содСрТит Π² сСбС ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΎ стСкС логичСских ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ.
11 11 /// </summary>
12 12 /// <remarks>
13 13 /// ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ трассировки пСрСдаСтся ΡΠ»ΡƒΡˆΠ°Ρ‚Π΅Π»ΡΠΌ событий для опрСдСлСния мСста, Π³Π΄Π΅ Π²ΠΎΠ·Π½ΠΈΠΊΠ»ΠΎ событиС.
14 14 /// </remarks>
15 15 public class TraceContext {
16 16 LogicalOperation m_currentOperation;
17 17 readonly LogicalOperation m_bound;
18 18 readonly int m_threadId;
19 19
20 20 [ThreadStatic]
21 21 static TraceContext _current;
22 22
23 23 /// <summary>
24 24 /// Π’Π΅ΠΊΡƒΡ‰ΠΈΠΉ контСкст трассировки для ΠΏΠΎΡ‚ΠΎΠΊΠ°, создаСтся астоматичСски ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΌ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠΈ.
25 25 /// </summary>
26 26 public static TraceContext Current {
27 27 get {
28 if (_current == null)
28 if (_current == null) {
29 29 _current = new TraceContext();
30 _current.LogEvent(TraceEventType.Created,"[{0}]", _current.ThreadId);
31 }
30 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 41 if (context == null)
36 42 throw new ArgumentNullException("context");
37 43
38 44 m_currentOperation = context.CurrentOperation;
39 m_bound = context.CurrentOperation;
45 m_bound = attach ? context.BoundOperation : context.CurrentOperation;
40 46 m_threadId = Thread.CurrentThread.ManagedThreadId;
41 47 }
42 48
43 49 TraceContext() {
44 50 m_currentOperation = new LogicalOperation();
45 51 m_bound = m_currentOperation;
46 52 m_threadId = Thread.CurrentThread.ManagedThreadId;
47 53 }
48 54
49 55 /// <summary>
50 56 /// ΠŸΡ€ΠΈ нСобходимости ΠΊΠΎΠΏΠΈΡ€ΡƒΠ΅Ρ‚ состояниС контСкста трассивровки Π² Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΏΠΎΡ‚ΠΎΠΊ.
51 57 /// </summary>
52 58 /// <param name="from">Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ контСкст трассировки, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ пСрСдаСтся.</param>
53 59 /// <remarks>
54 60 /// <para>
55 61 /// ΠšΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ происходит Π·Π° счСт создания Π½ΠΎΠ²ΠΎΠ³ΠΎ контСкста трассировки ΠΈ Π·Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ΠΌ Π΅Π³ΠΎ
56 62 /// состояния ΠΈΠ· ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½ΠΎΠ³ΠΎ контСкста. ΠŸΡ€ΠΈ этом копируСтся стСк ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ, ΠΎΠ΄Π½Π°ΠΊΠΎ Π² Π½ΠΎΠ²ΠΎΠΌ
57 63 /// контСкстС Ρ€Π°Π½Π΅Π΅ Π½Π°Ρ‡Π°Ρ‚Ρ‹Π΅ логичСскиС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Π½Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½Ρ‹.
58 64 /// </para>
59 65 /// <para>
60 /// Если ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° состояния ΡΠΎΡΡ‚ΠΎΡΠ»Π°ΡΡŒ, Ρ‚ΠΎ вызываСтся событиС трассировки <see cref="TraceEventType.Transfer"/>.
66 /// Если ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° состояния ΡΠΎΡΡ‚ΠΎΡΠ»Π°ΡΡŒ, Ρ‚ΠΎ вызываСтся событиС трассировки <see cref="TraceEventType.Fork"/>.
61 67 /// </para>
62 68 /// </remarks>
63 public static void Transfer(TraceContext from) {
69 public static void Fork(TraceContext from) {
64 70 if (_current == from)
65 71 return;
66 72 if (from != null) {
67 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 75 _current = context;
70 76 } else {
71 77 _current = new TraceContext();
72 78 }
73 79 }
74 80
75 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 116 /// </summary>
78 117 /// <returns>Копия Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ контСкста трассировки.</returns>
79 118 public static TraceContext Snapshot() {
80 119 return _current == null ? new TraceContext() : new TraceContext(_current);
81 120 }
82 121
83 122 /// <summary>
84 123 /// ВыполняСт ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½ΠΎΠ΅ дСйствиС Π² ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΌ контСкстС трассировки, ΠΏΠΎ ΠΎΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΠΈ восстанавливаСт ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΉ контСкст трассировки ΠΏΠΎΡ‚ΠΎΠΊΠ°.
85 124 /// </summary>
86 125 /// <param name="action"></param>
87 126 public void Invoke(Action action) {
88 127 if (action == null)
89 128 throw new ArgumentNullException("action");
90 129 var old = _current;
91 Transfer(this);
130 Fork(this);
92 131 try {
93 132 action();
94 133 } finally {
95 134 _current.EndAllOperations();
96 135 _current = old;
97 136 }
98 137 }
99 138
100 139 /// <summary>
101 140 /// ВСкущая логичСская опСрация.
102 141 /// </summary>
103 142 public LogicalOperation CurrentOperation {
104 143 get {
105 144 return m_currentOperation;
106 145 }
107 146 }
108 147
109 148 /// <summary>
110 149 /// ΠžΠΏΠ΅Ρ€Π°Ρ†ΠΈΡ Π½ΠΈΠΆΠ΅ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ нСльзя ΠΎΠΏΡƒΡΠΊΠ°Ρ‚ΡŒΡΡ Π² стСкС логичСских ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ, Ρ‚.Π΅. ΠΎΠ½Π° Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½Π° Π² Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌ контСкстС.
111 150 /// </summary>
112 151 public LogicalOperation BoundOperation {
113 152 get {
114 153 return m_bound;
115 154 }
116 155 }
117 156
118 157 /// <summary>
119 158 /// ΠŸΠΎΡ‚ΠΎΠΊ, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ создан контСкст трассировки.
120 159 /// </summary>
121 160 public int ThreadId {
122 161 get {
123 162 return m_threadId;
124 163 }
125 164 }
126 165
127 166 /// <summary>
128 167 /// НачинаСт Π±Π΅Π·Ρ‹ΠΌΡΠ½Π½ΡƒΡŽ Π»ΠΎΠ³ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ.
129 168 /// </summary>
130 169 public void StartLogicalOperation() {
131 170 StartLogicalOperation(null);
132 171 }
133 172
134 173 /// <summary>
135 174 /// НачинаСт Π»ΠΎΠ³ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ с ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΌ ΠΈΠΌΠ΅Π½Π΅ΠΌ. Бозданная опСрация Π±ΡƒΠ΄Π΅Ρ‚ Π΄ΠΎΠ±Π²Π°Π»Π΅Π½Π° Π² стСк логичСских ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ контСкста, Π·Π°Ρ‚Π΅ΠΌ Π±ΡƒΠ΄Π΅Ρ‚ создано ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΠ²ΡƒΡŽΡ‰Π΅Π΅ событиС.
136 175 /// </summary>
137 176 /// <param name="name">Имя Π½Π°Ρ‡ΠΈΠ½Π°Π΅ΠΌΠΎΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</param>
138 177 public void StartLogicalOperation(string name) {
139 178 m_currentOperation = new LogicalOperation(name, m_currentOperation);
140 179 LogEvent(TraceEventType.OperationStarted, name);
141 180 }
142 181
143 182 /// <summary>
144 183 /// Π—Π°ΠΊΠ°Π½Ρ‡ΠΈΠ²Π°Π΅Ρ‚ Π»ΠΎΠ³ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ Π½Π°Ρ‡Π°Ρ‚ΡƒΡŽ Π² Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌ контСкстС. ΠžΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ, Π½Π°Ρ‡Π°Ρ‚Ρ‹Π΅ Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… контСкстах Π½Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Π·Π°ΠΊΠΎΠ½Ρ‡Π΅Π½Ρ‹ Π² Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌ контСкстС.
145 184 /// </summary>
146 185 /// <remarks>
147 186 /// ΠŸΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° создаСтся событиС ΠΆΡƒΡ€Π½Π°Π»Π° трассировки, Π»ΠΈΠ±ΠΎ ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ, Π»ΠΈΠ±ΠΎ ΠΎΠ± ошибки, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ данная опСрация
148 187 /// Π½Π°Ρ‡Π°Ρ‚Π° Π² Π΄Ρ€ΡƒΠ³ΠΎΠΌ контСкстС.
149 188 /// </remarks>
150 189 public void EndLogicalOperation() {
151 190 if (m_bound == m_currentOperation) {
152 191 LogEvent(TraceEventType.Error, "Trying to end the operation which isn't belongs to current trace");
153 192 } else {
154 193 var op = m_currentOperation;
155 194 LogEvent(TraceEventType.OperationCompleted, "{0} {1} ms", op.Name, op.Duration);
156 195 m_currentOperation = m_currentOperation.Parent;
157 196 }
158 197 }
159 198
160 199 /// <summary>
161 200 /// Π—Π°Π²Ρ€Π΅ΡˆΠ°Π΅Ρ‚ всС Π½Π°Ρ‡Π°Ρ‚Ρ‹Π΅ Π² этом контСкстС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ
162 201 /// </summary>
163 202 public void EndAllOperations() {
164 203 while (m_bound != m_currentOperation)
165 204 EndLogicalOperation();
166 205 }
167 206
168 207 void LogEvent(TraceEventType type, string format, params object[] args) {
169 208 LogChannel<TraceEvent>.Default.LogEvent(this, TraceEvent.Create(type, format, args));
170 209 }
171 210 }
172 211 }
@@ -1,16 +1,19
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Threading.Tasks;
6 6
7 7 namespace Implab.Diagnostics {
8 8 public enum TraceEventType {
9 9 Information = 1,
10 10 Warning,
11 11 Error,
12 12 OperationStarted,
13 13 OperationCompleted,
14 Transfer
14 Fork,
15 Attach,
16 Detach,
17 Created
15 18 }
16 19 }
@@ -1,46 +1,62
1 using System;
1 using Implab.Diagnostics;
2 using System;
2 3 using System.Collections.Generic;
3 4 using System.Diagnostics;
4 5 using System.Linq;
5 6 using System.Web;
6 7
7 8 namespace Implab {
9 /// <summary>
10 /// ΠžΠ±ΡŠΠ΅ΠΊΡ‚, ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‰ΠΈΠΉ освобоТдСниС рСсурсов.
11 /// </summary>
8 12 public class Disposable : IDisposable {
9 13
10 14 bool m_disposed;
11 15
12 16 public event EventHandler Disposed;
13 17
14 18 public bool IsDisposed {
15 19 get { return m_disposed; }
16 20 }
17 21
18 22 protected void AssertNotDisposed() {
19 23 if (m_disposed)
20 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 36 protected virtual void Dispose(bool disposing) {
24 37 if (disposing && !m_disposed) {
25 38 m_disposed = true;
26 39
27 40 EventHandler temp = Disposed;
28 41 if (temp != null)
29 42 temp(this,EventArgs.Empty);
30 43 }
31 44 }
32 45 public void Dispose() {
33 46 Dispose(true);
34 47 GC.SuppressFinalize(this);
35 48 }
36 49
50 /// <summary>
51 /// ЗаписываСт сообщСниС ΠΎΠ± ΡƒΡ‚Π΅Ρ‡ΠΊΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°.
52 /// </summary>
37 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 57 ~Disposable() {
42 58 Dispose(false);
43 59 ReportObjectLeaks();
44 60 }
45 61 }
46 62 } No newline at end of file
@@ -1,191 +1,191
1 1 using Implab.Diagnostics;
2 2 using System;
3 3 using System.Collections.Generic;
4 4 using System.Diagnostics;
5 5 using System.Linq;
6 6 using System.Text;
7 7 using System.Threading;
8 8
9 9 namespace Implab.Parallels {
10 10 public static class ArrayTraits {
11 11 class ArrayIterator<TSrc> : DispatchPool<int> {
12 12 readonly Action<TSrc> m_action;
13 13 readonly TSrc[] m_source;
14 14 readonly Promise<int> m_promise = new Promise<int>();
15 15 readonly TraceContext m_traceContext;
16 16
17 17 int m_pending;
18 18 int m_next;
19 19
20 20 public ArrayIterator(TSrc[] source, Action<TSrc> action, int threads)
21 21 : base(threads) {
22 22
23 23 Debug.Assert(source != null);
24 24 Debug.Assert(action != null);
25 25
26 26 m_traceContext = TraceContext.Snapshot();
27 27 m_next = 0;
28 28 m_source = source;
29 29 m_pending = source.Length;
30 30 m_action = action;
31 31
32 32 m_promise.Anyway(() => Dispose());
33 33 m_promise.Cancelled(() => Dispose());
34 34
35 35 InitPool();
36 36 }
37 37
38 38 public Promise<int> Promise {
39 39 get {
40 40 return m_promise;
41 41 }
42 42 }
43 43
44 44 protected override void Worker() {
45 TraceContext.Transfer(m_traceContext);
45 TraceContext.Fork(m_traceContext);
46 46 base.Worker();
47 47 }
48 48
49 49 protected override bool TryDequeue(out int unit) {
50 50 unit = Interlocked.Increment(ref m_next) - 1;
51 51 return unit >= m_source.Length ? false : true;
52 52 }
53 53
54 54 protected override void InvokeUnit(int unit) {
55 55 try {
56 56 m_action(m_source[unit]);
57 57 var pending = Interlocked.Decrement(ref m_pending);
58 58 if (pending == 0)
59 59 m_promise.Resolve(m_source.Length);
60 60 } catch (Exception e) {
61 61 m_promise.Reject(e);
62 62 }
63 63 }
64 64 }
65 65
66 66 class ArrayMapper<TSrc, TDst>: DispatchPool<int> {
67 67 readonly Func<TSrc, TDst> m_transform;
68 68 readonly TSrc[] m_source;
69 69 readonly TDst[] m_dest;
70 70 readonly Promise<TDst[]> m_promise = new Promise<TDst[]>();
71 71 readonly TraceContext m_traceContext;
72 72
73 73 int m_pending;
74 74 int m_next;
75 75
76 76 public ArrayMapper(TSrc[] source, Func<TSrc, TDst> transform, int threads)
77 77 : base(threads) {
78 78
79 79 Debug.Assert (source != null);
80 80 Debug.Assert( transform != null);
81 81
82 82 m_next = 0;
83 83 m_source = source;
84 84 m_dest = new TDst[source.Length];
85 85 m_pending = source.Length;
86 86 m_transform = transform;
87 87 m_traceContext = TraceContext.Snapshot();
88 88
89 89 m_promise.Anyway(() => Dispose());
90 90 m_promise.Cancelled(() => Dispose());
91 91
92 92 InitPool();
93 93 }
94 94
95 95 public Promise<TDst[]> Promise {
96 96 get {
97 97 return m_promise;
98 98 }
99 99 }
100 100
101 101 protected override void Worker() {
102 TraceContext.Transfer(m_traceContext);
102 TraceContext.Fork(m_traceContext);
103 103 base.Worker();
104 104 }
105 105
106 106 protected override bool TryDequeue(out int unit) {
107 107 unit = Interlocked.Increment(ref m_next) - 1;
108 108 return unit >= m_source.Length ? false : true;
109 109 }
110 110
111 111 protected override void InvokeUnit(int unit) {
112 112 try {
113 113 m_dest[unit] = m_transform(m_source[unit]);
114 114 var pending = Interlocked.Decrement(ref m_pending);
115 115 if (pending == 0)
116 116 m_promise.Resolve(m_dest);
117 117 } catch (Exception e) {
118 118 m_promise.Reject(e);
119 119 }
120 120 }
121 121 }
122 122
123 123 public static IPromise<TDst[]> ParallelMap<TSrc, TDst> (this TSrc[] source, Func<TSrc,TDst> transform, int threads) {
124 124 if (source == null)
125 125 throw new ArgumentNullException("source");
126 126 if (transform == null)
127 127 throw new ArgumentNullException("transform");
128 128
129 129 var mapper = new ArrayMapper<TSrc, TDst>(source, transform, threads);
130 130 return mapper.Promise;
131 131 }
132 132
133 133 public static IPromise<int> ParallelForEach<TSrc>(this TSrc[] source, Action<TSrc> action, int threads) {
134 134 if (source == null)
135 135 throw new ArgumentNullException("source");
136 136 if (action == null)
137 137 throw new ArgumentNullException("action");
138 138
139 139 var iter = new ArrayIterator<TSrc>(source, action, threads);
140 140 return iter.Promise;
141 141 }
142 142
143 143 public static IPromise<TDst[]> ChainedMap<TSrc, TDst>(this TSrc[] source, ChainedOperation<TSrc, TDst> transform, int threads) {
144 144 if (source == null)
145 145 throw new ArgumentNullException("source");
146 146 if (transform == null)
147 147 throw new ArgumentNullException("transform");
148 148 if (threads <= 0)
149 149 throw new ArgumentOutOfRangeException("Threads number must be greater then zero");
150 150
151 151 if (source.Length == 0)
152 152 return Promise<TDst[]>.ResultToPromise(new TDst[0]);
153 153
154 154 var promise = new Promise<TDst[]>();
155 155 var res = new TDst[source.Length];
156 156 var pending = source.Length;
157 157
158 158 var semaphore = new Semaphore(threads, threads);
159 159
160 160 AsyncPool.InvokeNewThread(() => {
161 161 for (int i = 0; i < source.Length; i++) {
162 162 if(promise.IsResolved)
163 163 break; // stop processing in case of error or cancellation
164 164 var idx = i;
165 165 semaphore.WaitOne();
166 166 try {
167 167 var p1 = transform(source[i]);
168 168 p1.Anyway(() => semaphore.Release());
169 169 p1.Cancelled(() => semaphore.Release());
170 170 p1.Then(
171 171 x => {
172 172 res[idx] = x;
173 173 var left = Interlocked.Decrement(ref pending);
174 174 if (left == 0)
175 175 promise.Resolve(res);
176 176 },
177 177 e => promise.Reject(e)
178 178 );
179 179
180 180 } catch (Exception e) {
181 181 promise.Reject(e);
182 182 }
183 183 }
184 184 return 0;
185 185 });
186 186
187 187 return promise.Anyway(() => semaphore.Dispose());
188 188 }
189 189
190 190 }
191 191 }
@@ -1,50 +1,71
1 1 using Implab.Diagnostics;
2 2 using System;
3 3 using System.Threading;
4 4
5 5 namespace Implab.Parallels {
6 6 /// <summary>
7 7 /// Класс для распаралСливания Π·Π°Π΄Π°Ρ‡.
8 8 /// </summary>
9 9 /// <remarks>
10 10 /// Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ Π΄Π°Π½Π½Ρ‹ΠΉ класс ΠΈ лямда выраТСния ΠΌΠΎΠΆΠ½ΠΎ Ρ€Π°ΡΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΠΈΡ‚ΡŒ
11 11 /// вычислСния, для этого ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ концСпция ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ.
12 12 /// </remarks>
13 13 public static class AsyncPool {
14 14
15 15 public static IPromise<T> Invoke<T>(Func<T> func) {
16 16 var p = new Promise<T>();
17 17 var caller = TraceContext.Snapshot();
18 18
19 19 ThreadPool.QueueUserWorkItem(param => {
20 TraceContext.Transfer(caller);
20 TraceContext.Fork(caller);
21 21 try {
22 22 p.Resolve(func());
23 23 } catch(Exception e) {
24 24 p.Reject(e);
25 25 }
26 26 });
27 27
28 28 return p;
29 29 }
30 30
31 31 public static IPromise<T> InvokeNewThread<T>(Func<T> func) {
32 32 var p = new Promise<T>();
33 33
34 34 var caller = TraceContext.Snapshot();
35 35
36 36 var worker = new Thread(() => {
37 TraceContext.Transfer(caller);
37 TraceContext.Fork(caller);
38 38 try {
39 39 p.Resolve(func());
40 40 } catch (Exception e) {
41 41 p.Reject(e);
42 42 }
43 43 });
44 44 worker.IsBackground = true;
45 45 worker.Start();
46 46
47 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;
69 }
49 70 }
50 71 }
General Comments 0
You need to be logged in to leave comments. Login now