Auto status change to "Under Review"
@@ -0,0 +1,29 | |||||
|
1 | using System; | |||
|
2 | using System.Diagnostics; | |||
|
3 | ||||
|
4 | namespace Implab.Diagnostics { | |||
|
5 | public class ActivityScope : IDisposable { | |||
|
6 | readonly TraceSource m_source; | |||
|
7 | ||||
|
8 | readonly Guid m_prevId; | |||
|
9 | ||||
|
10 | readonly string m_activity; | |||
|
11 | ||||
|
12 | readonly int m_code; | |||
|
13 | ||||
|
14 | internal ActivityScope(TraceSource source, Guid prevId, int code, string activity) { | |||
|
15 | m_source = source; | |||
|
16 | m_prevId = prevId; | |||
|
17 | m_code = code; | |||
|
18 | m_activity = activity; | |||
|
19 | } | |||
|
20 | ||||
|
21 | ||||
|
22 | public void Dispose() { | |||
|
23 | if (Trace.CorrelationManager.ActivityId != m_prevId) | |||
|
24 | m_source.TraceTransfer(m_code, "Transfer", m_prevId); | |||
|
25 | m_source.TraceEvent(TraceEventType.Stop, 0, m_activity); | |||
|
26 | Trace.CorrelationManager.ActivityId = m_prevId; | |||
|
27 | } | |||
|
28 | } | |||
|
29 | } No newline at end of file |
@@ -0,0 +1,17 | |||||
|
1 | using System; | |||
|
2 | using System.Diagnostics; | |||
|
3 | ||||
|
4 | namespace Implab.Diagnostics { | |||
|
5 | public class LogicalOperation { | |||
|
6 | public Stopwatch OperationStopwatch { get; private set; } | |||
|
7 | ||||
|
8 | public string Name { get; private set; } | |||
|
9 | ||||
|
10 | internal LogicalOperation(string name) { | |||
|
11 | Name = string.IsNullOrEmpty(name) ? "<unnamed>" : name; | |||
|
12 | OperationStopwatch = Stopwatch.StartNew(); | |||
|
13 | } | |||
|
14 | ||||
|
15 | public override string ToString() => Name; | |||
|
16 | } | |||
|
17 | } No newline at end of file |
@@ -0,0 +1,21 | |||||
|
1 | using System; | |||
|
2 | using System.Diagnostics; | |||
|
3 | ||||
|
4 | namespace Implab.Diagnostics { | |||
|
5 | public class LogicalOperationScope : IDisposable { | |||
|
6 | readonly TraceSource m_source; | |||
|
7 | ||||
|
8 | readonly LogicalOperation m_operation; | |||
|
9 | ||||
|
10 | internal LogicalOperationScope(TraceSource source, LogicalOperation operation) { | |||
|
11 | m_source = source; | |||
|
12 | m_operation = operation; | |||
|
13 | } | |||
|
14 | ||||
|
15 | public void Dispose() { | |||
|
16 | m_operation.OperationStopwatch.Stop(); | |||
|
17 | Trace.CorrelationManager.StopLogicalOperation(); | |||
|
18 | m_source.TraceData(TraceEventType.Information, TraceEventCodes.StopLogicalOperation, m_operation); | |||
|
19 | } | |||
|
20 | } | |||
|
21 | } No newline at end of file |
@@ -0,0 +1,114 | |||||
|
1 | using System; | |||
|
2 | using System.Diagnostics; | |||
|
3 | using System.IO; | |||
|
4 | ||||
|
5 | namespace Implab.Diagnostics { | |||
|
6 | public class SimpleTraceListener : TextWriterTraceListener { | |||
|
7 | public SimpleTraceListener() { | |||
|
8 | } | |||
|
9 | ||||
|
10 | public SimpleTraceListener(Stream stream) : base(stream) { | |||
|
11 | } | |||
|
12 | ||||
|
13 | public SimpleTraceListener(TextWriter writer) : base(writer) { | |||
|
14 | } | |||
|
15 | ||||
|
16 | public SimpleTraceListener(string fileName) : base(fileName) { | |||
|
17 | } | |||
|
18 | ||||
|
19 | public SimpleTraceListener(Stream stream, string name) : base(stream, name) { | |||
|
20 | } | |||
|
21 | ||||
|
22 | public SimpleTraceListener(TextWriter writer, string name) : base(writer, name) { | |||
|
23 | } | |||
|
24 | ||||
|
25 | public SimpleTraceListener(string fileName, string name) : base(fileName, name) { | |||
|
26 | } | |||
|
27 | ||||
|
28 | public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data) { | |||
|
29 | switch (id) { | |||
|
30 | case TraceEventCodes.StartLogicalOperation: | |||
|
31 | TraceEvent(eventCache, source, eventType, id, "+{0}", data); | |||
|
32 | break; | |||
|
33 | case TraceEventCodes.StopLogicalOperation: | |||
|
34 | TraceEvent(eventCache, source, eventType, id, FormatStopLogicalOperation(data)); | |||
|
35 | break; | |||
|
36 | default: | |||
|
37 | TraceEvent(eventCache, source, eventType, id, data?.ToString()); | |||
|
38 | break; | |||
|
39 | } | |||
|
40 | } | |||
|
41 | ||||
|
42 | string FormatStopLogicalOperation(object data) { | |||
|
43 | if (data is LogicalOperation op) { | |||
|
44 | return string.Format("-{0} ({1})", op, FormatTimespan(op.OperationStopwatch.Elapsed)); | |||
|
45 | } else { | |||
|
46 | return data?.ToString(); | |||
|
47 | } | |||
|
48 | } | |||
|
49 | ||||
|
50 | string FormatTimespan(TimeSpan value) { | |||
|
51 | if (value.TotalSeconds < 10) { | |||
|
52 | return value.Milliseconds.ToString() + "ms"; | |||
|
53 | } else if (value.TotalSeconds < 30) { | |||
|
54 | return string.Format("{0:0.###}s", value.TotalSeconds); | |||
|
55 | } else { | |||
|
56 | return value.ToString(); | |||
|
57 | } | |||
|
58 | } | |||
|
59 | ||||
|
60 | public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, params object[] data) { | |||
|
61 | var prev = IndentLevel; | |||
|
62 | IndentLevel += eventCache.LogicalOperationStack.Count; | |||
|
63 | try { | |||
|
64 | base.TraceData(eventCache, source, eventType, id, data); | |||
|
65 | } finally { | |||
|
66 | IndentLevel = prev; | |||
|
67 | } | |||
|
68 | } | |||
|
69 | ||||
|
70 | public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id) { | |||
|
71 | var prev = IndentLevel; | |||
|
72 | IndentLevel += eventCache.LogicalOperationStack.Count; | |||
|
73 | try { | |||
|
74 | base.TraceEvent(eventCache, source, eventType, id); | |||
|
75 | } finally { | |||
|
76 | IndentLevel = prev; | |||
|
77 | } | |||
|
78 | } | |||
|
79 | ||||
|
80 | public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args) { | |||
|
81 | TraceEvent(eventCache, source, eventType, id, String.Format(format, args)); | |||
|
82 | } | |||
|
83 | ||||
|
84 | public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message) { | |||
|
85 | var prev = IndentLevel; | |||
|
86 | IndentLevel += eventCache.LogicalOperationStack.Count; | |||
|
87 | try { | |||
|
88 | LogicalOperation operation = null; | |||
|
89 | if (eventCache.LogicalOperationStack.Count > 0) | |||
|
90 | operation = eventCache.LogicalOperationStack.Peek() as LogicalOperation; | |||
|
91 | ||||
|
92 | if (operation != null) { | |||
|
93 | base.TraceData(eventCache, source, eventType, id, FormatTimespan(operation.OperationStopwatch.Elapsed) + ": " + message); | |||
|
94 | } else { | |||
|
95 | base.TraceData(eventCache, source, eventType, id, message); | |||
|
96 | } | |||
|
97 | } finally { | |||
|
98 | IndentLevel = prev; | |||
|
99 | } | |||
|
100 | } | |||
|
101 | ||||
|
102 | public override void TraceTransfer(TraceEventCache eventCache, string source, int id, string message, Guid relatedActivityId) { | |||
|
103 | var prev = IndentLevel; | |||
|
104 | IndentLevel += eventCache.LogicalOperationStack.Count; | |||
|
105 | try { | |||
|
106 | base.TraceTransfer(eventCache, source, id, message, relatedActivityId); | |||
|
107 | } finally { | |||
|
108 | IndentLevel = prev; | |||
|
109 | } | |||
|
110 | } | |||
|
111 | ||||
|
112 | ||||
|
113 | } | |||
|
114 | } No newline at end of file |
@@ -0,0 +1,10 | |||||
|
1 | namespace Implab.Diagnostics { | |||
|
2 | public class TraceEventCodes { | |||
|
3 | public const int EventCodesBase = 1024; | |||
|
4 | ||||
|
5 | public const int StartLogicalOperation = EventCodesBase + 1; | |||
|
6 | ||||
|
7 | public const int StopLogicalOperation = EventCodesBase + 2; | |||
|
8 | ||||
|
9 | } | |||
|
10 | } No newline at end of file |
@@ -4,34 +4,26 using System.Threading; | |||||
4 | using Implab.Diagnostics; |
|
4 | using Implab.Diagnostics; | |
5 | using Xunit; |
|
5 | using Xunit; | |
6 |
|
6 | |||
7 | namespace Implab.Test |
|
7 | namespace Implab.Test { | |
8 | { |
|
8 | using System.Threading.Tasks; | |
9 | using static Trace<UnitTest1>; |
|
9 | using static Trace<UnitTest1>; | |
10 | public class UnitTest1 |
|
10 | public class UnitTest1 { | |
11 | { |
|
|||
12 | [Fact] |
|
11 | [Fact] | |
13 |
public |
|
12 | public async Task Test1() { | |
14 | { |
|
13 | var listener = new SimpleTraceListener(Console.Out); | |
15 | var listener = new TextWriterTraceListener(Console.Out); |
|
14 | ||
16 | var source = TraceSource; |
|
15 | var source = TraceSource; | |
17 | source.Switch.Level = SourceLevels.All; |
|
16 | source.Switch.Level = SourceLevels.All; | |
18 |
|
17 | |||
19 | source.Listeners.Add(listener); |
|
18 | source.Listeners.Add(listener); | |
20 | Trace.Listeners.Add(listener); |
|
|||
21 |
|
19 | |||
22 | Trace.WriteLine("Hello!"); |
|
20 | using (var op = LogicalOperation(nameof(Test1))) | |
23 |
|
|
21 | using (LogicalOperation("InnerOperation")){ | |
24 |
|
22 | await Task.Yield(); | ||
25 |
|
|
23 | Log("Inner"); | |
26 | foreach(var x in Trace.CorrelationManager.LogicalOperationStack) |
|
24 | await Task.Yield(); | |
27 | Trace.WriteLine($"-{x}"); |
|
25 | Log("source event"); | |
28 | Log("source event"); |
|
26 | } | |
29 |
|
||||
30 | listener.IndentLevel = 1; |
|
|||
31 |
|
||||
32 | source.TraceData(TraceEventType.Start, 1, DateTime.Now); |
|
|||
33 |
|
||||
34 | StopLogicalOperation(); |
|
|||
35 | } |
|
27 | } | |
36 | } |
|
28 | } | |
37 | } |
|
29 | } |
@@ -62,7 +62,7 namespace Implab { | |||||
62 | if (TransitionalState != Interlocked.CompareExchange(ref m_state, ResolvedState, TransitionalState)) |
|
62 | if (TransitionalState != Interlocked.CompareExchange(ref m_state, ResolvedState, TransitionalState)) | |
63 | throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); |
|
63 | throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); | |
64 | #else |
|
64 | #else | |
65 | m_state = state; |
|
65 | m_state = ResolvedState; | |
66 | #endif |
|
66 | #endif | |
67 | Signal(); |
|
67 | Signal(); | |
68 | } |
|
68 | } |
@@ -29,7 +29,7 namespace Implab.Diagnostics { | |||||
29 | /// <param name="name">Name.</param> |
|
29 | /// <param name="name">Name.</param> | |
30 | [Conditional("TRACE")] |
|
30 | [Conditional("TRACE")] | |
31 | public static void StartLogicalOperation(string name) { |
|
31 | public static void StartLogicalOperation(string name) { | |
32 | Trace.CorrelationManager.StartLogicalOperation(); |
|
32 | Trace.CorrelationManager.StartLogicalOperation(name); | |
33 | } |
|
33 | } | |
34 |
|
34 | |||
35 | /// <summary> |
|
35 | /// <summary> | |
@@ -47,7 +47,7 namespace Implab.Diagnostics { | |||||
47 | /// <param name="arguments">Arguments.</param> |
|
47 | /// <param name="arguments">Arguments.</param> | |
48 | [Conditional("TRACE")] |
|
48 | [Conditional("TRACE")] | |
49 | public static void Log(string format, params object[] arguments) { |
|
49 | public static void Log(string format, params object[] arguments) { | |
50 |
TraceSource.TraceEvent(TraceEventType.Information, |
|
50 | TraceSource.TraceEvent(TraceEventType.Information, 0, format, arguments); | |
51 | } |
|
51 | } | |
52 |
|
52 | |||
53 | /// <summary> |
|
53 | /// <summary> | |
@@ -57,17 +57,71 namespace Implab.Diagnostics { | |||||
57 | /// <param name="arguments">Arguments.</param> |
|
57 | /// <param name="arguments">Arguments.</param> | |
58 | [Conditional("TRACE")] |
|
58 | [Conditional("TRACE")] | |
59 | public static void Warn(string format, params object[] arguments) { |
|
59 | public static void Warn(string format, params object[] arguments) { | |
60 |
TraceSource.TraceEvent(TraceEventType.Warning, |
|
60 | TraceSource.TraceEvent(TraceEventType.Warning, 0, format, arguments); | |
61 | } |
|
61 | } | |
62 |
|
62 | |||
63 | [Conditional("TRACE")] |
|
63 | [Conditional("TRACE")] | |
64 | public static void Error(string format, params object[] arguments) { |
|
64 | public static void Error(string format, params object[] arguments) { | |
65 |
TraceSource.TraceEvent(TraceEventType.Error, |
|
65 | TraceSource.TraceEvent(TraceEventType.Error, 0, format, arguments); | |
66 | } |
|
66 | } | |
67 |
|
67 | |||
68 | [Conditional("TRACE")] |
|
68 | [Conditional("TRACE")] | |
69 | public static void Error(Exception err) { |
|
69 | public static void Error(Exception err) { | |
70 |
TraceSource.TraceData(TraceEventType.Error, |
|
70 | TraceSource.TraceData(TraceEventType.Error, 0, err); | |
|
71 | } | |||
|
72 | ||||
|
73 | /// <summary> | |||
|
74 | /// This method save the current activity, and transfers to the specified activity, | |||
|
75 | /// emits <see cref="TraceEventType.Start"/> and returns a scope of the new | |||
|
76 | /// activity. | |||
|
77 | /// </summary> | |||
|
78 | /// <param name="activityName">The name of the new activity/</param> | |||
|
79 | /// <param name="activityId">The identifier of the activity to which | |||
|
80 | /// the control will be transferred</param> | |||
|
81 | /// <returns>A scope of the new activity, dispose it to transfer | |||
|
82 | /// the control back to the original activity.</returns> | |||
|
83 | public static ActivityScope TransferActivity(string activityName, Guid activityId) { | |||
|
84 | var prev = Trace.CorrelationManager.ActivityId; | |||
|
85 | ||||
|
86 | TraceSource.TraceTransfer(0, "Transfer", activityId); | |||
|
87 | Trace.CorrelationManager.ActivityId = activityId; | |||
|
88 | TraceSource.TraceEvent(TraceEventType.Start, 0, activityName); | |||
|
89 | ||||
|
90 | return new ActivityScope(TraceSource, prev, 0, activityName); | |||
|
91 | } | |||
|
92 | ||||
|
93 | /// <summary> | |||
|
94 | /// Emits <see cref="TraceEventType.Start"/> and returns a scope of the | |||
|
95 | /// activity. | |||
|
96 | /// </summary> | |||
|
97 | /// <param name="activityName">The name of the activity to start</param> | |||
|
98 | /// <returns>A scope of the new activity, dispose it to emit | |||
|
99 | /// <see cref="TraceEventType.Stop"/> for the current activity.</returns> | |||
|
100 | public static ActivityScope StartActivity(string activityName) { | |||
|
101 | if (Trace.CorrelationManager.ActivityId == Guid.Empty) | |||
|
102 | Trace.CorrelationManager.ActivityId = Guid.NewGuid(); | |||
|
103 | ||||
|
104 | var prev = Trace.CorrelationManager.ActivityId; | |||
|
105 | ||||
|
106 | TraceSource.TraceEvent(TraceEventType.Start, 0, activityName); | |||
|
107 | return new ActivityScope(TraceSource, prev, 0, activityName); | |||
|
108 | } | |||
|
109 | ||||
|
110 | /// <summary> | |||
|
111 | /// Creates new <see cref="LogicalOperation(string)"/> and calls | |||
|
112 | /// to <see cref="CorrelationManager.StartLogicalOperation(object)"/> | |||
|
113 | /// passing the created operation as identity. Calls | |||
|
114 | /// <see cref="TraceSource.TraceData(TraceEventType, int, object)"/> | |||
|
115 | /// to notify listeners on operation start. | |||
|
116 | /// </summary> | |||
|
117 | /// <param name="name">The name of the logical operation.</param> | |||
|
118 | /// <returns>Logical operation scope, disposing it will stop | |||
|
119 | /// logical operation and notify trace listeners.</returns> | |||
|
120 | public static LogicalOperationScope LogicalOperation(string name) { | |||
|
121 | var operation = new LogicalOperation(name); | |||
|
122 | TraceSource.TraceData(TraceEventType.Information, TraceEventCodes.StartLogicalOperation, operation); | |||
|
123 | Trace.CorrelationManager.StartLogicalOperation(operation); | |||
|
124 | return new LogicalOperationScope(TraceSource, operation); | |||
71 | } |
|
125 | } | |
72 | } |
|
126 | } | |
73 | } |
|
127 | } |
@@ -1,6 +1,16 | |||||
1 | <Project Sdk="Microsoft.NET.Sdk"> |
|
1 | <Project Sdk="Microsoft.NET.Sdk"> | |
2 |
|
2 | |||
3 | <PropertyGroup> |
|
3 | <PropertyGroup> | |
|
4 | <Authors>Sergey Smirnov</Authors> | |||
|
5 | <Title>Implab library</Title> | |||
|
6 | <Description>Provides some helper clesses like XML serialization helpers, JSON XML reader, | |||
|
7 | JSON pull-parser, ECMA-style promises, lightweight synchonization routines Signal | |||
|
8 | and SharedLock, Trace helpers on top of System.Diagnostics, ObjectPool etc. | |||
|
9 | </Description> | |||
|
10 | <Copyright>2012-2018 Sergey Smirnov</Copyright> | |||
|
11 | <LicenseUrl>https://opensource.org/licenses/BSD-2-Clause</LicenseUrl> | |||
|
12 | <ProjectUrl>https://implab.org</ProjectUrl> | |||
|
13 | <RepositoryUrl>https://hg.implab.org/pub/ImplabNet/</RepositoryUrl> | |||
4 | <TargetFrameworks>netstandard2.0;net45</TargetFrameworks> |
|
14 | <TargetFrameworks>netstandard2.0;net45</TargetFrameworks> | |
5 | <FrameworkPathOverride Condition="'$(TargetFramework)'=='net45' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride> |
|
15 | <FrameworkPathOverride Condition="'$(TargetFramework)'=='net45' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride> | |
6 | </PropertyGroup> |
|
16 | </PropertyGroup> |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 3
ok, latest stable version should be in default
You need to be logged in to leave comments.
Login now