Skip to content

Commit 6181785

Browse files
authored
Port EnC telemetry improvements to 17.6 (#67752)
* Use exception with specific type and HResult to aid tracking in telemetry * Associate rude edits with project id
1 parent a6aeb31 commit 6181785

File tree

7 files changed

+56
-34
lines changed

7 files changed

+56
-34
lines changed

src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ namespace Microsoft.CodeAnalysis.EditAndContinue
2525
[ExportMetadata("UIContext", EditAndContinueUIContext.EncCapableProjectExistsInWorkspaceUIContextString)]
2626
internal sealed class EditAndContinueLanguageService : IManagedHotReloadLanguageService, IEditAndContinueSolutionProvider
2727
{
28+
private sealed class NoSessionException : InvalidOperationException
29+
{
30+
public NoSessionException()
31+
: base("Internal error: no session.")
32+
{
33+
// unique enough HResult to distinguish from other exceptions
34+
HResult = unchecked((int)0x801315087);
35+
}
36+
}
37+
2838
private readonly PdbMatchingSourceTextProvider _sourceTextProvider;
2939
private readonly Lazy<IManagedHotReloadService> _debuggerService;
3040
private readonly IDiagnosticAnalyzerService _diagnosticService;
@@ -85,11 +95,7 @@ private Solution GetCurrentCompileTimeSolution(Solution? currentDesignTimeSoluti
8595
}
8696

8797
private RemoteDebuggingSessionProxy GetDebuggingSession()
88-
{
89-
var debuggingSession = _debuggingSession;
90-
Contract.ThrowIfNull(debuggingSession);
91-
return debuggingSession;
92-
}
98+
=> _debuggingSession ?? throw new NoSessionException();
9399

94100
private IActiveStatementTrackingService GetActiveStatementTrackingService()
95101
=> WorkspaceProvider.Value.Workspace.Services.GetRequiredService<IActiveStatementTrackingService>();

src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -112,19 +112,30 @@ private static (Solution, Document) AddDefaultTestProject(
112112
return (solution, solution.Projects.Single().Documents.Single());
113113
}
114114

115+
private static Project AddEmptyTestProject(Solution solution)
116+
{
117+
var projectId = ProjectId.CreateNewId();
118+
119+
return solution.
120+
AddProject(ProjectInfo.Create(
121+
projectId,
122+
VersionStamp.Create(),
123+
"proj",
124+
"proj",
125+
LanguageNames.CSharp,
126+
parseOptions: CSharpParseOptions.Default.WithNoRefSafetyRulesAttribute())
127+
.WithTelemetryId(s_defaultProjectTelemetryId)).GetProject(projectId).
128+
WithMetadataReferences(TargetFrameworkUtil.GetReferences(DefaultTargetFramework));
129+
}
130+
115131
private static Solution AddDefaultTestProject(
116132
Solution solution,
117133
string[] sources,
118134
ISourceGenerator generator = null,
119135
string additionalFileText = null,
120136
(string key, string value)[] analyzerConfig = null)
121137
{
122-
var projectId = ProjectId.CreateNewId();
123-
124-
var project = solution.
125-
AddProject(ProjectInfo.Create(projectId, VersionStamp.Create(), "proj", "proj", LanguageNames.CSharp, parseOptions: CSharpParseOptions.Default.WithNoRefSafetyRulesAttribute()).WithTelemetryId(s_defaultProjectTelemetryId)).GetProject(projectId).
126-
WithMetadataReferences(TargetFrameworkUtil.GetReferences(DefaultTargetFramework));
127-
138+
var project = AddEmptyTestProject(solution);
128139
solution = project.Solution;
129140

130141
if (generator != null)
@@ -1428,7 +1439,7 @@ public async Task RudeEdits(bool breakMode)
14281439
{
14291440
"Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2",
14301441
"Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=",
1431-
"Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True"
1442+
"Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}"
14321443
}, _telemetryLog);
14331444
}
14341445
else
@@ -1437,7 +1448,7 @@ public async Task RudeEdits(bool breakMode)
14371448
{
14381449
"Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0",
14391450
"Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=",
1440-
"Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True"
1451+
"Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}"
14411452
}, _telemetryLog);
14421453
}
14431454
}
@@ -1563,10 +1574,7 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode)
15631574

