##// 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
@@ -1,155 +1,38
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Diagnostics;
3 using System.Diagnostics;
4 using System.Dynamic;
4 using System.Dynamic;
5 using System.Linq;
5 using System.Linq;
6 using Implab.Components;
6 using Implab.Components;
7 using Implab.Diagnostics;
7 using Implab.Diagnostics;
8 using Implab.ServiceHost.Unity;
8 using Implab.ServiceHost.Unity;
9 using Implab.Xml;
9 using Implab.Xml;
10 using Unity;
10 using Unity;
11 using Unity.Injection;
11 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
153
36
154 }
37 }
155 }
38 }
@@ -1,143 +1,145
1 using System;
1 using System;
2 using System.IO;
2 using System.IO;
3 using System.Reflection;
3 using System.Reflection;
4 using Implab.Diagnostics;
4 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
12 readonly TypeResolver m_resolver;
12 readonly TypeResolver m_resolver;
13
13
14 readonly IUnityContainer m_container;
14 readonly IUnityContainer m_container;
15
15
16 readonly ContainerConfigurationSchema m_schema;
16 readonly ContainerConfigurationSchema m_schema;
17
17
18 Uri m_location;
18 Uri m_location;
19
19
20 public IUnityContainer Container {
20 public IUnityContainer Container {
21 get {
21 get {
22 return m_container;
22 return m_container;
23 }
23 }
24 }
24 }
25
25
26 public ContainerBuilder() : this(null, null) {
26 public ContainerBuilder() : this(null, null) {
27 }
27 }
28
28
29 public ContainerBuilder(IUnityContainer container, ContainerConfigurationSchema schema) {
29 public ContainerBuilder(IUnityContainer container, ContainerConfigurationSchema schema) {
30 m_container = container ?? new UnityContainer();
30 m_container = container ?? new UnityContainer();
31 m_resolver = new TypeResolver();
31 m_resolver = new TypeResolver();
32 m_schema = schema ?? ContainerConfigurationSchema.Default;
32 m_schema = schema ?? ContainerConfigurationSchema.Default;
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) {
40 Safe.ArgumentNotNull(registration, nameof(registration));
42 Safe.ArgumentNotNull(registration, nameof(registration));
41
43
42 var registrationType = registration.GetRegistrationType(this);
44 var registrationType = registration.GetRegistrationType(this);
43 var implementationType = registration.GetImplementationType(this) ?? registrationType;
45 var implementationType = registration.GetImplementationType(this) ?? registrationType;
44
46
45 if (registrationType == null)
47 if (registrationType == null)
46 throw new Exception($"A type must be specified for the registration {registration.Name}");
48 throw new Exception($"A type must be specified for the registration {registration.Name}");
47
49
48 var builder = new TypeRegistrationBuilder(
50 var builder = new TypeRegistrationBuilder(
49 m_resolver,
51 m_resolver,
50 registrationType,
52 registrationType,
51 implementationType
53 implementationType
52 );
54 );
53
55
54 builder.Lifetime = registration.GetLifetime(this);
56 builder.Lifetime = registration.GetLifetime(this);
55
57
56 if (registration.MemberInjections != null) {
58 if (registration.MemberInjections != null) {
57 foreach(var member in registration.MemberInjections)
59 foreach(var member in registration.MemberInjections)
58 member.Visit(builder);
60 member.Visit(builder);
59 }
61 }
60
62
61 m_container.RegisterType(
63 m_container.RegisterType(
62 builder.RegistrationType,
64 builder.RegistrationType,
63 builder.ImplementationType,
65 builder.ImplementationType,
64 registration.Name,
66 registration.Name,
65 builder.Lifetime,
67 builder.Lifetime,
66 builder.Injections
68 builder.Injections
67 );
69 );
68 }
70 }
69
71
70 public void Visit(IInstanceRegistration registration) {
72 public void Visit(IInstanceRegistration registration) {
71 Safe.ArgumentNotNull(registration, nameof(registration));
73 Safe.ArgumentNotNull(registration, nameof(registration));
72
74
73 var registrationType = registration.GetRegistrationType(this);
75 var registrationType = registration.GetRegistrationType(this);
74
76
75 var builder = new InstanceRegistrationBuilder (
77 var builder = new InstanceRegistrationBuilder (
76 m_resolver,
78 m_resolver,
77 registrationType
79 registrationType
78 );
80 );
79
81
80 builder.Lifetime = registration.GetLifetime(this);
82 builder.Lifetime = registration.GetLifetime(this);
81
83
82 if (registration.MemberInjections != null) {
84 if (registration.MemberInjections != null) {
83 foreach(var member in registration.MemberInjections)
85 foreach(var member in registration.MemberInjections)
84 member.Visit(builder.ValueBuilder);
86 member.Visit(builder.ValueBuilder);
85 }
87 }
86
88
87 if (builder.RegistrationType == null && builder.ValueBuilder.ValueType == null)
89 if (builder.RegistrationType == null && builder.ValueBuilder.ValueType == null)
88 throw new Exception($"A type must be specified for the registration {registration.Name}");
90 throw new Exception($"A type must be specified for the registration {registration.Name}");
89
91
90 m_container.RegisterInstance(
92 m_container.RegisterInstance(
91 builder.RegistrationType ?? builder.ValueBuilder.ValueType,
93 builder.RegistrationType ?? builder.ValueBuilder.ValueType,
92 registration.Name,
94 registration.Name,
93 builder.ValueBuilder.Value,
95 builder.ValueBuilder.Value,
94 builder.Lifetime
96 builder.Lifetime
95 );
97 );
96 }
98 }
97
99
98 public void AddNamespace(string ns) {
100 public void AddNamespace(string ns) {
99 m_resolver.AddNamespace(ns);
101 m_resolver.AddNamespace(ns);
100 }
102 }
101
103
102 public void AddAssembly(string assembly) {
104 public void AddAssembly(string assembly) {
103
105
104 }
106 }
105
107
106 /// <summary>
108 /// <summary>
107 /// Includes the confguration. Creates a new <see cref="ContainerBuilder"/>,
109 /// Includes the confguration. Creates a new <see cref="ContainerBuilder"/>,
108 /// and loads the configuration to it. The created builder will share the
110 /// and loads the configuration to it. The created builder will share the
109 /// container and will have its own isolated type resolver.
111 /// container and will have its own isolated type resolver.
110 /// </summary>
112 /// </summary>
111 /// <param name="file">A path to configuration relative to the current configuration.</param>
113 /// <param name="file">A path to configuration relative to the current configuration.</param>
112 public void Include(string file) {
114 public void Include(string file) {
113 var includeContext = new ContainerBuilder(m_container, m_schema);
115 var includeContext = new ContainerBuilder(m_container, m_schema);
114
116
115 if (m_location != null) {
117 if (m_location != null) {
116 var uri = new Uri(m_location, file);
118 var uri = new Uri(m_location, file);
117 includeContext.LoadConfig(uri);
119 includeContext.LoadConfig(uri);
118 } else {
120 } else {
119 includeContext.LoadConfig(file);
121 includeContext.LoadConfig(file);
120 }
122 }
121 }
123 }
122
124
123 /// <summary>
125 /// <summary>
124 /// Loads a configuration from the specified local file.
126 /// Loads a configuration from the specified local file.
125 /// </summary>
127 /// </summary>
126 /// <param name="file">The path to the configuration file.</param>
128 /// <param name="file">The path to the configuration file.</param>
127 public void LoadConfig(string file) {
129 public void LoadConfig(string file) {
128 Safe.ArgumentNotEmpty(file, nameof(file));
130 Safe.ArgumentNotEmpty(file, nameof(file));
129
131
130 LoadConfig(new Uri(Path.GetFullPath(file)));
132 LoadConfig(new Uri(Path.GetFullPath(file)));
131 }
133 }
132
134
133 public void LoadConfig(Uri location) {
135 public void LoadConfig(Uri location) {
134 Safe.ArgumentNotNull(location, nameof(location));
136 Safe.ArgumentNotNull(location, nameof(location));
135
137
136 m_location = location;
138 m_location = location;
137
139
138 var config = m_schema.LoadConfig(location.ToString());
140 var config = m_schema.LoadConfig(location.ToString());
139 config.Visit(this);
141 config.Visit(this);
140 }
142 }
141
143
142 }
144 }
143 } No newline at end of file
145 }
@@ -1,17 +1,27
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;
16 }
26 }
17 } No newline at end of file
27 }
@@ -1,21 +1,21
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3
3
4 namespace Implab.Diagnostics {
4 namespace Implab.Diagnostics {
5 public class LogicalOperationScope : IDisposable {
5 public class LogicalOperationScope : IDisposable {
6 readonly TraceSource m_source;
6 readonly TraceSource m_source;
7
7
8 readonly LogicalOperation m_operation;
8 readonly LogicalOperation m_operation;
9
9
10 internal LogicalOperationScope(TraceSource source, LogicalOperation operation) {
10 internal LogicalOperationScope(TraceSource source, LogicalOperation operation) {
11 m_source = source;
11 m_source = source;
12 m_operation = operation;
12 m_operation = operation;
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 }
20 }
20 }
21 } No newline at end of file
21 }
@@ -1,114 +1,114
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3 using System.IO;
3 using System.IO;
4
4
5 namespace Implab.Diagnostics {
5 namespace Implab.Diagnostics {
6 public class SimpleTraceListener : TextWriterTraceListener {
6 public class SimpleTraceListener : TextWriterTraceListener {
7 public SimpleTraceListener() {
7 public SimpleTraceListener() {
8 }
8 }
9
9
10 public SimpleTraceListener(Stream stream) : base(stream) {
10 public SimpleTraceListener(Stream stream) : base(stream) {
11 }
11 }
12
12
13 public SimpleTraceListener(TextWriter writer) : base(writer) {
13 public SimpleTraceListener(TextWriter writer) : base(writer) {
14 }
14 }
15
15
16 public SimpleTraceListener(string fileName) : base(fileName) {
16 public SimpleTraceListener(string fileName) : base(fileName) {
17 }
17 }
18
18
19 public SimpleTraceListener(Stream stream, string name) : base(stream, name) {
19 public SimpleTraceListener(Stream stream, string name) : base(stream, name) {
20 }
20 }
21
21
22 public SimpleTraceListener(TextWriter writer, string name) : base(writer, name) {
22 public SimpleTraceListener(TextWriter writer, string name) : base(writer, name) {
23 }
23 }
24
24
25 public SimpleTraceListener(string fileName, string name) : base(fileName, name) {
25 public SimpleTraceListener(string fileName, string name) : base(fileName, name) {
26 }
26 }
27
27
28 public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data) {
28 public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data) {
29 switch (id) {
29 switch (id) {
30 case TraceEventCodes.StartLogicalOperation:
30 case TraceEventCodes.StartLogicalOperation:
31 TraceEvent(eventCache, source, eventType, id, "+{0}", data);
31 TraceEvent(eventCache, source, eventType, id, "+{0}", data);
32 break;
32 break;
33 case TraceEventCodes.StopLogicalOperation:
33 case TraceEventCodes.StopLogicalOperation:
34 TraceEvent(eventCache, source, eventType, id, FormatStopLogicalOperation(data));
34 TraceEvent(eventCache, source, eventType, id, FormatStopLogicalOperation(data));
35 break;
35 break;
36 default:
36 default:
37 TraceEvent(eventCache, source, eventType, id, data?.ToString());
37 TraceEvent(eventCache, source, eventType, id, data?.ToString());
38 break;
38 break;
39 }
39 }
40 }
40 }
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 }
48 }
48 }
49
49
50 string FormatTimespan(TimeSpan value) {
50 string FormatTimespan(TimeSpan value) {
51 if (value.TotalSeconds < 10) {
51 if (value.TotalSeconds < 10) {
52 return value.Milliseconds.ToString() + "ms";
52 return value.Milliseconds.ToString() + "ms";
53 } else if (value.TotalSeconds < 30) {
53 } else if (value.TotalSeconds < 30) {
54 return string.Format("{0:0.###}s", value.TotalSeconds);
54 return string.Format("{0:0.###}s", value.TotalSeconds);
55 } else {
55 } else {
56 return value.ToString();
56 return value.ToString();
57 }
57 }
58 }
58 }
59
59
60 public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, params object[] data) {
60 public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, params object[] data) {
61 var prev = IndentLevel;
61 var prev = IndentLevel;
62 IndentLevel += eventCache.LogicalOperationStack.Count;
62 IndentLevel += eventCache.LogicalOperationStack.Count;
63 try {
63 try {
64 base.TraceData(eventCache, source, eventType, id, data);
64 base.TraceData(eventCache, source, eventType, id, data);
65 } finally {
65 } finally {
66 IndentLevel = prev;
66 IndentLevel = prev;
67 }
67 }
68 }
68 }
69
69
70 public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id) {
70 public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id) {
71 var prev = IndentLevel;
71 var prev = IndentLevel;
72 IndentLevel += eventCache.LogicalOperationStack.Count;
72 IndentLevel += eventCache.LogicalOperationStack.Count;
73 try {
73 try {
74 base.TraceEvent(eventCache, source, eventType, id);
74 base.TraceEvent(eventCache, source, eventType, id);
75 } finally {
75 } finally {
76 IndentLevel = prev;
76 IndentLevel = prev;
77 }
77 }
78 }
78 }
79
79
80 public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args) {
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));
81 TraceEvent(eventCache, source, eventType, id, String.Format(format, args));
82 }
82 }
83
83
84 public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message) {
84 public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message) {
85 var prev = IndentLevel;
85 var prev = IndentLevel;
86 IndentLevel += eventCache.LogicalOperationStack.Count;
86 IndentLevel += eventCache.LogicalOperationStack.Count;
87 try {
87 try {
88 LogicalOperation operation = null;
88 LogicalOperation operation = null;
89 if (eventCache.LogicalOperationStack.Count > 0)
89 if (eventCache.LogicalOperationStack.Count > 0)
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 }
97 } finally {
97 } finally {
98 IndentLevel = prev;
98 IndentLevel = prev;
99 }
99 }
100 }
100 }
101
101
102 public override void TraceTransfer(TraceEventCache eventCache, string source, int id, string message, Guid relatedActivityId) {
102 public override void TraceTransfer(TraceEventCache eventCache, string source, int id, string message, Guid relatedActivityId) {
103 var prev = IndentLevel;
103 var prev = IndentLevel;
104 IndentLevel += eventCache.LogicalOperationStack.Count;
104 IndentLevel += eventCache.LogicalOperationStack.Count;
105 try {
105 try {
106 base.TraceTransfer(eventCache, source, id, message, relatedActivityId);
106 base.TraceTransfer(eventCache, source, id, message, relatedActivityId);
107 } finally {
107 } finally {
108 IndentLevel = prev;
108 IndentLevel = prev;
109 }
109 }
110 }
110 }
111
111
112
112
113 }
113 }
114 } No newline at end of file
114 }
@@ -1,160 +1,192
1 // enable System.Diagnostics trace methods
1 // enable System.Diagnostics trace methods
2 #define TRACE
2 #define TRACE
3
3
4 using System;
4 using System;
5 using System.Collections.Generic;
5 using System.Collections.Generic;
6 using System.Diagnostics;
6 using System.Diagnostics;
7 using System.Linq;
7 using System.Linq;
8 using System.Text;
8 using System.Text;
9 using System.Threading;
9 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>
45 /// <param name="name">Name.</param>
60 /// <param name="name">Name.</param>
46 #if NETFX_TRACE_BUG
61 #if NETFX_TRACE_BUG
47 public static void StartLogicalOperation(object name) {
62 public static void StartLogicalOperation(object name) {
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>
58 /// Ends the logical operation and restores the previous one.
90 /// Ends the logical operation and restores the previous one.
59 /// </summary>
91 /// </summary>
60 public static void StopLogicalOperation() {
92 public static void StopLogicalOperation() {
61 Trace.CorrelationManager.StopLogicalOperation();
93 Trace.CorrelationManager.StopLogicalOperation();
62 }
94 }
63
95
64 /// <summary>
96 /// <summary>
65 /// Writes a debug message.
97 /// Writes a debug message.
66 /// </summary>
98 /// </summary>
67 /// <param name="format">Format.</param>
99 /// <param name="format">Format.</param>
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>
75 /// Writes an informational message.
107 /// Writes an informational message.
76 /// </summary>
108 /// </summary>
77 /// <param name="format">Format.</param>
109 /// <param name="format">Format.</param>
78 /// <param name="arguments">Arguments.</param>
110 /// <param name="arguments">Arguments.</param>
79 [Conditional("TRACE")]
111 [Conditional("TRACE")]
80 public static void Log(string format, params object[] arguments) {
112 public static void Log(string format, params object[] arguments) {
81 TraceSource.TraceEvent(TraceEventType.Information, 0, format, arguments);
113 TraceSource.TraceEvent(TraceEventType.Information, 0, format, arguments);
82 }
114 }
83
115
84 /// <summary>
116 /// <summary>
85 /// Writes a warning message.
117 /// Writes a warning message.
86 /// </summary>
118 /// </summary>
87 /// <param name="format">Format.</param>
119 /// <param name="format">Format.</param>
88 /// <param name="arguments">Arguments.</param>
120 /// <param name="arguments">Arguments.</param>
89 public static void Warn(string format, params object[] arguments) {
121 public static void Warn(string format, params object[] arguments) {
90 TraceSource.TraceEvent(TraceEventType.Warning, 0, format, arguments);
122 TraceSource.TraceEvent(TraceEventType.Warning, 0, format, arguments);
91 }
123 }
92
124
93 /// <summary>
125 /// <summary>
94 /// Writes a error message.
126 /// Writes a error message.
95 /// </summary>
127 /// </summary>
96 /// <param name="format">Format.</param>
128 /// <param name="format">Format.</param>
97 /// <param name="arguments">Arguments.</param>
129 /// <param name="arguments">Arguments.</param>
98 public static void Error(string format, params object[] arguments) {
130 public static void Error(string format, params object[] arguments) {
99 TraceSource.TraceEvent(TraceEventType.Error, 0, format, arguments);
131 TraceSource.TraceEvent(TraceEventType.Error, 0, format, arguments);
100 }
132 }
101
133
102 public static void Error(Exception err) {
134 public static void Error(Exception err) {
103 TraceSource.TraceData(TraceEventType.Error, 0, err);
135 TraceSource.TraceData(TraceEventType.Error, 0, err);
104 }
136 }
105
137
106 /// <summary>
138 /// <summary>
107 /// This method save the current activity, and transfers to the specified activity,
139 /// This method save the current activity, and transfers to the specified activity,
108 /// emits <see cref="TraceEventType.Start"/> and returns a scope of the new
140 /// emits <see cref="TraceEventType.Start"/> and returns a scope of the new
109 /// activity.
141 /// activity.
110 /// </summary>
142 /// </summary>
111 /// <param name="activityName">The name of the new activity/</param>
143 /// <param name="activityName">The name of the new activity/</param>
112 /// <param name="activityId">The identifier of the activity to which
144 /// <param name="activityId">The identifier of the activity to which
113 /// the control will be transferred</param>
145 /// the control will be transferred</param>
114 /// <returns>A scope of the new activity, dispose it to transfer
146 /// <returns>A scope of the new activity, dispose it to transfer
115 /// the control back to the original activity.</returns>
147 /// the control back to the original activity.</returns>
116 public static ActivityScope TransferActivity(string activityName, Guid activityId) {
148 public static ActivityScope TransferActivity(string activityName, Guid activityId) {
117 var prev = Trace.CorrelationManager.ActivityId;
149 var prev = Trace.CorrelationManager.ActivityId;
118
150
119 TraceSource.TraceTransfer(0, "Transfer", activityId);
151 TraceSource.TraceTransfer(0, "Transfer", activityId);
120 Trace.CorrelationManager.ActivityId = activityId;
152 Trace.CorrelationManager.ActivityId = activityId;
121 TraceSource.TraceEvent(TraceEventType.Start, 0, activityName);
153 TraceSource.TraceEvent(TraceEventType.Start, 0, activityName);
122
154
123 return new ActivityScope(TraceSource, prev, 0, activityName);
155 return new ActivityScope(TraceSource, prev, 0, activityName);
124 }
156 }
125
157
126 /// <summary>
158 /// <summary>
127 /// Emits <see cref="TraceEventType.Start"/> and returns a scope of the
159 /// Emits <see cref="TraceEventType.Start"/> and returns a scope of the
128 /// activity.
160 /// activity.
129 /// </summary>
161 /// </summary>
130 /// <param name="activityName">The name of the activity to start</param>
162 /// <param name="activityName">The name of the activity to start</param>
131 /// <returns>A scope of the new activity, dispose it to emit
163 /// <returns>A scope of the new activity, dispose it to emit
132 /// <see cref="TraceEventType.Stop"/> for the current activity.</returns>
164 /// <see cref="TraceEventType.Stop"/> for the current activity.</returns>
133 public static ActivityScope StartActivity(string activityName) {
165 public static ActivityScope StartActivity(string activityName) {
134 if (Trace.CorrelationManager.ActivityId == Guid.Empty)
166 if (Trace.CorrelationManager.ActivityId == Guid.Empty)
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 }
142
174
143 /// <summary>
175 /// <summary>
144 /// Creates new <see cref="LogicalOperation(string)"/> and calls
176 /// Creates new <see cref="LogicalOperation(string)"/> and calls
145 /// to <see cref="CorrelationManager.StartLogicalOperation(object)"/>
177 /// to <see cref="CorrelationManager.StartLogicalOperation(object)"/>
146 /// passing the created operation as identity. Calls
178 /// passing the created operation as identity. Calls
147 /// <see cref="TraceSource.TraceData(TraceEventType, int, object)"/>
179 /// <see cref="TraceSource.TraceData(TraceEventType, int, object)"/>
148 /// to notify listeners on operation start.
180 /// to notify listeners on operation start.
149 /// </summary>
181 /// </summary>
150 /// <param name="name">The name of the logical operation.</param>
182 /// <param name="name">The name of the logical operation.</param>
151 /// <returns>Logical operation scope, disposing it will stop
183 /// <returns>Logical operation scope, disposing it will stop
152 /// logical operation and notify trace listeners.</returns>
184 /// logical operation and notify trace listeners.</returns>
153 public static LogicalOperationScope LogicalOperation(string name) {
185 public static LogicalOperationScope LogicalOperation(string name) {
154 var operation = new LogicalOperation(name);
186 var operation = new LogicalOperation(name);
155 TraceSource.TraceData(TraceEventType.Information, TraceEventCodes.StartLogicalOperation, operation);
187 TraceSource.TraceData(TraceEventType.Information, TraceEventCodes.StartLogicalOperation, operation);
156 StartLogicalOperation(operation);
188 StartLogicalOperation(operation);
157 return new LogicalOperationScope(TraceSource, operation);
189 return new LogicalOperationScope(TraceSource, operation);
158 }
190 }
159 }
191 }
160 }
192 }
@@ -1,10 +1,11
1 using System;
1 using System;
2
2
3 namespace Implab.Diagnostics {
3 namespace Implab.Diagnostics {
4 /// <summary>
4 /// <summary>
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