Skip to content

Commit d435bb2

Browse files
authored
Add SolutionSessionId and ProjectsWithAppliedChanges telemetry properties (#56947) (#56979)
2 parents ae62c5f + f9ec7d1 commit d435bb2

File tree

7 files changed

+101
-47
lines changed

7 files changed

+101
-47
lines changed

src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ private static TestWorkspace CreateWorkspace(string workspaceKind = null, bool d
3737
composition = composition.AddParts(typeof(TestOptionsServiceWithSharedGlobalOptionsServiceFactory));
3838
}
3939

40-
return new TestWorkspace(exportProvider: null, composition, workspaceKind, disablePartialSolutions);
40+
return new TestWorkspace(exportProvider: null, composition, workspaceKind, disablePartialSolutions: disablePartialSolutions);
4141
}
4242

4343
private static async Task WaitForWorkspaceOperationsToComplete(TestWorkspace workspace)

src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs

Lines changed: 41 additions & 37 deletions
Large diffs are not rendered by default.

src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,19 @@ public partial class TestWorkspace : Workspace
5555
private readonly Dictionary<string, ITextBuffer2> _createdTextBuffers = new();
5656
private readonly string _workspaceKind;
5757

58-
public TestWorkspace(ExportProvider? exportProvider = null, TestComposition? composition = null, string? workspaceKind = WorkspaceKind.Host, bool disablePartialSolutions = true, bool ignoreUnchangeableDocumentsWhenApplyingChanges = true)
58+
public TestWorkspace(
59+
ExportProvider? exportProvider = null,
60+
TestComposition? composition = null,
61+
string? workspaceKind = WorkspaceKind.Host,
62+
Guid solutionTelemetryId = default,
63+
bool disablePartialSolutions = true,
64+
bool ignoreUnchangeableDocumentsWhenApplyingChanges = true)
5965
: base(GetHostServices(exportProvider, composition), workspaceKind ?? WorkspaceKind.Host)
6066
{
6167
Contract.ThrowIfTrue(exportProvider != null && composition != null);
6268

69+
SetCurrentSolution(CreateSolution(SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Create()).WithTelemetryId(solutionTelemetryId)));
70+
6371
this.TestHookPartialSolutionsDisabled = disablePartialSolutions;
6472
this.ExportProvider = exportProvider ?? GetComposition(composition).ExportProviderFactory.CreateExportProvider();
6573
_workspaceKind = workspaceKind ?? WorkspaceKind.Host;

src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ internal sealed class DebuggingSession : IDisposable
8383
/// </summary>
8484
internal readonly bool ReportDiagnostics;
8585

86-
private readonly DebuggingSessionTelemetry _telemetry = new();
86+
private readonly DebuggingSessionTelemetry _telemetry;
8787
private readonly EditSessionTelemetry _editSessionTelemetry = new();
8888