15641575
using var _ = CreateWorkspace(out var solution, out var service);
15651576

1566-
var project = solution.
1567-
AddProject("test", "test", LanguageNames.CSharp).
1568-
AddMetadataReferences(TargetFrameworkUtil.GetReferences(TargetFramework.Mscorlib40));
1569-
1577+
var project = AddEmptyTestProject(solution);
15701578
solution = project.Solution;
15711579

15721580
// compile with source0:
@@ -1645,8 +1653,8 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode)
16451653
{
16461654
"Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2",
16471655
"Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=2|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=",
1648-
"Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True",
1649-
"Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True"
1656+
"Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}",
1657+
"Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}"
16501658
}, _telemetryLog);
16511659
}
16521660
else
@@ -1655,8 +1663,8 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode)
16551663
{
16561664
"Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0",
16571665
"Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=2|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=",
1658-
"Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True",
1659-
"Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True"
1666+
"Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}",
1667+
"Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}"
16601668
}, _telemetryLog);
16611669
}
16621670
}

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2427,16 +2427,16 @@ private async Task<ImmutableArray<SemanticEditInfo>> AnalyzeSemanticsAsync(
24272427
PooledDictionary<INamedTypeSymbol, ConstructorEdit>? instanceConstructorEdits = null;
24282428
PooledDictionary<INamedTypeSymbol, ConstructorEdit>? staticConstructorEdits = null;
24292429

2430-
var oldModel = (oldDocument != null) ? await oldDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false) : null;
2431-
var newModel = await newDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
2432-
var oldCompilation = oldModel?.Compilation ?? await oldProject.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
2433-
var newCompilation = newModel.Compilation;
2434-
24352430
using var _1 = PooledHashSet<ISymbol>.GetInstance(out var processedSymbols);
24362431
using var _2 = ArrayBuilder<SemanticEditInfo>.GetInstance(out var semanticEdits);
24372432

24382433
try
24392434
{
2435+
var oldModel = (oldDocument != null) ? await oldDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false) : null;
2436+
var newModel = await newDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
2437+
var oldCompilation = oldModel?.Compilation ?? await oldProject.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
2438+
var newCompilation = newModel.Compilation;
2439+
24402440
INamedTypeSymbol? lazyLayoutAttribute = null;
24412441

24422442
foreach (var edit in editScript.Edits)
@@ -3324,6 +3324,10 @@ private async Task<ImmutableArray<SemanticEditInfo>> AnalyzeSemanticsAsync(
33243324
cancellationToken);
33253325
}
33263326
}
3327+
catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken))
3328+
{
3329+
throw ExceptionUtilities.Unreachable();
3330+
}
33273331
finally
33283332
{
33293333
instanceConstructorEdits?.Free();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ CommittedSolution.DocumentState.Indeterminate or
506506
return ImmutableArray<Diagnostic>.Empty;
507507
}
508508

509-
EditSession.Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors);
509+
EditSession.Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors, project.State.Attributes.TelemetryId);
510510

511511
// track the document, so that we can refresh or clean diagnostics at the end of edit session:
512512
EditSession.TrackDocumentWithReportedDiagnostics(document.Id);

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public static void Log(Data data, Action<FunctionId, LogMessage> log, Func<int>
127127
map["Capabilities"] = (int)editSessionData.Capabilities;
128128

129129
// Ids of all projects whose binaries were successfully updated during the session.
130-
map["ProjectIdsWithAppliedChanges"] = editSessionData.Committed ? editSessionData.ProjectsWithValidDelta.Select(id => new PiiValue(id.ToString("B").ToUpperInvariant())) : "";
130+
map["ProjectIdsWithAppliedChanges"] = editSessionData.Committed ? editSessionData.ProjectsWithValidDelta.Select(ProjectIdToPii) : "";
131131
}));
132132

