V8: Merge package telemetry from V9 (#11785)
* Merge Telemetry classes from V9 * Use TelemetryService in ReportSiteTask * Migrate tests
This commit is contained in:
@@ -8,6 +8,7 @@ using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Packaging;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Core.Telemetry;
|
||||
|
||||
namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
{
|
||||
@@ -79,6 +80,8 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
factory.GetInstance<CompiledPackageXmlParser>(), factory.GetInstance<IPackageActionRunner>(),
|
||||
new DirectoryInfo(IOHelper.GetRootDirectorySafe())));
|
||||
|
||||
composition.RegisterUnique<ITelemetryService, TelemetryService>();
|
||||
|
||||
return composition;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Umbraco.Core.Manifest
|
||||
/// <summary>
|
||||
/// Gets all manifests.
|
||||
/// </summary>
|
||||
private IEnumerable<PackageManifest> GetManifests()
|
||||
internal IEnumerable<PackageManifest> GetManifests()
|
||||
{
|
||||
var manifests = new List<PackageManifest>();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
@@ -9,6 +10,28 @@ namespace Umbraco.Core.Manifest
|
||||
/// </summary>
|
||||
public class PackageManifest
|
||||
{
|
||||
private string _packageName;
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string PackageName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_packageName) is false)
|
||||
{
|
||||
return _packageName;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Source) is false)
|
||||
{
|
||||
_packageName = Path.GetFileName(Path.GetDirectoryName(Source));
|
||||
}
|
||||
|
||||
return _packageName;
|
||||
}
|
||||
set => _packageName = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the source path of the manifest.
|
||||
/// </summary>
|
||||
@@ -66,5 +89,17 @@ namespace Umbraco.Core.Manifest
|
||||
/// </summary>
|
||||
[JsonProperty("sections")]
|
||||
public ManifestSection[] Sections { get; set; } = Array.Empty<ManifestSection>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the version of the package
|
||||
/// </summary>
|
||||
[JsonProperty("version")]
|
||||
public string Version { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether telemetry is allowed
|
||||
/// </summary>
|
||||
[JsonProperty("allowPackageTelemetry")]
|
||||
public bool AllowPackageTelemetry { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
||||
15
src/Umbraco.Core/Telemetry/ITelemetryService.cs
Normal file
15
src/Umbraco.Core/Telemetry/ITelemetryService.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Umbraco.Core.Telemetry.Models;
|
||||
|
||||
namespace Umbraco.Core.Telemetry
|
||||
{
|
||||
/// <summary>
|
||||
/// Service which gathers the data for telemetry reporting
|
||||
/// </summary>
|
||||
public interface ITelemetryService
|
||||
{
|
||||
/// <summary>
|
||||
/// Try and get the <see cref="TelemetryReportData"/>
|
||||
/// </summary>
|
||||
bool TryGetTelemetryReportData(out TelemetryReportData telemetryReportData);
|
||||
}
|
||||
}
|
||||
28
src/Umbraco.Core/Telemetry/Models/PackageTelemetry.cs
Normal file
28
src/Umbraco.Core/Telemetry/Models/PackageTelemetry.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Telemetry.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializable class containing information about an installed package.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(Name = "packageTelemetry")]
|
||||
public class PackageTelemetry
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the installed package.
|
||||
/// </summary>
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the version of the installed package.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This may be an empty string if no version is specified, or if package telemetry has been restricted.
|
||||
/// </remarks>
|
||||
[DataMember(Name = "version")]
|
||||
public string Version { get; set; }
|
||||
}
|
||||
}
|
||||
34
src/Umbraco.Core/Telemetry/Models/TelemetryReportData.cs
Normal file
34
src/Umbraco.Core/Telemetry/Models/TelemetryReportData.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Telemetry.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializable class containing telemetry information.
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public class TelemetryReportData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a random GUID to prevent an instance posting multiple times pr. day.
|
||||
/// </summary>
|
||||
[DataMember(Name = "id")]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Umbraco CMS version.
|
||||
/// </summary>
|
||||
[DataMember(Name = "version")]
|
||||
public string Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an enumerable containing information about packages.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Contains only the name and version of the packages, unless no version is specified.
|
||||
/// </remarks>
|
||||
[DataMember(Name = "packages")]
|
||||
public IEnumerable<PackageTelemetry> Packages { get; set; }
|
||||
}
|
||||
}
|
||||
81
src/Umbraco.Core/Telemetry/TelemetryService.cs
Normal file
81
src/Umbraco.Core/Telemetry/TelemetryService.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.Telemetry.Models;
|
||||
|
||||
namespace Umbraco.Core.Telemetry
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
internal class TelemetryService : ITelemetryService
|
||||
{
|
||||
private readonly IUmbracoSettingsSection _settings;
|
||||
private readonly ManifestParser _manifestParser;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TelemetryService"/> class.
|
||||
/// </summary>
|
||||
public TelemetryService(
|
||||
ManifestParser manifestParser,
|
||||
IUmbracoSettingsSection settings)
|
||||
{
|
||||
_manifestParser = manifestParser;
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGetTelemetryReportData(out TelemetryReportData telemetryReportData)
|
||||
{
|
||||
if (TryGetTelemetryId(out Guid telemetryId) is false)
|
||||
{
|
||||
telemetryReportData = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
telemetryReportData = new TelemetryReportData
|
||||
{
|
||||
Id = telemetryId,
|
||||
Version = UmbracoVersion.SemanticVersion.ToSemanticString(),
|
||||
Packages = GetPackageTelemetry()
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryGetTelemetryId(out Guid telemetryId)
|
||||
{
|
||||
// Parse telemetry string as a GUID & verify its a GUID and not some random string
|
||||
// since users may have messed with or decided to empty the app setting or put in something random
|
||||
if (Guid.TryParse(_settings.BackOffice.Id, out var parsedTelemetryId) is false)
|
||||
{
|
||||
telemetryId = Guid.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
telemetryId = parsedTelemetryId;
|
||||
return true;
|
||||
}
|
||||
|
||||
private IEnumerable<PackageTelemetry> GetPackageTelemetry()
|
||||
{
|
||||
List<PackageTelemetry> packages = new ();
|
||||
var manifests = _manifestParser.GetManifests();
|
||||
|
||||
foreach (var manifest in manifests)
|
||||
{
|
||||
if (manifest.AllowPackageTelemetry is false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
packages.Add(new PackageTelemetry
|
||||
{
|
||||
Name = manifest.PackageName,
|
||||
Version = manifest.Version ?? string.Empty
|
||||
});
|
||||
}
|
||||
|
||||
return packages;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,6 +396,10 @@
|
||||
<Compile Include="Services\DateTypeServiceExtensions.cs" />
|
||||
<Compile Include="Services\PropertyValidationService.cs" />
|
||||
<Compile Include="Composing\TypeCollectionBuilderBase.cs" />
|
||||
<Compile Include="Telemetry\ITelemetryService.cs" />
|
||||
<Compile Include="Telemetry\Models\PackageTelemetry.cs" />
|
||||
<Compile Include="Telemetry\Models\TelemetryReportData.cs" />
|
||||
<Compile Include="Telemetry\TelemetryService.cs" />
|
||||
<Compile Include="TypeLoaderExtensions.cs" />
|
||||
<Compile Include="Composing\WeightAttribute.cs" />
|
||||
<Compile Include="Composing\WeightedCollectionBuilderBase.cs" />
|
||||
|
||||
@@ -443,5 +443,27 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2
|
||||
Assert.AreEqual("Content", manifest.Sections[0].Name);
|
||||
Assert.AreEqual("World", manifest.Sections[1].Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanParseManifest_Version()
|
||||
{
|
||||
const string json = @"{""name"": ""VersionPackage"", ""version"": ""1.0.0""}";
|
||||
PackageManifest manifest = _parser.ParseManifest(json);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual("VersionPackage", manifest.PackageName);
|
||||
Assert.AreEqual("1.0.0", manifest.Version);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanParseManifest_TrackingAllowed()
|
||||
{
|
||||
const string json = @"{""allowPackageTelemetry"": false }";
|
||||
PackageManifest manifest = _parser.ParseManifest(json);
|
||||
|
||||
Assert.IsFalse(manifest.AllowPackageTelemetry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Telemetry;
|
||||
using Umbraco.Web.Scheduling;
|
||||
|
||||
namespace Umbraco.Web.Telemetry
|
||||
@@ -17,14 +14,19 @@ namespace Umbraco.Web.Telemetry
|
||||
{
|
||||
private readonly IProfilingLogger _logger;
|
||||
private static HttpClient _httpClient;
|
||||
private readonly IUmbracoSettingsSection _settings;
|
||||
private readonly ITelemetryService _telemetryService;
|
||||
|
||||
public ReportSiteTask(IBackgroundTaskRunner<RecurringTaskBase> runner, int delayBeforeWeStart, int howOftenWeRepeat, IProfilingLogger logger, IUmbracoSettingsSection settings)
|
||||
public ReportSiteTask(
|
||||
IBackgroundTaskRunner<RecurringTaskBase> runner,
|
||||
int delayBeforeWeStart,
|
||||
int howOftenWeRepeat,
|
||||
IProfilingLogger logger,
|
||||
ITelemetryService telemetryService)
|
||||
: base(runner, delayBeforeWeStart, howOftenWeRepeat)
|
||||
{
|
||||
_logger = logger;
|
||||
_httpClient = new HttpClient();
|
||||
_settings = settings;
|
||||
_telemetryService = telemetryService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -34,12 +36,9 @@ namespace Umbraco.Web.Telemetry
|
||||
/// <returns>A value indicating whether to repeat the task.</returns>
|
||||
public override async Task<bool> PerformRunAsync(CancellationToken token)
|
||||
{
|
||||
// Try & get a value stored in umbracoSettings.config on the backoffice XML element ID attribute
|
||||
var backofficeIdentifierRaw = _settings.BackOffice.Id;
|
||||
|
||||
// Parse as a GUID & verify its a GUID and not some random string
|
||||
// In case of users may have messed or decided to empty the file contents or put in something random
|
||||
if (Guid.TryParse(backofficeIdentifierRaw, out var telemetrySiteIdentifier) == false)
|
||||
if (_telemetryService.TryGetTelemetryReportData(out var telemetryReportData) is false)
|
||||
{
|
||||
// Some users may have decided to mess with the XML attribute and put in something else
|
||||
// Stop repeating this task (no need to keep checking)
|
||||
@@ -61,8 +60,7 @@ namespace Umbraco.Web.Telemetry
|
||||
|
||||
using (var request = new HttpRequestMessage(HttpMethod.Post, "installs/"))
|
||||
{
|
||||
var postData = new TelemetryReportData { Id = telemetrySiteIdentifier, Version = UmbracoVersion.SemanticVersion.ToSemanticString() };
|
||||
request.Content = new StringContent(JsonConvert.SerializeObject(postData), Encoding.UTF8, "application/json"); //CONTENT-TYPE header
|
||||
request.Content = new StringContent(JsonConvert.SerializeObject(telemetryReportData), Encoding.UTF8, "application/json"); //CONTENT-TYPE header
|
||||
|
||||
// Set a low timeout - no need to use a larger default timeout for this POST request
|
||||
_httpClient.Timeout = new TimeSpan(0, 0, 1);
|
||||
@@ -86,15 +84,5 @@ namespace Umbraco.Web.Telemetry
|
||||
}
|
||||
|
||||
public override bool IsAsync => true;
|
||||
|
||||
[DataContract]
|
||||
private class TelemetryReportData
|
||||
{
|
||||
[DataMember(Name = "id")]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[DataMember(Name = "version")]
|
||||
public string Version { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Telemetry;
|
||||
using Umbraco.Web.Scheduling;
|
||||
|
||||
namespace Umbraco.Web.Telemetry
|
||||
@@ -8,13 +9,13 @@ namespace Umbraco.Web.Telemetry
|
||||
public class TelemetryComponent : IComponent
|
||||
{
|
||||
private readonly IProfilingLogger _logger;
|
||||
private readonly IUmbracoSettingsSection _settings;
|
||||
private readonly ITelemetryService _telemetryService;
|
||||
private BackgroundTaskRunner<IBackgroundTask> _telemetryReporterRunner;
|
||||
|
||||
public TelemetryComponent(IProfilingLogger logger, IUmbracoSettingsSection settings)
|
||||
public TelemetryComponent(IProfilingLogger logger, IUmbracoSettingsSection settings, ITelemetryService telemetryService)
|
||||
{
|
||||
_logger = logger;
|
||||
_settings = settings;
|
||||
_telemetryService = telemetryService;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
@@ -26,7 +27,7 @@ namespace Umbraco.Web.Telemetry
|
||||
const int howOftenWeRepeat = 60 * 1000 * 60 * 24; // 60 * 1000 * 60 * 24 = 24hrs (86400000)
|
||||
|
||||
// As soon as we add our task to the runner it will start to run (after its delay period)
|
||||
var task = new ReportSiteTask(_telemetryReporterRunner, delayBeforeWeStart, howOftenWeRepeat, _logger, _settings);
|
||||
var task = new ReportSiteTask(_telemetryReporterRunner, delayBeforeWeStart, howOftenWeRepeat, _logger, _telemetryService);
|
||||
_telemetryReporterRunner.TryAdd(task);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user