8989
private PendingSolutionUpdate? _pendingUpdate;
@@ -105,6 +105,7 @@ internal DebuggingSession(
105105
{
106106
_compilationOutputsProvider = compilationOutputsProvider;
107107
_reportTelemetry = ReportTelemetry;
108+
_telemetry = new DebuggingSessionTelemetry(solution.State.SolutionAttributes.TelemetryId);
108109

109110
Id = id;
110111
DebuggerService = debuggerService;
@@ -582,6 +583,8 @@ from region in moduleRegions.Regions
582583

583584
LastCommittedSolution.CommitSolution(pendingUpdate.Solution);
584585

586+
_editSessionTelemetry.LogCommitted();
587+
585588
// Restart edit session with no active statements (switching to run mode).
586589
RestartEditSession(newNonRemappableRegions, inBreakState: false, out documentsToReanalyze);
587590
}

src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Collections.Generic;
77
using System.Collections.Immutable;
8+
using System.Linq;
89
using Microsoft.CodeAnalysis.Internal.Log;
910

1011
namespace Microsoft.CodeAnalysis.EditAndContinue
@@ -13,12 +14,14 @@ internal sealed class DebuggingSessionTelemetry
1314
{
1415
internal readonly struct Data
1516
{
17+
public readonly Guid SolutionSessionId;
1618
public readonly ImmutableArray<EditSessionTelemetry.Data> EditSessionData;
1719
public readonly int EmptyEditSessionCount;
1820
public readonly int EmptyHotReloadEditSessionCount;
1921

2022
public Data(DebuggingSessionTelemetry telemetry)
2123
{
24+
SolutionSessionId = telemetry._solutionSessionId;
2225
EditSessionData = telemetry._editSessionData.ToImmutableArray();
2326
EmptyEditSessionCount = telemetry._emptyEditSessionCount;
2427
EmptyHotReloadEditSessionCount = telemetry._emptyHotReloadEditSessionCount;
@@ -27,10 +30,16 @@ public Data(DebuggingSessionTelemetry telemetry)
2730

2831
private readonly object _guard = new();
2932

33+
private readonly Guid _solutionSessionId;
3034
private readonly List<EditSessionTelemetry.Data> _editSessionData = new();
3135
private int _emptyEditSessionCount;
3236
private int _emptyHotReloadEditSessionCount;
3337

38+
public DebuggingSessionTelemetry(Guid solutionSessionId)
39+
{
40+
_solutionSessionId = solutionSessionId;
41+
}
42+
3443
public Data GetDataAndClear()
3544
{
3645
lock (_guard)
@@ -82,6 +91,7 @@ public static void Log(Data data, Action<FunctionId, LogMessage> log, Func<int>
8291

8392
log(FunctionId.Debugging_EncSession, KeyValueLogMessage.Create(map =>
8493
{
94+
map["SolutionSessionId"] = data.SolutionSessionId.ToString("B").ToUpperInvariant();
8595
map[SessionId] = debugSessionId;
8696
map["SessionCount"] = data.EditSessionData.Count(session => session.InBreakState);
8797
map["EmptySessionCount"] = data.EmptyEditSessionCount;
@@ -100,13 +110,24 @@ public static void Log(Data data, Action<FunctionId, LogMessage> log, Func<int>
100110

101111
map["HadCompilationErrors"] = editSessionData.HadCompilationErrors;
102112
map["HadRudeEdits"] = editSessionData.HadRudeEdits;
113+
114+
// Changes made to source code during the edit session were valid - they were significant and no rude edits were reported.
115+
// The changes still might fail to emit (see EmitDeltaErrorIdCount).
103116
map["HadValidChanges"] = editSessionData.HadValidChanges;
104117
map["HadValidInsignificantChanges"] = editSessionData.HadValidInsignificantChanges;
105118

106119
map["RudeEditsCount"] = editSessionData.RudeEdits.Length;
120+
121+
// Number of emit errors.
107122
map["EmitDeltaErrorIdCount"] = editSessionData.EmitErrorIds.Length;
123+
124+
// False for Hot Reload session, true or missing for EnC session (missing in older data that did not have this property).
108125
map["InBreakState"] = editSessionData.InBreakState;
126+
109127
map["Capabilities"] = (int)editSessionData.Capabilities;
128+
129+
// Ids of all projects whose binaries were successfully updated during the session.
130+
map["ProjectsWithAppliedChanges"] = editSessionData.Committed ? string.Join(",", editSessionData.ProjectsWithValidDelta.Select(id => id.ToString("B").ToUpperInvariant())) : "";
110131
}));
111132

112133
foreach (var errorId in editSessionData.EmitErrorIds)

src/Features/Core/Portable/EditAndContinue/EditSession.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ public async ValueTask<SolutionUpdate> EmitSolutionUpdateAsync(Solution solution
742742
// Bail before analyzing documents as the analysis needs to read the PDB which will likely fail if we can't even read the MVID.
743743
diagnostics.Add((newProject.Id, ImmutableArray.Create(mvidReadError)));
744744

745-
Telemetry.LogProjectAnalysisSummary(ProjectAnalysisSummary.ValidChanges, ImmutableArray.Create(mvidReadError.Descriptor.Id), InBreakState);
745+
Telemetry.LogProjectAnalysisSummary(ProjectAnalysisSummary.ValidChanges, newProject.State.ProjectInfo.Attributes.TelemetryId, ImmutableArray.Create(mvidReadError.Descriptor.Id), InBreakState);
746746
isBlocked = true;
747747
continue;
748748
}
@@ -813,7 +813,7 @@ public async ValueTask<SolutionUpdate> EmitSolutionUpdateAsync(Solution solution
813813

814814
if (isModuleEncBlocked || projectSummary != ProjectAnalysisSummary.ValidChanges)
815815
{
816-
Telemetry.LogProjectAnalysisSummary(projectSummary, moduleDiagnostics.NullToEmpty().SelectAsArray(d => d.Descriptor.Id), InBreakState);
816+
Telemetry.LogProjectAnalysisSummary(projectSummary, newProject.State.ProjectInfo.Attributes.TelemetryId, moduleDiagnostics.NullToEmpty().SelectAsArray(d => d.Descriptor.Id), InBreakState);
817817
continue;
818818
}
819819

@@ -824,7 +824,7 @@ public async ValueTask<SolutionUpdate> EmitSolutionUpdateAsync(Solution solution
824824
// Report diagnosics even when the module is never going to be loaded (e.g. in multi-targeting scenario, where only one framework being debugged).
825825
// This is consistent with reporting compilation errors - the IDE reports them for all TFMs regardless of what framework the app is running on.
826826
diagnostics.Add((newProject.Id, createBaselineDiagnostics));
827-
Telemetry.LogProjectAnalysisSummary(projectSummary, createBaselineDiagnostics, InBreakState);
827+
Telemetry.LogProjectAnalysisSummary(projectSummary, newProject.State.ProjectInfo.Attributes.TelemetryId, createBaselineDiagnostics, InBreakState);
828828
isBlocked = true;
829829
continue;
830830
}
@@ -927,7 +927,7 @@ public async ValueTask<SolutionUpdate> EmitSolutionUpdateAsync(Solution solution
927927
diagnostics.Add((newProject.Id, emitResult.Diagnostics));
928928
}
929929

930-
Telemetry.LogProjectAnalysisSummary(projectSummary, emitResult.Diagnostics, InBreakState);
930+
Telemetry.LogProjectAnalysisSummary(projectSummary, newProject.State.ProjectInfo.Attributes.TelemetryId, emitResult.Diagnostics, InBreakState);
931931
}
932932

933933
// log capabilities for edit sessions with changes or reported errors:

src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System;
56
using System.Collections.Generic;
67
using System.Collections.Immutable;
78
using System.Diagnostics;
@@ -16,38 +17,44 @@ internal readonly struct Data
1617
{
1718
public readonly ImmutableArray<(ushort EditKind, ushort SyntaxKind)> RudeEdits;
1819
public readonly ImmutableArray<string> EmitErrorIds;
20+
public readonly ImmutableArray<Guid> ProjectsWithValidDelta;
1921
public readonly EditAndContinueCapabilities Capabilities;
2022
public readonly bool HadCompilationErrors;
2123
public readonly bool HadRudeEdits;
2224
public readonly bool HadValidChanges;
2325
public readonly bool HadValidInsignificantChanges;
2426
public readonly bool InBreakState;
2527
public readonly bool IsEmpty;
28+
public readonly bool Committed;
2629

2730
public Data(EditSessionTelemetry telemetry)
2831
{
2932
RudeEdits = telemetry._rudeEdits.AsImmutable();
3033
EmitErrorIds = telemetry._emitErrorIds.AsImmutable();
34+
ProjectsWithValidDelta = telemetry._projectsWithValidDelta.AsImmutable();
3135
HadCompilationErrors = telemetry._hadCompilationErrors;
3236
HadRudeEdits = telemetry._hadRudeEdits;
3337
HadValidChanges = telemetry._hadValidChanges;
3438
HadValidInsignificantChanges = telemetry._hadValidInsignificantChanges;
3539
InBreakState = telemetry._inBreakState;
3640
Capabilities = telemetry._capabilities;
3741
IsEmpty = telemetry.IsEmpty;
42+
Committed = telemetry._committed;
3843
}
3944
}
4045

4146
private readonly object _guard = new();
4247

4348
private readonly HashSet<(ushort, ushort)> _rudeEdits = new();
4449
private readonly HashSet<string> _emitErrorIds = new();
50+
private readonly HashSet<Guid> _projectsWithValidDelta = new();
4551

4652
private bool _hadCompilationErrors;
4753
private bool _hadRudeEdits;
4854
private bool _hadValidChanges;
4955
private bool _hadValidInsignificantChanges;
5056
private bool _inBreakState;
57+
private bool _committed;
5158

5259
private EditAndContinueCapabilities _capabilities;
5360

@@ -58,19 +65,21 @@ public Data GetDataAndClear()
5865
var data = new Data(this);
5966
_rudeEdits.Clear();
6067
_emitErrorIds.Clear();
68+
_projectsWithValidDelta.Clear();
6169
_hadCompilationErrors = false;
6270
_hadRudeEdits = false;
6371
_hadValidChanges = false;
6472
_hadValidInsignificantChanges = false;
6573
_inBreakState = false;
6674
_capabilities = EditAndContinueCapabilities.None;
75+
_committed = false;
6776
return data;
6877
}
6978
}
7079

7180
public bool IsEmpty => !(_hadCompilationErrors || _hadRudeEdits || _hadValidChanges || _hadValidInsignificantChanges);
7281

73-
public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, ImmutableArray<string> errorsIds, bool inBreakState)
82+
public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, Guid projectTelemetryId, ImmutableArray<string> errorsIds, bool inBreakState)
7483
{
7584
lock (_guard)
7685
{
@@ -92,6 +101,12 @@ public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, ImmutableA
92101

93102
case ProjectAnalysisSummary.ValidChanges:
94103
_hadValidChanges = true;
104+
105+
if (errorsIds.IsEmpty)
106+
{
107+
_projectsWithValidDelta.Add(projectTelemetryId);
108+
}
109+
95110
break;
96111

97112
case ProjectAnalysisSummary.ValidInsignificantChanges:
@@ -104,8 +119,8 @@ public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, ImmutableA
104119
}
105120
}
106121

107-
public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, ImmutableArray<Diagnostic> emitDiagnostics, bool inBreakState)
108-
=> LogProjectAnalysisSummary(summary, emitDiagnostics.SelectAsArray(d => d.Severity == DiagnosticSeverity.Error, d => d.Id), inBreakState);
122+
public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, Guid projectTelemetryId, ImmutableArray<Diagnostic> emitDiagnostics, bool inBreakState)
123+
=> LogProjectAnalysisSummary(summary, projectTelemetryId, emitDiagnostics.SelectAsArray(d => d.Severity == DiagnosticSeverity.Error, d => d.Id), inBreakState);
109124

110125
public void LogRudeEditDiagnostics(ImmutableArray<RudeEditDiagnostic> diagnostics)
111126
{
@@ -126,5 +141,8 @@ public void LogRuntimeCapabilities(EditAndContinueCapabilities capabilities)
126141
_capabilities = capabilities;
127142
}
128143
}
144+
145+
internal void LogCommitted()
146+
=> _committed = true;
129147
}
130148
}

0 commit comments

Comments
 (0)