Skip to content

Commit 02872d5

Browse files
authored
Merge pull request #733 from fossa-app/license-metrics
Record Company License metrics
2 parents 272ad70 + f44313b commit 02872d5

7 files changed

+102
-20
lines changed

src/API.Core/DefaultCoreModule.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ protected override void Load(ContainerBuilder builder)
5757
.AsImplementedInterfaces()
5858
.SingleInstance();
5959

60+
builder
61+
.RegisterType<CompanyLicenseMetricsRecorder>()
62+
.AsImplementedInterfaces()
63+
.SingleInstance();
64+
6065
builder
6166
.RegisterType<CompanyLicenseCreator>()
6267
.AsImplementedInterfaces()

src/API.Core/Services/CompanyLicenseRetriever.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
11
using Fossa.API.Core.Entities;
22
using Fossa.API.Core.Repositories;
3+
using Fossa.API.Core.Telemetry;
34
using Fossa.Licensing;
45
using TIKSN.Licensing;
56

67
namespace Fossa.API.Core.Services;
78

89
public class CompanyLicenseRetriever : CompanyLicenseManager, ICompanyLicenseRetriever
910
{
11+
private readonly ICompanyLicenseMetricsRecorder _companyLicenseMetricsRecorder;
1012
private readonly ILicenseFileRepository _licenseFileRepository;
1113
private readonly ISystemLicenseRetriever _systemLicenseRetriever;
1214

1315
public CompanyLicenseRetriever(
1416
ILicenseFileRepository licenseFileRepository,
1517
ILicenseFactory<CompanyEntitlements, CompanyLicenseEntitlements> licenseFactory,
18+
ICompanyLicenseMetricsRecorder companyLicenseMetricsRecorder,
1619
ICertificateProvider certificateProvider,
1720
ISystemLicenseRetriever systemLicenseRetriever)
1821
: base(certificateProvider, licenseFactory)
1922
{
2023
_licenseFileRepository = licenseFileRepository ?? throw new ArgumentNullException(nameof(licenseFileRepository));
24+
_companyLicenseMetricsRecorder = companyLicenseMetricsRecorder ?? throw new ArgumentNullException(nameof(companyLicenseMetricsRecorder));
2125
_systemLicenseRetriever = systemLicenseRetriever ?? throw new ArgumentNullException(nameof(systemLicenseRetriever));
2226
}
2327

@@ -41,11 +45,15 @@ private async Task<Validation<Error, License<CompanyEntitlements>>> GetCompanyLi
4145

4246
var licenseData = licenseFile.Content.ToSeq();
4347

44-
return await ValidateCompanyLicenseAsync(
48+
var licenseValidation = await ValidateCompanyLicenseAsync(
4549
systemLicense,
4650
companyId,
4751
licenseData,
4852
cancellationToken)
4953
.ConfigureAwait(false);
54+
55+
_companyLicenseMetricsRecorder.Record(companyId, licenseValidation);
56+
57+
return licenseValidation;
5058
}
5159
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System.Diagnostics.Metrics;
2+
using Fossa.API.Core.Entities;
3+
using Fossa.Licensing;
4+
using TIKSN.Licensing;
5+
6+
namespace Fossa.API.Core.Telemetry;
7+
8+
public class CompanyLicenseMetricsRecorder : ICompanyLicenseMetricsRecorder
9+
{
10+
private readonly Gauge<double> _daysLeft;
11+
private readonly TimeProvider _timeProvider;
12+
13+
public CompanyLicenseMetricsRecorder(
14+
TimeProvider timeProvider,
15+
IMeterFactory meterFactory)
16+
{
17+
var meter = meterFactory.Create("Fossa.API.Core.Telemetry");
18+
_daysLeft = meter.CreateGauge<double>("fossa.api.core.telemetry.company_license_days_left");
19+
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
20+
}
21+
22+
public void Record(CompanyId companyId, Validation<Error, License<CompanyEntitlements>> license)
23+
{
24+
_daysLeft.Record(
25+
LicenseMetricsRecorderHelper.CalculateDaysLeft(license, _timeProvider),
26+
LicenseMetricsRecorderHelper.CreateLicenseStatusTag(license),
27+
new KeyValuePair<string, object?>("company_id", companyId.AsPrimitive()));
28+
}
29+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using Fossa.API.Core.Entities;
2+
using Fossa.Licensing;
3+
using TIKSN.Licensing;
4+
5+
namespace Fossa.API.Core.Telemetry;
6+
7+
public interface ICompanyLicenseMetricsRecorder
8+
{
9+
void Record(CompanyId companyId, Validation<Error, License<CompanyEntitlements>> license);
10+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using TIKSN.Licensing;
2+
3+
namespace Fossa.API.Core.Telemetry;
4+
5+
internal static class LicenseMetricsRecorderHelper
6+
{
7+
internal static double CalculateDaysLeft<T>(
8+
Validation<Error, License<T>> license,
9+
TimeProvider timeProvider)
10+
{
11+
return license.Match(
12+
validLicense => CalculateTimeLeft(validLicense, timeProvider).TotalDays,
13+
_ => 0.0);
14+
}
15+
16+
internal static TimeSpan CalculateTimeLeft<T>(
17+
License<T> validLicense,
18+
TimeProvider timeProvider)
19+
{
20+
var now = timeProvider.GetUtcNow();
21+
if (validLicense.Terms.NotAfter <= now)
22+
{
23+
return TimeSpan.Zero;
24+
}
25+
26+
return validLicense.Terms.NotAfter.Subtract(now);
27+
}
28+
29+
internal static KeyValuePair<string, object?> CreateLicenseStatusTag<T>(
30+
Validation<Error, License<T>> license)
31+
{
32+
return new KeyValuePair<string, object?>("license_status",
33+
license.Match(
34+
validLicense => "valid",
35+
_ => "invalid"));
36+
}
37+
}

src/API.Core/Telemetry/SystemLicenseMetricsRecorder.cs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,7 @@ public SystemLicenseMetricsRecorder(
2121
public void Record(Validation<Error, License<SystemEntitlements>> license)
2222
{
2323
_daysLeft.Record(
24-
license.Match(
25-
validLicense => CalculateTimeLeft(validLicense).TotalDays,
26-
_ => 0.0),
27-
new KeyValuePair<string, object?>("license_status",
28-
license.Match(
29-
validLicense => "valid",
30-
_ => "invalid")));
31-
}
32-
33-
private TimeSpan CalculateTimeLeft(License<SystemEntitlements> validLicense)
34-
{
35-
var now = _timeProvider.GetUtcNow();
36-
if (validLicense.Terms.NotAfter <= now)
37-
{
38-
return TimeSpan.Zero;
39-
}
40-
41-
return validLicense.Terms.NotAfter.Subtract(now);
24+
LicenseMetricsRecorderHelper.CalculateDaysLeft(license, _timeProvider),
25+
LicenseMetricsRecorderHelper.CreateLicenseStatusTag(license));
4226
}
4327
}

tests/API.UnitTests/PublicAPITests.CoreAssemblyHasNoPublicAPIChangesAsync.verified.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ namespace Fossa.API.Core.Services
902902
}
903903
public class CompanyLicenseRetriever : Fossa.API.Core.Services.CompanyLicenseManager, Fossa.API.Core.Services.ICompanyLicenseRetriever
904904
{
905-
public CompanyLicenseRetriever(Fossa.API.Core.Repositories.ILicenseFileRepository licenseFileRepository, TIKSN.Licensing.ILicenseFactory<Fossa.Licensing.CompanyEntitlements, Fossa.Licensing.CompanyLicenseEntitlements> licenseFactory, Fossa.API.Core.Services.ICertificateProvider certificateProvider, Fossa.API.Core.Services.ISystemLicenseRetriever systemLicenseRetriever) { }
905+
public CompanyLicenseRetriever(Fossa.API.Core.Repositories.ILicenseFileRepository licenseFileRepository, TIKSN.Licensing.ILicenseFactory<Fossa.Licensing.CompanyEntitlements, Fossa.Licensing.CompanyLicenseEntitlements> licenseFactory, Fossa.API.Core.Telemetry.ICompanyLicenseMetricsRecorder companyLicenseMetricsRecorder, Fossa.API.Core.Services.ICertificateProvider certificateProvider, Fossa.API.Core.Services.ISystemLicenseRetriever systemLicenseRetriever) { }
906906
public System.Threading.Tasks.Task<LanguageExt.Validation<LanguageExt.Common.Error, TIKSN.Licensing.License<Fossa.Licensing.CompanyEntitlements>>> GetAsync(Fossa.API.Core.Entities.CompanyId companyId, System.Threading.CancellationToken cancellationToken) { }
907907
}
908908
public class CountryProvider : Fossa.API.Core.Services.ICountryProvider
@@ -998,6 +998,15 @@ namespace Fossa.API.Core.Services
998998
}
999999
namespace Fossa.API.Core.Telemetry
10001000
{
1001+
public class CompanyLicenseMetricsRecorder : Fossa.API.Core.Telemetry.ICompanyLicenseMetricsRecorder
1002+
{
1003+
public CompanyLicenseMetricsRecorder(System.TimeProvider timeProvider, System.Diagnostics.Metrics.IMeterFactory meterFactory) { }
1004+
public void Record(Fossa.API.Core.Entities.CompanyId companyId, LanguageExt.Validation<LanguageExt.Common.Error, TIKSN.Licensing.License<Fossa.Licensing.CompanyEntitlements>> license) { }
1005+
}
1006+
public interface ICompanyLicenseMetricsRecorder
1007+
{
1008+
void Record(Fossa.API.Core.Entities.CompanyId companyId, LanguageExt.Validation<LanguageExt.Common.Error, TIKSN.Licensing.License<Fossa.Licensing.CompanyEntitlements>> license);
1009+
}
10011010
public interface ISystemLicenseMetricsRecorder
10021011
{
10031012
void Record(LanguageExt.Validation<LanguageExt.Common.Error, TIKSN.Licensing.License<Fossa.Licensing.SystemEntitlements>> license);

0 commit comments

Comments
 (0)