Skip to content

Commit 6dcc0a9

Browse files
Telemetry metrics for symbol push. (#6372)
* Add gallery telemetry metrics for the symbol push.
1 parent c0e6e72 commit 6dcc0a9

5 files changed

Lines changed: 134 additions & 4 deletions

File tree

src/NuGetGallery/Controllers/ApiController.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,9 @@ public virtual Task<ActionResult> CreatePackagePost()
395395
[ActionName("PushSymbolPackageApi")]
396396
public virtual async Task<ActionResult> CreateSymbolPackagePutAsync()
397397
{
398+
string id = null;
399+
string normalizedVersion = null;
400+
398401
try
399402
{
400403
// Get the user
@@ -422,8 +425,9 @@ public virtual async Task<ActionResult> CreateSymbolPackagePutAsync()
422425
using (var packageToPush = new PackageArchiveReader(symbolPackageStream, leaveStreamOpen: false))
423426
{
424427
var nuspec = packageToPush.GetNuspecReader();
425-
var id = nuspec.GetId();
428+
id = nuspec.GetId();
426429
var version = nuspec.GetVersion();
430+
normalizedVersion = version.ToNormalizedStringSafe();
427431

428432
// Ensure the corresponding package exists before pushing a snupkg.
429433
var package = PackageService.FindPackageByIdAndVersionStrict(id, version.ToStringSafe());
@@ -433,7 +437,7 @@ public virtual async Task<ActionResult> CreateSymbolPackagePutAsync()
433437
CultureInfo.CurrentCulture,
434438
Strings.SymbolsPackage_PackageIdAndVersionNotFound,
435439
id,
436-
version.ToNormalizedStringSafe()));
440+
normalizedVersion));
437441
}
438442

439443
// Check if this user has the permissions to push the corresponding symbol package
@@ -463,7 +467,7 @@ public virtual async Task<ActionResult> CreateSymbolPackagePutAsync()
463467
{
464468
message = ex.Message;
465469
}
466-
470+
TelemetryService.TrackSymbolPackageFailedGalleryValidationEvent(id, normalizedVersion);
467471
return new HttpStatusCodeWithBodyResult(HttpStatusCode.BadRequest, message);
468472
}
469473

@@ -493,6 +497,8 @@ public virtual async Task<ActionResult> CreateSymbolPackagePutAsync()
493497
throw new NotImplementedException($"The symbol package commit result {commitResult} is not supported.");
494498
}
495499

500+
TelemetryService.TrackSymbolPackagePushEvent(id, normalizedVersion);
501+
496502
return new HttpStatusCodeResult(HttpStatusCode.Created);
497503
}
498504
}
@@ -515,7 +521,7 @@ public virtual async Task<ActionResult> CreateSymbolPackagePutAsync()
515521
catch (Exception ex)
516522
{
517523
ex.Log();
518-
524+
TelemetryService.TrackSymbolPackagePushFailureEvent(id, normalizedVersion);
519525
throw ex;
520526
}
521527
}

src/NuGetGallery/Services/ITelemetryService.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,5 +146,26 @@ public interface ITelemetryService
146146
/// <param name="success">Whether sending the email was successful.</param>
147147
/// <param name="attemptNumber">The number of attempts the message has tried to be sent.</param>
148148
void TrackSendEmail(string smtpUri, DateTimeOffset startTime, TimeSpan duration, bool success, int attemptNumber);
149+
150+
/// <summary>
151+
/// A telemetry event emitted when a symbol package is pushed.
152+
/// </summary>
153+
/// <param name="packageId">The id of the package that has the symbols uploaded.</param>
154+
/// <param name="packageVersion">The version of the package that has the symbols uploaded.</param>
155+
void TrackSymbolPackagePushEvent(string packageId, string packageVersion);
156+
157+
/// <summary>
158+
/// A telemetry event emitted when a symbol package fails to be pushed.
159+
/// </summary>
160+
/// <param name="packageId">The id of the package that has the symbols uploaded.</param>
161+
/// <param name="packageVersion">The version of the package that has the symbols uploaded.</param>
162+
void TrackSymbolPackagePushFailureEvent(string packageId, string packageVersion);
163+
164+
/// <summary>
165+
/// A telemetry event emitted when a symbol package fails Gallery validation.
166+
/// </summary>
167+
/// <param name="packageId">The id of the package that has the symbols uploaded.</param>
168+
/// <param name="packageVersion">The version of the package that has the symbols uploaded.</param>
169+
void TrackSymbolPackageFailedGalleryValidationEvent(string packageId, string packageVersion);
149170
}
150171
}

