From a0ed5dc7485c6d6b8c8014528669dbb4acd19692 Mon Sep 17 00:00:00 2001 From: Cazzar Date: Fri, 19 Jan 2024 20:21:13 +1100 Subject: [PATCH] Sentry updates - Don't log NotLoggedInException - Don't log FileNotFoundException - Don't log DirectoryNotFoundException - Only init one version of sentry - Only report 50% of errors. This should reduce volumes --- .../UDP/Exceptions/NotLoggedInException.cs | 2 + Shoko.Server/Server/ShokoServer.cs | 41 ++------ Shoko.Server/Server/Startup.cs | 37 ++----- .../ErrorHandling/SentryIgnoreAttribute.cs | 9 ++ .../Services/ErrorHandling/SentryInit.cs | 96 +++++++++++++++++++ 5 files changed, 123 insertions(+), 62 deletions(-) create mode 100644 Shoko.Server/Services/ErrorHandling/SentryIgnoreAttribute.cs create mode 100644 Shoko.Server/Services/ErrorHandling/SentryInit.cs diff --git a/Shoko.Server/Providers/AniDB/UDP/Exceptions/NotLoggedInException.cs b/Shoko.Server/Providers/AniDB/UDP/Exceptions/NotLoggedInException.cs index d897d27c7..346b0b2ce 100644 --- a/Shoko.Server/Providers/AniDB/UDP/Exceptions/NotLoggedInException.cs +++ b/Shoko.Server/Providers/AniDB/UDP/Exceptions/NotLoggedInException.cs @@ -1,7 +1,9 @@ using System; +using Shoko.Server.Services.ErrorHandling; namespace Shoko.Server.Providers.AniDB.UDP.Exceptions; +[SentryIgnore] public class NotLoggedInException : Exception { } diff --git a/Shoko.Server/Server/ShokoServer.cs b/Shoko.Server/Server/ShokoServer.cs index c0344d9a0..86345881e 100644 --- a/Shoko.Server/Server/ShokoServer.cs +++ b/Shoko.Server/Server/ShokoServer.cs @@ -7,6 +7,7 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reflection; +using System.Text.RegularExpressions; using System.Threading; using System.Timers; using Microsoft.Extensions.DependencyInjection; @@ -27,6 +28,7 @@ using Shoko.Server.Repositories.Cached; using Shoko.Server.Scheduling.Jobs.Actions; using Shoko.Server.Scheduling.Jobs.Shoko; +using Shoko.Server.Services.ErrorHandling; using Shoko.Server.Settings; using Shoko.Server.Utilities; using Shoko.Server.Utilities.FileSystemWatcher; @@ -41,11 +43,11 @@ public class ShokoServer private readonly ILogger logger; private readonly ISettingsProvider _settingsProvider; private readonly ISchedulerFactory _schedulerFactory; + private readonly SentryInit _sentryInit; public static DateTime? StartTime; public static TimeSpan? UpTime => StartTime == null ? null : DateTime.Now - StartTime; - private static IDisposable _sentry; public static string PathAddressREST = "api/Image"; public static string PathAddressPlex = "api/Plex"; @@ -63,11 +65,13 @@ public class ShokoServer private BackgroundWorker downloadImagesWorker = new(); - public ShokoServer(ILogger logger, ISettingsProvider settingsProvider, ISchedulerFactory schedulerFactory) + public ShokoServer(ILogger logger, ISettingsProvider settingsProvider, ISchedulerFactory schedulerFactory, SentryInit sentryInit) { this.logger = logger; _settingsProvider = settingsProvider; _schedulerFactory = schedulerFactory; + _sentryInit = sentryInit; + var culture = CultureInfo.GetCultureInfo(settingsProvider.GetSettings().Culture); CultureInfo.DefaultThreadCurrentCulture = culture; CultureInfo.DefaultThreadCurrentUICulture = culture; @@ -81,42 +85,15 @@ private void ShutDown(object sender, CancelEventArgs e) ~ShokoServer() { - _sentry?.Dispose(); ShokoEventHandler.Instance.Shutdown -= ShutDown; } public bool StartUpServer() { var settings = _settingsProvider.GetSettings(); - // Only try to set up Sentry if the user DID NOT OPT __OUT__. - if (!settings.SentryOptOut && Constants.SentryDsn.StartsWith("https://")) - { - // Get the release and extra info from the assembly. - var extraInfo = Utils.GetApplicationExtraVersion(); - - // Only initialize the SDK if we're not on a debug build. - // - // If the release channel is not set or if it's set to "debug" then - // it's considered to be a debug build. - if (extraInfo.TryGetValue("channel", out var environment) && environment != "debug") - _sentry = SentrySdk.Init(opts => - { - // Assign the DSN key and release version. - opts.Dsn = Constants.SentryDsn; - opts.Environment = environment; - opts.Release = Utils.GetApplicationVersion(); - - // Conditionally assign the extra info if they're included in the assembly. - if (extraInfo.TryGetValue("commit", out var gitCommit)) - opts.DefaultTags.Add("commit", gitCommit); - if (extraInfo.TryGetValue("tag", out var gitTag)) - opts.DefaultTags.Add("commit.tag", gitTag); - - // Append the release channel for the release on non-stable branches. - if (environment != "stable") - opts.Release += string.IsNullOrEmpty(gitCommit) ? $"-{environment}" : $"-{environment}-{gitCommit[0..7]}"; - }); - } + + _sentryInit.Init(); + // Check if any of the DLL are blocked, common issue with daily builds if (!CheckBlockedFiles()) diff --git a/Shoko.Server/Server/Startup.cs b/Shoko.Server/Server/Startup.cs index 95756e6bb..98f7c9adf 100644 --- a/Shoko.Server/Server/Startup.cs +++ b/Shoko.Server/Server/Startup.cs @@ -20,6 +20,7 @@ using Shoko.Server.Scheduling; using Shoko.Server.Services; using Shoko.Server.Services.Connectivity; +using Shoko.Server.Services.ErrorHandling; using Shoko.Server.Settings; using Shoko.Server.Utilities; using ISettingsProvider = Shoko.Server.Settings.ISettingsProvider; @@ -62,6 +63,7 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddQuartz(); @@ -144,38 +146,13 @@ private IWebHost InitWebHost(ISettingsProvider settingsProvider) logging.AddFilter("Shoko.Server.API", LogLevel.Warning); #endif }).UseNLog(); - - // Only try to set up Sentry if the user DID NOT OPT __OUT__. - if (!settings.SentryOptOut && Constants.SentryDsn.StartsWith("https://")) - { - // Get the release and extra info from the assembly. - var extraInfo = Utils.GetApplicationExtraVersion(); - - // Only initialize the SDK if we're not on a debug build. - // - // If the release channel is not set or if it's set to "debug" then - // it's considered to be a debug build. - if (extraInfo.TryGetValue("channel", out var environment) && environment != "debug") - builder = builder.UseSentry(opts => - { - // Assign the DSN key and release version. - opts.Dsn = Constants.SentryDsn; - opts.Environment = environment; - opts.Release = Utils.GetApplicationVersion(); - - // Conditionally assign the extra info if they're included in the assembly. - if (extraInfo.TryGetValue("commit", out var gitCommit)) - opts.DefaultTags.Add("commit", gitCommit); - if (extraInfo.TryGetValue("tag", out var gitTag)) - opts.DefaultTags.Add("commit.tag", gitTag); - - // Append the release channel for the release on non-stable branches. - if (environment != "stable") - opts.Release += string.IsNullOrEmpty(gitCommit) ? $"-{environment}" : $"-{environment}-{gitCommit[0..7]}"; - }); - } + var result = builder.Build(); + + // Init Sentry + result.Services.GetRequiredService().Init(); + Utils.SettingsProvider = result.Services.GetRequiredService(); Utils.ServiceContainer = result.Services; return result; diff --git a/Shoko.Server/Services/ErrorHandling/SentryIgnoreAttribute.cs b/Shoko.Server/Services/ErrorHandling/SentryIgnoreAttribute.cs new file mode 100644 index 000000000..3c195279e --- /dev/null +++ b/Shoko.Server/Services/ErrorHandling/SentryIgnoreAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Shoko.Server.Services.ErrorHandling; + +[AttributeUsage(AttributeTargets.Class)] +public class SentryIgnoreAttribute : Attribute +{ + +} diff --git a/Shoko.Server/Services/ErrorHandling/SentryInit.cs b/Shoko.Server/Services/ErrorHandling/SentryInit.cs new file mode 100644 index 000000000..f8455c132 --- /dev/null +++ b/Shoko.Server/Services/ErrorHandling/SentryInit.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using NLog; +using Sentry; +using Shoko.Server.Settings; +using Shoko.Server.Utilities; +using Constants = Shoko.Server.Server.Constants; + +#nullable enable + +namespace Shoko.Server.Services.ErrorHandling; + +public class SentryInit : IDisposable +{ + private readonly ISettingsProvider _settingsProvider; + private IDisposable? _sentry; + + public SentryInit(ISettingsProvider settingsProvider) + { + _settingsProvider = settingsProvider; + } + + public void Init() + { + if (_sentry is not null) + return; + + var settings = _settingsProvider.GetSettings(); + + // Only try to set up Sentry if the user DID NOT OPT __OUT__. + if (settings.SentryOptOut || !Constants.SentryDsn.StartsWith("https://")) + return; + + // Get the release and extra info from the assembly. + var extraInfo = Utils.GetApplicationExtraVersion(); + + // Only initialize the SDK if we're not on a debug build. + // + // If the release channel is not set or if it's set to "debug" then + // it's considered to be a debug build. + if (extraInfo.TryGetValue("channel", out var environment) && environment != "debug") + Init(environment, extraInfo); + } + + private void Init(string environment, Dictionary extraInfo) + { + _sentry = SentrySdk.Init(opts => + { + // Assign the DSN key and release version. + opts.Dsn = Constants.SentryDsn; + opts.Environment = environment; + opts.Release = Utils.GetApplicationVersion(); + + // Conditionally assign the extra info if they're included in the assembly. + if (extraInfo.TryGetValue("commit", out var gitCommit)) + opts.DefaultTags.Add("commit", gitCommit); + if (extraInfo.TryGetValue("tag", out var gitTag)) + opts.DefaultTags.Add("commit.tag", gitTag); + + // Append the release channel for the release on non-stable branches. + if (environment != "stable") + opts.Release += string.IsNullOrEmpty(gitCommit) ? $"-{environment}" : $"-{environment}-{gitCommit[0..7]}"; + + opts.SampleRate = 0.5f; + + opts.BeforeSend += BeforeSentrySend; + }); + + LogManager.Configuration.AddSentry(o => + { + o.MinimumEventLevel = LogLevel.Fatal; + }); + } + + private SentryEvent? BeforeSentrySend(SentryEvent arg) + { + if (arg.Exception is FileNotFoundException) + return null; + + if (arg.Exception is DirectoryNotFoundException) + return null; + + if (arg.Exception?.GetType().GetCustomAttribute() is not null) + return null; + + return arg; + } + + public void Dispose() + { + _sentry?.Dispose(); + } +}