Skip to content

Commit 5500362

Browse files
committed
WIP: tool install
1 parent e026384 commit 5500362

File tree

7 files changed

+89
-21
lines changed

7 files changed

+89
-21
lines changed

Directory.Packages.props

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
<!-- Using multiple feeds isn't supported by Maestro: https://github.com/dotnet/arcade/issues/14155. -->
55
<NoWarn>$(NoWarn);NU1507</NoWarn>
66
</PropertyGroup>
7-
87
<ItemGroup>
98
<PackageVersion Include="Basic.CompilerLog.Util" Version="0.9.9" />
109
<PackageVersion Include="AwesomeAssertions" Version="$(AwesomeAssertionsVersion)" />
@@ -95,6 +94,9 @@
9594
<PackageVersion Include="NuGet.ProjectModel" Version="$(NuGetProjectModelPackageVersion)" />
9695
<PackageVersion Include="NuGet.Protocol" Version="$(NuGetBuildTasksPackageVersion)" />
9796
<PackageVersion Include="NuGet.Versioning" Version="$(NuGetVersioningPackageVersion)" />
97+
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
98+
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
99+
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />
98100
<PackageVersion Include="runtime.linux-musl-x64.Microsoft.NETCore.DotNetHostResolver" Version="$(MicrosoftNETCoreDotNetHostResolverPackageVersion)" />
99101
<PackageVersion Include="runtime.linux-x64.Microsoft.NETCore.DotNetHostResolver" Version="$(MicrosoftNETCoreDotNetHostResolverPackageVersion)" />
100102
<PackageVersion Include="runtime.osx-x64.Microsoft.NETCore.DotNetHostResolver" Version="$(MicrosoftNETCoreDotNetHostResolverPackageVersion)" />
@@ -126,7 +128,6 @@
126128
<PackageVersion Include="Xunit.Combinatorial" Version="$(XunitCombinatorialVersion)" />
127129
<PackageVersion Include="xunit.console" Version="$(XUnitVersion)" />
128130
</ItemGroup>
129-
130131
<!-- Use different versions of Microsoft.Build.* depending on whether the output will be used in
131132
.NET Framework (VS) or only in the .NET SDK.
132133
@@ -158,4 +159,4 @@
158159
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="$(MicrosoftBuildMinimumVersion)" />
159160
<PackageVersion Include="Microsoft.NET.StringTools" Version="$(MicrosoftBuildMinimumVersion)" />
160161
</ItemGroup>
161-
</Project>
162+
</Project>

src/Cli/dotnet/Activities.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Diagnostics;
2+
using Microsoft.DotNet.Cli.Utils;
3+
4+
namespace Microsoft.DotNet.Cli;
5+
6+
7+
public static class Activities
8+
{
9+
public static ActivitySource s_source = new("dotnet-cli", Product.Version);
10+
}

src/Cli/dotnet/Commands/Tool/Install/ToolInstallGlobalOrToolPathCommand.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ public override int Execute()
144144

145145
private int ExecuteInstallCommand(PackageId packageId)
146146
{
147+
using var _activity = Activities.s_source.StartActivity("install-tool");
148+
_activity?.DisplayName = $"Install {packageId}";
149+
_activity?.SetTag("toolId", packageId);
147150
ValidateArguments();
148151

149152
DirectoryPath? toolPath = null;
@@ -167,12 +170,14 @@ private int ExecuteInstallCommand(PackageId packageId)
167170
if (oldPackageNullable != null)
168171
{
169172
NuGetVersion nugetVersion = GetBestMatchNugetVersion(packageId, versionRange, toolPackageDownloader);
173+
_activity?.DisplayName = $"Install {packageId}@{nugetVersion}";
174+
_activity?.SetTag("toolVersion", nugetVersion);
170175

171176
if (ToolVersionAlreadyInstalled(oldPackageNullable, nugetVersion))
172177
{
173178
_reporter.WriteLine(string.Format(CliCommandStrings.ToolAlreadyInstalled, oldPackageNullable.Id, oldPackageNullable.Version.ToNormalizedString()).Green());
174179
return 0;
175-
}
180+
}
176181
}
177182

