Skip to content

Commit d012eef

Browse files
Support creating binlogs for the language server's design time builds
This allows you to configure a directory where we will write binlogs for any design time builds. This is only needed when debugging project system issues, but when you need this, you really need this.
1 parent 47b1d1c commit d012eef

File tree

3 files changed

+51
-3
lines changed

3 files changed

+51
-3
lines changed

src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs

+29-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
using System.Diagnostics;
99
using System.Runtime.CompilerServices;
1010
using Microsoft.Build.Locator;
11+
using Microsoft.Build.Logging;
1112
using Microsoft.CodeAnalysis.Collections;
1213
using Microsoft.CodeAnalysis.Host.Mef;
1314
using Microsoft.CodeAnalysis.MSBuild;
1415
using Microsoft.CodeAnalysis.MSBuild.Build;
16+
using Microsoft.CodeAnalysis.Options;
1517
using Microsoft.CodeAnalysis.ProjectSystem;
1618
using Microsoft.CodeAnalysis.Shared.TestHooks;
1719
using Microsoft.CodeAnalysis.Workspaces.ProjectSystem;
@@ -32,13 +34,23 @@ internal sealed class LanguageServerProjectSystem
3234
/// This is just we don't have code simultaneously trying to load and unload solutions at once.
3335
/// </summary>
3436
private readonly SemaphoreSlim _gate = new SemaphoreSlim(initialCount: 1);
35-
3637
private bool _msbuildLoaded = false;
3738

39+
/// <summary>
40+
/// The suffix to use for the binary log name; incremented each time we have a new build. Should be incremented with <see cref="Interlocked.Increment(ref int)"/>.
41+
/// </summary>
42+
private int _binaryLogNumericSuffix;
43+
44+
/// <summary>
45+
/// A GUID put into all binary log file names, so that way one session doesn't accidentally overwrite the logs from a prior session.
46+
/// </summary>
47+
private readonly Guid _binaryLogGuidSuffix = Guid.NewGuid();
48+
3849
private readonly AsyncBatchingWorkQueue<string> _projectsToLoadAndReload;
3950

4051
private readonly LanguageServerWorkspaceFactory _workspaceFactory;
4152
private readonly IFileChangeWatcher _fileChangeWatcher;
53+
private readonly IGlobalOptionService _globalOptionService;
4254
private readonly ILogger _logger;
4355

4456
/// <summary>
@@ -54,11 +66,13 @@ internal sealed class LanguageServerProjectSystem
5466
public LanguageServerProjectSystem(
5567
LanguageServerWorkspaceFactory workspaceFactory,
5668
IFileChangeWatcher fileChangeWatcher,
69+
IGlobalOptionService globalOptionService,
5770
ILoggerFactory loggerFactory,
5871
IAsynchronousOperationListenerProvider listenerProvider)
5972
{
6073
_workspaceFactory = workspaceFactory;
6174
_fileChangeWatcher = fileChangeWatcher;
75+
_globalOptionService = globalOptionService;
6276
_logger = loggerFactory.CreateLogger(nameof(LanguageServerProjectSystem));
6377

6478
// TODO: remove the DiagnosticReporter that's coupled to the Workspace here
@@ -164,7 +178,7 @@ private async ValueTask LoadOrReloadProjectsAsync(ImmutableSegmentedList<string>
164178
var stopwatch = Stopwatch.StartNew();
165179

166180
// TODO: support configuration switching
167-
var projectBuildManager = new ProjectBuildManager(additionalGlobalProperties: ImmutableDictionary<string, string>.Empty);
181+
var projectBuildManager = new ProjectBuildManager(additionalGlobalProperties: ImmutableDictionary<string, string>.Empty, msbuildLogger: CreateMSBuildLogger());
168182

169183
projectBuildManager.StartBatchBuild();
170184

@@ -202,6 +216,19 @@ private async ValueTask LoadOrReloadProjectsAsync(ImmutableSegmentedList<string>
202216
}
203217
}
204218

219+
private Build.Framework.ILogger? CreateMSBuildLogger()
220+
{
221+
if (_globalOptionService.GetOption(LanguageServerProjectSystemOptionsStorage.BinaryLogPath) is not string binaryLogDirectory)
222+
return null;
223+
224+
var numericSuffix = Interlocked.Increment(ref _binaryLogNumericSuffix);
225+
var binaryLogPath = Path.Combine(binaryLogDirectory, $"LanguageServerDesignTimeBuild-{_binaryLogGuidSuffix}-{numericSuffix}.binlog");
226+
227+
_logger.LogInformation($"Logging design-time builds to {binaryLogPath}");
228+
229+
return new BinaryLogger { Parameters = binaryLogPath, Verbosity = Build.Framework.LoggerVerbosity.Diagnostic };
230+
}
231+
205232
private async Task<LSP.MessageType?> LoadOrReloadProjectAsync(string projectPath, ProjectBuildManager projectBuildManager, CancellationToken cancellationToken)
206233
{
207234
try
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.CodeAnalysis.Options;
6+
7+
namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace
8+
{
9+
internal static class LanguageServerProjectSystemOptionsStorage
10+
{
11+
private static readonly OptionGroup s_optionGroup = new(name: "project_loading", description: "");
12+
13+
/// <summary>
14+
/// A folder to log binlogs to when running design-time builds.
15+
/// </summary>
16+
public static readonly Option2<string?> BinaryLogPath = new Option2<string?>("dotnet_binary_log_path", defaultValue: null, s_optionGroup);
17+
}
18+
}

src/Features/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OptionList.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.CodeAnalysis.Formatting;
99
using Microsoft.CodeAnalysis.ImplementType;
1010
using Microsoft.CodeAnalysis.InlineHints;
11+
using Microsoft.CodeAnalysis.LanguageServer.HostWorkspace;
1112
using Microsoft.CodeAnalysis.MetadataAsSource;
1213
using Microsoft.CodeAnalysis.Options;
1314
using Microsoft.CodeAnalysis.QuickInfo;
@@ -58,6 +59,8 @@ internal partial class DidChangeConfigurationNotificationHandler
5859
SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption,
5960
// Code lens options
6061
LspOptionsStorage.LspEnableReferencesCodeLens,
61-
LspOptionsStorage.LspEnableTestsCodeLens);
62+
LspOptionsStorage.LspEnableTestsCodeLens,
63+
// Project system
64+
LanguageServerProjectSystemOptionsStorage.BinaryLogPath);
6265
}
6366
}

0 commit comments

Comments
 (0)