diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Telemetry/Activity/Contracts/ITelemetryActivityStorage.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Telemetry/Activity/Contracts/ITelemetryActivityStorage.cs index 7be3636022..f1c2203b01 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Telemetry/Activity/Contracts/ITelemetryActivityStorage.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Telemetry/Activity/Contracts/ITelemetryActivityStorage.cs @@ -17,6 +17,5 @@ public interface ITelemetryActivityStorage Task EndSessionAsync(); Task ShouldAddDeviceInfoAsync(); Task ShouldAddSolutionInformation(Guid solutionId); - Task ShouldAddApplicationInfoAsync(Guid applicationId); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Telemetry/Activity/Storage/TelemetryActivityStorage.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Telemetry/Activity/Storage/TelemetryActivityStorage.cs index fea21ff317..1474e822e3 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Telemetry/Activity/Storage/TelemetryActivityStorage.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Telemetry/Activity/Storage/TelemetryActivityStorage.cs @@ -13,6 +13,10 @@ namespace Volo.Abp.Telemetry.Activity.Storage; public class TelemetryActivityStorage : ITelemetryActivityStorage, ISingletonDependency { + private const int MaxFileRetries = 5; + private const int RetryDelayMs = 100; + private static readonly TimeSpan InfoExpirationPeriod = TimeSpan.FromDays(7); + private TelemetryActivityStorageState? _cachedState; public async Task BufferActivityAsync(ActivityData activityData) @@ -31,19 +35,16 @@ public class TelemetryActivityStorage : ITelemetryActivityStorage, ISingletonDep public async Task EndSessionAsync() { var state = await GetStateAsync(); - state.SessionId = null; await SaveAsync(); } - public async Task GetLastActivitySendTimeAsync() { var state = await GetStateAsync(); return state.ActivitySendTime; } - public async Task GetOrCreateSessionInfoAsync() { var state = await GetStateAsync(); @@ -58,7 +59,6 @@ public class TelemetryActivityStorage : ITelemetryActivityStorage, ISingletonDep state.ActivitySendTime = DateTimeOffset.UtcNow; state.Activities.Clear(); state.SessionId = null; - await SaveAsync(); } @@ -68,29 +68,12 @@ public class TelemetryActivityStorage : ITelemetryActivityStorage, ISingletonDep state.Solutions[solutionId] = DateTimeOffset.UtcNow; await SaveAsync(); } - public async Task MarkApplicationInfoAsAddedAsync(Guid applicationInfo) - { - var state = await GetStateAsync(); - state.Solutions[applicationInfo] = DateTimeOffset.UtcNow; - await SaveAsync(); - } - - private async Task GetLastSolutionInfoSendTimeAsync(Guid id) - { - var state = await GetStateAsync(); - - if (state.Solutions.TryGetValue(id, out var date)) - { - return date; - } - - return null; - } - private async Task GetLastDeviceInfoSendTimeAsync() + public async Task MarkApplicationInfoAsAddedAsync(Guid applicationId) { var state = await GetStateAsync(); - return state.LastDeviceInfoAddTime; + state.ApplicationInfos[applicationId] = DateTimeOffset.UtcNow; + await SaveAsync(); } public async Task MarkDeviceInfoAsAddedAsync() @@ -99,22 +82,41 @@ public class TelemetryActivityStorage : ITelemetryActivityStorage, ISingletonDep state.LastDeviceInfoAddTime = DateTimeOffset.UtcNow; await SaveAsync(); } - + public virtual async Task ShouldAddDeviceInfoAsync() { var lastSend = await GetLastDeviceInfoSendTimeAsync(); - return lastSend is null || DateTimeOffset.UtcNow - lastSend > TimeSpan.FromDays(7); + return ShouldAddInfo(lastSend); } public virtual async Task ShouldAddSolutionInformation(Guid solutionId) { var lastSend = await GetLastSolutionInfoSendTimeAsync(solutionId); - return lastSend is null || DateTimeOffset.UtcNow - lastSend > TimeSpan.FromDays(7); + return ShouldAddInfo(lastSend); } + public virtual async Task ShouldAddApplicationInfoAsync(Guid applicationId) { var lastSend = await GetLastApplicationInfoSendTimeAsync(applicationId); - return lastSend is null || DateTimeOffset.UtcNow - lastSend > TimeSpan.FromDays(7); + return ShouldAddInfo(lastSend); + } + + private async Task GetLastSolutionInfoSendTimeAsync(Guid solutionId) + { + var state = await GetStateAsync(); + return state.Solutions.TryGetValue(solutionId, out var date) ? date : null; + } + + private async Task GetLastApplicationInfoSendTimeAsync(Guid applicationId) + { + var state = await GetStateAsync(); + return state.ApplicationInfos.TryGetValue(applicationId, out var date) ? date : null; + } + + private async Task GetLastDeviceInfoSendTimeAsync() + { + var state = await GetStateAsync(); + return state.LastDeviceInfoAddTime; } private async Task GetStateAsync() @@ -129,19 +131,15 @@ public class TelemetryActivityStorage : ITelemetryActivityStorage, ISingletonDep { using var reader = new StreamReader(stream, Encoding.UTF8); var json = await reader.ReadToEndAsync(); - return JsonSerializer.Deserialize(json, - new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }) ?? - new TelemetryActivityStorageState(); - }); + return JsonSerializer.Deserialize(json, GetJsonSerializerOptions()) + ?? new TelemetryActivityStorageState(); + }) ?? new TelemetryActivityStorageState(); return _cachedState; } - private async Task WithExclusiveFileLockAsync(Func> action) + private async Task WithExclusiveFileLockAsync(Func> action) { - const int maxRetries = 5; - const int retryDelayMs = 100; - - for (int i = 0; i < maxRetries; i++) + for (int i = 0; i < MaxFileRetries; i++) { try { @@ -156,27 +154,29 @@ public class TelemetryActivityStorage : ITelemetryActivityStorage, ISingletonDep } catch (IOException) { - if (i == maxRetries - 1) + if (i == MaxFileRetries - 1) { - throw; + return default; } - await Task.Delay(retryDelayMs); + await Task.Delay(RetryDelayMs); + } + catch + { + return default; } } - throw new IOException("Unable to acquire file lock for ActivityStorage."); + return default; } private Task SaveAsync() { - var json = JsonSerializer.Serialize(_cachedState ?? new TelemetryActivityStorageState(), - new JsonSerializerOptions { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + var json = JsonSerializer.Serialize(_cachedState ?? new TelemetryActivityStorageState(), GetJsonSerializerOptions()); File.WriteAllText(TelemetryPaths.ActivityStorage, json, Encoding.UTF8); return Task.CompletedTask; } - private Task EnsureFileExistsAsync() { try @@ -190,31 +190,29 @@ public class TelemetryActivityStorage : ITelemetryActivityStorage, ISingletonDep if (!File.Exists(TelemetryPaths.ActivityStorage)) { - var json = JsonSerializer.Serialize(_cachedState ?? new TelemetryActivityStorageState(), - new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true - }); + var json = JsonSerializer.Serialize(_cachedState ?? new TelemetryActivityStorageState(), GetJsonSerializerOptions()); File.WriteAllText(TelemetryPaths.ActivityStorage, json, Encoding.UTF8); } } catch { - //ignored + // Ignored intentionally } return Task.CompletedTask; } - private async Task GetLastApplicationInfoSendTimeAsync(Guid applicationId) + private static JsonSerializerOptions GetJsonSerializerOptions() { - var state = await GetStateAsync(); - if (state.ApplicationInfos.TryGetValue(applicationId, out var lastActivitySendTime)) + return new JsonSerializerOptions { - return lastActivitySendTime; - } + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = true + }; + } - return null; + private static bool ShouldAddInfo(DateTimeOffset? lastSend) + { + return lastSend is null || DateTimeOffset.UtcNow - lastSend > InfoExpirationPeriod; } - } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Telemetry/TelemetryService.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Telemetry/TelemetryService.cs index b2bdc96ed5..81bf294f85 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Telemetry/TelemetryService.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Telemetry/TelemetryService.cs @@ -26,6 +26,7 @@ public class TelemetryService : ITelemetryService, IScopedDependency public IAsyncDisposable TrackActivity(string activityName, Action? configure = null) { + Check.NotNullOrEmpty(activityName, nameof(activityName)); var stopwatch = Stopwatch.StartNew(); var activityData = new ActivityData(activityName); @@ -87,6 +88,7 @@ public class TelemetryService : ITelemetryService, IScopedDependency public async Task AddActivityAsync(string activityName, Action configure) { + Check.NotNullOrEmpty(activityName, nameof(activityName)); var activityData = new ActivityData(activityName); configure?.Invoke(activityData);