##// END OF EJS Templates
Working on Implab.Diagnostics
cin -
r286:67ebcfd7d1c8 v3
parent child
Show More
@@ -0,0 +1,17
1 namespace Implab.Diagnostics
2 {
3 public abstract class TraceChannel {
4 readonly object m_id;
5
6 public object Id {
7 get {
8 return m_id;
9 }
10 }
11
12 protected TraceChannel(object id) {
13 m_id = id ?? new object();
14 }
15
16 }
17 } No newline at end of file
@@ -0,0 +1,83
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using Implab.Parallels;
5
6 namespace Implab.Diagnostics {
7 public class TraceRegistry {
8
9 class Subscription : IDisposable {
10 readonly WeakReference<TraceRegistry> m_registry;
11 readonly Action<object> m_unsubscribe;
12
13 public Subscription(TraceRegistry registry) {
14 m_registry = new WeakReference<TraceRegistry>(registry);
15 }
16
17 public void Dispose() {
18 TraceRegistry t;
19 if (m_registry.TryGetTarget(out t))
20 t.RemoveSubscription(this);
21 }
22 }
23
24 public static TraceRegistry Global { get; } = new TraceRegistry();
25
26 readonly object m_lock = new object();
27
28 readonly Dictionary<object, Action<TraceChannel>> m_subscriptions = new Dictionary<object, Action<TraceChannel>>();
29 readonly SimpleAsyncQueue<TraceChannel> m_channels = new SimpleAsyncQueue<TraceChannel>();
30
31 internal void Register(TraceChannel channel) {
32 // notifications can run in parallel
33 Action<TraceChannel>[] handlers = null;
34
35 lock(m_lock) {
36 m_channels.Enqueue(channel);
37 if (m_subscriptions.Count > 0) {
38 handlers = new Action<TraceChannel>[m_subscriptions.Count];
39 m_subscriptions.Values.CopyTo(handlers, 0);
40 }
41 }
42
43 if (handlers != null)
44 foreach(var h in handlers)
45 h(channel);
46 }
47
48 /// <summary>
49 /// Subscribes the specified handler to notifications about new trace
50 /// channels
51 /// </summary>
52 /// <param name="handler"></param>
53 /// <returns></returns>
54 public IDisposable Subscribe(Action<TraceChannel> handler, bool existing) {
55 Safe.ArgumentNotNull(handler, nameof(handler));
56
57 var cookie = new Subscription(this);
58
59 IEnumerable<TraceChannel> snap;
60
61 // lock to ensure that no new channels will be added
62 // while the subscription is added
63 lock(m_lock) {
64 m_subscriptions.Add(cookie, handler);
65 snap = m_channels.Snapshot();
66 }
67
68 // announce previously declared channels if required
69 if (existing) {
70 foreach(var c in snap)
71 handler(c);
72 }
73
74 // return the subscription
75 return cookie;
76 }
77
78 void RemoveSubscription(object cookie) {
79 lock(m_lock)
80 m_subscriptions.Remove(cookie);
81 }
82 }
83 } No newline at end of file
@@ -0,0 +1,27
1 using TraceSource = System.Diagnostics.TraceSource;
2
3 namespace Implab.Diagnostics {
4
5 /// <summary>
6 /// Trace channel which incapsulates <see cref="System.Diagnostics.TraceSource"/> instance.
7 /// </summary>
8 public class TraceSourceChannel : TraceChannel {
9 readonly TraceSource m_trace;
10
11 public TraceSourceChannel() : base(new object()) {
12 }
13
14 public TraceSourceChannel(object id) : base(id) {
15 }
16
17 public TraceSourceChannel(object id, string name) : base(id) {
18 m_trace = new TraceSource(name);
19 }
20
21 public TraceSource Source {
22 get {
23 return m_trace;
24 }
25 }
26 }
27 } No newline at end of file
@@ -0,0 +1,33
1 using System;
2 using System.Threading;
3 using TraceSource = System.Diagnostics.TraceSource;
4
5 namespace Implab.Diagnostics {
6 /// <summary>
7 /// This class is used to provide a single <see cref="TraceSourceChannel"/>
8 /// instance for the specified class in <typeparamref name="T"/> parameter.
9 /// </summary>
10 /// <typeparam name="T">
11 /// The class for which <see cref="TraceSourceChannel"/> is required.
12 /// </typeparam>
13 /// <remarks>
14 /// The <see cref="TraceSourceChannel"/> instance will be created on demand
15 /// and automatically registered in <see cref="TraceRegistry.Global"/>.
16 /// </remarks>
17 public static class TraceSourceChannel<T> {
18 static Lazy<TraceSourceChannel> _traceSource = new Lazy<TraceSourceChannel>(CreateChannel, LazyThreadSafetyMode.ExecutionAndPublication);
19
20 /// <summary>
21 /// The default <see cref="TraceSourceChannel"/> instance.
22 /// </summary>
23 public static TraceSourceChannel Default { get { return _traceSource.Value; } }
24
25 static TraceSourceChannel CreateChannel() {
26 var channel = new TraceSourceChannel(typeof(T), typeof(T).Name);
27
28 TraceRegistry.Global.Register(channel);
29
30 return channel;
31 }
32 }
33 } No newline at end of file
@@ -12,141 +12,24 using Unity.Injection;
12 using Unity.Registration;
12 using Unity.Registration;
13
13
14 namespace Implab.Playground {
14 namespace Implab.Playground {
15
15 using static Trace<Bar>;
16 public class Foo {
16
17
17 class Foo {
18 public class Bar {
19
20 }
21
22 public string Name { get; set; }
23
24 public int IntValue { get; set; }
25
26 public string StringValue { get; set; }
27
28 public void AddRange(Foo[] items) {
29 Console.WriteLine($"AddRange: Foo[]");
30 }
31
18
32 }
19 }
33
20
34 public class FooFactory : IFactory<Foo>, IFactory<Foo.Bar> {
21 class Bar : Foo {
35
36 public bool UseSsl { get; set; }
37
38 public string Connection { get; set; }
39
40 public Foo Create() {
41 return new Foo() {
42 Name = "AutoFac"
43 };
44 }
45
46 Foo.Bar IFactory<Foo.Bar>.Create() {
47 return new Foo.Bar();
48 }
49 }
50
51 public interface IContainer<T> {
52 T Instance { get; set; }
53 }
54
55 public class Container<T> : IContainer<T> {
56 public class Bar {
57
58 }
59
22
60 public class Bar<T2> {
61 public class Baz {
62
63 }
64
65 }
66
67 public Container() {
68
69 }
70
71 public Container(T instance) {
72 Instance = instance;
73 }
74
75 public T Instance { get; set; }
76
77 public void SetInstance(T value) {
78 Instance = value;
79 }
80
81 public void AddRange(List<T> items) {
82 Console.WriteLine($"AddRange: {typeof(List<T>)}");
83 }
84
85 public void AddRange(T[] items) {
86 Console.WriteLine($"AddRange: T[] ofType {typeof(T[])}");
87 }
88 }
23 }
89
90 public class Program {
24 public class Program {
91
25
92 static void Main(string[] args) {
26 static void Main(string[] args) {
93 var u1 = new Uri("/some/one");
94
95 dynamic obj = new ExpandoObject();
96
97 obj.Name = "Dynamo";
98
99 obj.Hello = new Func<string>(() => { return "Hello"; });
100
101 Console.WriteLine($"{obj.Hello()}");
102
103 }
104
105 static void Main2(string[] args) {
106 var listener = new SimpleTraceListener(Console.Out);
107 var source = Trace<TypeResolver>.TraceSource;
108 source.Switch.Level = SourceLevels.All;
109 source.Listeners.Add(listener);
110
111 var stopwatch = new Stopwatch();
112 stopwatch.Start();
113
114 var container = new UnityContainer();
115
116 Console.WriteLine($"Created: {stopwatch.ElapsedMilliseconds}");
117 stopwatch.Restart();
118
27
119 container.LoadXmlConfiguration("data/sample.xml");
28 using(TraceRegistry.Global.Subscribe(ch => {
120
29 Console.WriteLine($"{ch.Id}: {ch.Source.Name}");
121 Console.WriteLine($"Loaded: {stopwatch.ElapsedMilliseconds}");
30 }, true)) {
122
31 Trace<Foo>.Log("Hi!");
123 stopwatch.Restart();
32 Log("Respect!");
124 var instace1 = container.Resolve<IContainer<string>>();
125 Console.WriteLine($"Resolved1: {stopwatch.ElapsedMilliseconds}");
126
127 stopwatch.Restart();
128 var instace2 = container.Resolve<IContainer<Foo>>();
129 Console.WriteLine($"Resolved2: {stopwatch.ElapsedMilliseconds}");
130
131 DisplayContainerRegistrations(container);
132 }
133
134 static void DisplayContainerRegistrations(IUnityContainer theContainer) {
135 string regName, regType, mapTo, lifetime;
136 Console.WriteLine("Container has {0} Registrations:",
137 theContainer.Registrations.Count());
138 foreach (ContainerRegistration item in theContainer.Registrations) {
139 regType = item.RegisteredType.FullName;
140 mapTo = item.MappedToType.FullName;
141 regName = item.Name ?? "[default]";
142 lifetime = item.LifetimeManager.LifetimeType.Name;
143 if (mapTo != regType) {
144 mapTo = " -> " + mapTo;
145 } else {
146 mapTo = string.Empty;
147 }
148 lifetime = lifetime.Substring(0, lifetime.Length - "LifetimeManager".Length);
149 Console.WriteLine("+ {0}{1} '{2}' {3}", regType, mapTo, regName, lifetime);
150 }
33 }
151 }
34 }
152
35
@@ -5,7 +5,7 using Implab.Diagnostics;
5 using Unity;
5 using Unity;
6
6
7 namespace Implab.ServiceHost.Unity {
7 namespace Implab.ServiceHost.Unity {
8 using static Trace<ContainerBuilder>;
8 using Log = Trace<ContainerBuilder>;
9
9
10 public class ContainerBuilder {
10 public class ContainerBuilder {
11
11
@@ -33,7 +33,9 namespace Implab.ServiceHost.Unity {
33 }
33 }
34
34
35 public Type ResolveType(string typeReference) {
35 public Type ResolveType(string typeReference) {
36 return string.IsNullOrEmpty(typeReference) ? null : m_resolver.Resolve(typeReference, true);
36 var resolved = string.IsNullOrEmpty(typeReference) ? null : m_resolver.Resolve(typeReference, true);
37 Log.Debug("ResolveType('{0}'): {1}", typeReference, resolved?.FullName);
38 return resolved;
37 }
39 }
38
40
39 public void Visit(ITypeRegistration registration) {
41 public void Visit(ITypeRegistration registration) {
@@ -1,15 +1,25
1 using System;
1 using System;
2 using System.Diagnostics;
2 using Stopwatch = System.Diagnostics.Stopwatch;
3
3
4 namespace Implab.Diagnostics {
4 namespace Implab.Diagnostics {
5 public class LogicalOperation {
5 public class LogicalOperation {
6 public Stopwatch OperationStopwatch { get; private set; }
6 readonly Stopwatch m_stopwatch;
7
7
8 public string Name { get; private set; }
8 public string Name { get; private set; }
9
9
10 internal LogicalOperation(string name) {
10 internal LogicalOperation(string name) {
11 Name = string.IsNullOrEmpty(name) ? "<unnamed>" : name;
11 Name = string.IsNullOrEmpty(name) ? "<unnamed>" : name;
12 OperationStopwatch = Stopwatch.StartNew();
12 m_stopwatch = Stopwatch.StartNew();
13 }
14
15 public TimeSpan Elapsed {
16 get {
17 return m_stopwatch.Elapsed;
18 }
19 }
20
21 public void End() {
22 m_stopwatch.Stop();
13 }
23 }
14
24
15 public override string ToString() => Name;
25 public override string ToString() => Name;
@@ -13,7 +13,7 namespace Implab.Diagnostics {
13 }
13 }
14
14
15 public void Dispose() {
15 public void Dispose() {
16 m_operation.OperationStopwatch.Stop();
16 m_operation.End();
17 Trace.CorrelationManager.StopLogicalOperation();
17 Trace.CorrelationManager.StopLogicalOperation();
18 m_source.TraceData(TraceEventType.Information, TraceEventCodes.StopLogicalOperation, m_operation);
18 m_source.TraceData(TraceEventType.Information, TraceEventCodes.StopLogicalOperation, m_operation);
19 }
19 }
@@ -41,7 +41,7 namespace Implab.Diagnostics {
41
41
42 string FormatStopLogicalOperation(object data) {
42 string FormatStopLogicalOperation(object data) {
43 if (data is LogicalOperation op) {
43 if (data is LogicalOperation op) {
44 return string.Format("-{0} ({1})", op, FormatTimespan(op.OperationStopwatch.Elapsed));
44 return string.Format("-{0} ({1})", op, FormatTimespan(op.Elapsed));
45 } else {
45 } else {
46 return data?.ToString();
46 return data?.ToString();
47 }
47 }
@@ -90,7 +90,7 namespace Implab.Diagnostics {
90 operation = eventCache.LogicalOperationStack.Peek() as LogicalOperation;
90 operation = eventCache.LogicalOperationStack.Peek() as LogicalOperation;
91
91
92 if (operation != null) {
92 if (operation != null) {
93 base.TraceData(eventCache, source, eventType, id, FormatTimespan(operation.OperationStopwatch.Elapsed) + ": " + message);
93 base.TraceData(eventCache, source, eventType, id, FormatTimespan(operation.Elapsed) + ": " + message);
94 } else {
94 } else {
95 base.TraceData(eventCache, source, eventType, id, message);
95 base.TraceData(eventCache, source, eventType, id, message);
96 }
96 }
@@ -10,35 +10,50 using System.Threading;
10 using System.Threading.Tasks;
10 using System.Threading.Tasks;
11
11
12 namespace Implab.Diagnostics {
12 namespace Implab.Diagnostics {
13 /// <summary>
14 /// Static class which creates an individual <see cref="TraceSource"/> for
15 /// the type specified in the parameter <typeparamref name="T"/>.
16 /// </summary>
17 /// <typeparam name="T">The type for which tracing is demanded.</typeparam>
13 public static class Trace<T> {
18 public static class Trace<T> {
14
19
15 static Lazy<TraceSource> _traceSource = new Lazy<TraceSource>(CreateChannel, LazyThreadSafetyMode.ExecutionAndPublication);
20 readonly static Lazy<TraceSource> _trace = new Lazy<TraceSource>(() => TraceSourceChannel<T>.Default.Source);
16
17 static int _nextId;
18
21
19 static TraceSource CreateChannel() {
22 public static TraceSource TraceSource { get { return _trace.Value; } }
20 var id = Interlocked.Increment(ref _nextId);
21 var trs = new TraceSource(typeof(T).Name);
22
23 TraceChannelRegistry.AllCannels.NotifyChannelCreated(new ChannelInfo(typeof(T), trs));
24
25 return trs;
26 }
27
28 public static TraceSource TraceSource { get { return _traceSource.Value; } }
29
23
30 #if NETFX_TRACE_BUG
24 #if NETFX_TRACE_BUG
31 readonly static AsyncLocal<object> m_currentOperation = new AsyncLocal<object>();
25 readonly static AsyncLocal<object> m_currentOperation = new AsyncLocal<object>();
32 #endif
26 #endif
33
27
34 /// <summary>
28 /// <summary>
35 /// Starts the logical operation nested to the current operation nested to the current one.
29 /// If this property is set then <see cref="Debug(string, object[])"/> will produce output.
30 /// </summary>
31 public static bool TraceVerbose {
32 get {
33 return TraceSource.Switch.ShouldTrace(TraceEventType.Verbose);
34 }
35 }
36
37 /// <summary>
38 /// If this property is set then <see cref="Log(string, object[])"/> will produce output.
36 /// </summary>
39 /// </summary>
37 public static void StartLogicalOperation() {
40 public static bool TraceInformation {
38 Trace.CorrelationManager.StartLogicalOperation();
41 get {
42 return TraceSource.Switch.ShouldTrace(TraceEventType.Information);
43 }
44 }
39
45
46 /// <summary>
47 /// If this property is set then <see cref="Warn(string, object[])"/> will produce output.
48 /// </summary>
49 public static bool TraceWarnings {
50 get {
51 return TraceSource.Switch.ShouldTrace(TraceEventType.Warning);
52 }
40 }
53 }
41
54
55
56
42 /// <summary>
57 /// <summary>
43 /// Starts the logical operation with the specified name, this name is usefull in logs.
58 /// Starts the logical operation with the specified name, this name is usefull in logs.
44 /// </summary>
59 /// </summary>
@@ -48,10 +63,27 namespace Implab.Diagnostics {
48 m_currentOperation.Value = name;
63 m_currentOperation.Value = name;
49 Trace.CorrelationManager.StartLogicalOperation(name);
64 Trace.CorrelationManager.StartLogicalOperation(name);
50 }
65 }
66
67 /// <summary>
68 /// Starts the logical operation nested to the current operation nested to the current one.
69 /// </summary>
70 public static void StartLogicalOperation() {
71 m_currentOperation.Value = new object();
72 Trace.CorrelationManager.StartLogicalOperation();
73
74 }
51 #else
75 #else
52 public static void StartLogicalOperation(object name) {
76 public static void StartLogicalOperation(object name) {
53 Trace.CorrelationManager.StartLogicalOperation(name);
77 Trace.CorrelationManager.StartLogicalOperation(name);
54 }
78 }
79
80 /// <summary>
81 /// Starts the logical operation nested to the current operation nested to the current one.
82 /// </summary>
83 public static void StartLogicalOperation() {
84 Trace.CorrelationManager.StartLogicalOperation();
85
86 }
55 #endif
87 #endif
56
88
57 /// <summary>
89 /// <summary>
@@ -68,7 +100,7 namespace Implab.Diagnostics {
68 /// <param name="arguments">Arguments.</param>
100 /// <param name="arguments">Arguments.</param>
69 [Conditional("DEBUG")]
101 [Conditional("DEBUG")]
70 public static void Debug(string format, params object[] arguments) {
102 public static void Debug(string format, params object[] arguments) {
71
103 TraceSource.TraceEvent(TraceEventType.Verbose, 0, format, arguments);
72 }
104 }
73
105
74 /// <summary>
106 /// <summary>
@@ -135,7 +167,7 namespace Implab.Diagnostics {
135 Trace.CorrelationManager.ActivityId = Guid.NewGuid();
167 Trace.CorrelationManager.ActivityId = Guid.NewGuid();
136
168
137 var prev = Trace.CorrelationManager.ActivityId;
169 var prev = Trace.CorrelationManager.ActivityId;
138
170
139 TraceSource.TraceEvent(TraceEventType.Start, 0, activityName);
171 TraceSource.TraceEvent(TraceEventType.Start, 0, activityName);
140 return new ActivityScope(TraceSource, prev, 0, activityName);
172 return new ActivityScope(TraceSource, prev, 0, activityName);
141 }
173 }
@@ -5,6 +5,7 namespace Implab.Diagnostics {
5 /// Used to mark class which uses <see cref="Trace{T}"/> class to trace it's events
5 /// Used to mark class which uses <see cref="Trace{T}"/> class to trace it's events
6 /// </summary>
6 /// </summary>
7 [AttributeUsage(AttributeTargets.Class)]
7 [AttributeUsage(AttributeTargets.Class)]
8 [Obsolete("Use TraceRegistry to monitor trace sources")]
8 public class TraceSourceAttribute : Attribute {
9 public class TraceSourceAttribute : Attribute {
9 }
10 }
10 }
11 }
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