133133
foreach (var errorId in editSessionData.EmitErrorIds)
@@ -140,7 +140,7 @@ public static void Log(Data data, Action<FunctionId, LogMessage> log, Func<int>
140140
}));
141141
}
142142

143-
foreach (var (editKind, syntaxKind) in editSessionData.RudeEdits)
143+
foreach (var (editKind, syntaxKind, projectId) in editSessionData.RudeEdits)
144144
{
145145
log(FunctionId.Debugging_EncSession_EditSession_RudeEdit, KeyValueLogMessage.Create(map =>
146146
{
@@ -150,8 +150,12 @@ public static void Log(Data data, Action<FunctionId, LogMessage> log, Func<int>
150150
map["RudeEditKind"] = editKind;
151151
map["RudeEditSyntaxKind"] = syntaxKind;
152152
map["RudeEditBlocking"] = editSessionData.HadRudeEdits;
153+
map["RudeEditProjectId"] = ProjectIdToPii(projectId);
153154
}));
154155
}
156+
157+
static PiiValue ProjectIdToPii(Guid projectId)
158+
=> new(projectId.ToString("B").ToUpperInvariant());
155159
}
156160
}
157161
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ public async ValueTask<SolutionUpdate> EmitSolutionUpdateAsync(Solution solution
925925
if (analysis.RudeEditErrors.Length > 0)
926926
{
927927
documentsWithRudeEdits.Add((analysis.DocumentId, analysis.RudeEditErrors));
928-
Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors);
928+
Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors, newProject.State.Attributes.TelemetryId);
929929
}
930930
}
931931

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ internal sealed class EditSessionTelemetry
1515
{
1616
internal readonly struct Data
1717
{
18-
public readonly ImmutableArray<(ushort EditKind, ushort SyntaxKind)> RudeEdits;
18+
public readonly ImmutableArray<(ushort EditKind, ushort SyntaxKind, Guid projectId)> RudeEdits;
1919
public readonly ImmutableArray<string> EmitErrorIds;
2020
public readonly ImmutableArray<Guid> ProjectsWithValidDelta;
2121
public readonly EditAndContinueCapabilities Capabilities;
@@ -50,7 +50,7 @@ public Data(EditSessionTelemetry telemetry)
5050
// Limit the number of reported items to limit the size of the telemetry event (max total size is 64K).
5151
private const int MaxReportedProjectIds = 20;
5252

53-
private readonly HashSet<(ushort, ushort)> _rudeEdits = new();
53+
private readonly HashSet<(ushort, ushort, Guid)> _rudeEdits = new();
5454
private readonly HashSet<string> _emitErrorIds = new();
5555
private readonly HashSet<Guid> _projectsWithValidDelta = new();
5656

@@ -129,13 +129,13 @@ public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, Guid proje
129129
public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, Guid projectTelemetryId, ImmutableArray<Diagnostic> emitDiagnostics)
130130
=> LogProjectAnalysisSummary(summary, projectTelemetryId, emitDiagnostics.SelectAsArray(d => d.Severity == DiagnosticSeverity.Error, d => d.Id));
131131

132-
public void LogRudeEditDiagnostics(ImmutableArray<RudeEditDiagnostic> diagnostics)
132+
public void LogRudeEditDiagnostics(ImmutableArray<RudeEditDiagnostic> diagnostics, Guid projectTelemetryId)
133133
{
134134
lock (_guard)
135135
{
136136
foreach (var diagnostic in diagnostics)
137137
{
138-
_rudeEdits.Add(((ushort)diagnostic.Kind, diagnostic.SyntaxKind));
138+
_rudeEdits.Add(((ushort)diagnostic.Kind, diagnostic.SyntaxKind, projectTelemetryId));
139139
}
140140
}
141141
}

0 commit comments

Comments
 (0)