src/NuGetGallery/Services/TelemetryService.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ internal class Events
4848
public const string PackageRegistrationRequiredSignerSet = "PackageRegistrationRequiredSignerSet";
4949
public const string AccountDeleteCompleted = "AccountDeleteCompleted";
5050
public const string AccountDeleteRequested = "AccountDeleteRequested";
51+
public const string SymbolPackagePush = "SymbolPackagePush";
52+
public const string SymbolPackagePushFailure = "SymbolPackagePushFailure";
53+
public const string SymbolPackageGalleryValidation = "SymbolPackageGalleryValidation";
5154
}
5255

5356
private IDiagnosticsSource _diagnosticsSource;
@@ -346,6 +349,21 @@ public void TrackException(Exception exception, Action<Dictionary<string, string
346349
_telemetryClient.TrackException(exception, telemetryProperties, metrics: null);
347350
}
348351

352+
public void TrackSymbolPackagePushEvent(string packageId, string packageVersion)
353+
{
354+
TrackMetricForSymbolPackage(Events.SymbolPackagePush, packageId, packageVersion);
355+
}
356+
357+
public void TrackSymbolPackagePushFailureEvent(string packageId, string packageVersion)
358+
{
359+
TrackMetricForSymbolPackage(Events.SymbolPackagePushFailure, packageId, packageVersion);
360+
}
361+
362+
public void TrackSymbolPackageFailedGalleryValidationEvent(string packageId, string packageVersion)
363+
{
364+
TrackMetricForSymbolPackage(Events.SymbolPackageGalleryValidation, packageId, packageVersion);
365+
}
366+
349367
private void TrackMetricForAccountActivity(string eventName, User user, Credential credential, bool wasMultiFactorAuthenticated = false)
350368
{
351369
if (user == null)
@@ -410,6 +428,22 @@ private static string GetApiKeyCreationDate(User user, IIdentity identity)
410428
return apiKey?.Created.ToString("O") ?? "N/A";
411429
}
412430

431+
private void TrackMetricForSymbolPackage(
432+
string metricName,
433+
string packageId,
434+
string packageVersion,
435+
Action<Dictionary<string, string>> addProperties = null)
436+
{
437+
TrackMetric(metricName, 1, properties => {
438+
properties.Add(ClientVersion, GetClientVersion());
439+
properties.Add(ProtocolVersion, GetProtocolVersion());
440+
properties.Add(ClientInformation, GetClientInformation());
441+
properties.Add(PackageId, packageId);
442+
properties.Add(PackageVersion, packageVersion);
443+
addProperties?.Invoke(properties);
444+
});
445+
}
446+
413447
private void TrackMetricForPackage(
414448
string metricName,
415449
Package package,

tests/NuGetGallery.Facts/Controllers/ApiControllerFacts.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,9 @@ public async Task CreateSymbolPackage_WillReturn400ForInvalidPackage()
408408
ActionResult result = await controller.CreateSymbolPackagePutAsync();
409409

410410
// Assert
411+
controller.MockTelemetryService.Verify(
412+
x => x.TrackSymbolPackageFailedGalleryValidationEvent(It.IsAny<string>(), It.IsAny<string>()),
413+
Times.Once());
411414
ResultAssert.IsStatusCode(result, HttpStatusCode.BadRequest);
412415
}
413416

