##// END OF EJS Templates
Implab.Diagnostics drafts
cin -
r253:34df34841225 v3.0.1-beta v3
parent child
Show More
@@ -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 void Test1()
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 StartLogicalOperation();
21 using (LogicalOperation("InnerOperation")){
24
22 await Task.Yield();
25 Trace.WriteLine("Inner");
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, 1, format, arguments);
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, 1, format, arguments);
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, 1, format, arguments);
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, 1, err);
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
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now