From 2faabba4021897db05e3a05650ef623269714c0a Mon Sep 17 00:00:00 2001 From: Daniel Hindrikes Date: Tue, 1 Oct 2024 08:25:54 +0200 Subject: [PATCH] Added GetProviders method and some code cleaning. #31 #32 --- TinyInsights.TestApp/App.xaml.cs | 14 +++- TinyInsights.TestApp/MainPage.xaml.cs | 34 ++++++++- TinyInsights.TestApp/MauiProgram.cs | 15 ++++ TinyInsights/ApplicationInsightsProvider.cs | 81 ++++++++++----------- TinyInsights/IInsights.cs | 1 + TinyInsights/Insights.cs | 19 +++-- TinyInsights/InsightsExtension.cs | 8 +- 7 files changed, 115 insertions(+), 57 deletions(-) diff --git a/TinyInsights.TestApp/App.xaml.cs b/TinyInsights.TestApp/App.xaml.cs index 672644b..57a297e 100644 --- a/TinyInsights.TestApp/App.xaml.cs +++ b/TinyInsights.TestApp/App.xaml.cs @@ -1,11 +1,19 @@ -namespace TinyInsights.TestApp; + +namespace TinyInsights.TestApp; public partial class App : Application { - public App() + private readonly AppShell shell; + + public App(AppShell shell) { InitializeComponent(); - MainPage = new AppShell(); + this.shell = shell; + } + + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(shell); } } \ No newline at end of file diff --git a/TinyInsights.TestApp/MainPage.xaml.cs b/TinyInsights.TestApp/MainPage.xaml.cs index bc7a404..19d36f7 100644 --- a/TinyInsights.TestApp/MainPage.xaml.cs +++ b/TinyInsights.TestApp/MainPage.xaml.cs @@ -7,18 +7,30 @@ public partial class MainPage : ContentPage { private readonly IInsights insights; private readonly InsightsMessageHandler insightsMessageHandler; + private readonly ILogger logger; - public MainPage(IInsights insights, InsightsMessageHandler insightsMessageHandler) + public MainPage(IInsights insights, InsightsMessageHandler insightsMessageHandler, ILogger logger) { this.insights = insights; this.insightsMessageHandler = insightsMessageHandler; - + this.logger = logger; BindingContext = this; insights.OverrideAnonymousUserId("TestUser"); InitializeComponent(); } + private bool useILogger; + public bool UseILogger + { + get => useILogger; + set + { + useILogger = value; + OnPropertyChanged(); + } + } + private async void PageViewButton_OnClicked(object? sender, EventArgs e) { var data = new Dictionary() @@ -27,12 +39,24 @@ private async void PageViewButton_OnClicked(object? sender, EventArgs e) {"key2", "value2"} }; + if (UseILogger) + { + logger.LogTrace("MainView"); + return; + } + await insights.TrackPageViewAsync("MainView", data); } private async void EventButton_OnClicked(object? sender, EventArgs e) { + if (UseILogger) + { + logger.LogInformation("EventButton"); + return; + } + await insights.TrackEventAsync("EventButton"); } @@ -44,6 +68,12 @@ private async void ExceptionButton_OnClicked(object? sender, EventArgs e) } catch (Exception ex) { + if (UseILogger) + { + logger.LogError(ex, "ExceptionButton"); + return; + } + await insights.TrackErrorAsync(ex); } } diff --git a/TinyInsights.TestApp/MauiProgram.cs b/TinyInsights.TestApp/MauiProgram.cs index 17b87c8..6d2da6c 100644 --- a/TinyInsights.TestApp/MauiProgram.cs +++ b/TinyInsights.TestApp/MauiProgram.cs @@ -26,11 +26,26 @@ public static MauiApp CreateMauiApp() provider.IsAutoTrackPageViewsEnabled = true; }); + builder.Services.AddSingleton((serviceProvider) => + { + var insights = serviceProvider.GetRequiredService(); + var providers = insights.GetProviders(); + + if (providers.Any()) + { + return (ILogger)providers.First(); + } + + throw new InvalidOperationException("No insights provider found"); + }); + #if DEBUG builder.Logging.AddDebug(); #endif builder.Services.AddTransient(); + builder.Services.AddSingleton(); + return builder.Build(); } } \ No newline at end of file diff --git a/TinyInsights/ApplicationInsightsProvider.cs b/TinyInsights/ApplicationInsightsProvider.cs index 430c559..2568b00 100644 --- a/TinyInsights/ApplicationInsightsProvider.cs +++ b/TinyInsights/ApplicationInsightsProvider.cs @@ -10,16 +10,16 @@ namespace TinyInsights; public class ApplicationInsightsProvider : IInsightsProvider, ILogger { - private readonly string _connectionString; - private static ApplicationInsightsProvider provider; + private readonly string connectionString; + private static ApplicationInsightsProvider? provider; private const string userIdKey = nameof(userIdKey); private const string crashLogFilename = "crashes.mauiinsights"; private readonly string logPath = FileSystem.CacheDirectory; - private TelemetryClient? _client; - private TelemetryClient? Client => _client ?? CreateTelemetryClient(); + private TelemetryClient? client; + private TelemetryClient? Client => client ?? CreateTelemetryClient(); public bool IsTrackErrorsEnabled { get; set; } = true; public bool IsTrackCrashesEnabled { get; set; } = true; @@ -32,7 +32,7 @@ public class ApplicationInsightsProvider : IInsightsProvider, ILogger public ApplicationInsightsProvider(string connectionString) { - _connectionString = connectionString; + this.connectionString = connectionString; provider = this; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; @@ -58,7 +58,7 @@ void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs #elif WINDOWS public ApplicationInsightsProvider(MauiWinUIApplication app, string connectionString) { - _connectionString = connectionString; + this.connectionString = connectionString; provider = this; app.UnhandledException += App_UnhandledException; @@ -72,8 +72,9 @@ void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionE } } #elif NET8_0_OR_GREATER - public ApplicationInsightsProvider(string connectionString) + public ApplicationInsightsProvider() { + connectionString = string.Empty; // Do nothing. The net8.0 target exists for enabling unit testing, not for actual use. } #endif @@ -107,51 +108,51 @@ public void Initialize() private static void OnAppearing(object? sender, Page e) { var pageType = e.GetType(); - provider.TrackPageViewAsync(pageType.FullName ?? pageType.Name, new Dictionary { { "DisplayName", pageType.Name } }); + provider?.TrackPageViewAsync(pageType.FullName ?? pageType.Name, new Dictionary { { "DisplayName", pageType.Name } }); } readonly Dictionary _globalProperties = []; private TelemetryClient? CreateTelemetryClient() { - if (_client is not null) + if (client is not null) { - return _client; + return client; } try { var configuration = new TelemetryConfiguration() { - ConnectionString = _connectionString + ConnectionString = connectionString }; - _client = new TelemetryClient(configuration); + client = new TelemetryClient(configuration); - _client.Context.Device.OperatingSystem = DeviceInfo.Platform.ToString(); - _client.Context.Device.Model = DeviceInfo.Model; - _client.Context.Device.Type = DeviceInfo.Idiom.ToString(); + client.Context.Device.OperatingSystem = DeviceInfo.Platform.ToString(); + client.Context.Device.Model = DeviceInfo.Model; + client.Context.Device.Type = DeviceInfo.Idiom.ToString(); // Role name will show device name if we don't set it to empty and we want it to be so anonymous as possible. - _client.Context.Cloud.RoleName = string.Empty; - _client.Context.Cloud.RoleInstance = string.Empty; - _client.Context.User.Id = GetUserId(); + client.Context.Cloud.RoleName = string.Empty; + client.Context.Cloud.RoleInstance = string.Empty; + client.Context.User.Id = GetUserId(); // Add any global properties, the user has already added foreach (var property in _globalProperties) { - _client.Context.GlobalProperties[property.Key] = property.Value; + client.Context.GlobalProperties[property.Key] = property.Value; } - _client.Context.GlobalProperties.TryAdd("Language", CultureInfo.CurrentUICulture.TwoLetterISOLanguageName); - _client.Context.GlobalProperties.TryAdd("Manufacturer", DeviceInfo.Manufacturer); - _client.Context.GlobalProperties.TryAdd("AppVersion", AppInfo.VersionString); - _client.Context.GlobalProperties.TryAdd("AppBuildNumber", AppInfo.BuildString); - _client.Context.GlobalProperties.TryAdd("OperatingSystemVersion", DeviceInfo.VersionString); + client.Context.GlobalProperties.TryAdd("Language", CultureInfo.CurrentUICulture.TwoLetterISOLanguageName); + client.Context.GlobalProperties.TryAdd("Manufacturer", DeviceInfo.Manufacturer); + client.Context.GlobalProperties.TryAdd("AppVersion", AppInfo.VersionString); + client.Context.GlobalProperties.TryAdd("AppBuildNumber", AppInfo.BuildString); + client.Context.GlobalProperties.TryAdd("OperatingSystemVersion", DeviceInfo.VersionString); Task.Run(SendCrashes); - return _client; + return client; } catch (Exception) { @@ -329,13 +330,13 @@ private void HandleCrash(Exception ex) } } - public Task TrackErrorAsync(Exception ex, Dictionary? properties = null) + public async Task TrackErrorAsync(Exception ex, Dictionary? properties = null) { try { if (Client is null) { - return Task.CompletedTask; + return; } Debug.WriteLine($"TinyInsights: Tracking error {ex.Message}"); @@ -348,67 +349,61 @@ public Task TrackErrorAsync(Exception ex, Dictionary? properties } Client.TrackException(ex, properties); - Client.Flush(); + await Client.FlushAsync(CancellationToken.None); } catch (Exception) { Debug.WriteLine("TinyInsights: Error tracking error"); } - - return Task.CompletedTask; } - public Task TrackEventAsync(string eventName, Dictionary? properties = null) + public async Task TrackEventAsync(string eventName, Dictionary? properties = null) { try { if (Client is null) { - return Task.CompletedTask; + return; } Debug.WriteLine($"TinyInsights: Tracking event {eventName}"); Client.TrackEvent(eventName, properties); - Client.Flush(); + await Client.FlushAsync(CancellationToken.None); } catch (Exception) { Debug.WriteLine("TinyInsights: Error tracking event"); } - - return Task.CompletedTask; } - public Task TrackPageViewAsync(string viewName, Dictionary? properties = null) + public async Task TrackPageViewAsync(string viewName, Dictionary? properties = null) { try { if (Client is null) { - return Task.CompletedTask; + return; } Debug.WriteLine($"TinyInsights: tracking page view {viewName}"); Client.TrackPageView(viewName); - Client.Flush(); + await Client.FlushAsync(CancellationToken.None); } catch (Exception) { Debug.WriteLine("TinyInsights: Error tracking page view"); } - - return Task.CompletedTask; } - public Task TrackDependencyAsync(string dependencyType, string dependencyName, string data, HttpMethod? httpMethod, DateTimeOffset startTime, TimeSpan duration, bool success, int resultCode = 0, Exception? exception = null) + public async Task TrackDependencyAsync(string dependencyType, string dependencyName, string data, HttpMethod? httpMethod, DateTimeOffset startTime, TimeSpan duration, bool success, int resultCode = 0, Exception? exception = null) { try { if (Client is null) { - return Task.CompletedTask; + return; } Debug.WriteLine($"TinyInsights: Tracking dependency {dependencyName}"); @@ -452,13 +447,13 @@ public Task TrackDependencyAsync(string dependencyType, string dependencyName, s } Client.TrackDependency(dependency); + await Client.FlushAsync(CancellationToken.None); } catch (Exception) { Debug.WriteLine("TinyInsights: Error tracking dependency"); } - return Task.CompletedTask; } public Task TrackDependencyAsync(string dependencyType, string dependencyName, string data, DateTimeOffset startTime, TimeSpan duration, bool success, int resultCode = 0, Exception? exception = null) diff --git a/TinyInsights/IInsights.cs b/TinyInsights/IInsights.cs index d05d06d..bcf84bc 100644 --- a/TinyInsights/IInsights.cs +++ b/TinyInsights/IInsights.cs @@ -3,6 +3,7 @@ namespace TinyInsights; public interface IInsights { void AddProvider(IInsightsProvider provider); + IReadOnlyList GetProviders(); void UpsertGlobalProperty(string key, string value); diff --git a/TinyInsights/Insights.cs b/TinyInsights/Insights.cs index bfb6c4f..e990dfd 100644 --- a/TinyInsights/Insights.cs +++ b/TinyInsights/Insights.cs @@ -6,7 +6,7 @@ public class Insights : IInsights public void UpsertGlobalProperty(string key, string value) { - foreach(var provider in insightsProviders.Where(x => x.IsTrackErrorsEnabled)) + foreach (var provider in insightsProviders.Where(x => x.IsTrackErrorsEnabled)) { provider.UpsertGlobalProperty(key, value); } @@ -17,11 +17,16 @@ public void AddProvider(IInsightsProvider provider) insightsProviders.Add(provider); } + public IReadOnlyList GetProviders() + { + return insightsProviders; + } + public Task TrackErrorAsync(Exception ex, Dictionary? properties = null) { var tasks = new List(); - foreach(var provider in insightsProviders.Where(x => x.IsTrackErrorsEnabled)) + foreach (var provider in insightsProviders.Where(x => x.IsTrackErrorsEnabled)) { var task = provider.TrackErrorAsync(ex, properties); tasks.Add(task); @@ -36,7 +41,7 @@ public Task TrackPageViewAsync(string viewName, Dictionary? prop { var tasks = new List(); - foreach(var provider in insightsProviders.Where(x => x.IsTrackPageViewsEnabled)) + foreach (var provider in insightsProviders.Where(x => x.IsTrackPageViewsEnabled)) { var task = provider.TrackPageViewAsync(viewName, properties); tasks.Add(task); @@ -50,7 +55,7 @@ public Task TrackEventAsync(string eventName, Dictionary? proper { var tasks = new List(); - foreach(var provider in insightsProviders.Where(x => x.IsTrackEventsEnabled)) + foreach (var provider in insightsProviders.Where(x => x.IsTrackEventsEnabled)) { var task = provider.TrackEventAsync(eventName, properties); tasks.Add(task); @@ -72,7 +77,7 @@ public Task TrackDependencyAsync(string dependencyType, string dependencyName, s { var tasks = new List(); - foreach(var provider in insightsProviders.Where(x => x.IsTrackDependencyEnabled)) + foreach (var provider in insightsProviders.Where(x => x.IsTrackDependencyEnabled)) { var task = provider.TrackDependencyAsync(dependencyType, dependencyName, data, httpMethod, startTime, duration, success, resultCode, exception); tasks.Add(task); @@ -106,7 +111,7 @@ public Dependency CreateDependencyTracker(string dependencyType, string dependen public void OverrideAnonymousUserId(string userId) { - foreach(var provider in insightsProviders.Where(x => x.IsTrackDependencyEnabled)) + foreach (var provider in insightsProviders.Where(x => x.IsTrackDependencyEnabled)) { provider.OverrideAnonymousUserId(userId); } @@ -114,7 +119,7 @@ public void OverrideAnonymousUserId(string userId) public void GenerateNewAnonymousUserId() { - foreach(var provider in insightsProviders.Where(x => x.IsTrackDependencyEnabled)) + foreach (var provider in insightsProviders.Where(x => x.IsTrackDependencyEnabled)) { provider.GenerateNewAnonymousUserId(); } diff --git a/TinyInsights/InsightsExtension.cs b/TinyInsights/InsightsExtension.cs index 5c2fa54..57b7be7 100644 --- a/TinyInsights/InsightsExtension.cs +++ b/TinyInsights/InsightsExtension.cs @@ -18,8 +18,10 @@ public static MauiAppBuilder UseTinyInsights(this MauiAppBuilder appBuilder, str #if WINDOWS var provider = new ApplicationInsightsProvider(MauiWinUIApplication.Current, applicationInsightsConnectionString); -#else +#elif ANDROID || IOS || MACCATALYST var provider = new ApplicationInsightsProvider(applicationInsightsConnectionString); +#else + var provider = new ApplicationInsightsProvider(); #endif configureProvider?.Invoke(provider); @@ -42,8 +44,10 @@ public static MauiAppBuilder UseTinyInsightsAsILogger(this MauiAppBuilder appBui { #if WINDOWS var provider = new ApplicationInsightsProvider(MauiWinUIApplication.Current, applicationInsightsConnectionString); -#else +#elif ANDROID || IOS || MACCATALYST var provider = new ApplicationInsightsProvider(applicationInsightsConnectionString); +#else + var provider = new ApplicationInsightsProvider(); #endif configureProvider?.Invoke(provider);