@@ -488,8 +491,53 @@ public async Task CreateSymbolPackage_WillCreateSymbolPackageSuccessfully()
488491
ActionResult result = await controller.CreateSymbolPackagePutAsync();
489492

490493
// Assert
494+
controller.MockTelemetryService.Verify(
495+
x => x.TrackSymbolPackagePushEvent(It.IsAny<string>(), It.IsAny<string>()),
496+
Times.Once());
491497
ResultAssert.IsStatusCode(result, HttpStatusCode.Created);
492498
}
499+
500+
[Fact]
501+
public async Task CreateSymbolPackage_WillTraceFailureToPushEvent()
502+
{
503+
// Arrange
504+
var user = new User() { EmailAddress = "[email protected]" };
505+
506+
var controller = new TestableApiController(GetConfigurationService());
507+
controller.SetCurrentUser(user);
508+
509+
var nuGetPackage = TestPackage.CreateTestPackageStream("theId", "1.0.42");
510+
controller.SetupPackageFromInputStream(nuGetPackage);
511+
512+
var package = new Package()
513+
{
514+
PackageRegistration = new PackageRegistration()
515+
{
516+
Id = "TheId"
517+
},
518+
Version = "1.0.42",
519+
SymbolPackages = new HashSet<SymbolPackage>()
520+
};
521+
522+
controller.MockPackageService
523+
.Setup(x => x.FindPackageByIdAndVersionStrict(It.IsAny<string>(), It.IsAny<string>()))
524+
.Returns(package);
525+
526+
controller.MockSymbolPackageUploadService
527+
.Setup(x => x.CreateAndUploadSymbolsPackage(
528+
package,
529+
It.IsAny<PackageStreamMetadata>(),
530+
It.IsAny<Stream>()))
531+
.ThrowsAsync(new SymbolsTestException("Test exception."));
532+
533+
// Act
534+
var exception = await Assert.ThrowsAsync<SymbolsTestException>(() => controller.CreateSymbolPackagePutAsync());
535+
536+
// Assert
537+
controller.MockTelemetryService.Verify(
538+
x => x.TrackSymbolPackagePushFailureEvent(It.IsAny<string>(), It.IsAny<string>()),
539+
Times.Once());
540+
}
493541
}
494542

495543
public class TheCreatePackageAction
@@ -2554,5 +2602,14 @@ public void RedirectsToDist()
25542602
Assert.Equal("https://dist.nuget.org/win-x86-commandline/v2.8.6/nuget.exe", redirect.Url);
25552603
}
25562604
}
2605+
2606+
public class SymbolsTestException : Exception
2607+
{
2608+
public SymbolsTestException(string message) : base (message)
2609+
{
2610+
2611+
}
2612+
}
2613+
25572614
}
25582615
}

tests/NuGetGallery.Facts/Services/TelemetryServiceFacts.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,18 @@ public static IEnumerable<object[]> TrackMetricNames_Data
179179
yield return new object[] { "AccountDeleteRequested",
180180
(TrackAction)(s => s.TrackRequestForAccountDeletion(fakes.User))
181181
};
182+
183+
yield return new object[] { "SymbolPackagePush",
184+
(TrackAction)(s => s.TrackSymbolPackagePushEvent("id", "version"))
185+
};
186+
187+
yield return new object[] { "SymbolPackagePushFailure",
188+
(TrackAction)(s => s.TrackSymbolPackagePushFailureEvent("id", "version"))
189+
};
190+
191+
yield return new object[] { "SymbolPackageGalleryValidation",
192+
(TrackAction)(s => s.TrackSymbolPackageFailedGalleryValidationEvent("id", "version"))
193+
};
182194
}
183195
}
184196

0 commit comments

Comments
 (0)