├── .editorconfig
├── .gitignore
├── .nuget
└── packages.config
├── Build.bat
├── Build.ps1
├── Build.psake.ps1
├── Building.txt
├── EventSourceProxy.Example
├── EventSourceProxy.Example.csproj
├── IExampleLogSource.cs
└── Program.cs
├── EventSourceProxy.Tests
├── BaseLoggingTest.cs
├── EventActivityScopeTests.cs
├── EventAttributeProviderTests.cs
├── EventDataTypesTests.cs
├── EventSourceImplementerTests.cs
├── EventSourceProxy.Tests.csproj
├── FluentInterfaceTests.cs
├── ParameterProviderTests.cs
├── Properties
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── SerializationTests.cs
├── TestEventListener.cs
├── TraceContextProviderTests.cs
└── TracingProxyTests.cs
├── EventSourceProxy.nuspec
├── EventSourceProxy.sln
├── EventSourceProxy.snk
├── EventSourceProxy
├── Any.cs
├── CodeAnalysisRules.ruleset
├── CustomDictionary.xml
├── EventActivityScope.cs
├── EventAttributeHelper.cs
├── EventAttributeProvider.cs
├── EventAttributeProviderAttribute.cs
├── EventExceptionAttribute.cs
├── EventSourceAttributeHelper.cs
├── EventSourceImplementationAttribute.cs
├── EventSourceImplementer.cs
├── EventSourceManifest.cs
├── EventSourceProxy.csproj
├── GlobalSuppressions.cs
├── InvocationContext.cs
├── InvocationContextTypes.cs
├── JsonObjectSerializer.cs
├── NullObjectSerializer.cs
├── ParameterBuilder.cs
├── ParameterBuilderValue.cs
├── ParameterConverter.cs
├── ParameterDefinition.cs
├── ParameterMapping.cs
├── Properties
│ └── AssemblyInfo.cs
├── ProviderManager.cs
├── ProxyHelper.cs
├── Settings.StyleCop
├── StaticFieldStorage.cs
├── ToStringObjectSerializer.cs
├── TraceAsAttribute.cs
├── TraceAsDataAttribute.cs
├── TraceContext.cs
├── TraceContextAttribute.cs
├── TraceContextProvider.cs
├── TraceContextProviderAttribute.cs
├── TraceIgnoreAttribute.cs
├── TraceMemberAttribute.cs
├── TraceParameterProvider.cs
├── TraceParameterProviderAttribute.cs
├── TraceProviderAttribute.cs
├── TraceSerializationAttribute.cs
├── TraceSerializationContext.cs
├── TraceSerializationProvider.cs
├── TraceSerializationProviderAttribute.cs
├── TraceTransformAttribute.cs
├── TracingProxy.cs
├── TracingProxyImplementer.cs
└── TypeImplementer.cs
├── GenerateProxyManifest
├── GenerateProxyManifest.csproj
└── Program.cs
├── LICENSE
└── README.md
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | end_of_line = crlf
3 | insert_final_newline = true
4 | indent_style = tab
5 | indent_size = 4
6 | trim_tailing_whitespace = true
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | obj
3 | *.user
4 | *.suo
5 | *.docstates
6 | *.nupkg
7 | *.orig
8 | *.rej
9 | StyleCop.Cache
10 | Output
11 | TestResult.xml
12 | packages
13 | PerfView.exe
--------------------------------------------------------------------------------
/.nuget/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Build.bat:
--------------------------------------------------------------------------------
1 | PowerShell .\build.ps1 %1
--------------------------------------------------------------------------------
/Build.ps1:
--------------------------------------------------------------------------------
1 | param (
2 | [string] $target = "default"
3 | )
4 |
5 | Invoke-psake .\Build.psake.ps1 -taskList $target
6 |
--------------------------------------------------------------------------------
/Build.psake.ps1:
--------------------------------------------------------------------------------
1 | $psake.use_exit_on_error = $true
2 |
3 | #########################################
4 | # to build a new version
5 | # 1. git tag 1.0.x
6 | # 2. build package
7 | #########################################
8 |
9 | properties {
10 | $version = git describe --abbrev=0 --tags
11 | }
12 |
13 | Task default -depends Build
14 |
15 | Task Build {
16 | Write-Output "Building Version $version"
17 |
18 | Exec {
19 | dotnet build --configuration Release /p:Version=$version
20 | }
21 | }
22 |
23 | Task Test {
24 | dotnet test --configuration Release
25 | }
26 |
27 | Task Package -depends Test {
28 | nuget pack .\EventSourceProxy.nuspec -version $version
29 | }
30 |
31 | Task Push {
32 | cmd /c "for %p in (*.nupkg) do nuget push %p -source https://www.nuget.org/api/v2/package"
33 | }
--------------------------------------------------------------------------------
/Building.txt:
--------------------------------------------------------------------------------
1 | Notes for Building EventSourceProxy
2 | ===================================
3 |
4 | * Building requires Psake - you can get it from http://nuget.org/packages/psake/
5 |
--------------------------------------------------------------------------------
/EventSourceProxy.Example/EventSourceProxy.Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Exe
9 | netcoreapp2.0
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/EventSourceProxy.Example/IExampleLogSource.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Tracing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace EventSourceProxy.Example
9 | {
10 | public interface IExampleLogSource
11 | {
12 | [Event(1, Message="Starting")]
13 | void Starting();
14 | void AnEvent(string data);
15 | [Event(2, Message = "Stopping")]
16 | void Stopping();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/EventSourceProxy.Example/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Diagnostics.Tracing;
5 | using System.Linq;
6 | using System.Reflection;
7 | using System.Runtime.InteropServices;
8 | using System.Security;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using EventSourceProxy;
12 |
13 | namespace EventSourceProxy.Example
14 | {
15 | public class Foo
16 | {
17 | public virtual void Bar() {}
18 | public virtual int Bar2() { return 1; }
19 | }
20 |
21 | public class TestListener : EventListener
22 | {
23 | protected override void OnEventWritten(EventWrittenEventArgs eventData)
24 | {
25 | Console.Write("Activity: {0} ", EventActivityScope.CurrentActivityId);
26 | Console.WriteLine(eventData.Message, eventData.Payload.ToArray());
27 | }
28 | }
29 |
30 | class Program
31 | {
32 | static void Main(string[] args)
33 | {
34 | // create the log
35 | var log = EventSourceImplementer.GetEventSourceAs();
36 | EventSource es = (EventSource)log;
37 | Console.WriteLine("Provider GUID = {0}", es.Guid);
38 |
39 | // create a listener
40 | var listener = new TestListener();
41 | listener.EnableEvents(es, EventLevel.LogAlways);
42 |
43 | using (new EventActivityScope())
44 | {
45 | log.Starting();
46 | for (int i = 0; i < 10; i++)
47 | {
48 | using (new EventActivityScope())
49 | {
50 | log.AnEvent(String.Format("i = {0}", i));
51 | }
52 | }
53 | log.Stopping();
54 | }
55 |
56 | TracingProxy.Create(new Foo()).Bar();
57 | TracingProxy.Create(new Foo()).Bar2();
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/EventSourceProxy.Tests/BaseLoggingTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using NUnit.Framework;
7 | using System.Diagnostics.Tracing;
8 |
9 | namespace EventSourceProxy.Tests
10 | {
11 | public class BaseLoggingTest
12 | {
13 | #region Setup and TearDown
14 | internal TestEventListener _listener;
15 |
16 | [SetUp]
17 | public void SetUp()
18 | {
19 | _listener = new TestEventListener();
20 | }
21 | #endregion
22 |
23 | protected void EnableLogging() where TLog : class
24 | {
25 | // create the logger and make sure it is serializing the parameters properly
26 | var logger = EventSourceImplementer.GetEventSource();
27 | _listener.EnableEvents(logger, EventLevel.LogAlways);
28 | }
29 |
30 | protected void EnableLogging(object proxy)
31 | {
32 | // create the logger and make sure it is serializing the parameters properly
33 | _listener.EnableEvents((EventSource)proxy, EventLevel.LogAlways);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/EventSourceProxy.Tests/EventActivityScopeTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using NUnit.Framework;
7 |
8 | namespace EventSourceProxy.Tests
9 | {
10 | [TestFixture]
11 | public class EventActivityScopeTests
12 | {
13 | [Test]
14 | public void GetActivityIdShouldReturnEmptyGuid()
15 | {
16 | using (EventActivityScope scope1 = new EventActivityScope())
17 | {
18 | Assert.AreEqual(Guid.Empty, scope1.PreviousActivityId);
19 | }
20 | }
21 |
22 | [Test]
23 | public void NewScopeShouldGenerateNewActivity()
24 | {
25 | using (EventActivityScope scope1 = new EventActivityScope())
26 | {
27 | // make sure we don't have an outer activity, but do have an inner activity
28 | Assert.AreEqual(Guid.Empty, scope1.PreviousActivityId);
29 | Assert.AreNotEqual(Guid.Empty, scope1.ActivityId);
30 |
31 | using (EventActivityScope scope2 = new EventActivityScope())
32 | {
33 | Assert.AreEqual(scope1.ActivityId, scope2.PreviousActivityId);
34 | Assert.AreNotEqual(scope1.ActivityId, scope2.ActivityId);
35 | }
36 | }
37 | }
38 |
39 | [Test]
40 | public void ReuseScopeShouldReuseActivityId()
41 | {
42 | using (EventActivityScope scope1 = new EventActivityScope())
43 | {
44 | // make sure we don't have an outer activity, but do have an inner activity
45 | Assert.AreEqual(Guid.Empty, scope1.PreviousActivityId);
46 | Assert.AreNotEqual(Guid.Empty, scope1.ActivityId);
47 |
48 | using (EventActivityScope scope2 = new EventActivityScope(true))
49 | {
50 | Assert.AreEqual(scope1.ActivityId, scope2.PreviousActivityId);
51 | Assert.AreEqual(scope1.ActivityId, scope2.ActivityId);
52 | }
53 | }
54 | }
55 |
56 | [Test]
57 | public void NewScopeWithExistingActivityIdShouldUseCorrectActivityId()
58 | {
59 | Guid externalGuid = Guid.Parse("c2cbe3e9-53ee-440c-b16b-2dec89df7202");
60 | using (EventActivityScope scope1 = new EventActivityScope(externalGuid))
61 | {
62 | Assert.AreEqual(scope1.ActivityId, externalGuid);
63 | }
64 | }
65 |
66 | [Test]
67 | public void ReuseScopeShouldReuseExternalActivityId()
68 | {
69 | Guid externalGuid = Guid.Parse("b423a74f-f5c7-4707-8555-552567ec446a");
70 | using (EventActivityScope scope1 = new EventActivityScope(externalGuid))
71 | {
72 | Assert.AreEqual(scope1.ActivityId, externalGuid);
73 | // make sure we don't have an outer activity, but do have an inner activity
74 | Assert.AreEqual(Guid.Empty, scope1.PreviousActivityId);
75 | Assert.AreNotEqual(Guid.Empty, scope1.ActivityId);
76 |
77 | using (EventActivityScope scope2 = new EventActivityScope(true))
78 | {
79 | Assert.AreEqual(scope1.ActivityId, scope2.PreviousActivityId);
80 | Assert.AreEqual(scope1.ActivityId, scope2.ActivityId);
81 | }
82 | }
83 | }
84 |
85 | [Test]
86 | public void NewScopeShouldGenerateNewActivityIdWhenParentHasExternalActivityId()
87 | {
88 | Guid externalGuid = Guid.Parse("adc174e5-6f7b-4280-a4a4-8d8550ab4f89");
89 | using (EventActivityScope scope1 = new EventActivityScope(externalGuid))
90 | {
91 | Assert.AreEqual(scope1.ActivityId, externalGuid);
92 | // make sure we don't have an outer activity, but do have an inner activity
93 | Assert.AreEqual(Guid.Empty, scope1.PreviousActivityId);
94 | Assert.AreNotEqual(Guid.Empty, scope1.ActivityId);
95 |
96 | using (EventActivityScope scope2 = new EventActivityScope())
97 | {
98 | Assert.AreEqual(scope1.ActivityId, scope2.PreviousActivityId);
99 | Assert.AreNotEqual(scope1.ActivityId, scope2.ActivityId);
100 | }
101 | }
102 | }
103 |
104 | [Test]
105 | public void NewScopeWithExternalActivityIdShouldUseCorrectActivityId()
106 | {
107 | Guid externalGuid = Guid.Parse("64a49a09-c775-4a91-b4ec-91a9a6e3caeb");
108 | using (EventActivityScope scope1 = new EventActivityScope())
109 | {
110 | // make sure we don't have an outer activity, but do have an inner activity
111 | Assert.AreEqual(Guid.Empty, scope1.PreviousActivityId);
112 | Assert.AreNotEqual(Guid.Empty, scope1.ActivityId);
113 |
114 | using (EventActivityScope scope2 = new EventActivityScope(externalGuid))
115 | {
116 | Assert.AreEqual(scope2.ActivityId, externalGuid);
117 | Assert.AreEqual(scope1.ActivityId, scope2.PreviousActivityId);
118 | Assert.AreNotEqual(scope1.ActivityId, scope2.ActivityId);
119 | }
120 | }
121 | }
122 |
123 | #region Async Tests
124 | public interface ILogForAsync
125 | {
126 | void Log();
127 | }
128 |
129 | public async Task TestActivityIDAsync()
130 | {
131 | var log = EventSourceImplementer.GetEventSourceAs();
132 |
133 | using (var scope = new EventSourceProxy.EventActivityScope())
134 | {
135 | var before = EventActivityScope.CurrentActivityId;
136 |
137 | log.Log();
138 |
139 | await Task.Factory.StartNew(() => {});
140 |
141 | Assert.AreEqual(before, EventActivityScope.CurrentActivityId);
142 | Assert.AreEqual(before, scope.ActivityId);
143 | }
144 | }
145 |
146 | [Test]
147 | public void ActivityIDShouldRestoreAfterAwait()
148 | {
149 | TestActivityIDAsync().Wait();
150 | }
151 | #endregion
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/EventSourceProxy.Tests/EventAttributeProviderTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Tracing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using NUnit.Framework;
8 |
9 | namespace EventSourceProxy.Tests
10 | {
11 | [TestFixture]
12 | public class EventAttributeProviderTests : BaseLoggingTest
13 | {
14 | #region Provider Attribute Tests
15 | [EventAttributeProvider(typeof(MyEventAttributeProvider))]
16 | public interface ILogInterfaceWithAttribute
17 | {
18 | void DoSomething();
19 | }
20 |
21 | public class LogInterfaceWithAttribute : ILogInterfaceWithAttribute
22 | {
23 | public void DoSomething() { throw new ApplicationException(); }
24 | }
25 |
26 | public class MyEventAttributeProvider : EventAttributeProvider
27 | {
28 | public MyEventAttributeProvider() : base(EventLevel.Warning, EventLevel.Critical)
29 | {
30 | }
31 | }
32 |
33 | [Test]
34 | public void AttributeShouldDetermineProvider()
35 | {
36 | var logger = EventSourceImplementer.GetEventSourceAs();
37 | _listener.EnableEvents((EventSource)logger, EventLevel.LogAlways);
38 |
39 | logger.DoSomething();
40 |
41 | // look at the events
42 | var events = _listener.Events.ToArray();
43 | Assert.AreEqual(1, events.Length);
44 | Assert.AreEqual(EventLevel.Warning, events[0].Level);
45 |
46 | _listener.Reset();
47 | var proxy = TracingProxy.Create(new LogInterfaceWithAttribute());
48 | try { proxy.DoSomething(); }
49 | catch { }
50 |
51 | events = _listener.Events.ToArray();
52 | Assert.AreEqual(2, events.Length);
53 | Assert.AreEqual(EventLevel.Critical, events[1].Level);
54 | }
55 | #endregion
56 |
57 | #region Exception Attribute Tests
58 | [EventException(EventLevel.Critical)]
59 | public interface ILogInterfaceWithExceptionAttribute
60 | {
61 | void DoSomething();
62 | }
63 |
64 | public class LogInterfaceWithExceptionAttribute : ILogInterfaceWithExceptionAttribute
65 | {
66 | public void DoSomething() { throw new ApplicationException(); }
67 | }
68 |
69 | public interface ILogInterfaceWithExceptionMethodAttribute
70 | {
71 | [EventException(EventLevel.Critical)]
72 | void DoSomething();
73 | }
74 |
75 | public class LogInterfaceWithExceptionMethodAttribute : ILogInterfaceWithExceptionMethodAttribute
76 | {
77 | public void DoSomething() { throw new ApplicationException(); }
78 | }
79 |
80 | [Test]
81 | public void ExceptionAttributeShouldDetermineLevel()
82 | {
83 | Assert.AreEqual(EventLevel.Error, new EventAttributeProvider().ExceptionEventLevel);
84 |
85 | var logger = EventSourceImplementer.GetEventSourceAs();
86 | _listener.EnableEvents((EventSource)logger, EventLevel.LogAlways);
87 |
88 | logger.DoSomething();
89 |
90 | // look at the events
91 | var events = _listener.Events.ToArray();
92 | Assert.AreEqual(1, events.Length);
93 | Assert.AreEqual(EventLevel.Informational, events[0].Level);
94 |
95 | _listener.Reset();
96 | var proxy = TracingProxy.Create(new LogInterfaceWithExceptionAttribute());
97 | try { proxy.DoSomething(); }
98 | catch { }
99 |
100 | events = _listener.Events.ToArray();
101 | Assert.AreEqual(2, events.Length);
102 | Assert.AreEqual(EventLevel.Critical, events[1].Level);
103 | }
104 |
105 | [Test]
106 | public void ExceptionAttributeOnMethodShouldDetermineLevel()
107 | {
108 | Assert.AreEqual(EventLevel.Error, new EventAttributeProvider().ExceptionEventLevel);
109 |
110 | var logger = EventSourceImplementer.GetEventSourceAs();
111 | _listener.EnableEvents((EventSource)logger, EventLevel.LogAlways);
112 |
113 | logger.DoSomething();
114 |
115 | // look at the events
116 | var events = _listener.Events.ToArray();
117 | Assert.AreEqual(1, events.Length);
118 | Assert.AreEqual(EventLevel.Informational, events[0].Level);
119 |
120 | _listener.Reset();
121 | var proxy = TracingProxy.Create(new LogInterfaceWithExceptionMethodAttribute());
122 | try { proxy.DoSomething(); }
123 | catch { }
124 |
125 | events = _listener.Events.ToArray();
126 | Assert.AreEqual(2, events.Length);
127 | Assert.AreEqual(EventLevel.Critical, events[1].Level);
128 | }
129 | #endregion
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/EventSourceProxy.Tests/EventDataTypesTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Tracing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using NUnit.Framework;
8 |
9 | namespace EventSourceProxy.Tests
10 | {
11 | [TestFixture]
12 | public class EventDataTypesTests
13 | {
14 | #region Tests for Built-in Types
15 | public enum FooEnum
16 | {
17 | Foo,
18 | Bar
19 | }
20 |
21 | public interface ITypeLog
22 | {
23 | void Log(T t);
24 | }
25 |
26 | public static class TypeLogTester
27 | {
28 | public static void Test(T t)
29 | {
30 | var testLog = (EventSource)EventSourceImplementer.GetEventSourceAs>();
31 |
32 | using (var listener = new TestEventListener())
33 | {
34 | listener.EnableEvents(testLog, EventLevel.LogAlways);
35 |
36 | ITypeLog tLog = (ITypeLog)testLog;
37 | tLog.Log(t);
38 |
39 | object value = listener.Events.Last().Payload[0];
40 | if (TypeIsSupportedByEventSource(typeof(T)))
41 | Assert.AreEqual(t, value);
42 | else
43 | Assert.AreEqual(t.ToString(), value);
44 |
45 | listener.DisableEvents(testLog);
46 | }
47 | }
48 |
49 | internal static bool TypeIsSupportedByEventSource(Type type)
50 | {
51 | if (type == typeof(string)) return true;
52 | if (type == typeof(int)) return true;
53 | if (type == typeof(long)) return true;
54 | if (type == typeof(ulong)) return true;
55 | if (type == typeof(byte)) return true;
56 | if (type == typeof(sbyte)) return true;
57 | if (type == typeof(short)) return true;
58 | if (type == typeof(ushort)) return true;
59 | if (type == typeof(float)) return true;
60 | if (type == typeof(double)) return true;
61 | if (type == typeof(bool)) return true;
62 | if (type == typeof(Guid)) return true;
63 | if (type.IsEnum) return true;
64 |
65 | return false;
66 | }
67 | }
68 |
69 | [Test]
70 | public void BuiltInTypesCanBeLogged()
71 | {
72 | TypeLogTester.Test("string");
73 | TypeLogTester.Test(5);
74 | TypeLogTester.Test(0x800000000);
75 | TypeLogTester.Test(0x1800000000);
76 | TypeLogTester.Test(0x78);
77 | TypeLogTester.Test(0x20);
78 | TypeLogTester.Test(0x1001);
79 | TypeLogTester.Test(0x8010);
80 | TypeLogTester.Test(1.234f);
81 | TypeLogTester.Test(2.3456);
82 | TypeLogTester.Test(true);
83 | TypeLogTester.Test(Guid.NewGuid());
84 | TypeLogTester.Test(FooEnum.Bar);
85 | TypeLogTester.Test(new IntPtr(1234));
86 | TypeLogTester.Test('c');
87 | TypeLogTester.Test(3.456m);
88 |
89 | TypeLogTester.Test(5);
90 | TypeLogTester.Test(0x800000000);
91 | TypeLogTester.Test(0x1800000000);
92 | TypeLogTester.Test(0x78);
93 | TypeLogTester.Test(0x20);
94 | TypeLogTester.Test(0x1001);
95 | TypeLogTester.Test(0x8010);
96 | TypeLogTester.Test(1.234f);
97 | TypeLogTester.Test(2.3456);
98 | TypeLogTester.Test(true);
99 | TypeLogTester.Test(Guid.NewGuid());
100 | TypeLogTester.Test(FooEnum.Bar);
101 | TypeLogTester.Test(new IntPtr(1234));
102 | TypeLogTester.Test('c');
103 | TypeLogTester.Test(3.456m);
104 |
105 | TypeLogTester.Test(null);
106 | TypeLogTester.Test(null);
107 | TypeLogTester.Test(null);
108 | TypeLogTester.Test(null);
109 | TypeLogTester.Test(null);
110 | TypeLogTester.Test(null);
111 | TypeLogTester.Test(null);
112 | TypeLogTester.Test(null);
113 | TypeLogTester.Test(null);
114 | TypeLogTester.Test(null);
115 | TypeLogTester.Test(null);
116 | TypeLogTester.Test(null);
117 | TypeLogTester.Test(null);
118 | TypeLogTester.Test(null);
119 | TypeLogTester.Test(null);
120 | }
121 | #endregion
122 |
123 | #region Serialized Types in Abstract Methods Tests
124 | public abstract class TypeLogWithSerializedTypesInAbstractMethod : EventSource
125 | {
126 | public abstract void LogIntPtr(IntPtr p);
127 | public abstract void LogChar(char c);
128 | public abstract void LogDecimal(decimal d);
129 | }
130 |
131 | [Test]
132 | public void BuiltInSerializedTypesCanBeLoggedInAbstractMethods()
133 | {
134 | var listener = new TestEventListener();
135 | var testLog = EventSourceImplementer.GetEventSourceAs();
136 | listener.EnableEvents(testLog, EventLevel.LogAlways);
137 |
138 | testLog.LogIntPtr(new IntPtr(1234)); Assert.AreEqual("1234", listener.Events.Last().Payload[0].ToString());
139 | testLog.LogChar('c'); Assert.AreEqual("c", listener.Events.Last().Payload[0].ToString());
140 | testLog.LogDecimal(3.456m); Assert.AreEqual("3.456", listener.Events.Last().Payload[0].ToString());
141 | }
142 | #endregion
143 |
144 | #region Serialized Types in Direct Methods Tests
145 | public class TypeLogWithSerializedTypesInDirectMethod : EventSource
146 | {
147 | public void LogIntPtr(IntPtr p) { WriteEvent(1, p); }
148 | public void LogChar(char c) { WriteEvent(2, c); }
149 | public void LogDecimal(decimal d) { WriteEvent(3, d); }
150 | }
151 |
152 | [Test]
153 | public void BuiltInSerializedTypesCanBeLoggedInDirectMethods()
154 | {
155 | var listener = new TestEventListener();
156 | var testLog = EventSourceImplementer.GetEventSourceAs();
157 | listener.EnableEvents(testLog, EventLevel.LogAlways);
158 |
159 | testLog.LogIntPtr(new IntPtr(1234)); Assert.AreEqual("1234", listener.Events.Last().Payload[0].ToString());
160 | testLog.LogChar('c'); Assert.AreEqual("c", listener.Events.Last().Payload[0].ToString());
161 | testLog.LogDecimal(3.456m); Assert.AreEqual("3.456", listener.Events.Last().Payload[0].ToString());
162 | }
163 | #endregion
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/EventSourceProxy.Tests/EventSourceProxy.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0;net46
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/EventSourceProxy.Tests/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.34014
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace EventSourceProxy.Tests.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("EventSourceProxy.Tests.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized string similar to 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901 [rest of string was truncated]";.
65 | ///
66 | internal static string TooBig {
67 | get {
68 | return ResourceManager.GetString("TooBig", resourceCulture);
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/EventSourceProxy.Tests/SerializationTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Tracing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Newtonsoft.Json;
8 | using NUnit.Framework;
9 |
10 | namespace EventSourceProxy.Tests
11 | {
12 | [TestFixture]
13 | public class SerializationTests : BaseLoggingTest
14 | {
15 | #region Test Classes
16 | public class ClassData
17 | {
18 | public string Name { get; set; }
19 | public int Age { get; set; }
20 |
21 | public static ClassData Test = new ClassData() { Name = "Fred", Age = 38 };
22 | public static string TestJson = JsonConvert.SerializeObject(Test);
23 | }
24 |
25 | public struct StructData
26 | {
27 | public string Name { get; set; }
28 | public int Age { get; set; }
29 |
30 | public static StructData Test = new StructData() { Name = "Fred", Age = 38 };
31 | public static string TestJson = JsonConvert.SerializeObject(Test);
32 | }
33 |
34 | public interface ILogInterfaceWithClassData
35 | {
36 | void SendData(ClassData data);
37 | }
38 |
39 | public interface ILogInterfaceWithStructData
40 | {
41 | void SendData(StructData data);
42 | }
43 |
44 | public abstract class LogClassWithClassData : EventSource
45 | {
46 | public abstract void SendData(ClassData data);
47 | }
48 |
49 | public abstract class LogClassWithStructData : EventSource
50 | {
51 | public abstract void SendData(StructData data);
52 | }
53 |
54 | public interface ILogInterfaceWithClassData2
55 | {
56 | void SendData(ClassData data);
57 | }
58 |
59 | public class ILogClassWithClassData : ILogInterfaceWithClassData2
60 | {
61 | public void SendData(ClassData data)
62 | {
63 | }
64 | }
65 | #endregion
66 |
67 | #region Test Cases
68 | [Test]
69 | public void InterfaceWithClassShouldSerializeAsJson()
70 | {
71 | EventSourceImplementer.RegisterProvider(new JsonObjectSerializer());
72 | var logger = EventSourceImplementer.GetEventSourceAs();
73 | _listener.EnableEvents((EventSource)logger, EventLevel.LogAlways);
74 |
75 | logger.SendData(ClassData.Test);
76 |
77 | // look at the events
78 | var events = _listener.Events.ToArray();
79 | Assert.AreEqual(1, events.Length);
80 | Assert.AreEqual(1, events[0].EventId);
81 | Assert.AreEqual(ClassData.TestJson, events[0].Payload[0]);
82 | }
83 |
84 | [Test]
85 | public void InterfaceWithStructShouldSerializeAsJson()
86 | {
87 | EventSourceImplementer.RegisterProvider(new JsonObjectSerializer());
88 | var logger = EventSourceImplementer.GetEventSourceAs();
89 | _listener.EnableEvents((EventSource)logger, EventLevel.LogAlways);
90 |
91 | logger.SendData(StructData.Test);
92 |
93 | // look at the events
94 | var events = _listener.Events.ToArray();
95 | Assert.AreEqual(1, events.Length);
96 | Assert.AreEqual(1, events[0].EventId);
97 | Assert.AreEqual(StructData.TestJson, events[0].Payload[0]);
98 | }
99 |
100 | [Test]
101 | public void ClassWithClassShouldSerializeAsJson()
102 | {
103 | EventSourceImplementer.RegisterProvider(new JsonObjectSerializer());
104 | var logger = EventSourceImplementer.GetEventSourceAs();
105 | _listener.EnableEvents((EventSource)logger, EventLevel.LogAlways);
106 |
107 | logger.SendData(ClassData.Test);
108 |
109 | // look at the events
110 | var events = _listener.Events.ToArray();
111 | Assert.AreEqual(1, events.Length);
112 | Assert.AreEqual(1, events[0].EventId);
113 | Assert.AreEqual(ClassData.TestJson, events[0].Payload[0]);
114 | }
115 |
116 | [Test]
117 | public void ClassWithStructShouldSerializeAsJson()
118 | {
119 | EventSourceImplementer.RegisterProvider(new JsonObjectSerializer());
120 | var logger = EventSourceImplementer.GetEventSourceAs();
121 | _listener.EnableEvents((EventSource)logger, EventLevel.LogAlways);
122 |
123 | logger.SendData(StructData.Test);
124 |
125 | // look at the events
126 | var events = _listener.Events.ToArray();
127 | Assert.AreEqual(1, events.Length);
128 | Assert.AreEqual(1, events[0].EventId);
129 | Assert.AreEqual(StructData.TestJson, events[0].Payload[0]);
130 | }
131 |
132 | [Test]
133 | public void ClassImplementingAnInterfaceShouldSerializeData()
134 | {
135 | EventSourceImplementer.RegisterProvider(new JsonObjectSerializer());
136 | var logger = EventSourceImplementer.GetEventSourceAs();
137 | _listener.EnableEvents((EventSource)logger, EventLevel.LogAlways);
138 |
139 | var proxy = TracingProxy.Create(new ILogClassWithClassData());
140 |
141 | proxy.SendData(ClassData.Test);
142 |
143 | // look at the events
144 | var events = _listener.Events.ToArray();
145 | Assert.AreEqual(2, events.Length);
146 | Assert.AreEqual(1, events[0].EventId);
147 | Assert.AreEqual(ClassData.TestJson, events[0].Payload[0]);
148 | }
149 | #endregion
150 |
151 | #region ToStringSerializer Tests
152 | public interface ILogInterfaceWithClassDataToString
153 | {
154 | void SendData(ClassData data);
155 | }
156 |
157 | [Test]
158 | public void InterfaceWithClassShouldSerializeToString()
159 | {
160 | // register the provider
161 | EventSourceImplementer.RegisterProvider(new ToStringObjectSerializer());
162 |
163 | var logger = EventSourceImplementer.GetEventSourceAs();
164 | _listener.EnableEvents((EventSource)logger, EventLevel.LogAlways);
165 |
166 | logger.SendData(ClassData.Test);
167 |
168 | // look at the events
169 | var events = _listener.Events.ToArray();
170 | Assert.AreEqual(1, events.Length);
171 | Assert.AreEqual(1, events[0].EventId);
172 | Assert.AreEqual(ClassData.Test.ToString(), events[0].Payload[0]);
173 | }
174 | #endregion
175 |
176 | #region NullSerializer Tests
177 | public interface ILogInterfaceWithClassDataToNull
178 | {
179 | void SendData(ClassData data);
180 | }
181 |
182 | [Test]
183 | public void InterfaceWithClassShouldSerializeAsNull()
184 | {
185 | // register the provider
186 | EventSourceImplementer.RegisterProvider(new NullObjectSerializer());
187 |
188 | var logger = EventSourceImplementer.GetEventSourceAs();
189 | _listener.EnableEvents((EventSource)logger, EventLevel.LogAlways);
190 |
191 | logger.SendData(ClassData.Test);
192 |
193 | // look at the events
194 | var events = _listener.Events.ToArray();
195 | Assert.AreEqual(1, events.Length);
196 | Assert.AreEqual(1, events[0].EventId);
197 | Assert.AreEqual(String.Empty, events[0].Payload[0]);
198 | }
199 | #endregion
200 |
201 | #region CustomSerializer Tests
202 | public interface ILogInterfaceWithClassDataToCustom
203 | {
204 | void SendData(ClassData data);
205 | }
206 |
207 | class CustomSerializer : TraceSerializationProvider
208 | {
209 | public override string SerializeObject(object value, TraceSerializationContext context)
210 | {
211 | return "custom";
212 | }
213 |
214 | public override EventLevel? GetEventLevelForContext(TraceSerializationContext context)
215 | {
216 | return EventLevel.LogAlways;
217 | }
218 |
219 | public override bool ShouldSerialize(TraceSerializationContext context)
220 | {
221 | return true;
222 | }
223 | }
224 |
225 | [Test]
226 | public void InterfaceWithClassShouldSerializeToCustom()
227 | {
228 | // register the provider
229 | EventSourceImplementer.RegisterProvider(new CustomSerializer());
230 |
231 | var logger = EventSourceImplementer.GetEventSourceAs();
232 | _listener.EnableEvents((EventSource)logger, EventLevel.LogAlways);
233 |
234 | logger.SendData(ClassData.Test);
235 |
236 | // look at the events
237 | var events = _listener.Events.ToArray();
238 | Assert.AreEqual(1, events.Length);
239 | Assert.AreEqual(1, events[0].EventId);
240 | Assert.AreEqual("custom", events[0].Payload[0]);
241 | }
242 | #endregion
243 |
244 | #region Provider Attribute Tests
245 | [TraceSerializationProvider(typeof(FakeSerializer))]
246 | public interface ILogInterfaceWithSerializationAttribute
247 | {
248 | void SendData(ClassData data);
249 | }
250 |
251 | [TraceSerializationProvider(typeof(FakeSerializer))]
252 | public interface ILogInterfaceWithAttribute2
253 | {
254 | void SendData(ClassData data);
255 | }
256 |
257 | public class FakeSerializer : TraceSerializationProvider
258 | {
259 | public override string SerializeObject(object value, TraceSerializationContext context)
260 | {
261 | return "nope";
262 | }
263 | }
264 |
265 | [Test]
266 | public void AttributeShouldDetermineSerializer()
267 | {
268 | var logger = EventSourceImplementer.GetEventSourceAs();
269 | _listener.EnableEvents((EventSource)logger, EventLevel.LogAlways);
270 |
271 | logger.SendData(ClassData.Test);
272 |
273 | // look at the events
274 | var events = _listener.Events.ToArray();
275 | Assert.AreEqual(1, events.Length);
276 | Assert.AreEqual(1, events[0].EventId);
277 | Assert.AreEqual("nope", events[0].Payload[0]);
278 | }
279 |
280 | [Test]
281 | public void RegisterProviderShouldOverrideAttribute()
282 | {
283 | EventSourceImplementer.RegisterProvider(new JsonObjectSerializer(EventLevel.Verbose));
284 | var logger = EventSourceImplementer.GetEventSourceAs();
285 |
286 | _listener.EnableEvents((EventSource)logger, EventLevel.Informational);
287 | logger.SendData(ClassData.Test);
288 |
289 | // look at the events
290 | var events = _listener.Events.ToArray();
291 | Assert.AreEqual(1, events.Length);
292 | Assert.AreEqual(1, events[0].EventId);
293 | Assert.AreEqual(String.Empty, events[0].Payload[0]);
294 |
295 | _listener.Reset();
296 | _listener.EnableEvents((EventSource)logger, EventLevel.Verbose);
297 | logger.SendData(ClassData.Test);
298 |
299 | // look at the events
300 | events = _listener.Events.ToArray();
301 | Assert.AreEqual(1, events.Length);
302 | Assert.AreEqual(1, events[0].EventId);
303 | Assert.AreEqual(ClassData.TestJson, events[0].Payload[0]);
304 | }
305 | #endregion
306 |
307 | #region Level Attribute Tests
308 | public interface ISerializeNormally
309 | {
310 | void SendData(ClassData data);
311 | }
312 |
313 | [TraceSerialization(EventLevel.Informational)]
314 | public interface ISerializeVerbosely
315 | {
316 | void SendData(ClassData data);
317 | }
318 |
319 | public interface ISerializeVerboselyByMethod
320 | {
321 | [TraceSerialization(EventLevel.Informational)]
322 | void SendData(ClassData data);
323 | }
324 |
325 | public interface ISerializeVerboselyByParameter
326 | {
327 | void SendData([TraceSerialization(EventLevel.Informational)]ClassData data);
328 | }
329 |
330 | [TraceSerialization(EventLevel.Informational)]
331 | public class ClassData2 : ClassData
332 | {
333 | }
334 |
335 | public interface ISerializeVerboselyByParameterClass
336 | {
337 | void SendData(ClassData2 data);
338 | }
339 |
340 | [Test]
341 | public void ShouldNormallyBeDisabledAtInfoAndEnabledAtVerbose()
342 | {
343 | var logger = EventSourceImplementer.GetEventSourceAs();
344 | _listener.EnableEvents((EventSource)logger, EventLevel.Informational);
345 |
346 | logger.SendData(ClassData.Test);
347 |
348 | // look at the events
349 | var events = _listener.Events.ToArray();
350 | Assert.AreEqual(1, events.Length);
351 | Assert.AreEqual(1, events[0].EventId);
352 | Assert.AreEqual(String.Empty, events[0].Payload[0]);
353 |
354 | _listener.Reset();
355 | _listener.EnableEvents((EventSource)logger, EventLevel.Verbose);
356 | logger.SendData(ClassData.Test);
357 | events = _listener.Events.ToArray();
358 | Assert.AreEqual(1, events.Length);
359 | Assert.AreEqual(1, events[0].EventId);
360 | Assert.IsNotNull(events[0].Payload[0]);
361 | }
362 |
363 | [Test]
364 | public void AttributeCanChangeLevelAtClassLevel()
365 | {
366 | var logger = EventSourceImplementer.GetEventSourceAs();
367 | _listener.EnableEvents((EventSource)logger, EventLevel.Informational);
368 |
369 | logger.SendData(ClassData.Test);
370 |
371 | // look at the events
372 | var events = _listener.Events.ToArray();
373 | Assert.AreEqual(1, events.Length);
374 | Assert.AreEqual(1, events[0].EventId);
375 | Assert.IsNotNull(events[0].Payload[0]);
376 | }
377 |
378 | [Test]
379 | public void AttributeCanChangeLevelAtMethodLevel()
380 | {
381 | var logger = EventSourceImplementer.GetEventSourceAs();
382 | _listener.EnableEvents((EventSource)logger, EventLevel.Informational);
383 |
384 | logger.SendData(ClassData.Test);
385 |
386 | // look at the events
387 | var events = _listener.Events.ToArray();
388 | Assert.AreEqual(1, events.Length);
389 | Assert.AreEqual(1, events[0].EventId);
390 | Assert.IsNotNull(events[0].Payload[0]);
391 | }
392 |
393 | [Test]
394 | public void AttributeCanChangeLevelAtParameterLevel()
395 | {
396 | var logger = EventSourceImplementer.GetEventSourceAs();
397 | _listener.EnableEvents((EventSource)logger, EventLevel.Informational);
398 |
399 | logger.SendData(ClassData.Test);
400 |
401 | // look at the events
402 | var events = _listener.Events.ToArray();
403 | Assert.AreEqual(1, events.Length);
404 | Assert.AreEqual(1, events[0].EventId);
405 | Assert.IsNotNull(events[0].Payload[0]);
406 | }
407 |
408 | [Test]
409 | public void AttributeCanChangeLevelAtParameterTypeLevel()
410 | {
411 | var logger = EventSourceImplementer.GetEventSourceAs();
412 | _listener.EnableEvents((EventSource)logger, EventLevel.Informational);
413 |
414 | logger.SendData(new ClassData2() { Name = "Fred", Age = 38 });
415 |
416 | // look at the events
417 | var events = _listener.Events.ToArray();
418 | Assert.AreEqual(1, events.Length);
419 | Assert.AreEqual(1, events[0].EventId);
420 | Assert.IsNotNull(events[0].Payload[0]);
421 | }
422 | #endregion
423 | }
424 | }
425 |
--------------------------------------------------------------------------------
/EventSourceProxy.Tests/TestEventListener.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.Diagnostics.Tracing;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace EventSourceProxy.Tests
10 | {
11 | ///
12 | /// Listens to events and records them for testing.
13 | ///
14 | class TestEventListener : EventListener
15 | {
16 | public IReadOnlyCollection Events { get { return new ReadOnlyCollection(_events); } }
17 | private List _events = new List();
18 |
19 | public void Reset()
20 | {
21 | _events.Clear();
22 | }
23 |
24 | protected override void OnEventWritten(EventWrittenEventArgs eventData)
25 | {
26 | _events.Add(eventData);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/EventSourceProxy.Tests/TraceContextProviderTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Tracing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using NUnit.Framework;
8 |
9 | namespace EventSourceProxy.Tests
10 | {
11 | [TestFixture]
12 | public class TraceContextProviderTests : BaseLoggingTest
13 | {
14 | #region Test Classes
15 | public interface ILog
16 | {
17 | void DoSomething();
18 | }
19 |
20 | public interface ILog2 { }
21 | public interface ILog3 { }
22 | public interface ILog4
23 | {
24 | void DoSomething();
25 | }
26 |
27 | class MyTraceContextProvider : TraceContextProvider
28 | {
29 | public bool WasCalled = false;
30 | public string Method = null;
31 |
32 | public override string ProvideContext(InvocationContext context)
33 | {
34 | Method = context.MethodInfo.Name;
35 | WasCalled = true;
36 | return "context";
37 | }
38 | }
39 | #endregion
40 |
41 | #region Base Test Cases
42 | [Test]
43 | public void ProviderShouldBeCalledOnLog()
44 | {
45 | var contextProvider = new MyTraceContextProvider();
46 | EventSourceImplementer.RegisterProvider(contextProvider);
47 |
48 | var testLog = EventSourceImplementer.GetEventSourceAs();
49 | _listener.EnableEvents((EventSource)testLog, EventLevel.LogAlways);
50 |
51 | testLog.DoSomething();
52 |
53 | Assert.IsTrue(contextProvider.WasCalled);
54 | Assert.AreEqual("DoSomething", contextProvider.Method);
55 |
56 | // look at the events
57 | var events = _listener.Events.ToArray();
58 | Assert.AreEqual(1, events.Length);
59 | Assert.AreEqual("context", events[0].Payload[0]);
60 | }
61 |
62 | [Test]
63 | public void ProviderShouldNotBeCalledWhenLogIsDisabled()
64 | {
65 | var contextProvider = new MyTraceContextProvider();
66 | EventSourceImplementer.RegisterProvider(contextProvider);
67 |
68 | var testLog = EventSourceImplementer.GetEventSourceAs();
69 | testLog.DoSomething();
70 |
71 | Assert.IsFalse(contextProvider.WasCalled);
72 | Assert.IsNull(contextProvider.Method);
73 |
74 | // look at the events
75 | var events = _listener.Events.ToArray();
76 | Assert.AreEqual(0, events.Length);
77 | }
78 |
79 | [Test]
80 | public void RegisterProviderTwiceShouldFail()
81 | {
82 | var contextProvider = new MyTraceContextProvider();
83 | EventSourceImplementer.RegisterProvider(contextProvider);
84 | Assert.Throws(() => EventSourceImplementer.RegisterProvider(contextProvider));
85 | }
86 |
87 | [Test]
88 | public void RegisterProviderAfterSourceCreationShouldFail()
89 | {
90 | var log = EventSourceImplementer.GetEventSource();
91 |
92 | var contextProvider = new MyTraceContextProvider();
93 | Assert.Throws(() => EventSourceImplementer.RegisterProvider(contextProvider));
94 | }
95 | #endregion
96 |
97 | #region Attribute Tests
98 | [TraceContextProvider(typeof(MyTraceContextProvider))]
99 | public interface ILogWithProviderAttribute
100 | {
101 | void DoSomething();
102 | }
103 |
104 | [TraceContextProvider(typeof(MyTraceContextProvider))]
105 | [TraceContext(false)]
106 | public interface ILogWithAttributeDisabled
107 | {
108 | void DoSomething();
109 | }
110 |
111 | [TraceContextProvider(typeof(MyTraceContextProvider))]
112 | [TraceContext(false)]
113 | public interface ILogWithAttributeDisabledAndMethodEnabled
114 | {
115 | [TraceContext(true)]
116 | void DoSomething();
117 | }
118 |
119 | [Test]
120 | public void ProviderCanBeSpecifiedByAttribute()
121 | {
122 | var testLog = EventSourceImplementer.GetEventSourceAs();
123 | _listener.EnableEvents((EventSource)testLog, EventLevel.LogAlways);
124 |
125 | testLog.DoSomething();
126 |
127 | // look at the events
128 | var events = _listener.Events.ToArray();
129 | Assert.AreEqual(1, events.Length);
130 | Assert.AreEqual("context", events[0].Payload[0]);
131 | }
132 |
133 | [Test]
134 | public void ContextCanBeControlledByClassAttribute()
135 | {
136 | var testLog = EventSourceImplementer.GetEventSourceAs();
137 | _listener.EnableEvents((EventSource)testLog, EventLevel.LogAlways);
138 |
139 | testLog.DoSomething();
140 |
141 | // look at the events
142 | var events = _listener.Events.ToArray();
143 | Assert.AreEqual(1, events.Length);
144 | Assert.AreEqual(0, events[0].Payload.Count);
145 | }
146 |
147 | [Test]
148 | public void ContextCanBeControlledByMethodAttribute()
149 | {
150 | var testLog = EventSourceImplementer.GetEventSourceAs();
151 | _listener.EnableEvents((EventSource)testLog, EventLevel.LogAlways);
152 |
153 | testLog.DoSomething();
154 |
155 | // look at the events
156 | var events = _listener.Events.ToArray();
157 | Assert.AreEqual(1, events.Length);
158 | Assert.AreEqual(1, events[0].Payload.Count);
159 | }
160 | #endregion
161 |
162 | #region Rich Context Tests
163 | public interface IHaveRichContext
164 | {
165 | void Log(string message);
166 | }
167 |
168 | [Test]
169 | public void TestAddingContextToEachMethod()
170 | {
171 | TraceParameterProvider.Default.For()
172 | .AddContextData("Site.Id")
173 | .AddContextData("Site.Name")
174 | .AddContextData("PID");
175 |
176 | var proxy = EventSourceImplementer.GetEventSourceAs();
177 | EnableLogging(proxy);
178 |
179 | using (var context = TraceContext.Begin())
180 | {
181 | context["PID"] = 1234;
182 |
183 | using (var context2 = TraceContext.Begin())
184 | {
185 | context2["Site.Id"] = "Ts1";
186 | context2["Site.Name"] = "TestSite1";
187 |
188 | proxy.Log("message");
189 | }
190 | }
191 |
192 | // look at the events
193 | var events = _listener.Events.ToArray();
194 | Assert.AreEqual(1, events.Length);
195 | Assert.AreEqual(4, events[0].Payload.Count);
196 | Assert.AreEqual("message", events[0].Payload[0]);
197 | Assert.AreEqual("Ts1", events[0].Payload[1]);
198 | Assert.AreEqual("TestSite1", events[0].Payload[2]);
199 | Assert.AreEqual(1234, events[0].Payload[3]);
200 | }
201 | #endregion
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/EventSourceProxy.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | EventSourceProxy
5 | 1.0.0
6 | EventSourceProxy
7 | Jon Wagner
8 |
9 | Automatically implements the tedious part of the .NET EventSource classes.
10 | Also automatically converts any interface to an ETW trace point.
11 | Wrap your interfaces and get free ETW tracing.
12 | ** Now with .NET Standard 2.0 support! **
13 |
14 | en-US
15 | http://github.com/jonwagner/EventSourceProxy
16 | MS-PL OR MIT
17 | EventSource log semantic structured strongly-typed logging ETW tracing event listener block lab LOB slab
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/EventSourceProxy.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.30110.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventSourceProxy", "EventSourceProxy\EventSourceProxy.csproj", "{40DABAAD-795A-4420-982F-08BE1978FE02}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventSourceProxy.Tests", "EventSourceProxy.Tests\EventSourceProxy.Tests.csproj", "{33A95AA5-4F87-47CF-B37A-2023CE9E0400}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventSourceProxy.Example", "EventSourceProxy.Example\EventSourceProxy.Example.csproj", "{581BDCB4-6413-4272-B85F-4D39F6C131B8}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GenerateProxyManifest", "GenerateProxyManifest\GenerateProxyManifest.csproj", "{A01CE647-4B33-43E0-8DD4-F45F732D4C77}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{773540B5-F7A1-4E68-8343-C738E2183769}"
15 | ProjectSection(SolutionItems) = preProject
16 | Build.bat = Build.bat
17 | Build.ps1 = Build.ps1
18 | Build.psake.ps1 = Build.psake.ps1
19 | Building.txt = Building.txt
20 | EventSourceProxy.nuspec = EventSourceProxy.nuspec
21 | EventSourceProxy.snk = EventSourceProxy.snk
22 | README.md = README.md
23 | EndProjectSection
24 | EndProject
25 | Global
26 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
27 | Debug|Any CPU = Debug|Any CPU
28 | Release|Any CPU = Release|Any CPU
29 | EndGlobalSection
30 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
31 | {40DABAAD-795A-4420-982F-08BE1978FE02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {40DABAAD-795A-4420-982F-08BE1978FE02}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {40DABAAD-795A-4420-982F-08BE1978FE02}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 | {40DABAAD-795A-4420-982F-08BE1978FE02}.Release|Any CPU.Build.0 = Release|Any CPU
35 | {33A95AA5-4F87-47CF-B37A-2023CE9E0400}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 | {33A95AA5-4F87-47CF-B37A-2023CE9E0400}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 | {33A95AA5-4F87-47CF-B37A-2023CE9E0400}.Release|Any CPU.ActiveCfg = Release|Any CPU
38 | {33A95AA5-4F87-47CF-B37A-2023CE9E0400}.Release|Any CPU.Build.0 = Release|Any CPU
39 | {581BDCB4-6413-4272-B85F-4D39F6C131B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
40 | {581BDCB4-6413-4272-B85F-4D39F6C131B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
41 | {581BDCB4-6413-4272-B85F-4D39F6C131B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
42 | {581BDCB4-6413-4272-B85F-4D39F6C131B8}.Release|Any CPU.Build.0 = Release|Any CPU
43 | {A01CE647-4B33-43E0-8DD4-F45F732D4C77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 | {A01CE647-4B33-43E0-8DD4-F45F732D4C77}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 | {A01CE647-4B33-43E0-8DD4-F45F732D4C77}.Release|Any CPU.ActiveCfg = Release|Any CPU
46 | {A01CE647-4B33-43E0-8DD4-F45F732D4C77}.Release|Any CPU.Build.0 = Release|Any CPU
47 | {B151A261-B9A0-4EE1-A61C-C04FFE94C373}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
48 | {B151A261-B9A0-4EE1-A61C-C04FFE94C373}.Debug|Any CPU.Build.0 = Debug|Any CPU
49 | {B151A261-B9A0-4EE1-A61C-C04FFE94C373}.Release|Any CPU.ActiveCfg = Release|Any CPU
50 | {B151A261-B9A0-4EE1-A61C-C04FFE94C373}.Release|Any CPU.Build.0 = Release|Any CPU
51 | {FDB8844B-BB34-45E6-BDE1-BA657663A868}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
52 | {FDB8844B-BB34-45E6-BDE1-BA657663A868}.Debug|Any CPU.Build.0 = Debug|Any CPU
53 | {FDB8844B-BB34-45E6-BDE1-BA657663A868}.Release|Any CPU.ActiveCfg = Release|Any CPU
54 | {FDB8844B-BB34-45E6-BDE1-BA657663A868}.Release|Any CPU.Build.0 = Release|Any CPU
55 | {0BF86E34-2AFC-4620-A5C6-E084448347A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
56 | {0BF86E34-2AFC-4620-A5C6-E084448347A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
57 | {0BF86E34-2AFC-4620-A5C6-E084448347A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
58 | {0BF86E34-2AFC-4620-A5C6-E084448347A2}.Release|Any CPU.Build.0 = Release|Any CPU
59 | EndGlobalSection
60 | GlobalSection(SolutionProperties) = preSolution
61 | HideSolutionNode = FALSE
62 | EndGlobalSection
63 | EndGlobal
64 |
--------------------------------------------------------------------------------
/EventSourceProxy.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonwagner/EventSourceProxy/2d672e26afb8eb57e0e42daddd2f954d468a90b5/EventSourceProxy.snk
--------------------------------------------------------------------------------
/EventSourceProxy/Any.cs:
--------------------------------------------------------------------------------
1 | namespace EventSourceProxy
2 | {
3 | ///
4 | /// Encapsulates a placeholder value that can be passed to a method.
5 | ///
6 | /// The type of the placeholder.
7 | public static class Any
8 | {
9 | ///
10 | /// Gets the default value for the Any type.
11 | ///
12 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
13 | public static TType Value
14 | {
15 | get { return default(TType); }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/EventSourceProxy/CodeAnalysisRules.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/EventSourceProxy/CustomDictionary.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GetEventSource
6 | EventSource
7 | EventActivityIdControl
8 |
9 |
10 | EventSource
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/EventSourceProxy/EventActivityScope.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Diagnostics.CodeAnalysis;
5 | using System.Globalization;
6 | using System.Linq;
7 | using System.Runtime.InteropServices;
8 | using System.Security;
9 | using System.Text;
10 | using System.Threading;
11 | using System.Threading.Tasks;
12 |
13 | namespace EventSourceProxy
14 | {
15 | ///
16 | /// Manages the lifetime of an ETW Activity ID.
17 | ///
18 | public sealed class EventActivityScope : IDisposable
19 | {
20 | #region Private Members
21 | ///
22 | /// The name of the call context slot we use for the activity ID.
23 | ///
24 | private static AsyncLocal _storage = new AsyncLocal();
25 |
26 | ///
27 | /// The Activity ID outside of this scope. It is restored on the disposal of the scope.
28 | ///
29 | private Guid _previousActivityId;
30 |
31 | ///
32 | /// The Activity ID of this scope.
33 | ///
34 | private Guid _activityId;
35 | #endregion
36 |
37 | #region Constructors
38 | ///
39 | /// Initializes a new instance of the EventActivityScope class.
40 | /// A new Activity ID is generated and assigned to the current thread.
41 | ///
42 | public EventActivityScope()
43 | : this(false)
44 | {
45 | }
46 |
47 | ///
48 | /// Initializes a new instance of the EventActivityScope class.
49 | /// A new Activity ID is generated and assigned to the current thread.
50 | ///
51 | ///
52 | /// True to reuse an existing Activity ID if one is already in use.
53 | /// Since EventSource currently does not support Activity ID transfer, you
54 | /// may want to call this constructor with 'true' so you are sure to have an Activity ID,
55 | /// but to keep the current activity if one has already been established.
56 | ///
57 | public EventActivityScope(bool reuseExistingActivityId)
58 | {
59 | _previousActivityId = GetActivityId();
60 |
61 | if (!reuseExistingActivityId || _previousActivityId == Guid.Empty)
62 | {
63 | _activityId = Guid.NewGuid();
64 | SetActivityId(_activityId);
65 | }
66 | else
67 | _activityId = _previousActivityId;
68 | }
69 |
70 | ///
71 | /// Initializes a new instance of the EventActivityScope class with a given Activity ID.
72 | ///
73 | ///
74 | /// The existing Activity ID to use.
75 | ///
76 | public EventActivityScope(Guid externalActivityId)
77 | {
78 | _previousActivityId = GetActivityId();
79 | _activityId = externalActivityId;
80 | SetActivityId(_activityId);
81 | }
82 | #endregion
83 |
84 | #region Properties
85 | ///
86 | /// Gets the current Activity Id.
87 | ///
88 | public static Guid CurrentActivityId
89 | {
90 | get
91 | {
92 | return GetActivityId();
93 | }
94 | }
95 |
96 | ///
97 | /// Gets the Activity ID of the enclosing scope.
98 | ///
99 | public Guid PreviousActivityId { get { return _previousActivityId; } }
100 |
101 | ///
102 | /// Gets a value indicating whether the Activity ID of the enclosing scope.
103 | ///
104 | public bool IsNewScope { get { return _previousActivityId == Guid.Empty; } }
105 |
106 | ///
107 | /// Gets the Activity ID of this scope.
108 | ///
109 | public Guid ActivityId { get { return _activityId; } }
110 | #endregion
111 |
112 | ///
113 | /// Perform an action within an activity scope.
114 | /// This method ensures that an activity scope exists.
115 | /// If an activity scope exists, it is reused.
116 | ///
117 | /// The action to perform.
118 | public static void DoInScope(Action action)
119 | {
120 | Do(action, newScope: false);
121 | }
122 |
123 | ///
124 | /// Perform an action within a new activity scope.
125 | ///
126 | /// The action to perform.
127 | public static void DoInNewScope(Action action)
128 | {
129 | Do(action, newScope: true);
130 | }
131 |
132 | ///
133 | /// Disposes the current Activity Scope by restoring the previous scope.
134 | ///
135 | public void Dispose()
136 | {
137 | SetActivityId(_previousActivityId);
138 | _activityId = _previousActivityId;
139 | GC.SuppressFinalize(this);
140 | }
141 |
142 | #region Helper Methods
143 | ///
144 | /// Performs an action in an activity scope.
145 | ///
146 | /// The action to perform.
147 | /// True to always create a new scope.
148 | private static void Do(Action action, bool newScope)
149 | {
150 | Guid previousActivityId = GetActivityId();
151 | if (newScope || previousActivityId == Guid.Empty)
152 | {
153 | Guid activityID = Guid.NewGuid();
154 | try
155 | {
156 | SetActivityId(activityID);
157 | action();
158 | }
159 | finally
160 | {
161 | SetActivityId(previousActivityId);
162 | }
163 | }
164 | }
165 |
166 | ///
167 | /// Get the current Activity Id.
168 | ///
169 | /// The current activity Id.
170 | private static Guid GetActivityId()
171 | {
172 | return Trace.CorrelationManager.ActivityId;
173 | }
174 |
175 | ///
176 | /// Sets the current Activity Id.
177 | ///
178 | /// The activity Id to set.
179 | private static void SetActivityId(Guid activityId)
180 | {
181 | Trace.CorrelationManager.ActivityId = activityId;
182 | }
183 | #endregion
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/EventSourceProxy/EventAttributeHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Tracing;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Reflection.Emit;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace EventSourceProxy
11 | {
12 | ///
13 | /// Helps emit attribute data to IL.
14 | ///
15 | static class EventAttributeHelper
16 | {
17 | #region EventAttribute Members
18 | ///
19 | /// The constructor for EventAttribute.
20 | ///
21 | private static ConstructorInfo _eventAttributeConstructor = typeof(EventAttribute).GetConstructor(new[] { typeof(int) });
22 |
23 | ///
24 | /// The array of properties used to serialize the custom attribute values.
25 | ///
26 | private static PropertyInfo[] _eventAttributePropertyInfo = new PropertyInfo[]
27 | {
28 | typeof(EventAttribute).GetProperty("Keywords"),
29 | typeof(EventAttribute).GetProperty("Level"),
30 | typeof(EventAttribute).GetProperty("Message"),
31 | typeof(EventAttribute).GetProperty("Opcode"),
32 | typeof(EventAttribute).GetProperty("Task"),
33 | typeof(EventAttribute).GetProperty("Version"),
34 | typeof(EventAttribute).GetProperty("Channel"),
35 | };
36 |
37 | ///
38 | /// A set of empty parameters that can be sent to a method call.
39 | ///
40 | private static object[] _emptyParameters = new object[0];
41 | #endregion
42 |
43 | ///
44 | /// Converts an EventAttribute to a CustomAttributeBuilder so it can be assigned to a method.
45 | ///
46 | /// The attribute to copy.
47 | /// A CustomAttributeBuilder that can be assigned to a method.
48 | internal static CustomAttributeBuilder ConvertEventAttributeToAttributeBuilder(EventAttribute attribute)
49 | {
50 | var propertyValues = new object[]
51 | {
52 | attribute.Keywords,
53 | attribute.Level,
54 | attribute.Message,
55 | attribute.Opcode,
56 | attribute.Task,
57 | attribute.Version,
58 | attribute.Channel
59 | };
60 |
61 | CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(
62 | _eventAttributeConstructor,
63 | new object[] { attribute.EventId },
64 | _eventAttributePropertyInfo,
65 | propertyValues);
66 |
67 | return attributeBuilder;
68 | }
69 |
70 | ///
71 | /// Creates an empty NonEventAttribute.
72 | ///
73 | /// A CustomAttributeBuilder that can be added to a method.
74 | internal static CustomAttributeBuilder CreateNonEventAttribute()
75 | {
76 | return new CustomAttributeBuilder(typeof(NonEventAttribute).GetConstructor(Type.EmptyTypes), _emptyParameters);
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/EventSourceProxy/EventAttributeProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Tracing;
4 | using System.Globalization;
5 | using System.Linq;
6 | using System.Reflection;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace EventSourceProxy
11 | {
12 | ///
13 | /// Provides the Event attributes when generating proxy classes.
14 | /// The default implementation uses EventAttribute and EventExceptionAttribute to generate the values.
15 | ///
16 | public class EventAttributeProvider
17 | {
18 | ///
19 | /// Initializes a new instance of the EventAttributeProvider class.
20 | ///
21 | public EventAttributeProvider() : this(EventLevel.Informational, EventLevel.Error)
22 | {
23 | }
24 |
25 | ///
26 | /// Initializes a new instance of the EventAttributeProvider class.
27 | ///
28 | /// The default EventLevel for events if not specified by EventAttributes.
29 | /// The default exception events if not specified by EventExceptionAttributes.
30 | public EventAttributeProvider(EventLevel eventLevel, EventLevel exceptionEventLevel)
31 | {
32 | EventLevel = eventLevel;
33 | ExceptionEventLevel = exceptionEventLevel;
34 | }
35 |
36 | ///
37 | /// Gets the default EventLevel for methods.
38 | ///
39 | public EventLevel EventLevel { get; private set; }
40 |
41 | ///
42 | /// Gets the default EventLevel for exceptions generated by methods.
43 | ///
44 | public EventLevel ExceptionEventLevel { get; private set; }
45 |
46 | ///
47 | /// Returns an EventAttribute for the given call context.
48 | ///
49 | /// The context of the call.
50 | /// The next event ID to use if not specified by some other mechanism.
51 | /// The parameter mapping for the method, or null if not a method call.
52 | /// The EventAttribute for the call context.
53 | public virtual EventAttribute GetEventAttribute(InvocationContext context, int nextEventId, IReadOnlyCollection parameterMapping)
54 | {
55 | if (context == null) throw new ArgumentNullException("context");
56 |
57 | EventAttribute eventAttribute = context.MethodInfo.GetCustomAttribute();
58 | if (eventAttribute != null)
59 | return eventAttribute;
60 |
61 | return new EventAttribute(nextEventId)
62 | {
63 | Level = GetEventLevelForContext(context, null),
64 | Message = GetEventMessage(context, parameterMapping)
65 | };
66 | }
67 |
68 | ///
69 | /// Returns an EventAttribute for the Completed or Faulted events for a call context.
70 | ///
71 | /// The EventAttribute for the method call that should be copied.
72 | /// The context of the call.
73 | /// The next event ID to use if not specified by some other mechanism.
74 | /// The EventAttribute for the call context.
75 | public virtual EventAttribute CopyEventAttribute(EventAttribute baseAttribute, InvocationContext context, int nextEventId)
76 | {
77 | if (baseAttribute == null) throw new ArgumentNullException("baseAttribute");
78 | if (context == null) throw new ArgumentNullException("context");
79 |
80 | return new EventAttribute(nextEventId)
81 | {
82 | Keywords = baseAttribute.Keywords,
83 | Level = GetEventLevelForContext(context, baseAttribute),
84 | Message = GetEventMessage(context, null),
85 | Opcode = baseAttribute.Opcode,
86 | Task = baseAttribute.Task,
87 | Version = baseAttribute.Version
88 | };
89 | }
90 |
91 | ///
92 | /// Gets the appropriate EventLevel for the call context.
93 | ///
94 | /// The context of the call.
95 | /// The base attribute to copy if there are no additional attributes.
96 | /// The EventLevel for the call context.
97 | protected virtual EventLevel GetEventLevelForContext(InvocationContext context, EventAttribute baseAttribute)
98 | {
99 | if (context == null) throw new ArgumentNullException("context");
100 |
101 | // for faulted methods, allow the EventExceptionAttribute to override the event level
102 | if (context.ContextType == InvocationContextTypes.MethodFaulted)
103 | {
104 | var attribute = context.MethodInfo.GetCustomAttribute();
105 | if (attribute != null)
106 | return attribute.Level;
107 |
108 | attribute = context.MethodInfo.DeclaringType.GetCustomAttribute();
109 | if (attribute != null)
110 | return attribute.Level;
111 |
112 | return ExceptionEventLevel;
113 | }
114 |
115 | // check for an attribute on the type
116 | var implementationAttribute = context.MethodInfo.DeclaringType.GetCustomAttribute();
117 | if (implementationAttribute != null && implementationAttribute.DefaultLevel.HasValue)
118 | return implementationAttribute.DefaultLevel.Value;
119 |
120 | if (baseAttribute != null)
121 | return baseAttribute.Level;
122 |
123 | return EventLevel;
124 | }
125 |
126 | ///
127 | /// Gets the message for an event.
128 | ///
129 | /// The context of the call.
130 | /// The parameter mapping for the method, or null if not a method call.
131 | /// The message for the event.
132 | protected virtual string GetEventMessage(InvocationContext context, IReadOnlyCollection parameterMapping)
133 | {
134 | if (context == null) throw new ArgumentNullException("context");
135 |
136 | switch (context.ContextType)
137 | {
138 | case InvocationContextTypes.MethodCall:
139 | if (parameterMapping == null) throw new ArgumentNullException("parameterMapping");
140 | return String.Join(" ", Enumerable.Range(0, parameterMapping.Count).Select(i => String.Format(CultureInfo.InvariantCulture, "{{{0}}}", i)));
141 |
142 | case InvocationContextTypes.MethodFaulted:
143 | return "{0}";
144 |
145 | case InvocationContextTypes.MethodCompletion:
146 | if (context.MethodInfo.ReturnType != typeof(void))
147 | return "{0}";
148 | else
149 | return String.Empty;
150 | }
151 |
152 | return String.Empty;
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/EventSourceProxy/EventAttributeProviderAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace EventSourceProxy
8 | {
9 | ///
10 | /// Specifies the TraceSerializationProvider to use for a class or interface.
11 | ///
12 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
13 | public sealed class EventAttributeProviderAttribute : TraceProviderAttribute
14 | {
15 | ///
16 | /// Initializes a new instance of the EventAttributeProviderAttribute class.
17 | ///
18 | /// The type of the provider to assign to this class or interface.
19 | public EventAttributeProviderAttribute(Type providerType)
20 | : base(providerType)
21 | {
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/EventSourceProxy/EventExceptionAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.CodeAnalysis;
4 | using System.Diagnostics.Tracing;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace EventSourceProxy
10 | {
11 | ///
12 | /// Specifies the EventLevel for an exception generated by a method.
13 | ///
14 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Method, AllowMultiple = false)]
15 | public sealed class EventExceptionAttribute : Attribute
16 | {
17 | ///
18 | /// Initializes a new instance of the EventExceptionAttribute class.
19 | ///
20 | /// The EventLevel to use for exceptions generated by a method.
21 | public EventExceptionAttribute(EventLevel level)
22 | {
23 | Level = level;
24 | }
25 |
26 | ///
27 | /// Gets the EventLevel to use for exceptions generated by a method.
28 | ///
29 | public EventLevel Level { get; private set; }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/EventSourceProxy/EventSourceAttributeHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Collections.Generic;
4 | using System.Diagnostics.Tracing;
5 | using System.Linq;
6 | using System.Reflection;
7 | using System.Reflection.Emit;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace EventSourceProxy
12 | {
13 | ///
14 | /// Helps emit attribute data to IL.
15 | ///
16 | static class EventSourceAttributeHelper
17 | {
18 | #region EventSourceAttribute Members
19 | ///
20 | /// The constructor for EventSourceAttribute.
21 | ///
22 | private static ConstructorInfo _eventSourceAttributeConstructor = typeof(EventSourceAttribute).GetConstructor(Type.EmptyTypes);
23 |
24 | ///
25 | /// The array of properties used to serialize the custom attribute values.
26 | ///
27 | private static PropertyInfo[] _eventSourceAttributePropertyInfo = new PropertyInfo[]
28 | {
29 | typeof(EventSourceAttribute).GetProperty("Name"),
30 | typeof(EventSourceAttribute).GetProperty("Guid"),
31 | typeof(EventSourceAttribute).GetProperty("LocalizationResources"),
32 | };
33 |
34 | ///
35 | /// Manages a list of the types that have been implemented so far.
36 | ///
37 | private static List _typesImplemented = new List();
38 |
39 | ///
40 | /// An empty parameter list.
41 | ///
42 | private static object[] _emptyParameters = new object[0];
43 | #endregion
44 |
45 | #region Helper Methods
46 | ///
47 | /// Copies the EventSourceAttribute from the interfaceType to a CustomAttributeBuilder.
48 | ///
49 | /// The interfaceType to copy.
50 | /// A CustomAttributeBuilder that can be assigned to a type.
51 | internal static CustomAttributeBuilder GetEventSourceAttributeBuilder(Type type)
52 | {
53 | var attribute = type.GetCustomAttribute() ?? new EventSourceAttribute();
54 | var implementation = EventSourceImplementationAttribute.GetAttributeFor(type);
55 |
56 | // by default, we will use a null guid, which will tell EventSource to generate the guid from the name
57 | // but if we have already generated this type, we will have to generate a new one
58 | string guid = implementation.Guid ?? attribute.Guid ?? null;
59 | if (guid == null)
60 | {
61 | lock (_typesImplemented)
62 | {
63 | if (_typesImplemented.Contains(type))
64 | guid = Guid.NewGuid().ToString();
65 | else
66 | _typesImplemented.Add(type);
67 | }
68 | }
69 |
70 | var propertyValues = new object[]
71 | {
72 | implementation.Name ?? attribute.Name ?? (type.IsGenericType ? type.FullName : type.Name),
73 | guid,
74 | implementation.LocalizationResources ?? attribute.LocalizationResources ?? null
75 | };
76 |
77 | CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(
78 | _eventSourceAttributeConstructor,
79 | _emptyParameters,
80 | _eventSourceAttributePropertyInfo,
81 | propertyValues);
82 |
83 | return attributeBuilder;
84 | }
85 | #endregion
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/EventSourceProxy/EventSourceImplementationAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using System.Collections.Concurrent;
4 | using System.Collections.Generic;
5 | using System.Diagnostics.Tracing;
6 | using System.Reflection;
7 |
8 | namespace EventSourceProxy
9 | {
10 | ///
11 | /// Specifies the classes to use for the Keywords, Tasks, and Opcodes enumerations for an EventSource.
12 | ///
13 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
14 | public class EventSourceImplementationAttribute : Attribute
15 | {
16 | #region Static Fields
17 | ///
18 | /// The overridden attributes
19 | ///
20 | private static ConcurrentDictionary _attributes = new ConcurrentDictionary();
21 | #endregion
22 |
23 | ///
24 | /// Specifies whether complement methods should be emitted.
25 | ///
26 | private bool _implementComplementMethods = true;
27 |
28 | ///
29 | /// Gets or sets the name of the EventSource. This overrides any EventSource attribute.
30 | ///
31 | public string Name { get; set; }
32 |
33 | ///
34 | /// Gets or sets a value indicating whether event write errors should throw. Used when constructing the EventSource. This specifies whether to throw an exception when an error occurs in the underlying Windows code. Default is false.
35 | ///
36 | public bool ThrowOnEventWriteErrors { get; set; }
37 |
38 | ///
39 | /// Gets or sets a value indicating whether the guid of the EventSource. This overrides any EventSource attribute.
40 | ///
41 | public string Guid { get; set; }
42 |
43 | ///
44 | /// Gets or sets the LocalizationResources of the EventSource. This overrides any EventSource attribute.
45 | ///
46 | public string LocalizationResources { get; set; }
47 |
48 | ///
49 | /// Gets or sets a value indicating whether the EventSource should auto-generate keywords.
50 | ///
51 | public bool AutoKeywords { get; set; }
52 |
53 | ///
54 | /// Gets or sets the type that contains the Keywords enumeration for the EventSource.
55 | ///
56 | public Type Keywords { get; set; }
57 |
58 | ///
59 | /// Gets or sets the type that contains the Tasks enumeration for the EventSource.
60 | ///
61 | public Type Tasks { get; set; }
62 |
63 | ///
64 | /// Gets or sets the type that contains the Opcodes enumeration for the EventSource.
65 | ///
66 | public Type OpCodes { get; set; }
67 |
68 | ///
69 | /// Gets or sets the default event level for the EventSource. Defaults to Verbose.
70 | ///
71 | public EventLevel Level { get; set; }
72 | internal EventLevel? DefaultLevel { get; set; }
73 |
74 | ///
75 | /// Gets or sets a value indicating whether the _Completed and _Faulted methods should be implemented
76 | /// on the EventSource. The default (null) indicates that complement methods are implemented on all classes
77 | /// that do not derive from EventSource.
78 | ///
79 | public bool ImplementComplementMethods
80 | {
81 | get { return _implementComplementMethods; }
82 | set { _implementComplementMethods = value; }
83 | }
84 |
85 | ///
86 | /// Overrides the EventSourceImplementationAttribute for a type. Allows you to define logging for other people's interfaces.
87 | ///
88 | /// The type of interface we are overriding.
89 | /// The new EventSourceImplementationAttribute for the type.
90 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
91 | public static void For(EventSourceImplementationAttribute attribute)
92 | {
93 | if (attribute == null) throw new ArgumentNullException("attribute");
94 |
95 | _attributes.AddOrUpdate(typeof(T), attribute, (t, a) => a);
96 | }
97 |
98 | ///
99 | /// Get the EventSourceImplementationAttribute for a type.
100 | ///
101 | /// The type.
102 | /// The attribute.
103 | internal static EventSourceImplementationAttribute GetAttributeFor(Type type)
104 | {
105 | EventSourceImplementationAttribute attribute;
106 | if (_attributes.TryGetValue(type, out attribute))
107 | return attribute;
108 |
109 | return type.GetCustomAttribute() ?? new EventSourceImplementationAttribute();
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/EventSourceProxy/EventSourceImplementer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Collections.Generic;
4 | using System.Diagnostics.Tracing;
5 | using System.Globalization;
6 | using System.Linq;
7 | using System.Reflection;
8 | using System.Reflection.Emit;
9 | using System.Security.Cryptography;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 |
13 | namespace EventSourceProxy
14 | {
15 | ///
16 | /// Completes the implementation of an EventSource by generating a class from an interface or from an abstract class.
17 | ///
18 | public static class EventSourceImplementer
19 | {
20 | #region Private Members
21 | ///
22 | /// The cache of constructors.
23 | ///
24 | private static ConcurrentDictionary _eventSources = new ConcurrentDictionary();
25 | #endregion
26 |
27 | #region Public Members
28 | ///
29 | /// Gets or sets a value indicating whether EventSources should always have auto-keywords.
30 | /// Set this to true if you were using ESP before v3.0 and need auto-keywords to be on.
31 | ///
32 | public static bool ForceAutoKeywords { get; set; }
33 |
34 | ///
35 | /// Implements an EventSource that matches the virtual or abstract methods of a type.
36 | /// If the type is an interface, this creates a type derived from EventSource that implements the interface.
37 | /// If the type is a class derived from EventSource, this derives from the type and implements any abstract methods.
38 | /// If the type is a class not derived from EventSource, this method fails while casting to T. Use GetEventSource instead.
39 | ///
40 | /// An type to implement as an EventSource.
41 | /// An EventSource that is compatible with the given type.
42 | public static T GetEventSourceAs() where T : class
43 | {
44 | // if it's not an interface or a subclass of EventSource
45 | // then we have to make an entirely new class that isn't derived from T
46 | // and the cast below will fail. Give the programmer a hint.
47 | if (!typeof(T).IsInterface && !typeof(T).IsSubclassOf(typeof(EventSource)))
48 | throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "{0} must be derived from EventSource. Use GetEventSource instead.", typeof(T).FullName));
49 |
50 | return (T)(object)GetEventSource(typeof(T));
51 | }
52 |
53 | ///
54 | /// Implements an EventSource that matches the virtual or abstract methods of a type.
55 | /// If the type is an interface, this creates a type derived from EventSource that implements the interface.
56 | /// If the type is a class derived from EventSource, this derives from the type and implements any abstract methods.
57 | /// If the type is a class not derived from EventSource, this creates a type derived from EventSource that implements
58 | /// method that match the virtual methods of the target type.
59 | ///
60 | /// An type to implement as an EventSource.
61 | /// An EventSource that is compatible with the given type.
62 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
63 | public static EventSource GetEventSource() where T : class
64 | {
65 | return GetEventSource(typeof(T));
66 | }
67 |
68 | ///
69 | /// Implements an EventSource that matches the virtual or abstract methods of a type.
70 | /// If the type is an interface, this creates a type derived from EventSource that implements the interface.
71 | /// If the type is a class derived from EventSource, this derives from the type and implements any abstract methods.
72 | /// If the type is a class not derived from EventSource, this creates a type derived from EventSource that implements
73 | /// method that match the virtual methods of the target type.
74 | ///
75 | /// An type to implement as an EventSource.
76 | /// An EventSource that is compatible with the given type.
77 | public static EventSource GetEventSource(Type type)
78 | {
79 | lock (_eventSources)
80 | {
81 | return (EventSource)_eventSources.GetOrAdd(type, t => new TypeImplementer(t).EventSource);
82 | }
83 | }
84 |
85 | ///
86 | /// Registers a Context Provider for a given event source.
87 | ///
88 | /// The type of event source to register with.
89 | /// The provider to register.
90 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
91 | public static void RegisterProvider(TraceContextProvider provider)
92 | {
93 | RegisterProvider(typeof(TLog), typeof(TraceContextProvider), provider);
94 | }
95 |
96 | ///
97 | /// Registers a Context Provider for a given event source.
98 | ///
99 | /// The type of event source to register with.
100 | /// The provider to register.
101 | public static void RegisterProvider(Type type, TraceContextProvider provider)
102 | {
103 | RegisterProvider(type, typeof(TraceContextProvider), provider);
104 | }
105 |
106 | ///
107 | /// Registers a default TraceContextProvider for all event sources.
108 | ///
109 | /// The provider to register.
110 | public static void RegisterDefaultProvider(TraceContextProvider provider)
111 | {
112 | RegisterProvider(null, provider);
113 | }
114 |
115 | ///
116 | /// Registers a Serialization Provider for a given event source.
117 | ///
118 | /// The type of event source to register with.
119 | /// The provider to register.
120 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
121 | public static void RegisterProvider(TraceSerializationProvider provider)
122 | {
123 | RegisterProvider(typeof(TLog), typeof(TraceSerializationProvider), provider);
124 | }
125 |
126 | ///
127 | /// Registers a Serialization Provider for a given event source.
128 | ///
129 | /// The type of event source to register with.
130 | /// The provider to register.
131 | public static void RegisterProvider(Type type, TraceSerializationProvider provider)
132 | {
133 | RegisterProvider(type, typeof(TraceSerializationProvider), provider);
134 | }
135 |
136 | ///
137 | /// Registers a default TraceSerializationProvider for all event sources.
138 | ///
139 | /// The provider to register.
140 | public static void RegisterDefaultProvider(TraceSerializationProvider provider)
141 | {
142 | RegisterProvider(null, provider);
143 | }
144 |
145 | ///
146 | /// Registers an EventAttributeProvider for a given event source.
147 | ///
148 | /// The type of event source to register with.
149 | /// The provider to register.
150 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
151 | public static void RegisterProvider(EventAttributeProvider provider)
152 | {
153 | RegisterProvider(typeof(TLog), typeof(EventAttributeProvider), provider);
154 | }
155 |
156 | ///
157 | /// Registers a EventAttributeProvider for a given event source.
158 | ///
159 | /// The type of event source to register with.
160 | /// The provider to register.
161 | public static void RegisterProvider(Type type, EventAttributeProvider provider)
162 | {
163 | RegisterProvider(type, typeof(EventAttributeProvider), provider);
164 | }
165 |
166 | ///
167 | /// Registers a default EventAttributeProvider for all event sources.
168 | ///
169 | /// The provider to register.
170 | public static void RegisterDefaultProvider(EventAttributeProvider provider)
171 | {
172 | RegisterProvider(null, provider);
173 | }
174 |
175 | ///
176 | /// Registers an TraceParameterProvider for a given event source.
177 | ///
178 | /// The type of event source to register with.
179 | /// The provider to register.
180 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
181 | public static void RegisterProvider(TraceParameterProvider provider)
182 | {
183 | RegisterProvider(typeof(TLog), typeof(TraceParameterProvider), provider);
184 | }
185 |
186 | ///
187 | /// Registers a TraceParameterProvider for a given event source.
188 | ///
189 | /// The type of event source to register with.
190 | /// The provider to register.
191 | public static void RegisterProvider(Type type, TraceParameterProvider provider)
192 | {
193 | RegisterProvider(type, typeof(TraceParameterProvider), provider);
194 | }
195 |
196 | ///
197 | /// Registers a default TraceParameterProvider for all event sources.
198 | ///
199 | /// The provider to register.
200 | public static void RegisterDefaultProvider(TraceParameterProvider provider)
201 | {
202 | RegisterProvider(null, provider);
203 | }
204 |
205 | ///
206 | /// Gets the keyword value for a method on a type.
207 | ///
208 | /// The type of the EventSource.
209 | /// The name of the method.
210 | /// The keyword value.
211 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
212 | public static EventKeywords GetKeywordValue(string methodName) where T : class
213 | {
214 | if (methodName == null) throw new ArgumentNullException("methodName");
215 |
216 | var logType = GetEventSourceAs().GetType();
217 |
218 | var keywordType = logType.GetNestedType("Keywords");
219 | if (keywordType == null)
220 | throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Keywords have not been defined for {0}", typeof(T)));
221 |
222 | var keyword = keywordType.GetField(methodName);
223 | if (keyword == null)
224 | throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Keyword has not been defined for {1} on {0}", typeof(T), methodName));
225 |
226 | return (EventKeywords)keyword.GetValue(null);
227 | }
228 | #endregion
229 |
230 | #region Internal Members
231 | ///
232 | /// Registers a Provider for a given event source.
233 | ///
234 | /// The type of event source to register with. If null, then the default provider is overridden.
235 | /// The type of provider being provided.
236 | /// The provider to register.
237 | private static void RegisterProvider(Type logType, Type providerType, object provider)
238 | {
239 | if (providerType == null) throw new ArgumentNullException("providerType");
240 |
241 | lock (_eventSources)
242 | {
243 | // if the eventsource already exists, then fail
244 | if (logType != null && _eventSources.ContainsKey(logType))
245 | throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Cannot register {0} after creating a log for type {1}", providerType.Name, logType.Name));
246 |
247 | ProviderManager.RegisterProvider(logType, providerType, provider);
248 | }
249 | }
250 | #endregion
251 | }
252 | }
253 |
--------------------------------------------------------------------------------
/EventSourceProxy/EventSourceManifest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Tracing;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Security.Cryptography;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace EventSourceProxy
11 | {
12 | ///
13 | /// Exposes ETW manifest information for provider types.
14 | ///
15 | public static class EventSourceManifest
16 | {
17 | #region Metadata Members
18 | ///
19 | /// Return the GUID of a provider name.
20 | ///
21 | /// The name of the provider.
22 | /// The GUID representing the name.
23 | public static Guid GetGuidFromProviderName(string providerName)
24 | {
25 | if (providerName == null) throw new ArgumentNullException("providerName");
26 |
27 | string name = providerName.ToUpperInvariant();
28 | byte[] buffer = new byte[(name.Length * 2) + 0x10];
29 | uint num = 0x482c2db2;
30 | uint num2 = 0xc39047c8;
31 | uint num3 = 0x87f81a15;
32 | uint num4 = 0xbfc130fb;
33 | for (int i = 3; 0 <= i; i--)
34 | {
35 | buffer[i] = (byte)num;
36 | num = num >> 8;
37 | buffer[i + 4] = (byte)num2;
38 | num2 = num2 >> 8;
39 | buffer[i + 8] = (byte)num3;
40 | num3 = num3 >> 8;
41 | buffer[i + 12] = (byte)num4;
42 | num4 = num4 >> 8;
43 | }
44 |
45 | for (int j = 0; j < name.Length; j++)
46 | {
47 | buffer[((2 * j) + 0x10) + 1] = (byte)name[j];
48 | buffer[(2 * j) + 0x10] = (byte)(name[j] >> 8);
49 | }
50 |
51 | using (SHA1 sha = SHA1.Create())
52 | {
53 | byte[] buffer2 = sha.ComputeHash(buffer);
54 | int a = (((((buffer2[3] << 8) + buffer2[2]) << 8) + buffer2[1]) << 8) + buffer2[0];
55 | short b = (short)((buffer2[5] << 8) + buffer2[4]);
56 | short num9 = (short)((buffer2[7] << 8) + buffer2[6]);
57 | return new System.Guid(a, b, (short)((num9 & 0xfff) | 0x5000), buffer2[8], buffer2[9], buffer2[10], buffer2[11], buffer2[12], buffer2[13], buffer2[14], buffer2[15]);
58 | }
59 | }
60 |
61 | ///
62 | /// Return the GUID of a provider.
63 | ///
64 | /// The provider type.
65 | /// The GUID representing the name.
66 | public static Guid GetGuid(Type type)
67 | {
68 | EventSource eventSource = EventSourceImplementer.GetEventSource(type);
69 | return eventSource.Guid;
70 | }
71 |
72 | ///
73 | /// Return the manifest of a provider for the given type.
74 | ///
75 | /// The provider type.
76 | /// The XML manifest content.
77 | public static string GenerateManifest(Type type)
78 | {
79 | EventSource eventSource = EventSourceImplementer.GetEventSource(type);
80 | return EventSource.GenerateManifest(eventSource.GetType(), Assembly.GetAssembly(type).Location);
81 | }
82 | #endregion
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/EventSourceProxy/EventSourceProxy.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0;net46
5 | true
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/EventSourceProxy/GlobalSuppressions.cs:
--------------------------------------------------------------------------------
1 | // This file is used by Code Analysis to maintain SuppressMessage
2 | // attributes that are applied to this project.
3 | // Project-level suppressions either have no target or are given
4 | // a specific target and scoped to a namespace, type, member, etc.
5 | //
6 | // To add a suppression to this file, right-click the message in the
7 | // Code Analysis results, point to "Suppress Message", and click
8 | // "In Suppression File".
9 | // You do not need to add suppressions to this file manually.
10 |
11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")]
12 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "With", Scope = "member", Target = "EventSourceProxy.IParameterBuilder.#With`1()")]
13 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "And", Scope = "member", Target = "EventSourceProxy.IParameterBuilderWithParameter.#And(System.String[])")]
14 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "With", Scope = "member", Target = "EventSourceProxy.IParameterBuilder.#With`1(System.String)")]
15 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "And", Scope = "member", Target = "EventSourceProxy.IParameterBuilderWithParameter.#And`2(System.Linq.Expressions.Expression`1>[])")]
16 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Alias", Scope = "member", Target = "EventSourceProxy.IParameterBuilderWithParameter.#TogetherAs(System.String)")]
17 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "With", Scope = "member", Target = "EventSourceProxy.IParameterBuilderWithType`1.#With`1()")]
18 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "With", Scope = "member", Target = "EventSourceProxy.IParameterBuilderWithType`1.#With`1(System.String)")]
19 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "And", Scope = "member", Target = "EventSourceProxy.IParameterBuilderWithTypeAndParameter`1.#And(System.String[])")]
20 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "And", Scope = "member", Target = "EventSourceProxy.IParameterBuilderWithTypeAndParameter`1.#And`1(System.Linq.Expressions.Expression`1>[])")]
21 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "As", Scope = "member", Target = "EventSourceProxy.IParameterBuilderWithTypeAndParameter`1.#As(System.String[])")]
22 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Alias", Scope = "member", Target = "EventSourceProxy.IParameterBuilderWithTypeAndParameter`1.#TogetherAs(System.String)")]
23 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "With", Scope = "member", Target = "EventSourceProxy.IParameterBuilderWithTypeAndParameter`1.#With`1()")]
24 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "With", Scope = "member", Target = "EventSourceProxy.IParameterBuilderWithTypeAndParameter`1.#With`1(System.String)")]
25 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Scope = "member", Target = "EventSourceProxy.IParameterBuilder.#Ignore`1()")]
26 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "As", Scope = "member", Target = "EventSourceProxy.IParameterBuilderWithParameter.#As(System.String[])")]
27 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "For", Scope = "member", Target = "EventSourceProxy.IParameterBuilderBase.#For`1()")]
28 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "For", Scope = "member", Target = "EventSourceProxy.IParameterBuilderBase.#For`1(System.Linq.Expressions.Expression`1>)")]
29 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "With", Scope = "member", Target = "EventSourceProxy.IParameterBuilderBase.#With`1()")]
30 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "With", Scope = "member", Target = "EventSourceProxy.IParameterBuilderBase.#With`1(System.String)")]
31 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Scope = "member", Target = "EventSourceProxy.ParameterMapping.#AddSource(System.Reflection.ParameterInfo,System.String,System.Linq.Expressions.LambdaExpression)")]
32 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Alias", Scope = "member", Target = "EventSourceProxy.IParameterBuilder.#WithContext`1(System.String,System.Linq.Expressions.Expression`1>)")]
33 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Scope = "member", Target = "EventSourceProxy.IParameterBuilder.#WithContext`1(System.String,System.Linq.Expressions.Expression`1>)")]
34 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Alias", Scope = "member", Target = "EventSourceProxy.IParameterBuilder.#AddContext`1(System.String,System.Linq.Expressions.Expression`1>)")]
35 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Scope = "member", Target = "EventSourceProxy.IParameterBuilder.#AddContext`1(System.String,System.Linq.Expressions.Expression`1>)")]
36 |
--------------------------------------------------------------------------------
/EventSourceProxy/InvocationContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Tracing;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Reflection.Emit;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace EventSourceProxy
11 | {
12 | ///
13 | /// Specifies the invocation of a method and the type of the invocation (MethodCall, MethodCompletion, or MethodFaulted).
14 | ///
15 | public class InvocationContext
16 | {
17 | ///
18 | /// Initializes a new instance of the InvocationContext class.
19 | ///
20 | /// The handle of the method being invoked.
21 | /// The context type for this invocation.
22 | internal InvocationContext(MethodInfo methodInfo, InvocationContextTypes contextType)
23 | {
24 | MethodInfo = methodInfo;
25 | ContextType = contextType;
26 | }
27 |
28 | ///
29 | /// Gets the EventSource associated with the InvocationContext.
30 | ///
31 | public EventSource EventSource { get; internal set; }
32 |
33 | ///
34 | /// Gets the method being invoked.
35 | ///
36 | public MethodInfo MethodInfo { get; private set; }
37 |
38 | ///
39 | /// Gets the type of the invocation.
40 | ///
41 | public InvocationContextTypes ContextType { get; private set; }
42 |
43 | ///
44 | /// Creates a clone of this InvocationContext, changing the type of the context.
45 | ///
46 | /// The new InvocationContextType.
47 | /// A clone of this InvocationContext with a new context type.
48 | internal InvocationContext SpecifyType(InvocationContextTypes contextType)
49 | {
50 | InvocationContext context = (InvocationContext)this.MemberwiseClone();
51 | context.ContextType = contextType;
52 | return context;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/EventSourceProxy/InvocationContextTypes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace EventSourceProxy
8 | {
9 | ///
10 | /// Specifies the type of invocation of the method.
11 | ///
12 | [Flags]
13 | public enum InvocationContextTypes
14 | {
15 | ///
16 | /// The invocation is the method call.
17 | ///
18 | MethodCall = 1 << 0,
19 |
20 | ///
21 | /// The invocation is the completion of the method.
22 | /// The parameter is the return value, if any.
23 | ///
24 | MethodCompletion = 1 << 1,
25 |
26 | ///
27 | /// The invocation is the exception event.
28 | /// The parameter is the exception.
29 | ///
30 | MethodFaulted = 1 << 2,
31 |
32 | ///
33 | /// No types of method invocations.
34 | ///
35 | None = 0,
36 |
37 | ///
38 | /// The invocation is to bundle a set of parameters into a single parameter.
39 | /// The parameter is a string-to-string map.
40 | ///
41 | BundleParameters = 1 << 4,
42 |
43 | ///
44 | /// All types of method invocations.
45 | ///
46 | All = MethodCall | MethodCompletion | MethodFaulted | BundleParameters
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/EventSourceProxy/JsonObjectSerializer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.CodeAnalysis;
4 | using System.Diagnostics.Tracing;
5 | using System.Globalization;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using Newtonsoft.Json;
10 |
11 | namespace EventSourceProxy
12 | {
13 | ///
14 | /// Used internally to serialize a string. By default, it uses Newtonsoft.Json to JSON serialize the object.
15 | ///
16 | public class JsonObjectSerializer : TraceSerializationProvider
17 | {
18 | #region Constructors
19 | ///
20 | /// Initializes a new instance of the JsonObjectSerializer class.
21 | /// The default is to serialize objects only in Verbose tracing.
22 | ///
23 | public JsonObjectSerializer() : base(EventLevel.Verbose)
24 | {
25 | }
26 |
27 | ///
28 | /// Initializes a new instance of the JsonObjectSerializer class.
29 | ///
30 | ///
31 | /// The default EventLevel to allow object serialization.
32 | /// The default is to serialize objects whenever tracing occurs, but this can be used to allow serialization
33 | /// only when logging is at a particular level of verbosity.
34 | ///
35 | public JsonObjectSerializer(EventLevel defaultEventLevel) : base(defaultEventLevel)
36 | {
37 | }
38 | #endregion
39 |
40 | ///
41 | /// Serializes an object to a string.
42 | ///
43 | /// The object to serialize.
44 | /// The context of the serialization.
45 | /// The serialized representation of the object.
46 | [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Logging should not affect program behavior.")]
47 | public override string SerializeObject(object value, TraceSerializationContext context)
48 | {
49 | try
50 | {
51 | // if we have a task, don't attempt to serialize the task if it's not completed
52 | Task t = value as Task;
53 | if (t != null && !t.IsCompleted)
54 | {
55 | return JsonConvert.SerializeObject(new { TaskId = t.Id });
56 | }
57 |
58 | return JsonConvert.SerializeObject(value);
59 | }
60 | catch (Exception e)
61 | {
62 | // don't let serialization exceptions blow up processing
63 | return String.Format(CultureInfo.InvariantCulture, "{{ Exception: '{0}' }}", e.Message.Replace("'", "\\'"));
64 | }
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/EventSourceProxy/NullObjectSerializer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Tracing;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Newtonsoft.Json;
9 |
10 | namespace EventSourceProxy
11 | {
12 | ///
13 | /// Serializes an object by returning null. This is effectively a NoOp.
14 | ///
15 | public class NullObjectSerializer : TraceSerializationProvider
16 | {
17 | #region Constructors
18 | ///
19 | /// Initializes a new instance of the NullObjectSerializer class.
20 | /// The Null serializer serializes everything as null.
21 | ///
22 | public NullObjectSerializer()
23 | {
24 | }
25 | #endregion
26 |
27 | ///
28 | /// Serializes an object to a string.
29 | ///
30 | /// The object to serialize.
31 | /// The context of the serialization.
32 | /// The serialized representation of the object.
33 | public override string SerializeObject(object value, TraceSerializationContext context)
34 | {
35 | return String.Empty;
36 | }
37 |
38 | ///
39 | /// Returns if the should the given parameter be serialized.
40 | ///
41 | /// The context of the serialization.
42 | /// True if the value should be serialized, false otherwise.
43 | public override bool ShouldSerialize(TraceSerializationContext context)
44 | {
45 | return true;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/EventSourceProxy/ParameterBuilderValue.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Reflection;
6 |
7 | namespace EventSourceProxy
8 | {
9 | ///
10 | /// Represents a value to be extracted from a parameter list.
11 | ///
12 | class ParameterBuilderValue
13 | {
14 | ///
15 | /// Initializes a new instance of the ParameterBuilderValue class.
16 | ///
17 | /// The name of the parameter to bind to, or null to bind to parameters of any name.
18 | /// The name to use to trace the parameter.
19 | /// The type of parameter to filter on.
20 | /// An expression used to convert the parameter to another value, or null to use the parameter as it is.
21 | public ParameterBuilderValue(string parameterName, string alias, Type parameterType, LambdaExpression converter)
22 | {
23 | Alias = alias;
24 | ParameterName = parameterName;
25 |
26 | Converter = converter;
27 |
28 | if (converter != null && converter.Parameters.Count > 0)
29 | ParameterType = parameterType ?? converter.Parameters[0].Type;
30 | else
31 | ParameterType = parameterType;
32 | }
33 |
34 | ///
35 | /// Gets or sets the name to use to log the value.
36 | ///
37 | public string Alias { get; set; }
38 |
39 | ///
40 | /// Gets the name of the parameter to bind to, or null, representing binding to a parameter of any name.
41 | ///
42 | public string ParameterName { get; private set; }
43 |
44 | ///
45 | /// Gets the type of parameter to bind to.
46 | ///
47 | public Type ParameterType { get; private set; }
48 |
49 | ///
50 | /// Gets the expression to use to convert the value. If set, the value will only bind to parameters matching the given type.
51 | ///
52 | public LambdaExpression Converter { get; private set; }
53 |
54 | ///
55 | /// Gets or sets a value indicating whether the parameter should be ignored.
56 | ///
57 | public bool Ignore { get; set; }
58 |
59 | ///
60 | /// Returns all of the parameters that match this value's name and converter.
61 | ///
62 | /// The parameter to evaluate.
63 | /// An enumeration of the matching parameters.
64 | public bool Matches(ParameterInfo parameter)
65 | {
66 | // if both name and type are not specified, then this only matches the null parameter
67 | // otherwise we will match every parameter
68 | if (ParameterName == null && ParameterType == null)
69 | return parameter == null;
70 | if (parameter == null)
71 | return false;
72 |
73 | // filter by name and/or parameter type
74 | return
75 | (ParameterName == null || String.Compare(parameter.Name, ParameterName, StringComparison.OrdinalIgnoreCase) == 0) &&
76 | (ParameterType == null || parameter.ParameterType == ParameterType || parameter.ParameterType.IsSubclassOf(ParameterType));
77 | }
78 |
79 | ///
80 | /// Returns all of the parameters that match this value's name and converter.
81 | ///
82 | /// The parameters to evaluate.
83 | /// An enumeration of the matching parameters.
84 | public IEnumerable Matches(IEnumerable parameters)
85 | {
86 | // filter by name and/or parameter type
87 | return parameters.Where(p => Matches(p));
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/EventSourceProxy/ParameterConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 | using System.Reflection.Emit;
4 |
5 | namespace EventSourceProxy
6 | {
7 | ///
8 | /// Handles custom conversion of logging data by invoking LambdaExpressions.
9 | ///
10 |
11 | class ParameterConverter
12 | {
13 | ///
14 | /// Gets the type of the input parameter, or null if there are no parameters.
15 | ///
16 | public Type InputType { get; private set; }
17 |
18 | ///
19 | /// Gets the type of the return value.
20 | ///
21 | public Type ReturnType { get; private set; }
22 |
23 | private Func _generator;
24 |
25 | ///
26 | /// Initializes a new instance of the ParameterConverter class.
27 | ///
28 | /// The type of the input parameter.
29 | /// The type returned from the converter.
30 | /// A function that emits the conversion code and returns the return type.
31 | public ParameterConverter(Type inputType, Type returnType, Func generator)
32 | {
33 | InputType = inputType;
34 | ReturnType = returnType;
35 | _generator = generator;
36 | }
37 |
38 | ///
39 | /// Initializes a new instance of the ParameterConverter class.
40 | ///
41 | /// A LambdaExpression that converts the value.
42 | public ParameterConverter(LambdaExpression expression)
43 | {
44 | var hasParameters = (expression.Parameters.Count > 0);
45 |
46 | InputType = hasParameters ? expression.Parameters[0].Type : null;
47 | ReturnType = expression.ReturnType;
48 |
49 | _generator = (il =>
50 | {
51 | var del = expression.Compile();
52 |
53 | if (hasParameters)
54 | {
55 | var local = il.DeclareLocal(InputType);
56 | il.Emit(OpCodes.Stloc, local.LocalIndex);
57 | StaticFieldStorage.EmitLoad(il, del);
58 | il.Emit(OpCodes.Ldloc, local.LocalIndex);
59 | il.Emit(OpCodes.Call, del.GetType().GetMethod("Invoke"));
60 | }
61 | else
62 | {
63 | StaticFieldStorage.EmitLoad(il, del);
64 | il.Emit(OpCodes.Call, del.GetType().GetMethod("Invoke"));
65 | }
66 |
67 | return expression.ReturnType;
68 | });
69 | }
70 |
71 | ///
72 | /// Emits the IL to perform the conversion.
73 | ///
74 | /// The return type of the conversion.
75 | public Type Emit(ILGenerator il)
76 | {
77 | return _generator(il);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/EventSourceProxy/ParameterDefinition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Reflection;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace EventSourceProxy
10 | {
11 | ///
12 | /// Represents the definition of a parameter.
13 | ///
14 | class ParameterDefinition
15 | {
16 | ///
17 | /// Initializes a new instance of the ParameterDefinition class from a parameter.
18 | ///
19 | /// The name of the parameter.
20 | /// The position of the parameter on the stack.
21 | /// The type of the parameter.
22 | public ParameterDefinition(string alias, int position, Type sourceType)
23 | {
24 | if (sourceType == null) throw new ArgumentNullException("sourceType");
25 | if (alias == null) throw new ArgumentNullException("alias");
26 | if (position < 0) throw new ArgumentOutOfRangeException("position", "position must not be negative");
27 |
28 | Position = position;
29 | SourceType = sourceType;
30 | Alias = alias;
31 | }
32 |
33 | ///
34 | /// Initializes a new instance of the ParameterDefinition class from parameter.
35 | ///
36 | /// The name of the parameter.
37 | /// The parameter to bind to.
38 | /// An optional converter that converts the parameter to a desired result.
39 | public ParameterDefinition(string alias, ParameterInfo parameterInfo, ParameterConverter converter = null)
40 | {
41 | if (alias == null) throw new ArgumentNullException("alias");
42 |
43 | Alias = alias;
44 | Converter = converter;
45 |
46 | if (parameterInfo != null)
47 | {
48 | Position = parameterInfo.Position;
49 | SourceType = parameterInfo.ParameterType;
50 |
51 | if (converter != null)
52 | {
53 | if (SourceType != converter.InputType && !SourceType.IsSubclassOf(converter.InputType))
54 | throw new ArgumentException("The conversion expression must match the type of the parameter.", "converter");
55 | }
56 | }
57 | else
58 | {
59 | if (converter == null)
60 | throw new ArgumentException("A conversion expression must be specified.", "converter");
61 | if (converter.InputType != null)
62 | throw new ArgumentException("The conversion expression must take no parameters.", "converter");
63 |
64 | Position = -1;
65 | SourceType = converter.ReturnType;
66 | }
67 | }
68 |
69 | ///
70 | /// Gets the position of the parameter.
71 | ///
72 | /// If less than zero, then there is no source of the parameter.
73 | public int Position { get; private set; }
74 |
75 | ///
76 | /// Gets the type of the parameter.
77 | ///
78 | /// If null, then there is no source of the parameter.
79 | public Type SourceType { get; private set; }
80 |
81 | ///
82 | /// Gets the name to use to log the parameter.
83 | ///
84 | public string Alias { get; private set; }
85 |
86 | ///
87 | /// Gets an expression that converts the parameter to the intended logged value.
88 | ///
89 | public ParameterConverter Converter { get; private set; }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/EventSourceProxy/ParameterMapping.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Reflection;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace EventSourceProxy
10 | {
11 | ///
12 | /// Represents the mapping between the caller's parameters and the parameters for the underlying method.
13 | ///
14 | public class ParameterMapping
15 | {
16 | ///
17 | /// The sources of the parameter.
18 | ///
19 | private List _sources = new List();
20 |
21 | ///
22 | /// Initializes a new instance of the ParameterMapping class with an empty source list.
23 | ///
24 | /// The name of the parameter.
25 | public ParameterMapping(string name)
26 | {
27 | Name = name;
28 | }
29 |
30 | ///
31 | /// Gets the name of the parameter.
32 | ///
33 | public string Name { get; private set; }
34 |
35 | ///
36 | /// Gets the sources of the parameter.
37 | ///
38 | internal IEnumerable Sources { get { return _sources; } }
39 |
40 | ///
41 | /// Gets the target type of the parameter.
42 | ///
43 | internal Type TargetType
44 | {
45 | get
46 | {
47 | if (_sources.Count == 1)
48 | {
49 | // if there is one source, then we use the type of the individual source
50 | var source = _sources[0];
51 | if (source.Converter != null)
52 | return source.Converter.ReturnType;
53 |
54 | return source.SourceType;
55 | }
56 |
57 | // otherwise we have multiple sources, or a context, so we target a string
58 | return typeof(string);
59 | }
60 | }
61 |
62 | ///
63 | /// Gets the target type of the parameter, compatible with ETW.
64 | ///
65 | internal Type CleanTargetType { get { return TypeImplementer.GetTypeSupportedByEventSource(TargetType); } }
66 |
67 | ///
68 | /// Gets a value indicating whether this mapping has any sources.
69 | ///
70 | internal bool HasSource { get { return _sources.Any(); } }
71 |
72 | ///
73 | /// Gets the source type of the parameter.
74 | ///
75 | internal Type SourceType
76 | {
77 | get
78 | {
79 | // if there is one source, then use its type, otherwise we are reading from an object
80 | if (_sources.Count == 1)
81 | return _sources[0].SourceType;
82 | else
83 | return typeof(object);
84 | }
85 | }
86 |
87 | ///
88 | /// Adds a parameter source to this mapping.
89 | ///
90 | /// The parameter to add.
91 | /// The alias to use to log the parameter.
92 | /// A converter that converts the parameter to a desired value.
93 | public void AddSource(ParameterInfo pi, string alias = null, LambdaExpression converter = null)
94 | {
95 | if (alias == null)
96 | {
97 | if (pi == null)
98 | throw new ArgumentNullException("pi");
99 | else
100 | alias = pi.Name;
101 | }
102 |
103 | var pc = (converter != null) ? new ParameterConverter(converter) : null;
104 |
105 | _sources.Add(new ParameterDefinition(alias, pi, pc));
106 | }
107 |
108 | ///
109 | /// Adds a parameter source to this mapping.
110 | ///
111 | /// The input type of the converter.
112 | /// The output type of the converter.
113 | /// The parameter to add.
114 | /// The alias to use to log the parameter.
115 | /// A converter that converts the parameter to a desired value.
116 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures"),
117 | System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "This lets the compiler know to generate expressions")]
118 | public void AddSource(ParameterInfo pi, string alias, Expression> converter)
119 | {
120 | if (pi == null) throw new ArgumentNullException("pi");
121 |
122 | AddSource(pi, alias, (LambdaExpression)converter);
123 | }
124 |
125 | ///
126 | /// Adds a parameter source to this mapping.
127 | ///
128 | /// The input type of the converter.
129 | /// The output type of the converter.
130 | /// The parameter to add.
131 | /// A converter that converts the parameter to a desired value.
132 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures"),
133 | System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "This lets the compiler know to generate expressions")]
134 | public void AddSource(ParameterInfo pi, Expression> converter)
135 | {
136 | if (pi == null) throw new ArgumentNullException("pi");
137 |
138 | AddSource(pi, pi.Name, (LambdaExpression)converter);
139 | }
140 |
141 | ///
142 | /// Adds a context method to this mapping.
143 | ///
144 | /// The output type of the context expression
145 | /// The alias to use to log the context.
146 | /// An expression that can generate context.
147 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures"),
148 | System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "This lets the compiler know to generate expressions")]
149 | public void AddContext(string alias, Expression> contextExpression)
150 | {
151 | AddSource(null, alias, (LambdaExpression)contextExpression);
152 | }
153 |
154 | ///
155 | /// Adds a parameter source to this mapping.
156 | ///
157 | /// The parameter to add.
158 | internal void AddSource(ParameterDefinition source)
159 | {
160 | if (source == null) throw new ArgumentNullException("source");
161 |
162 | _sources.Add(source);
163 | }
164 |
165 | ///
166 | /// Adds a parameter source to this mapping.
167 | ///
168 | /// The parameter to add.
169 | /// The alias to use to log the parameter.
170 | /// A converter that converts the parameter to a desired value.
171 | internal void AddSource(ParameterInfo pi, string alias, ParameterConverter converter)
172 | {
173 | if (alias == null)
174 | {
175 | if (pi == null)
176 | throw new ArgumentNullException("pi");
177 | else
178 | alias = pi.Name;
179 | }
180 |
181 | _sources.Add(new ParameterDefinition(alias, pi, converter));
182 | }
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/EventSourceProxy/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using System;
3 |
4 | [assembly: InternalsVisibleTo("EventSourceProxy.Tests")]
5 |
--------------------------------------------------------------------------------
/EventSourceProxy/ProviderManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Collections.Generic;
4 | using System.Globalization;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace EventSourceProxy
10 | {
11 | ///
12 | /// Manages the providers for the Event Sources.
13 | ///
14 | class ProviderManager
15 | {
16 | ///
17 | /// The list of registered providers.
18 | ///
19 | private static ConcurrentDictionary, object> _providers = new ConcurrentDictionary, object>();
20 |
21 | ///
22 | /// Registers a Provider for a given event source.
23 | ///
24 | /// The type of event source to register with.
25 | /// The type of provider being provided.
26 | /// The provider to register.
27 | internal static void RegisterProvider(Type logType, Type providerType, object provider)
28 | {
29 | var key = Tuple.Create(logType, providerType);
30 |
31 | // if the provider is null, then remove the provider
32 | if (provider == null)
33 | {
34 | _providers.TryRemove(key, out provider);
35 | return;
36 | }
37 |
38 | if (!providerType.IsInstanceOfType(provider))
39 | throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Provider must be an instance of {0}", providerType.Name));
40 |
41 | // save the provider for future construction
42 | // if the provider already exists, then fail
43 | if (!_providers.TryAdd(key, provider))
44 | throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "{0} already exists for type {1}", providerType.Name, logType.Name));
45 | }
46 |
47 | ///
48 | /// Gets the given type of provider for the given type of log.
49 | ///
50 | /// The type of provider being provided.
51 | /// The type of event source to register with.
52 | /// The type of the ProviderAttribute that can specify the provider.
53 | /// The constructor to use to create the provider if it does not exist.
54 | /// The provider for a given type, or null if there is no provider.
55 | internal static T GetProvider(Type logType, Type attributeType, Func defaultConstructor)
56 | {
57 | if (defaultConstructor == null)
58 | defaultConstructor = () => default(T);
59 |
60 | return (T)GetProvider(logType, typeof(T), attributeType, () => defaultConstructor());
61 | }
62 |
63 | ///
64 | /// Gets the given type of provider for the given type of log.
65 | ///
66 | /// The type of event source to register with.
67 | /// The type of provider being provided.
68 | /// The type of the ProviderAttribute that can specify the provider.
69 | /// The constructor to use to create the provider if it does not exist.
70 | /// The provider for a given type, or null if there is no provider.
71 | private static object GetProvider(Type logType, Type providerType, Type attributeType, Func