Skip to content

Commit a9171b2

Browse files
author
Scott Bommarito
authored
Add "PackageDeprecate" telemetry event (#7245)
1 parent 9b746db commit a9171b2

7 files changed

Lines changed: 287 additions & 56 deletions

File tree

src/NuGetGallery.Services/Telemetry/ITelemetryService.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ public interface ITelemetryService
3434

3535
void TrackPackageRevalidate(Package package);
3636

37+
void TrackPackageDeprecate(
38+
IReadOnlyList<Package> packages,
39+
PackageDeprecationStatus status,
40+
PackageRegistration alternateRegistration,
41+
Package alternatePackage,
42+
bool hasCustomMessage);
43+
3744
void TrackPackageReadMeChangeEvent(Package package, string readMeSourceType, PackageEditReadMeState readMeState);
3845

3946
void TrackCreatePackageVerificationKeyEvent(string packageId, string packageVersion, User user, IIdentity identity);

src/NuGetGallery/Controllers/ManageDeprecationJsonApiController.cs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,15 @@ namespace NuGetGallery
1717
public partial class ManageDeprecationJsonApiController
1818
: AppController
1919
{
20-
private readonly IAuditingService _auditingService;
2120
private readonly IPackageService _packageService;
2221
private readonly IPackageDeprecationService _deprecationService;
2322
private readonly IFeatureFlagService _featureFlagService;
2423

2524
public ManageDeprecationJsonApiController(
26-
IAuditingService auditingService,
2725
IPackageService packageService,
2826
IPackageDeprecationService deprecationService,
2927
IFeatureFlagService featureFlagService)
3028
{
31-
_auditingService = auditingService ?? throw new ArgumentNullException(nameof(auditingService));
3229
_packageService = packageService ?? throw new ArgumentNullException(nameof(packageService));
3330
_deprecationService = deprecationService ?? throw new ArgumentNullException(nameof(deprecationService));
3431
_featureFlagService = featureFlagService ?? throw new ArgumentNullException(nameof(featureFlagService));
@@ -169,16 +166,6 @@ await _deprecationService.UpdateDeprecation(
169166
customMessage,
170167
currentUser);
171168

172-
foreach (var packageToUpdate in packagesToUpdate)
173-
{
174-
await _auditingService.SaveAuditRecordAsync(
175-
new PackageAuditRecord(
176-
packageToUpdate,
177-
status == PackageDeprecationStatus.NotDeprecated ? AuditedPackageAction.Undeprecate : AuditedPackageAction.Deprecate,
178-
status == PackageDeprecationStatus.NotDeprecated ? PackageUndeprecatedVia.Web : PackageDeprecatedVia.Web));
179-
180-
}
181-
182169
return Json(HttpStatusCode.OK);
183170
}
184171

src/NuGetGallery/Services/PackageDeprecationService.cs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,27 @@
77
using System.Linq;
88
using System.Threading.Tasks;
99
using NuGet.Services.Entities;
10+
using NuGetGallery.Auditing;
1011

1112
namespace NuGetGallery
1213
{
1314
public class PackageDeprecationService : IPackageDeprecationService
1415
{
1516
private readonly IEntitiesContext _entitiesContext;
1617
private readonly IPackageUpdateService _packageUpdateService;
17-
private readonly IIndexingService _indexingService;
18+
private readonly ITelemetryService _telemetryService;
19+
private readonly IAuditingService _auditingService;
1820

1921
public PackageDeprecationService(
2022
IEntitiesContext entitiesContext,
2123
IPackageUpdateService packageUpdateService,
22-
IIndexingService indexingService)
24+
ITelemetryService telemetryService,
25+
IAuditingService auditingService)
2326
{
2427
_entitiesContext = entitiesContext ?? throw new ArgumentNullException(nameof(entitiesContext));
2528
_packageUpdateService = packageUpdateService ?? throw new ArgumentNullException(nameof(packageUpdateService));
26-
_indexingService = indexingService ?? throw new ArgumentNullException(nameof(indexingService));
29+
_telemetryService = telemetryService ?? throw new ArgumentNullException(nameof(telemetryService));
30+
_auditingService = auditingService ?? throw new ArgumentNullException(nameof(auditingService));
2731
}
2832

2933
public async Task UpdateDeprecation(
@@ -103,6 +107,22 @@ public async Task UpdateDeprecation(
103107
await _packageUpdateService.UpdatePackagesAsync(packages);
104108

105109
transaction.Commit();
110+
111+
_telemetryService.TrackPackageDeprecate(
112+
packages,
113+
status,
114+
alternatePackageRegistration,
115+
alternatePackage,
116+
!string.IsNullOrWhiteSpace(customMessage));
117+
118+
foreach (var package in packages)
119+
{
120+
await _auditingService.SaveAuditRecordAsync(
121+
new PackageAuditRecord(
122+
package,
123+
status == PackageDeprecationStatus.NotDeprecated ? AuditedPackageAction.Undeprecate : AuditedPackageAction.Deprecate,
124+
status == PackageDeprecationStatus.NotDeprecated ? PackageUndeprecatedVia.Web : PackageDeprecatedVia.Web));
125+
}
106126
}
107127
}
108128

src/NuGetGallery/Services/TelemetryService.cs

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Net.Http;
88
using System.Security.Principal;
99
using System.Web;
10+
using System.Web.Helpers;
1011
using Newtonsoft.Json;
1112
using NuGet.Services.Entities;
1213
using NuGet.Services.FeatureFlags;
@@ -39,6 +40,7 @@ internal class Events
3940
public const string PackageUnlisted = "PackageUnlisted";
4041
public const string PackageListed = "PackageListed";
4142
public const string PackageDelete = "PackageDelete";
43+
public const string PackageDeprecate = "PackageDeprecate";
4244
public const string PackageReupload = "PackageReupload";
4345
public const string PackageHardDeleteReflow = "PackageHardDeleteReflow";
4446
public const string PackageRevalidate = "PackageRevalidate";
@@ -96,7 +98,7 @@ internal class Events
9698
// ODataCustomQuery properties
9799
public const string IsCustomQuery = "IsCustomQuery";
98100

99-
// Package push properties
101+
// Package event properties
100102
public const string AuthenticationMethod = "AuthenticationMethod";
101103
public const string ClientVersion = "ClientVersion";
102104
public const string ProtocolVersion = "ProtocolVersion";
@@ -106,6 +108,13 @@ internal class Events
106108
public const string KeyCreationDate = "KeyCreationDate";
107109
public const string PackageId = "PackageId";
108110
public const string PackageVersion = "PackageVersion";
111+
public const string PackageVersions = "PackageVersions";
112+
113+
// Package deprecate properties
114+
public const string DeprecationReason = "PackageDeprecationReason";
115+
public const string DeprecationAlternatePackageId = "PackageDeprecationAlternatePackageId";
116+
public const string DeprecationAlternatePackageVersion = "PackageDeprecationAlternatePackageVersion";
117+
public const string DeprecationCustomMessage = "PackageDeprecationCustomMessage";
109118

110119
// User properties
111120
public const string RegistrationMethod = "RegistrationMethod";
@@ -392,6 +401,25 @@ public void TrackPackageRevalidate(Package package)
392401
TrackMetricForPackage(Events.PackageRevalidate, package);
393402
}
394403

404+
public void TrackPackageDeprecate(
405+
IReadOnlyList<Package> packages,
406+
PackageDeprecationStatus status,
407+
PackageRegistration alternateRegistration,
408+
Package alternatePackage,
409+
bool hasCustomMessage)
410+
{
411+
TrackMetricForPackageVersions(
412+
Events.PackageDeprecate,
413+
packages,
414+
properties =>
415+
{
416+
properties.Add(DeprecationReason, ((int)status).ToString());
417+
properties.Add(DeprecationAlternatePackageId, alternateRegistration?.Id ?? alternatePackage?.Id);
418+
properties.Add(DeprecationAlternatePackageVersion, alternatePackage?.NormalizedVersion);
419+
properties.Add(DeprecationCustomMessage, hasCustomMessage.ToString());
420+
});
421+
}
422+
395423
public void TrackPackageMetadataComplianceError(string packageId, string packageVersion, IEnumerable<string> complianceFailures)
396424
{
397425
TrackMetricForPackage(
@@ -648,6 +676,39 @@ private void TrackMetricForPackage(
648676
});
649677
}
650678

679+
private void TrackMetricForPackageVersions(
680+
string metricName,
681+
IReadOnlyList<Package> packages,
682+
Action<Dictionary<string, string>> addProperties = null)
683+
{
684+
if (packages == null || !packages.Any() || packages.Select(p => p.PackageRegistrationKey).Distinct().Count() > 1)
685+
{
686+
throw new ArgumentException(nameof(packages));
687+
}
688+
689+
TrackMetricForPackageVersions(
690+
metricName,
691+
packages.First().PackageRegistration.Id,
692+
packages.Select(p => p.NormalizedVersion).ToList(),
693+
addProperties);
694+
}
695+
696+
private void TrackMetricForPackageVersions(
697+
string metricName,
698+
string packageId,
699+
IReadOnlyList<string> packageVersions,
700+
Action<Dictionary<string, string>> addProperties = null)
701+
{
702+
TrackMetric(metricName, packageVersions.Count(), properties => {
703+
properties.Add(ClientVersion, GetClientVersion());
704+
properties.Add(ProtocolVersion, GetProtocolVersion());
705+
properties.Add(ClientInformation, GetClientInformation());
706+
properties.Add(PackageId, packageId);
707+
properties.Add(PackageVersion, BuildArrayProperty(packageVersions));
708+
addProperties?.Invoke(properties);
709+
});
710+
}
711+
651712
public void TrackUserPackageDeleteChecked(UserPackageDeleteEvent details, UserPackageDeleteOutcome outcome)
652713
{
653714
if (details == null)
@@ -727,7 +788,7 @@ public void TrackAccountDeletionCompleted(User deletedUser, User deletedBy, bool
727788
}
728789

729790
TrackMetric(Events.AccountDeleteCompleted, 1, properties => {
730-
properties.Add(AccountDeletedByRole, string.Join(",", deletedBy.Roles?.Select( role => role.Name) ?? new List<string>()));
791+
properties.Add(AccountDeletedByRole, BuildArrayProperty(deletedBy.Roles?.Select(role => role.Name) ?? new string[0]));
731792
properties.Add(AccountIsSelfDeleted, $"{deletedUser.Key == deletedBy.Key}");
732793
properties.Add(AccountDeletedIsOrganization, $"{deletedUser is Organization}");
733794
properties.Add(AccountDeleteSucceeded, $"{success}");
@@ -766,7 +827,7 @@ public void TrackMetricForTyposquattingCheckResultAndTotalTime(
766827
TrackMetric(Events.TyposquattingCheckResultAndTotalTimeInMs, totalTime.TotalMilliseconds, properties => {
767828
properties.Add(PackageId, packageId);
768829
properties.Add(WasUploadBlocked, wasUploadBlocked.ToString());
769-
properties.Add(CollisionPackageIds, string.Join(",", collisionPackageIds.Take(TyposquattingCollisionIdsMaxPropertyValue)));
830+
properties.Add(CollisionPackageIds, BuildArrayProperty(collisionPackageIds.Take(TyposquattingCollisionIdsMaxPropertyValue)));
770831
properties.Add(CollisionPackageIdsCount, collisionPackageIds.Count.ToString());
771832
properties.Add(CheckListLength, checkListLength.ToString());
772833
properties.Add(HasExtraCollisionPackageIds, (collisionPackageIds.Count > TyposquattingCollisionIdsMaxPropertyValue).ToString());
@@ -900,5 +961,10 @@ protected virtual void TrackMetric(string metricName, double value, Action<Dicti
900961

901962
_telemetryClient.TrackMetric(metricName, value, telemetryProperties);
902963
}
964+
965+
private string BuildArrayProperty(IEnumerable<string> list)
966+
{
967+
return JsonConvert.SerializeObject(list);
968+
}
903969
}
904970
}

tests/NuGetGallery.Facts/Controllers/ManageDeprecationJsonApiControllerFacts.cs

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -831,8 +831,6 @@ private async Task AssertSuccessful(
831831
.Completes()
832832
.Verifiable();
833833

834-
var auditingService = GetService<IAuditingService>();
835-
836834
var controller = GetController<ManageDeprecationJsonApiController>();
837835
controller.SetCurrentUser(currentUser);
838836

@@ -852,31 +850,6 @@ private async Task AssertSuccessful(
852850
// Assert
853851
AssertSuccessResponse(controller);
854852

855-
if (expectedStatus == PackageDeprecationStatus.NotDeprecated)
856-
{
857-
foreach (var normalizedVersion in packageNormalizedVersions)
858-
{
859-
auditingService.WroteRecord<PackageAuditRecord>(
860-
r => r.Action == AuditedPackageAction.Undeprecate
861-
&& r.Reason == PackageUndeprecatedVia.Web
862-
&& r.DeprecationRecord == null
863-
&& r.Id == id
864-
&& r.PackageRecord.NormalizedVersion == normalizedVersion);
865-
}
866-
}
867-
else
868-
{
869-
foreach (var normalizedVersion in packageNormalizedVersions)
870-
{
871-
auditingService.WroteRecord<PackageAuditRecord>(
872-
r => r.Action == AuditedPackageAction.Deprecate
873-
&& r.Reason == PackageDeprecatedVia.Web
874-
&& r.DeprecationRecord.Status == (int)expectedStatus
875-
&& r.Id == id
876-
&& r.PackageRecord.NormalizedVersion == normalizedVersion);
877-
}
878-
}
879-
880853
featureFlagService.Verify();
881854
packageService.Verify();
882855
deprecationService.Verify();

0 commit comments

Comments
 (0)