From cbdd573574ec1828c7853c70433d7fec43e8dd59 Mon Sep 17 00:00:00 2001 From: ysmoradi Date: Wed, 19 Nov 2025 20:00:01 +0100 Subject: [PATCH 1/8] fix --- ...ogging, OpenTelemetry and Health Checks.md | 25 +++---------------- .../SignalR/AppChatbot.cs | 6 ++--- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/.docs/15- Logging, OpenTelemetry and Health Checks.md b/src/Templates/Boilerplate/Bit.Boilerplate/.docs/15- Logging, OpenTelemetry and Health Checks.md index 7c57baf63d..e3ad19ef81 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/.docs/15- Logging, OpenTelemetry and Health Checks.md +++ b/src/Templates/Boilerplate/Bit.Boilerplate/.docs/15- Logging, OpenTelemetry and Health Checks.md @@ -251,29 +251,12 @@ The project is **pre-configured** for easy integration with popular logging prov ### How It Works -The OpenTelemetry configuration automatically exports to Application Insights if a connection string is provided: +1- The OpenTelemetry configuration automatically exports to Application Insights if a connection string is provided: -From [`src/Server/Boilerplate.Server.Shared/Extensions/WebApplicationBuilderExtensions.cs`](/src/Server/Boilerplate.Server.Shared/Extensions/WebApplicationBuilderExtensions.cs): - -```csharp -private static TBuilder AddOpenTelemetryExporters(this TBuilder builder) - where TBuilder : IHostApplicationBuilder -{ - var appInsightsConnectionString = string.IsNullOrWhiteSpace(builder.Configuration["ApplicationInsights:ConnectionString"]) is false - ? builder.Configuration["ApplicationInsights:ConnectionString"] - : null; +From [`src/Server/Boilerplate.Server.Shared/Extensions/IOpenTelemetryExtensions.cs`](/src/Server/Boilerplate.Server.Shared/Extensions/IOpenTelemetryExtensions.cs): - if (appInsightsConnectionString is not null) - { - builder.Services.AddOpenTelemetry().UseAzureMonitor(options => - { - builder.Configuration.Bind("ApplicationInsights", options); - }).AddAzureMonitorProfiler(); - } - - return builder; -} -``` +2- The Azure Application Insights JavaScript SDK added by `BlazorApplicationInsights` nuget in Client.Core project would collect JavaScript erros and more from +Browser and Blazor Hybrid's WebView ### OpenTelemetry Configuration diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppChatbot.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppChatbot.cs index ff7881ae61..ac70a50c86 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppChatbot.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppChatbot.cs @@ -27,7 +27,7 @@ public partial class AppChatbot [AutoInject] private ILogger logger = default!; [AutoInject] private IServiceProvider serviceProvider = default!; - private string? variables; + private string? variablesPrompt; private string? supportSystemPrompt; private List chatMessages = []; @@ -66,7 +66,7 @@ public async Task StartChat( }, token: cancellationToken); - variables = @$" + variablesPrompt = @$" ### Variables: {{{{UserCulture}}}}: ""{culture?.NativeName ?? "English"}"" {{{{DeviceInfo}}}}: ""{request.DeviceInfo ?? "Generic Device"}"" @@ -107,7 +107,7 @@ public async Task ProcessNewMessage( var chatOptions = CreateChatOptions(serverApiAddress, cancellationToken); await foreach (var response in chatClient.GetStreamingResponseAsync([ - new (ChatRole.System, variables), + new (ChatRole.System, variablesPrompt), new (ChatRole.System, supportSystemPrompt), .. chatMessages, new (ChatRole.User, incomingMessage) From 25886fc8608ed6e64cc0e886c556b9d6431a8b09 Mon Sep 17 00:00:00 2001 From: ysmoradi Date: Wed, 19 Nov 2025 22:21:44 +0100 Subject: [PATCH 2/8] enable open telemtry for bit Boilerplate client maui & windows (#11682) --- .../Boilerplate.Client.Maui.csproj | 4 +- .../Extensions/IOpenTelemetryExtensions.cs | 64 +++++++++++++++++++ .../MauiProgram.Services.cs | 16 +---- .../MauiAppInsightsTelemetryInitializer.cs | 35 ---------- .../MauiTelemetryEnrichmentProcessor.cs | 55 ++++++++++++++++ .../Boilerplate.Client.Windows.csproj | 9 ++- .../Program.Services.cs | 17 ++--- .../Boilerplate.Client.Windows/Program.cs | 6 +- .../WindowsAppInsightsTelemetryInitializer.cs | 25 -------- .../WindowsTelemetryEnrichmentProcessor.cs | 45 +++++++++++++ .../src/Directory.Packages.props | 10 +-- .../Boilerplate.Server.AppHost.csproj | 1 + .../Boilerplate.Server.AppHost/Program.cs | 53 +++++++++++++-- 13 files changed, 244 insertions(+), 96 deletions(-) create mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs delete mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiAppInsightsTelemetryInitializer.cs create mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryEnrichmentProcessor.cs delete mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsAppInsightsTelemetryInitializer.cs create mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryEnrichmentProcessor.cs diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj index acaa1a8750..b31051a705 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj @@ -169,10 +169,12 @@ + + - + diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs new file mode 100644 index 0000000000..32026c006e --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs @@ -0,0 +1,64 @@ +//+:cnd:noEmit +//#if (appInsights == true) +using Azure.Monitor.OpenTelemetry.Exporter; +//#endif +using OpenTelemetry; +using OpenTelemetry.Logs; +using OpenTelemetry.Trace; +using OpenTelemetry.Metrics; +using OpenTelemetry.Resources; +using System.Diagnostics.Metrics; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class IOpenTelemetryExtensions +{ + public static IServiceCollection AddOpenTelemetry(this IServiceCollection services, IConfiguration configuration, string serviceName) + where TProcessor : BaseProcessor + { + var useOtlpExporter = string.IsNullOrWhiteSpace(configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]) is false; + + bool useOpenTelemetry = useOtlpExporter == true; + + //#if (appInsights == true) + var appInsightsConnectionString = string.IsNullOrWhiteSpace(configuration["ApplicationInsights:ConnectionString"]) is false ? configuration["ApplicationInsights:ConnectionString"] : null; + useOpenTelemetry = useOpenTelemetry || string.IsNullOrEmpty(appInsightsConnectionString) is false; + //#endif + + if (useOpenTelemetry is false) + return services; + + services.AddOpenTelemetry() + .ConfigureResource(resource => resource.AddService(serviceName)) + .WithTracing(tracing => tracing + .AddProcessor() + .AddSource(ActivitySource.Current.Name) + .AddSource(serviceName)) + .WithMetrics(metrics => metrics + .AddMeter(Meter.Current.Name) + .AddRuntimeInstrumentation()); + + services.AddLogging(loggingBuilder => + { + loggingBuilder.AddOpenTelemetry(logging => + { + var resBuilder = logging.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(serviceName)); + if (useOtlpExporter) + { + resBuilder.AddOtlpExporter(); + } + //#if (appInsights == true) + if (string.IsNullOrEmpty(appInsightsConnectionString) is false) + { + resBuilder.AddAzureMonitorLogExporter(c => c.ConnectionString = appInsightsConnectionString); + } + //#endif + logging.IncludeFormattedMessage = true; + logging.IncludeScopes = true; + }); + }); + + return services; + } +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs index bcb80b1cb0..2d1d17bf65 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Logging; +using OpenTelemetry; +using Microsoft.Extensions.Logging; using Boilerplate.Client.Maui.Services; using Boilerplate.Client.Core.Services.HttpMessageHandlers; @@ -57,18 +58,7 @@ public static void ConfigureServices(this MauiAppBuilder builder) builder.Logging.AddEventLog(options => configuration.GetRequiredSection("Logging:EventLog").Bind(options)); } - //+:cnd:noEmit - //#if (appInsights == true) - if (string.IsNullOrEmpty(settings.ApplicationInsights?.ConnectionString) is false) - { - builder.Logging.AddApplicationInsights(config => - { - config.TelemetryInitializers.Add(new MauiAppInsightsTelemetryInitializer()); - configuration.GetRequiredSection("ApplicationInsights").Bind(config); - }, options => configuration.GetRequiredSection("Logging:ApplicationInsights").Bind(options)); - } - //#endif - //-:cnd:noEmit + services.AddOpenTelemetry(configuration, builder.Environment.ApplicationName); services.AddOptions() .Bind(configuration) diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiAppInsightsTelemetryInitializer.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiAppInsightsTelemetryInitializer.cs deleted file mode 100644 index c730f6089c..0000000000 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiAppInsightsTelemetryInitializer.cs +++ /dev/null @@ -1,35 +0,0 @@ -//+:cnd:noEmit -using Microsoft.ApplicationInsights.Channel; -using Microsoft.ApplicationInsights.Extensibility; - -namespace Boilerplate.Client.Maui.Services; - -public partial class MauiAppInsightsTelemetryInitializer : ITelemetryInitializer -{ - public void Initialize(ITelemetry telemetry) - { - if (ITelemetryContext.Current is not null) - { - telemetry.Context.Session.Id = ITelemetryContext.Current.AppSessionId.ToString(); - telemetry.Context.Component.Version = ITelemetryContext.Current.AppVersion; - telemetry.Context.Device.OperatingSystem = ITelemetryContext.Current.Platform; - telemetry.Context.User.AuthenticatedUserId = ITelemetryContext.Current.UserId?.ToString(); - - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.UserSessionId)] = ITelemetryContext.Current.UserSessionId?.ToString(); - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.WebView)] = ITelemetryContext.Current.WebView; - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.TimeZone)] = ITelemetryContext.Current.TimeZone; - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.Culture)] = ITelemetryContext.Current.Culture; - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.IsOnline)] = ITelemetryContext.Current.IsOnline?.ToString().ToLowerInvariant(); - } - - telemetry.Context.Session.IsFirst = VersionTracking.IsFirstLaunchEver; - telemetry.Context.Device.OemName = DeviceInfo.Current.Manufacturer; - telemetry.Context.Device.Model = DeviceInfo.Current.Model; - telemetry.Context.Device.Type = DeviceInfo.Idiom.ToString(); - - if (AppPlatform.IsIosOnMacOS) - { - telemetry.Context.GlobalProperties["IsiOSApplicationOnMac"] = "true"; - } - } -} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryEnrichmentProcessor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryEnrichmentProcessor.cs new file mode 100644 index 0000000000..f68a0ea3c8 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryEnrichmentProcessor.cs @@ -0,0 +1,55 @@ +//+:cnd:noEmit +using OpenTelemetry; + +namespace Boilerplate.Client.Maui.Services; + +/// +/// OpenTelemetry processor that enriches telemetry data with MAUI-specific context. +/// +public partial class MauiTelemetryEnrichmentProcessor : BaseProcessor +{ + public override void OnStart(Activity activity) + { + if (activity.DisplayName.Contains("Microsoft.AspNetCore.Components.Server.ComponentHub")) + { + activity.IsAllDataRequested = false; // Prevents Blazor Server's SignalR from being exported + } + else if (activity.OperationName is "Microsoft.AspNetCore.Components.HandleEvent") + { + activity.IsAllDataRequested = false; // Prevents Blazor's events from being exported. + } + + if (ITelemetryContext.Current is not null) + { + // Set standard OpenTelemetry semantic convention attributes + activity.SetTag("app.session.id", ITelemetryContext.Current.AppSessionId); + activity.SetTag("app.version", ITelemetryContext.Current.AppVersion); + activity.SetTag("os.description", ITelemetryContext.Current.Platform); + + activity.SetTag("enduser.id", ITelemetryContext.Current.UserId); + + // Add custom context properties + activity.SetTag("user.session.id", ITelemetryContext.Current.UserSessionId); + + activity.SetTag("webview.version", ITelemetryContext.Current.WebView); + + activity.SetTag("user.timezone", ITelemetryContext.Current.TimeZone); + + activity.SetTag("user.culture", ITelemetryContext.Current.Culture); + + activity.SetTag("network.online", ITelemetryContext.Current.IsOnline); + } + + activity.SetTag("device.first.launch", VersionTracking.IsFirstLaunchEver); + activity.SetTag("device.manufacturer", DeviceInfo.Current.Manufacturer); + activity.SetTag("device.model", DeviceInfo.Current.Model); + activity.SetTag("device.type", DeviceInfo.Idiom); + + if (AppPlatform.IsIosOnMacOS) + { + activity.SetTag("device.ios.on.mac", "true"); + } + + base.OnStart(activity); + } +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj index f4babaa16a..20e1431d2f 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj @@ -37,14 +37,17 @@ + + + - + PreserveNewest @@ -65,6 +68,10 @@ + + + + diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs index 0f5a4d90f8..fc21b09dcc 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs @@ -1,7 +1,8 @@ //+:cnd:noEmit -using Microsoft.Extensions.Logging; -using Boilerplate.Client.Windows.Services; using Boilerplate.Client.Core.Services.HttpMessageHandlers; +using Boilerplate.Client.Windows.Services; +using Microsoft.Extensions.Logging; +using OpenTelemetry; namespace Boilerplate.Client.Windows; @@ -55,18 +56,10 @@ public static void AddClientWindowsProjectServices(this IServiceCollection servi loggingBuilder.AddEventSourceLogger(); loggingBuilder.AddEventLog(options => configuration.GetRequiredSection("Logging:EventLog").Bind(options)); - //#if (appInsights == true) - if (string.IsNullOrEmpty(settings.ApplicationInsights?.ConnectionString) is false) - { - loggingBuilder.AddApplicationInsights(config => - { - config.TelemetryInitializers.Add(new WindowsAppInsightsTelemetryInitializer()); - configuration.GetRequiredSection("ApplicationInsights").Bind(config); - }, options => configuration.GetRequiredSection("Logging:ApplicationInsights").Bind(options)); - } - //#endif }); + services.AddOpenTelemetry(configuration, "Boilerplate-Windows"); + services.AddOptions() .Bind(configuration) .ValidateDataAnnotations() diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.cs index f0d64de004..4ee5a0bfe7 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.cs @@ -25,7 +25,11 @@ public static void Main(string[] args) Application.SetColorMode(SystemColorMode.System); - var configuration = new ConfigurationBuilder().AddClientConfigurations(clientEntryAssemblyName: "Boilerplate.Client.Windows").Build(); + var configuration = new ConfigurationBuilder() + .AddClientConfigurations(clientEntryAssemblyName: "Boilerplate.Client.Windows") + .AddEnvironmentVariables() + .Build(); + var services = new ServiceCollection(); services.AddClientWindowsProjectServices(configuration); Services = services.BuildServiceProvider(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsAppInsightsTelemetryInitializer.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsAppInsightsTelemetryInitializer.cs deleted file mode 100644 index 1bba6b420c..0000000000 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsAppInsightsTelemetryInitializer.cs +++ /dev/null @@ -1,25 +0,0 @@ -//+:cnd:noEmit -using Microsoft.ApplicationInsights.Channel; -using Microsoft.ApplicationInsights.Extensibility; - -namespace Boilerplate.Client.Windows.Services; - -public partial class WindowsAppInsightsTelemetryInitializer : ITelemetryInitializer -{ - public void Initialize(ITelemetry telemetry) - { - if (ITelemetryContext.Current is not null) - { - telemetry.Context.Session.Id = ITelemetryContext.Current.AppSessionId.ToString(); - telemetry.Context.Component.Version = ITelemetryContext.Current.AppVersion; - telemetry.Context.Device.OperatingSystem = ITelemetryContext.Current.Platform; - telemetry.Context.User.AuthenticatedUserId = ITelemetryContext.Current.UserId?.ToString(); - - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.UserSessionId)] = ITelemetryContext.Current.UserSessionId?.ToString(); - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.WebView)] = ITelemetryContext.Current.WebView; - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.TimeZone)] = ITelemetryContext.Current.TimeZone; - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.Culture)] = ITelemetryContext.Current.Culture; - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.IsOnline)] = ITelemetryContext.Current.IsOnline?.ToString().ToLowerInvariant(); - } - } -} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryEnrichmentProcessor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryEnrichmentProcessor.cs new file mode 100644 index 0000000000..52032716ab --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryEnrichmentProcessor.cs @@ -0,0 +1,45 @@ +//+:cnd:noEmit +using OpenTelemetry; + +namespace Boilerplate.Client.Windows.Services; + +/// +/// OpenTelemetry processor that enriches telemetry data with Windows-specific context. +/// +public partial class WindowsTelemetryEnrichmentProcessor : BaseProcessor +{ + public override void OnStart(Activity activity) + { + if (activity.DisplayName.Contains("Microsoft.AspNetCore.Components.Server.ComponentHub")) + { + activity.IsAllDataRequested = false; // Prevents Blazor Server's SignalR from being exported + } + else if (activity.OperationName is "Microsoft.AspNetCore.Components.HandleEvent") + { + activity.IsAllDataRequested = false; // Prevents Blazor's events from being exported. + } + + if (ITelemetryContext.Current is not null) + { + // Set standard OpenTelemetry semantic convention attributes + activity.SetTag("app.session.id", ITelemetryContext.Current.AppSessionId); + activity.SetTag("app.version", ITelemetryContext.Current.AppVersion); + activity.SetTag("os.description", ITelemetryContext.Current.Platform); + + activity.SetTag("enduser.id", ITelemetryContext.Current.UserId); + + // Add custom context properties + activity.SetTag("user.session.id", ITelemetryContext.Current.UserSessionId); + + activity.SetTag("webview.version", ITelemetryContext.Current.WebView); + + activity.SetTag("user.timezone", ITelemetryContext.Current.TimeZone); + + activity.SetTag("user.culture", ITelemetryContext.Current.Culture); + + activity.SetTag("network.online", ITelemetryContext.Current.IsOnline); + } + + base.OnStart(activity); + } +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props b/src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props index 6173130d89..333922a27c 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props @@ -26,6 +26,7 @@ + @@ -54,6 +55,7 @@ + @@ -74,9 +76,9 @@ - - - + + + @@ -91,7 +93,7 @@ - + diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Boilerplate.Server.AppHost.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Boilerplate.Server.AppHost.csproj index 2e71657350..78d83f8b11 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Boilerplate.Server.AppHost.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Boilerplate.Server.AppHost.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Program.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Program.cs index 0b6e78e48d..ebb9ee9541 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Program.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Program.cs @@ -111,10 +111,6 @@ serverWebProject.WithReference(mailpit); //#endif - // Blazor Hybrid Windows project. - builder.AddProject("clientwindows", "../../Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj") - .WithExplicitStart(); - //#if (api == "Standalone") builder.AddDevTunnel("api-dev-tunnel") .WithAnonymousAccess() @@ -124,6 +120,55 @@ var tunnel = builder.AddDevTunnel("web-dev-tunnel") .WithAnonymousAccess() .WithReference(serverWebProject.WithHttpEndpoint(name: "devTunnel").GetEndpoint("devTunnel")); + + if (OperatingSystem.IsWindows()) + { + // Blazor Hybrid Windows project. + builder.AddProject("clientwindows", "../../Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj") + .WithExplicitStart(); + } + + // Blazor Hybrid MAUI project. + var mauiapp = builder.AddMauiProject("mauiapp", @"../../Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj"); + + if (OperatingSystem.IsWindows()) + { + mauiapp.AddWindowsDevice() + .WithExplicitStart() + .WithReference(serverWebProject); + } + + if (OperatingSystem.IsMacOS()) + { + mauiapp.AddMacCatalystDevice() + .WithExplicitStart() + .WithReference(serverWebProject); + } + + if (OperatingSystem.IsMacOS()) + { + // Windows supports iOS Simulator and Physical devices if there's a mac connected to network, but the following runners only work on macOS for now. + + mauiapp.AddiOSDevice() + .WithExplicitStart() + .WithOtlpDevTunnel() // Required for OpenTelemetry data collection + .WithReference(serverWebProject, tunnel); + + mauiapp.AddiOSSimulator() + .WithExplicitStart() + .WithOtlpDevTunnel() // Required for OpenTelemetry data collection + .WithReference(serverWebProject, tunnel); + } + + mauiapp.AddAndroidDevice() + .WithExplicitStart() + .WithOtlpDevTunnel() // Required for OpenTelemetry data collection + .WithReference(serverWebProject, tunnel); + + mauiapp.AddAndroidEmulator() + .WithExplicitStart() + .WithOtlpDevTunnel() // Required for OpenTelemetry data collection + .WithReference(serverWebProject, tunnel); } await builder From 2812038ce9de3ed1f1332e02768fd558150b2f3f Mon Sep 17 00:00:00 2001 From: Yaser Moradi Date: Thu, 20 Nov 2025 11:20:23 +0100 Subject: [PATCH 3/8] Update src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Yaser Moradi --- .../Extensions/IOpenTelemetryExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs index 32026c006e..3cafd3123b 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs @@ -19,7 +19,7 @@ public static IServiceCollection AddOpenTelemetry(this IServiceColle { var useOtlpExporter = string.IsNullOrWhiteSpace(configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]) is false; - bool useOpenTelemetry = useOtlpExporter == true; + bool useOpenTelemetry = useOtlpExporter; //#if (appInsights == true) var appInsightsConnectionString = string.IsNullOrWhiteSpace(configuration["ApplicationInsights:ConnectionString"]) is false ? configuration["ApplicationInsights:ConnectionString"] : null; From c520ded2667832fb01af790f5934c067a95e5166 Mon Sep 17 00:00:00 2001 From: ysmoradi Date: Thu, 20 Nov 2025 13:09:25 +0100 Subject: [PATCH 4/8] fix --- .../Extensions/IOpenTelemetryExtensions.cs | 64 ------------------- .../Boilerplate.Client.Windows.csproj | 5 -- .../Program.Services.cs | 26 +++++++- 3 files changed, 24 insertions(+), 71 deletions(-) delete mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs deleted file mode 100644 index 3cafd3123b..0000000000 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Extensions/IOpenTelemetryExtensions.cs +++ /dev/null @@ -1,64 +0,0 @@ -//+:cnd:noEmit -//#if (appInsights == true) -using Azure.Monitor.OpenTelemetry.Exporter; -//#endif -using OpenTelemetry; -using OpenTelemetry.Logs; -using OpenTelemetry.Trace; -using OpenTelemetry.Metrics; -using OpenTelemetry.Resources; -using System.Diagnostics.Metrics; -using Microsoft.Extensions.Logging; - -namespace Microsoft.Extensions.DependencyInjection; - -public static class IOpenTelemetryExtensions -{ - public static IServiceCollection AddOpenTelemetry(this IServiceCollection services, IConfiguration configuration, string serviceName) - where TProcessor : BaseProcessor - { - var useOtlpExporter = string.IsNullOrWhiteSpace(configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]) is false; - - bool useOpenTelemetry = useOtlpExporter; - - //#if (appInsights == true) - var appInsightsConnectionString = string.IsNullOrWhiteSpace(configuration["ApplicationInsights:ConnectionString"]) is false ? configuration["ApplicationInsights:ConnectionString"] : null; - useOpenTelemetry = useOpenTelemetry || string.IsNullOrEmpty(appInsightsConnectionString) is false; - //#endif - - if (useOpenTelemetry is false) - return services; - - services.AddOpenTelemetry() - .ConfigureResource(resource => resource.AddService(serviceName)) - .WithTracing(tracing => tracing - .AddProcessor() - .AddSource(ActivitySource.Current.Name) - .AddSource(serviceName)) - .WithMetrics(metrics => metrics - .AddMeter(Meter.Current.Name) - .AddRuntimeInstrumentation()); - - services.AddLogging(loggingBuilder => - { - loggingBuilder.AddOpenTelemetry(logging => - { - var resBuilder = logging.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(serviceName)); - if (useOtlpExporter) - { - resBuilder.AddOtlpExporter(); - } - //#if (appInsights == true) - if (string.IsNullOrEmpty(appInsightsConnectionString) is false) - { - resBuilder.AddAzureMonitorLogExporter(c => c.ConnectionString = appInsightsConnectionString); - } - //#endif - logging.IncludeFormattedMessage = true; - logging.IncludeScopes = true; - }); - }); - - return services; - } -} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj index 20e1431d2f..9f7f20303b 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj @@ -43,7 +43,6 @@ - @@ -68,10 +67,6 @@ - - - - diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs index fc21b09dcc..96ed2e40b2 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs @@ -1,8 +1,10 @@ //+:cnd:noEmit +using Azure.Monitor.OpenTelemetry.Exporter; using Boilerplate.Client.Core.Services.HttpMessageHandlers; using Boilerplate.Client.Windows.Services; using Microsoft.Extensions.Logging; using OpenTelemetry; +using OpenTelemetry.Logs; namespace Boilerplate.Client.Windows; @@ -55,11 +57,31 @@ public static void AddClientWindowsProjectServices(this IServiceCollection servi loggingBuilder.ConfigureLoggers(configuration); loggingBuilder.AddEventSourceLogger(); + loggingBuilder.AddOpenTelemetry(options => + { + options.IncludeFormattedMessage = true; + options.IncludeScopes = true; + + //#if (appInsights == true) + if (string.IsNullOrEmpty(settings.ApplicationInsights?.ConnectionString) is false) + { + options.AddAzureMonitorLogExporter(o => + { + o.ConnectionString = settings.ApplicationInsights.ConnectionString; + }); + } + //#endif + + var useOtlpExporter = string.IsNullOrWhiteSpace(configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]) is false; + if (useOtlpExporter) + { + options.AddOtlpExporter(); + } + }); + loggingBuilder.AddEventLog(options => configuration.GetRequiredSection("Logging:EventLog").Bind(options)); }); - services.AddOpenTelemetry(configuration, "Boilerplate-Windows"); - services.AddOptions() .Bind(configuration) .ValidateDataAnnotations() From b1d632987df7f1d38184f8c73babd4ce1a36d22f Mon Sep 17 00:00:00 2001 From: ysmoradi Date: Thu, 20 Nov 2025 13:13:44 +0100 Subject: [PATCH 5/8] fix --- .../Boilerplate.Client.Maui.csproj | 7 +-- .../MauiProgram.Services.cs | 29 +++++++++- .../MauiTelemetryEnrichmentProcessor.cs | 55 ------------------- .../Program.Services.cs | 9 +-- .../WindowsTelemetryEnrichmentProcessor.cs | 45 --------------- 5 files changed, 34 insertions(+), 111 deletions(-) delete mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryEnrichmentProcessor.cs delete mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryEnrichmentProcessor.cs diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj index b31051a705..862c9b80f6 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj @@ -1,4 +1,4 @@ - + net10.0-android;net10.0-ios;net10.0-maccatalyst @@ -167,12 +167,11 @@ - - - + + diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs index 2d1d17bf65..bb7562a856 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs @@ -1,6 +1,9 @@ -using OpenTelemetry; +using OpenTelemetry.Logs; using Microsoft.Extensions.Logging; using Boilerplate.Client.Maui.Services; +//#if (appInsights == true) +using Azure.Monitor.OpenTelemetry.Exporter; +//#endif using Boilerplate.Client.Core.Services.HttpMessageHandlers; namespace Boilerplate.Client.Maui; @@ -53,13 +56,33 @@ public static void ConfigureServices(this MauiAppBuilder builder) builder.Logging.AddEventSourceLogger(); + builder.Logging.AddOpenTelemetry(options => + { + options.IncludeFormattedMessage = true; + options.IncludeScopes = true; + + //#if (appInsights == true) + if (string.IsNullOrEmpty(settings.ApplicationInsights?.ConnectionString) is false) + { + options.AddAzureMonitorLogExporter(o => + { + o.ConnectionString = settings.ApplicationInsights.ConnectionString; + }); + } + //#endif + + var useOtlpExporter = string.IsNullOrWhiteSpace(configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]) is false; + if (useOtlpExporter) + { + options.AddOtlpExporter(); + } + }); + if (AppPlatform.IsWindows) { builder.Logging.AddEventLog(options => configuration.GetRequiredSection("Logging:EventLog").Bind(options)); } - services.AddOpenTelemetry(configuration, builder.Environment.ApplicationName); - services.AddOptions() .Bind(configuration) .ValidateDataAnnotations() diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryEnrichmentProcessor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryEnrichmentProcessor.cs deleted file mode 100644 index f68a0ea3c8..0000000000 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryEnrichmentProcessor.cs +++ /dev/null @@ -1,55 +0,0 @@ -//+:cnd:noEmit -using OpenTelemetry; - -namespace Boilerplate.Client.Maui.Services; - -/// -/// OpenTelemetry processor that enriches telemetry data with MAUI-specific context. -/// -public partial class MauiTelemetryEnrichmentProcessor : BaseProcessor -{ - public override void OnStart(Activity activity) - { - if (activity.DisplayName.Contains("Microsoft.AspNetCore.Components.Server.ComponentHub")) - { - activity.IsAllDataRequested = false; // Prevents Blazor Server's SignalR from being exported - } - else if (activity.OperationName is "Microsoft.AspNetCore.Components.HandleEvent") - { - activity.IsAllDataRequested = false; // Prevents Blazor's events from being exported. - } - - if (ITelemetryContext.Current is not null) - { - // Set standard OpenTelemetry semantic convention attributes - activity.SetTag("app.session.id", ITelemetryContext.Current.AppSessionId); - activity.SetTag("app.version", ITelemetryContext.Current.AppVersion); - activity.SetTag("os.description", ITelemetryContext.Current.Platform); - - activity.SetTag("enduser.id", ITelemetryContext.Current.UserId); - - // Add custom context properties - activity.SetTag("user.session.id", ITelemetryContext.Current.UserSessionId); - - activity.SetTag("webview.version", ITelemetryContext.Current.WebView); - - activity.SetTag("user.timezone", ITelemetryContext.Current.TimeZone); - - activity.SetTag("user.culture", ITelemetryContext.Current.Culture); - - activity.SetTag("network.online", ITelemetryContext.Current.IsOnline); - } - - activity.SetTag("device.first.launch", VersionTracking.IsFirstLaunchEver); - activity.SetTag("device.manufacturer", DeviceInfo.Current.Manufacturer); - activity.SetTag("device.model", DeviceInfo.Current.Model); - activity.SetTag("device.type", DeviceInfo.Idiom); - - if (AppPlatform.IsIosOnMacOS) - { - activity.SetTag("device.ios.on.mac", "true"); - } - - base.OnStart(activity); - } -} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs index 96ed2e40b2..0c6d0ca8f5 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs @@ -1,10 +1,11 @@ //+:cnd:noEmit +using OpenTelemetry.Logs; +using Microsoft.Extensions.Logging; +using Boilerplate.Client.Windows.Services; +//#if (appInsights == true) using Azure.Monitor.OpenTelemetry.Exporter; +//#endif using Boilerplate.Client.Core.Services.HttpMessageHandlers; -using Boilerplate.Client.Windows.Services; -using Microsoft.Extensions.Logging; -using OpenTelemetry; -using OpenTelemetry.Logs; namespace Boilerplate.Client.Windows; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryEnrichmentProcessor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryEnrichmentProcessor.cs deleted file mode 100644 index 52032716ab..0000000000 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryEnrichmentProcessor.cs +++ /dev/null @@ -1,45 +0,0 @@ -//+:cnd:noEmit -using OpenTelemetry; - -namespace Boilerplate.Client.Windows.Services; - -/// -/// OpenTelemetry processor that enriches telemetry data with Windows-specific context. -/// -public partial class WindowsTelemetryEnrichmentProcessor : BaseProcessor -{ - public override void OnStart(Activity activity) - { - if (activity.DisplayName.Contains("Microsoft.AspNetCore.Components.Server.ComponentHub")) - { - activity.IsAllDataRequested = false; // Prevents Blazor Server's SignalR from being exported - } - else if (activity.OperationName is "Microsoft.AspNetCore.Components.HandleEvent") - { - activity.IsAllDataRequested = false; // Prevents Blazor's events from being exported. - } - - if (ITelemetryContext.Current is not null) - { - // Set standard OpenTelemetry semantic convention attributes - activity.SetTag("app.session.id", ITelemetryContext.Current.AppSessionId); - activity.SetTag("app.version", ITelemetryContext.Current.AppVersion); - activity.SetTag("os.description", ITelemetryContext.Current.Platform); - - activity.SetTag("enduser.id", ITelemetryContext.Current.UserId); - - // Add custom context properties - activity.SetTag("user.session.id", ITelemetryContext.Current.UserSessionId); - - activity.SetTag("webview.version", ITelemetryContext.Current.WebView); - - activity.SetTag("user.timezone", ITelemetryContext.Current.TimeZone); - - activity.SetTag("user.culture", ITelemetryContext.Current.Culture); - - activity.SetTag("network.online", ITelemetryContext.Current.IsOnline); - } - - base.OnStart(activity); - } -} From 2bc5fdb0207f9e74ef63449b35afd383ecf7630c Mon Sep 17 00:00:00 2001 From: ysmoradi Date: Thu, 20 Nov 2025 14:08:03 +0100 Subject: [PATCH 6/8] fix --- .../Boilerplate.Client.Maui.csproj | 1 - .../Boilerplate.Client.Maui/MauiProgram.Services.cs | 12 +++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj index 862c9b80f6..7c1aa01248 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj @@ -167,7 +167,6 @@ - diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs index bb7562a856..aad1cd0cbc 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs @@ -1,4 +1,4 @@ -using OpenTelemetry.Logs; +//+:cnd:noEmit using Microsoft.Extensions.Logging; using Boilerplate.Client.Maui.Services; //#if (appInsights == true) @@ -56,12 +56,12 @@ public static void ConfigureServices(this MauiAppBuilder builder) builder.Logging.AddEventSourceLogger(); + //#if (appInsights == true) builder.Logging.AddOpenTelemetry(options => { options.IncludeFormattedMessage = true; options.IncludeScopes = true; - //#if (appInsights == true) if (string.IsNullOrEmpty(settings.ApplicationInsights?.ConnectionString) is false) { options.AddAzureMonitorLogExporter(o => @@ -69,14 +69,8 @@ public static void ConfigureServices(this MauiAppBuilder builder) o.ConnectionString = settings.ApplicationInsights.ConnectionString; }); } - //#endif - - var useOtlpExporter = string.IsNullOrWhiteSpace(configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]) is false; - if (useOtlpExporter) - { - options.AddOtlpExporter(); - } }); + //#endif if (AppPlatform.IsWindows) { From 11a06a2a1683719cdef6ceb1d75aa610c0d380bd Mon Sep 17 00:00:00 2001 From: ysmoradi Date: Thu, 20 Nov 2025 14:26:50 +0100 Subject: [PATCH 7/8] fix --- .../Components/AppComponentBase.cs | 4 ++-- .../Components/Layout/MainLayout.razor.cs | 4 ++-- .../Pages/Management/RolesPage.razor.cs | 4 ++-- .../Pages/Management/UsersPage.razor.cs | 2 +- .../SignalR/AppHub.Chatbot.cs | 2 +- .../CancellationTokenSourceExtensions.cs | 20 +++++++++++++++++++ .../src/Shared/appsettings.json | 1 + 7 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/CancellationTokenSourceExtensions.cs diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppComponentBase.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppComponentBase.cs index c742d48f90..8487cbc34b 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppComponentBase.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppComponentBase.cs @@ -255,7 +255,7 @@ protected async Task Abort() using var currentCts = cts; cts = new(); - await currentCts.CancelAsync(); + await currentCts.TryCancel(); } public async ValueTask DisposeAsync() @@ -264,7 +264,7 @@ public async ValueTask DisposeAsync() { using var currentCts = cts; cts = null; - await currentCts.CancelAsync(); + await currentCts.TryCancel(); } await DisposeAsync(true); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/MainLayout.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/MainLayout.razor.cs index e64287f88e..311f1b8a4b 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/MainLayout.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/MainLayout.razor.cs @@ -143,7 +143,7 @@ private async Task SetCurrentUser(Task task) using var currentCts = getCurrentUserCts; getCurrentUserCts = new(); - await currentCts.CancelAsync(); + await currentCts.TryCancel(); if (authUser.IsAuthenticated() is false) { @@ -196,7 +196,7 @@ public async ValueTask DisposeAsync() { if (getCurrentUserCts is not null) { - await getCurrentUserCts.CancelAsync(); + await getCurrentUserCts.TryCancel(); getCurrentUserCts.Dispose(); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/RolesPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/RolesPage.razor.cs index 4472dab439..824dd81c10 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/RolesPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/RolesPage.razor.cs @@ -97,7 +97,7 @@ private async Task HandleOnSelectRole(BitNavItem? item) using var currentCts = loadRoleDataCts; loadRoleDataCts = new(); - await currentCts.CancelAsync(); + await currentCts.TryCancel(); } loadRoleDataCts = new(); @@ -398,7 +398,7 @@ protected override async ValueTask DisposeAsync(bool disposing) { if (loadRoleDataCts is not null) { - await loadRoleDataCts.CancelAsync(); + await loadRoleDataCts.TryCancel(); loadRoleDataCts.Dispose(); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/UsersPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/UsersPage.razor.cs index fd73144fdf..aa74af576a 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/UsersPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/UsersPage.razor.cs @@ -110,7 +110,7 @@ private async Task HandleOnSelectUser(BitNavItem? item) using var currentCts = loadRoleDataCts; loadRoleDataCts = new(); - await currentCts.CancelAsync(); + await currentCts.TryCancel(); } loadRoleDataCts = new(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.Chatbot.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.Chatbot.cs index 50d9e78344..1728bf75d4 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.Chatbot.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.Chatbot.cs @@ -43,7 +43,7 @@ async Task ReadIncomingMessages() await foreach (var incomingMessage in incomingMessages) { if (messageSpecificCancellationTokenSrc is not null) - await messageSpecificCancellationTokenSrc.CancelAsync(); + await messageSpecificCancellationTokenSrc.TryCancel(); messageSpecificCancellationTokenSrc = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); _ = chatbotService.ProcessNewMessage( diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/CancellationTokenSourceExtensions.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/CancellationTokenSourceExtensions.cs new file mode 100644 index 0000000000..263a12d9ff --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/CancellationTokenSourceExtensions.cs @@ -0,0 +1,20 @@ +namespace System.Threading; + +public static class CancellationTokenSourceExtensions +{ + /// + /// Tries to cancel the without throwing an exception if it has already been disposed. + /// + public static async Task TryCancel(this CancellationTokenSource source) + { + try + { + await source.CancelAsync(); + return true; + } + catch (ObjectDisposedException) + { + return false; + } + } +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.json b/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.json index b9d220a6b3..c4e9bb7cfd 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.json +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.json @@ -36,6 +36,7 @@ "Comment2": "Integrates Sentry across both backend and frontend projects", "Dsn": "", "SendDefaultPii": true, + "TracesSampleRate": 1.0, "EnableScopeSync": true, "LogLevel": { "Default": "Warning", From be1afd33456702f60de406de162ecc7686d42a67 Mon Sep 17 00:00:00 2001 From: ysmoradi Date: Thu, 20 Nov 2025 14:42:09 +0100 Subject: [PATCH 8/8] fix --- .../.docs/15- Logging, OpenTelemetry and Health Checks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/.docs/15- Logging, OpenTelemetry and Health Checks.md b/src/Templates/Boilerplate/Bit.Boilerplate/.docs/15- Logging, OpenTelemetry and Health Checks.md index e3ad19ef81..e0bb95449c 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/.docs/15- Logging, OpenTelemetry and Health Checks.md +++ b/src/Templates/Boilerplate/Bit.Boilerplate/.docs/15- Logging, OpenTelemetry and Health Checks.md @@ -255,7 +255,7 @@ The project is **pre-configured** for easy integration with popular logging prov From [`src/Server/Boilerplate.Server.Shared/Extensions/IOpenTelemetryExtensions.cs`](/src/Server/Boilerplate.Server.Shared/Extensions/IOpenTelemetryExtensions.cs): -2- The Azure Application Insights JavaScript SDK added by `BlazorApplicationInsights` nuget in Client.Core project would collect JavaScript erros and more from +2- The Azure Application Insights JavaScript SDK added by `BlazorApplicationInsights` nuget in Client.Core project would collect JavaScript errors and more from Browser and Blazor Hybrid's WebView ### OpenTelemetry Configuration