Skip to content

Commit d05110c

Browse files
CodeBlanchericstjtarekgh
authored
[DiagnosticSource] Add version event to EventSources used for out-of-proc monitoring (#107576)
* Add a version event to DS event sources. * Tweaks. * Code review. * Code review, bug fixes, and tests. * Fix GenerateFileFromTemplate and make it work with incremental build * Test fixes and code review. * Apply suggestions from code review --------- Co-authored-by: Eric StJohn <[email protected]> Co-authored-by: Tarek Mahmoud Sayed <[email protected]>
1 parent ca00ae3 commit d05110c

File tree

6 files changed

+139
-1
lines changed

6 files changed

+139
-1
lines changed

src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
8989

9090
<None Include="DiagnosticSourceUsersGuide.md" />
9191
<None Include="ActivityUserGuide.md" />
92+
<None Include="FlatRequestId.md" />
93+
<None Include="HierarchicalRequestId.md" />
94+
<None Include="HttpCorrelationProtocol.md" />
95+
<None Include="ThisAssembly.cs.in" />
9296
</ItemGroup>
9397

9498
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
@@ -158,4 +162,23 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
158162
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="$(SystemRuntimeCompilerServicesUnsafeVersion)" />
159163
</ItemGroup>
160164

165+
<ItemGroup>
166+
<PackageReference Include="Microsoft.DotNet.Build.Tasks.Templating" Version="$(MicrosoftDotNetBuildTasksTemplatingVersion)" PrivateAssets="All" IsImplicitlyDefined="true" />
167+
</ItemGroup>
168+
169+
<Target Name="_GenerateThisAssemblyInfo"
170+
BeforeTargets="CoreCompile"
171+
Inputs="ThisAssembly.cs.in"
172+
Outputs="$(IntermediateOutputPath)ThisAssembly.cs">
173+
<GenerateFileFromTemplate
174+
TemplateFile="ThisAssembly.cs.in"
175+
Properties="AssemblyVersion=$(AssemblyVersion);AssemblyFileVersion=$(FileVersion)"
176+
OutputPath="$(IntermediateOutputPath)ThisAssembly.cs" />
177+
178+
<ItemGroup>
179+
<Compile Include="$(IntermediateOutputPath)ThisAssembly.cs" />
180+
<FileWrites Include="$(IntermediateOutputPath)ThisAssembly.cs" />
181+
</ItemGroup>
182+
</Target>
183+
161184
</Project>

src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticSourceEventSource.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,12 +349,29 @@ public void ActivityStart(string SourceName, string ActivityName, IEnumerable<Ke
349349
public void ActivityStop(string SourceName, string ActivityName, IEnumerable<KeyValuePair<string, string?>> Arguments) =>
350350
WriteEvent(12, SourceName, ActivityName, Arguments);
351351

352+
/// <summary>
353+
/// Used to send version information.
354+
/// </summary>
355+
[Event(13, Keywords = Keywords.Messages)]
356+
public void Version(int Major, int Minor, int Patch)
357+
{
358+
WriteEvent(13, Major, Minor, Patch);
359+
}
360+
352361
/// <summary>
353362
/// Called when the EventSource gets a command from a EventListener or ETW.
354363
/// </summary>
355364
[NonEvent]
356365
protected override void OnEventCommand(EventCommandEventArgs command)
357366
{
367+
if (command.Command == EventCommand.Enable)
368+
{
369+
Version(
370+
ThisAssembly.AssemblyFileVersion.Major,
371+
ThisAssembly.AssemblyFileVersion.Minor,
372+
ThisAssembly.AssemblyFileVersion.Build);
373+
}
374+
358375
// On every command (which the debugger can force by turning on this EventSource with ETW)
359376
// call a function that the debugger can hook to do an arbitrary func evaluation.
360377
BreakPointWithDebuggerFuncEval();

src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,29 @@ public void MultipleSessionsConfiguredIncorrectlyError(string clientId, string e
277277
WriteEvent(17, clientId, expectedMaxHistograms, actualMaxHistograms, expectedMaxTimeSeries, actualMaxTimeSeries, expectedRefreshInterval, actualRefreshInterval);
278278
}
279279

280+
/// <summary>
281+
/// Used to send version information.
282+
/// </summary>
283+
[Event(18, Keywords = Keywords.Messages)]
284+
public void Version(int Major, int Minor, int Patch)
285+
{
286+
WriteEvent(18, Major, Minor, Patch);
287+
}
288+
280289
/// <summary>
281290
/// Called when the EventSource gets a command from a EventListener or ETW.
282291
/// </summary>
283292
[NonEvent]
284293
protected override void OnEventCommand(EventCommandEventArgs command)
285294
{
295+
if (command.Command == EventCommand.Enable)
296+
{
297+
Version(
298+
ThisAssembly.AssemblyFileVersion.Major,
299+
ThisAssembly.AssemblyFileVersion.Minor,
300+
ThisAssembly.AssemblyFileVersion.Build);
301+
}
302+
286303
lock (this)
287304
{
288305
Handler.OnEventCommand(command);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace System.Diagnostics;
5+
6+
internal static class ThisAssembly
7+
{
8+
private const string BuildAssemblyFileVersion = "${AssemblyFileVersion}";
9+
10+
public static Version AssemblyFileVersion { get; } = new(BuildAssemblyFileVersion);
11+
}

src/libraries/System.Diagnostics.DiagnosticSource/tests/DiagnosticSourceEventSourceBridgeTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Collections.Generic;
55
using System.Diagnostics.Tracing;
6+
using System.Reflection;
67
using System.Text;
78
using System.Threading;
89
using Microsoft.DotNet.RemoteExecutor;
@@ -959,6 +960,42 @@ public void TestMessages()
959960
}).Dispose();
960961
}
961962

963+
// Tests that version event from DiagnosticSourceEventSource is fired.
964+
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
965+
public void TestVersion()
966+
{
967+
RemoteExecutor.Invoke(static () =>
968+
{
969+
Activity a = new Activity("test"); // we need this to ensure DiagnosticSourceEventSource.Logger creation.
970+
971+
using (var eventSourceListener = new TestDiagnosticSourceEventListener())
972+
{
973+
Assert.Equal(0, eventSourceListener.EventCount);
974+
975+
Version? version = null;
976+
977+
eventSourceListener.OtherEventWritten += delegate (EventWrittenEventArgs evnt)
978+
{
979+
if (evnt.EventName == "Version")
980+
{
981+
version = new(
982+
(int)evnt.Payload[0],
983+
(int)evnt.Payload[1],
984+
(int)evnt.Payload[2]);
985+
}
986+
};
987+
988+
eventSourceListener.Enable("");
989+
Assert.Equal(0, eventSourceListener.EventCount);
990+
991+
Assert.NotNull(version);
992+
Assert.Equal(
993+
new Version(typeof(Activity).Assembly.GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version ?? "0.0.0").ToString(3),
994+
version.ToString());
995+
}
996+
}).Dispose();
997+
}
998+
962999
/// <summary>
9631000
/// Tests the feature to send the messages as EventSource Activities.
9641001
/// </summary>

src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,35 @@ public void GetInstanceMethodIsReflectable()
4646
Assert.True(o is EventSource, "Expected object returned from MetricsEventSource.GetInstance() to be assignable to EventSource");
4747
}
4848

49+
// Tests that version event from MetricsEventSource is fired.
50+
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
51+
public void TestVersion()
52+
{
53+
RemoteExecutor.Invoke(static () =>
54+
{
55+
using var meter = new Meter("test"); // we need this to ensure MetricsEventSource.Logger creation.
56+
57+
using (var eventSourceListener = new MetricsEventListener(NullTestOutputHelper.Instance, EventKeywords.All, 60))
58+
{
59+
var versionEvents = eventSourceListener.Events.Where(e => e.EventName == "Version");
60+
61+
Assert.Single(versionEvents);
62+
63+
var versionEvent = versionEvents.First();
64+
65+
var version = new Version(
66+
(int)versionEvent.Payload[0],
67+
(int)versionEvent.Payload[1],
68+
(int)versionEvent.Payload[2]);
69+
70+
Assert.NotNull(version);
71+
Assert.Equal(
72+
new Version(typeof(Meter).Assembly.GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version ?? "0.0.0").ToString(3),
73+
version.ToString());
74+
}
75+
}).Dispose();
76+
}
77+
4978
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
5079
[OuterLoop("Slow and has lots of console spew")]
5180
public void MultipleListeners_DifferentCounters()
@@ -2102,7 +2131,11 @@ public override void Dispose()
21022131
protected override void OnEventWritten(EventWrittenEventArgs eventData)
21032132
{
21042133
string sessionId = eventData.Payload[0].ToString();
2105-
if (eventData.EventName != "MultipleSessionsNotSupportedError" && eventData.EventName != "MultipleSessionsConfiguredIncorrectlyError" && sessionId != "" && sessionId != _sessionId)
2134+
if (eventData.EventName != "MultipleSessionsNotSupportedError"
2135+
&& eventData.EventName != "MultipleSessionsConfiguredIncorrectlyError"
2136+
&& eventData.EventName != "Version"
2137+
&& sessionId != ""
2138+
&& sessionId != _sessionId)
21062139
{
21072140
return;
21082141
}

0 commit comments

Comments
 (0)