178183
TransactionalAction.Run(() =>
@@ -188,6 +193,7 @@ private int ExecuteInstallCommand(PackageId packageId)
188193

189194
RunWithHandlingInstallError(() =>
190195
{
196+
var toolPackageDownloaderActivity = Activities.s_source.StartActivity("download-tool-package");
191197
IToolPackage newInstalledPackage = toolPackageDownloader.InstallPackage(
192198
new PackageLocation(nugetConfig: GetConfigFile(), sourceFeedOverrides: _source, additionalFeeds: _addSource),
193199
packageId: packageId,
@@ -199,6 +205,7 @@ private int ExecuteInstallCommand(PackageId packageId)
199205
verifySignatures: _verifySignatures ?? true,
200206
restoreActionConfig: restoreActionConfig
201207
);
208+
toolPackageDownloaderActivity?.Dispose();
202209

203210
EnsureVersionIsHigher(oldPackageNullable, newInstalledPackage, _allowPackageDowngrade);
204211

@@ -215,9 +222,10 @@ private int ExecuteInstallCommand(PackageId packageId)
215222
null :
216223
NuGetFramework.Parse(_framework);
217224
}
225+
var shimActivity = Activities.s_source.StartActivity("create-shell-shim");
218226
string appHostSourceDirectory = _shellShimTemplateFinder.ResolveAppHostSourceDirectoryAsync(_architectureOption, framework, RuntimeInformation.ProcessArchitecture).Result;
219-
220227
shellShimRepository.CreateShim(newInstalledPackage.Command, newInstalledPackage.PackagedShims);
228+
shimActivity?.Dispose();
221229

222230
foreach (string w in newInstalledPackage.Warnings)
223231
{
@@ -303,7 +311,7 @@ private static void RunWithHandlingUninstallError(Action uninstallAction, Packag
303311
{
304312
try
305313
{
306-
uninstallAction();
314+
uninstallAction();
307315
}
308316
catch (Exception ex)
309317
when (ToolUninstallCommandLowLevelErrorConverter.ShouldConvertToUserFacingError(ex))
@@ -381,7 +389,7 @@ private void PrintSuccessMessage(IToolPackage oldPackage, IToolPackage newInstal
381389
{
382390
_reporter.WriteLine(
383391
string.Format(
384-
392+
385393
newInstalledPackage.Version.IsPrerelease ?
386394
CliCommandStrings.UpdateSucceededPreVersionNoChange : CliCommandStrings.UpdateSucceededStableVersionNoChange,
387395
newInstalledPackage.Id, newInstalledPackage.Version).Green());

src/Cli/dotnet/Program.cs

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,45 @@
1616
using Microsoft.DotNet.Configurer;
1717
using Microsoft.Extensions.EnvironmentAbstractions;
1818
using NuGet.Frameworks;
19+
using OpenTelemetry;
20+
using OpenTelemetry.Metrics;
21+
using OpenTelemetry.Resources;
22+
using OpenTelemetry.Trace;
1923
using CommandResult = System.CommandLine.Parsing.CommandResult;
2024

2125
namespace Microsoft.DotNet.Cli;
2226

23-
public static class Activities
24-
{
25-
public static ActivitySource s_source = new("dotnet-cli", Product.Version);
26-
}
27-
2827
public class Program
2928
{
3029
private static readonly string ToolPathSentinelFileName = $"{Product.Version}.toolpath.sentinel";
3130

3231
public static ITelemetry TelemetryClient;
32+
// Create a new OpenTelemetry tracer provider and add the Azure Monitor trace exporter and the OTLP trace exporter.
33+
// It is important to keep the TracerProvider instance active throughout the process lifetime.
34+
private static TracerProvider tracerProvider = Sdk.CreateTracerProviderBuilder()
35+
.ConfigureResource(r =>
36+
{
37+
r.AddService("dotnet-cli", serviceVersion: Product.Version);
38+
})
39+
.AddSource(Activities.s_source.Name)
40+
.AddHttpClientInstrumentation()
41+
.AddOtlpExporter()
42+
.Build();
43+
44+
// Create a new OpenTelemetry meter provider and add the Azure Monitor metric exporter and the OTLP metric exporter.
45+
// It is important to keep the MetricsProvider instance active throughout the process lifetime.
46+
private static MeterProvider metricsProvider = Sdk.CreateMeterProviderBuilder()
47+
.ConfigureResource(r =>
48+
{
49+
r.AddService("dotnet-cli", serviceVersion: Product.Version);
50+
})
51+
.AddMeter(Activities.s_source.Name)
52+
.AddHttpClientInstrumentation()
53+
.AddRuntimeInstrumentation()
54+
.AddOtlpExporter()
55+
.Build();
56+
57+
3358
public static int Main(string[] args)
3459
{
3560
// capture the time to we can compute muxer/host startup overhead
@@ -86,17 +111,19 @@ public static int Main(string[] args)
86111
}
87112
finally
88113
{
114+
tracerProvider?.ForceFlush();
115+
metricsProvider?.ForceFlush();
89116
Activities.s_source.Dispose();
90117
}
91118
}
92119

93120
private static void TrackHostStartup(DateTime mainTimeStamp)
94121
{
95122
var hostStartupActivity = Activities.s_source.CreateActivity("host-startup", ActivityKind.Server);
96-
hostStartupActivity.SetStartTime(Process.GetCurrentProcess().StartTime);
97-
hostStartupActivity.SetEndTime(mainTimeStamp);
98-
hostStartupActivity.SetStatus(ActivityStatusCode.Ok);
99-
hostStartupActivity.Dispose();
123+
hostStartupActivity?.SetStartTime(Process.GetCurrentProcess().StartTime);
124+
hostStartupActivity?.SetEndTime(mainTimeStamp);
125+
hostStartupActivity?.SetStatus(ActivityStatusCode.Ok);
126+
hostStartupActivity?.Dispose();
100127
}
101128

102129
/// <summary>
@@ -182,8 +209,8 @@ internal static int ProcessArgs(string[] args)
182209
skipFirstTimeUseCheck: getStarOptionPassed);
183210
}
184211

185-
var telemetryClient = new Telemetry.Telemetry();
186-
TelemetryEventEntry.Subscribe(telemetryClient.TrackEvent);
212+
TelemetryClient = new Telemetry.Telemetry();
213+
TelemetryEventEntry.Subscribe(TelemetryClient.TrackEvent);
187214
TelemetryEventEntry.TelemetryFilter = new TelemetryFilter(Sha256Hasher.HashWithNormalizedCasing);
188215

189216
if (CommandLoggingContext.IsVerbose)
@@ -195,6 +222,16 @@ internal static int ProcessArgs(string[] args)
195222
if (parseResult.CanBeInvoked())
196223
{
197224
using var _invocationActivity = Activities.s_source.StartActivity("invocation");
225+
// walk the parent command tree to find the top-level command name and get the full command name for this parseresult
226+
List<string> parentNames = [parseResult.CommandResult.Command.Name];
227+
var current = parseResult.CommandResult.Parent;
228+
while (parseResult.CommandResult.Parent is CommandResult parentCommandResult)
229+
{
230+
parentNames.Add(parentCommandResult.Command.Name);
231+
current = parentCommandResult.Parent;
232+
}
233+
parentNames.Reverse();
234+
_invocationActivity?.DisplayName = string.Join(' ', parentNames);
198235
try
199236
{
200237
exitCode = parseResult.Invoke();
@@ -230,7 +267,7 @@ internal static int ProcessArgs(string[] args)
230267
}
231268
}
232269

233-
telemetryClient.Dispose();
270+
TelemetryClient.Dispose();
234271
return exitCode;
235272
}
236273

src/Cli/dotnet/ToolPackage/ToolPackageDownloader.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ protected override INuGetPackageDownloader CreateNuGetPackageDownloader(
4646
{
4747
verboseLogger = new NuGetConsoleLogger();
4848
}
49-
49+
5050
return new NuGetPackageDownloader.NuGetPackageDownloader(
5151
new DirectoryPath(),
5252
verboseLogger: verboseLogger,
@@ -66,14 +66,16 @@ protected override NuGetVersion DownloadAndExtractPackage(
6666
bool includeUnlisted = false
6767
)
6868
{
69+
using var _downloadActivity = Activities.s_source.StartActivity("download-tool");
70+
_downloadActivity?.DisplayName = $"Downloading tool {packageId}@{packageVersion}";
6971
var versionFolderPathResolver = new VersionFolderPathResolver(packagesRootPath);
7072

7173
string folderToDeleteOnFailure = null;
7274
return TransactionalAction.Run<NuGetVersion>(() =>
7375
{
7476
var packagePath = nugetPackageDownloader.DownloadPackageAsync(packageId, packageVersion, packageSourceLocation,
7577
includeUnlisted: includeUnlisted, downloadFolder: new DirectoryPath(packagesRootPath)).ConfigureAwait(false).GetAwaiter().GetResult();
76-
78+
_downloadActivity?.AddEvent(new("Downloaded package"));
7779
folderToDeleteOnFailure = Path.GetDirectoryName(packagePath);
7880

7981
// look for package on disk and read the version
@@ -83,17 +85,21 @@ protected override NuGetVersion DownloadAndExtractPackage(
8385
{
8486
PackageArchiveReader reader = new(packageStream);
8587
version = new NuspecReader(reader.GetNuspec()).GetVersion();
88+
_downloadActivity?.AddEvent(new("Read package version"));
8689

8790
var packageHash = Convert.ToBase64String(new CryptoHashProvider("SHA512").CalculateHash(reader.GetNuspec()));
8891
var hashPath = versionFolderPathResolver.GetHashPath(packageId.ToString(), version);
92+
_downloadActivity?.AddEvent(new("Calculated package hash"));
8993

9094
Directory.CreateDirectory(Path.GetDirectoryName(hashPath));
9195
File.WriteAllText(hashPath, packageHash);
96+
_downloadActivity?.AddEvent(new("Wrote package hash to disk"));
9297
}
9398

9499
// Extract the package
95100
var nupkgDir = versionFolderPathResolver.GetInstallPath(packageId.ToString(), version);
96101
nugetPackageDownloader.ExtractPackageAsync(packagePath, new DirectoryPath(nupkgDir)).ConfigureAwait(false).GetAwaiter().GetResult();
102+
_downloadActivity?.AddEvent(new("Extracted package to disk"));
97103

98104
return version;
99105
}, rollback: () =>

src/Cli/dotnet/ToolPackage/ToolPackageDownloaderBase.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,10 @@ protected IToolPackage InstallGlobalToolPackageInternal(
191191
// Create parent directory in global tool store, for example dotnet\tools\.store\powershell
192192
_fileSystem.Directory.CreateDirectory(toolStoreTargetDirectory.GetParentPath().Value);
193193

194+
var _moveContentActivity = Activities.s_source.StartActivity("move-global-tool-content");
194195
// Move tool files from stage to final location
195196
FileAccessRetrier.RetryOnMoveAccessFailure(() => _fileSystem.Directory.Move(_globalToolStageDir.Value, toolStoreTargetDirectory.Value));
197+
_moveContentActivity?.Dispose();
196198

197199
rollbackDirectory = toolStoreTargetDirectory.Value;
198200

@@ -353,6 +355,7 @@ protected void UpdateRuntimeConfig(
353355
ToolPackageInstance toolPackageInstance
354356
)
355357
{
358+
using var _updateRuntimeConfigActivity = Activities.s_source.StartActivity("update-runtimeconfig");
356359
var runtimeConfigFilePath = Path.ChangeExtension(toolPackageInstance.Command.Executable.Value, ".runtimeconfig.json");
357360

358361
// Update the runtimeconfig.json file

src/Cli/dotnet/dotnet.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@
5858
<PackageReference Include="Microsoft.Build" />
5959
<PackageReference Include="Microsoft.NET.HostModel" />
6060
<PackageReference Include="Microsoft.TemplateEngine.Orchestrator.RunnableProjects" />
61+
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
62+
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
63+
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
6164
<PackageReference Include="System.CommandLine" />
6265
<PackageReference Include="Microsoft.Deployment.DotNet.Releases" />
6366
<PackageReference Include="System.ServiceProcess.ServiceController" />

0 commit comments

Comments
 (0)