From f0ef6c3601265ca13afd1a46cb34450dfd84ef8a Mon Sep 17 00:00:00 2001 From: Qstick Date: Sun, 19 Jan 2020 16:04:16 -0500 Subject: [PATCH] Fixed: Improve Logging, Slowdown startup if non-recoverable errors --- src/NzbDrone.Api/Indexers/ReleaseModule.cs | 4 +- .../EnvironmentInfo/AppFolderFactory.cs | 17 ++++++++- .../Exceptions/RadarrStartupException.cs | 37 +++++++++++++++++++ .../GlobalExceptionHandlers.cs | 4 +- .../Instrumentation/NzbDroneLogger.cs | 2 +- .../Sentry/RadarrSentryPacket.cs | 2 + .../Sentry/SentryPacketCleanser.cs | 26 +++++++++++++ .../Instrumentation/Sentry/SentryTarget.cs | 16 ++++++-- src/NzbDrone.Common/NzbDrone.Common.csproj | 1 + .../Processes/PidFileProvider.cs | 7 ++-- src/NzbDrone.Console/ConsoleApp.cs | 25 ++++++++++++- .../Datastore/CorruptDatabaseException.cs | 4 +- src/NzbDrone.Core/Datastore/DbFactory.cs | 7 +++- .../DecisionEngine/DownloadDecisionMaker.cs | 2 +- .../Download/DownloadEventHub.cs | 6 +-- .../Housekeepers/DeleteBadMediaCovers.cs | 2 +- .../Housekeeping/HousekeepingService.cs | 4 +- .../IndexerSearch/NzbSearchService.cs | 2 +- src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 6 +-- src/NzbDrone.Core/Indexers/RssParser.cs | 4 +- .../MediaCover/MediaCoverService.cs | 2 +- .../MediaFiles/MovieFileMovingService.cs | 2 +- .../MovieImport/ImportDecisionMaker.cs | 4 +- .../Specifications/FreeSpaceSpecification.cs | 4 +- .../MediaFiles/RenameMovieFileService.cs | 2 +- .../Messaging/Commands/CommandExecutor.cs | 6 +-- .../Movies/RefreshMovieService.cs | 4 +- .../NetImport/HttpNetImportBase.cs | 2 +- .../NetImport/RSSImport/RSSImportParser.cs | 2 +- .../Notifications/Boxcar/BoxcarProxy.cs | 8 ++-- .../Notifications/Email/EmailService.cs | 2 +- .../Notifications/Growl/GrowlService.cs | 2 +- .../MediaBrowser/MediaBrowserService.cs | 2 +- .../Notifications/NotificationService.cs | 2 +- .../NotifyMyAndroid/NotifyMyAndroidProxy.cs | 2 +- .../Notifications/Plex/PlexClientService.cs | 2 +- .../Notifications/Plex/PlexServerService.cs | 4 +- .../Notifications/Prowl/ProwlService.cs | 2 +- .../PushBullet/PushBulletProxy.cs | 12 +++--- .../Notifications/Pushalot/PushalotProxy.cs | 10 ++--- .../Notifications/Pushover/PushoverService.cs | 2 +- .../Notifications/Telegram/TelegramService.cs | 2 +- .../Notifications/Twitter/TwitterService.cs | 2 +- .../Notifications/Xbmc/XbmcService.cs | 4 +- src/NzbDrone.Core/Parser/Parser.cs | 2 +- src/NzbDrone.Host/Bootstrap.cs | 6 +++ src/NzbDrone.Host/BrowserService.cs | 2 +- 47 files changed, 197 insertions(+), 77 deletions(-) create mode 100644 src/NzbDrone.Common/Exceptions/RadarrStartupException.cs diff --git a/src/NzbDrone.Api/Indexers/ReleaseModule.cs b/src/NzbDrone.Api/Indexers/ReleaseModule.cs index 510ceac86d..d798877146 100644 --- a/src/NzbDrone.Api/Indexers/ReleaseModule.cs +++ b/src/NzbDrone.Api/Indexers/ReleaseModule.cs @@ -95,11 +95,11 @@ private List GetMovieReleases(int movieId) } catch (NotImplementedException ex) { - _logger.Error(ex, "One or more indexer you selected does not support movie search yet: " + ex.Message); + _logger.Error(ex, "One or more indexer you selected does not support movie search yet: {0}", ex.Message); } catch (Exception ex) { - _logger.Error(ex, "Movie search failed: " + ex.Message); + _logger.Error(ex, "Movie search failed: {0}", ex.Message); } return new List(); diff --git a/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs b/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs index 7132d539fd..1e2d1da660 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs @@ -1,8 +1,9 @@ -using System; +using System; using System.Security.AccessControl; using System.Security.Principal; using NLog; using NzbDrone.Common.Disk; +using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; namespace NzbDrone.Common.EnvironmentInfo @@ -27,12 +28,24 @@ public AppFolderFactory(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider public void Register() { - _diskProvider.EnsureFolder(_appFolderInfo.AppDataFolder); + try + { + _diskProvider.EnsureFolder(_appFolderInfo.AppDataFolder); + } + catch (UnauthorizedAccessException) + { + throw new RadarrStartupException("Cannot create AppFolder, Access to the path {0} is denied", _appFolderInfo.AppDataFolder); + } if (OsInfo.IsWindows) { SetPermissions(); } + + if (!_diskProvider.FolderWritable(_appFolderInfo.AppDataFolder)) + { + throw new RadarrStartupException("AppFolder {0} is not writable", _appFolderInfo.AppDataFolder); + } } private void SetPermissions() diff --git a/src/NzbDrone.Common/Exceptions/RadarrStartupException.cs b/src/NzbDrone.Common/Exceptions/RadarrStartupException.cs new file mode 100644 index 0000000000..3cd74cc09a --- /dev/null +++ b/src/NzbDrone.Common/Exceptions/RadarrStartupException.cs @@ -0,0 +1,37 @@ +using System; + +namespace NzbDrone.Common.Exceptions +{ + public class RadarrStartupException : NzbDroneException + { + public RadarrStartupException(string message, params object[] args) + : base("Radarr failed to start: " + string.Format(message, args)) + { + } + + public RadarrStartupException(string message) + : base("Radarr failed to start: " + message) + { + } + + public RadarrStartupException() + : base("Radarr failed to start") + { + } + + public RadarrStartupException(Exception innerException, string message, params object[] args) + : base("Radarr failed to start: " + string.Format(message, args), innerException) + { + } + + public RadarrStartupException(Exception innerException, string message) + : base("Radarr failed to start: " + message, innerException) + { + } + + public RadarrStartupException(Exception innerException) + : base("Radarr failed to start: " + innerException.Message) + { + } + } +} diff --git a/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs b/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs index 99032f0107..f467248720 100644 --- a/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs +++ b/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs @@ -19,7 +19,7 @@ private static void HandleTaskException(object sender, UnobservedTaskExceptionEv var exception = e.Exception; Console.WriteLine("Task Error: {0}", exception); - Logger.Error(exception, "Task Error: " + exception.Message); + Logger.Error(exception, "Task Error"); } private static void HandleAppDomainException(object sender, UnhandledExceptionEventArgs e) @@ -48,7 +48,7 @@ private static void HandleAppDomainException(object sender, UnhandledExceptionEv Console.WriteLine(exception.StackTrace); Console.WriteLine("EPIC FAIL: {0}", exception); - Logger.Fatal(exception, "EPIC FAIL: " + exception.Message); + Logger.Fatal(exception, "EPIC FAIL."); } } } diff --git a/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs b/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs index d7aaab0696..64926c1ef3 100644 --- a/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs +++ b/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs @@ -69,7 +69,7 @@ private static void RegisterSentry(bool updateClient) else { dsn = RuntimeInfo.IsProduction - ? "https://ef145e92efdd4155a0771c11c099695e@sentry.radarr.video/2" + ? "https://a8e4c507c1f84578b55a841759a99dfb@sentry.radarr.video/2" : "https://dee5b3fe26844368ac4458faa7d00a1f@sentry.radarr.video/9"; } diff --git a/src/NzbDrone.Common/Instrumentation/Sentry/RadarrSentryPacket.cs b/src/NzbDrone.Common/Instrumentation/Sentry/RadarrSentryPacket.cs index d0d7ef3bc6..dba8210269 100644 --- a/src/NzbDrone.Common/Instrumentation/Sentry/RadarrSentryPacket.cs +++ b/src/NzbDrone.Common/Instrumentation/Sentry/RadarrSentryPacket.cs @@ -14,6 +14,8 @@ public RadarrSentryPacket(string project, SentryEvent @event) : { DefaultValueHandling = DefaultValueHandling.Ignore }; + + Breadcrumbs = @event.Breadcrumbs; } public override string ToString(Formatting formatting) diff --git a/src/NzbDrone.Common/Instrumentation/Sentry/SentryPacketCleanser.cs b/src/NzbDrone.Common/Instrumentation/Sentry/SentryPacketCleanser.cs index c765753c54..ab8e99b461 100644 --- a/src/NzbDrone.Common/Instrumentation/Sentry/SentryPacketCleanser.cs +++ b/src/NzbDrone.Common/Instrumentation/Sentry/SentryPacketCleanser.cs @@ -1,4 +1,7 @@ using Newtonsoft.Json.Linq; +using SharpRaven.Data; +using System; +using System.Linq; namespace NzbDrone.Common.Instrumentation.Sentry { @@ -22,6 +25,29 @@ public void CleansePacket(RadarrSentryPacket packet) new CleansingJsonVisitor().Visit(target); packet.Extra = target; } + + if (packet.Breadcrumbs != null) + { + for (var i = 0; i < packet.Breadcrumbs.Count; i++) + { + packet.Breadcrumbs[i] = CleanseBreadcrumb(packet.Breadcrumbs[i]); + } + } + } + + private static Breadcrumb CleanseBreadcrumb(Breadcrumb b) + { + try + { + var message = CleanseLogMessage.Cleanse(b.Message); + var data = b.Data?.ToDictionary(x => x.Key, y => CleanseLogMessage.Cleanse(y.Value)); + return new Breadcrumb(b.Category) { Message = message, Type = b.Type, Data = data, Level = b.Level }; + } + catch (Exception) + { + } + + return b; } } } diff --git a/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs b/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs index d9f9e4aecd..77de3acd89 100644 --- a/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs +++ b/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs @@ -76,6 +76,16 @@ public class SentryTarget : TargetWithLayout {LogLevel.Warn, ErrorLevel.Warning}, }; + private static readonly IDictionary BreadcrumbLevelMap = new Dictionary + { + { LogLevel.Debug, BreadcrumbLevel.Debug }, + { LogLevel.Error, BreadcrumbLevel.Error }, + { LogLevel.Fatal, BreadcrumbLevel.Critical }, + { LogLevel.Info, BreadcrumbLevel.Info }, + { LogLevel.Trace, BreadcrumbLevel.Debug }, + { LogLevel.Warn, BreadcrumbLevel.Warning }, + }; + private readonly SentryDebounce _debounce; private bool _unauthorized; @@ -199,6 +209,8 @@ protected override void Write(LogEventInfo logEvent) try { + _client.AddTrail(new Breadcrumb(logEvent.LoggerName) { Level = BreadcrumbLevelMap[logEvent.Level], Message = logEvent.FormattedMessage }); + // don't report non-critical events without exceptions if (!IsSentryMessage(logEvent)) { @@ -249,12 +261,8 @@ protected override void Write(LogEventInfo logEvent) Array.ForEach((string[])logEvent.Properties["Sentry"], sentryEvent.Fingerprint.Add); } - var osName = Environment.GetEnvironmentVariable("OS_NAME"); - var osVersion = Environment.GetEnvironmentVariable("OS_VERSION"); var runTimeVersion = Environment.GetEnvironmentVariable("RUNTIME_VERSION"); - sentryEvent.Tags.Add("os_name", osName); - sentryEvent.Tags.Add("os_version", $"{osName} {osVersion}"); sentryEvent.Tags.Add("runtime_version", $"{PlatformInfo.PlatformName} {runTimeVersion}"); _client.Capture(sentryEvent); diff --git a/src/NzbDrone.Common/NzbDrone.Common.csproj b/src/NzbDrone.Common/NzbDrone.Common.csproj index c22d7758cf..7331515efc 100644 --- a/src/NzbDrone.Common/NzbDrone.Common.csproj +++ b/src/NzbDrone.Common/NzbDrone.Common.csproj @@ -103,6 +103,7 @@ + diff --git a/src/NzbDrone.Common/Processes/PidFileProvider.cs b/src/NzbDrone.Common/Processes/PidFileProvider.cs index 17e7812259..b1c2af5fe2 100644 --- a/src/NzbDrone.Common/Processes/PidFileProvider.cs +++ b/src/NzbDrone.Common/Processes/PidFileProvider.cs @@ -1,7 +1,8 @@ -using System; +using System; using System.IO; using NLog; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Exceptions; namespace NzbDrone.Common.Processes { @@ -37,8 +38,8 @@ public void Write() } catch (Exception ex) { - _logger.Error(ex, "Unable to write PID file: " + filename); - throw; + _logger.Error(ex, "Unable to write PID file: {0}", filename); + throw new RadarrStartupException(ex, "Unable to write PID file {0}", filename); } } } diff --git a/src/NzbDrone.Console/ConsoleApp.cs b/src/NzbDrone.Console/ConsoleApp.cs index f36a8fa6ea..0182499be6 100644 --- a/src/NzbDrone.Console/ConsoleApp.cs +++ b/src/NzbDrone.Console/ConsoleApp.cs @@ -2,6 +2,7 @@ using System.Net.Sockets; using NLog; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; using Radarr.Host; @@ -15,7 +16,8 @@ private enum ExitCodes : int { Normal = 0, UnknownFailure = 1, - RecoverableFailure = 2 + RecoverableFailure = 2, + NonRecoverableFailure = 3 } public static void Main(string[] args) @@ -34,6 +36,13 @@ public static void Main(string[] args) } Bootstrap.Start(startupArgs, new ConsoleAlerts()); } + catch (RadarrStartupException ex) + { + System.Console.WriteLine(""); + System.Console.WriteLine(""); + Logger.Fatal(ex, "EPIC FAIL!"); + Exit(ExitCodes.NonRecoverableFailure); + } catch (SocketException e) { System.Console.WriteLine(""); @@ -53,7 +62,6 @@ public static void Main(string[] args) Exit(ExitCodes.Normal); } - private static void Exit(ExitCodes exitCode) { LogManager.Shutdown(); @@ -64,6 +72,19 @@ private static void Exit(ExitCodes exitCode) System.Threading.Thread.Sleep(1000); + if (exitCode == ExitCodes.NonRecoverableFailure) + { + System.Console.WriteLine("Non-recoverable failure, waiting for user intervention..."); + for (int i = 0; i < 3600; i++) + { + System.Threading.Thread.Sleep(1000); + if (System.Console.KeyAvailable) + { + break; + } + } + } + // Please note that ReadLine silently succeeds if there is no console, KeyAvailable does not. System.Console.ReadLine(); } diff --git a/src/NzbDrone.Core/Datastore/CorruptDatabaseException.cs b/src/NzbDrone.Core/Datastore/CorruptDatabaseException.cs index 1d8b6696d0..282b2bb6b6 100644 --- a/src/NzbDrone.Core/Datastore/CorruptDatabaseException.cs +++ b/src/NzbDrone.Core/Datastore/CorruptDatabaseException.cs @@ -1,9 +1,9 @@ -using System; +using System; using NzbDrone.Common.Exceptions; namespace NzbDrone.Core.Datastore { - public class CorruptDatabaseException : NzbDroneException + public class CorruptDatabaseException : RadarrStartupException { public CorruptDatabaseException(string message, params object[] args) : base(message, args) { diff --git a/src/NzbDrone.Core/Datastore/DbFactory.cs b/src/NzbDrone.Core/Datastore/DbFactory.cs index bbbd5907f4..a5280cff9e 100644 --- a/src/NzbDrone.Core/Datastore/DbFactory.cs +++ b/src/NzbDrone.Core/Datastore/DbFactory.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Data.SQLite; using Marr.Data; using Marr.Data.Reflection; @@ -6,6 +6,7 @@ using NzbDrone.Common.Composition; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; using NzbDrone.Core.Datastore.Migration.Framework; @@ -116,6 +117,10 @@ public IDatabase Create(MigrationContext migrationContext) throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://github.com/Radarr/Radarr/wiki/FAQ#i-am-getting-an-error-database-disk-image-is-malformed", ex, fileName); } } + catch (Exception e) + { + throw new RadarrStartupException(e, "Error creating main or log database"); + } var db = new Database(migrationContext.MigrationType.ToString(), () => { diff --git a/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs b/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs index 55dd90962b..9418b61042 100644 --- a/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs +++ b/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs @@ -206,7 +206,7 @@ private Rejection EvaluateSpec(IDecisionEngineSpecification spec, RemoteMovie re { e.Data.Add("report", remoteMovie.Release.ToJson()); e.Data.Add("parsed", remoteMovie.ParsedMovieInfo.ToJson()); - _logger.Error(e, "Couldn't evaluate decision on " + remoteMovie.Release.Title + ", with spec: " + spec.GetType().Name); + _logger.Error(e, "Couldn't evaluate decision on {0}, with spec: {1}", remoteMovie.Release.Title, spec.GetType().Name); return new Rejection(string.Format("{0}: {1}", spec.GetType().Name, e.Message));//TODO UPDATE SPECS! } diff --git a/src/NzbDrone.Core/Download/DownloadEventHub.cs b/src/NzbDrone.Core/Download/DownloadEventHub.cs index e6b08e20eb..5c2e41b6be 100644 --- a/src/NzbDrone.Core/Download/DownloadEventHub.cs +++ b/src/NzbDrone.Core/Download/DownloadEventHub.cs @@ -1,4 +1,4 @@ -using System; +using System; using NLog; using NzbDrone.Common.Messaging; using NzbDrone.Core.Configuration; @@ -74,8 +74,8 @@ private void RemoveFromDownloadClient(TrackedDownload trackedDownload) } catch (Exception e) { - _logger.Error(e, "Couldn't remove item from client " + trackedDownload.DownloadItem.Title); + _logger.Error(e, "Couldn't remove item {0} from client {1}", trackedDownload.DownloadItem.Title, downloadClient.Name); } } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/DeleteBadMediaCovers.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/DeleteBadMediaCovers.cs index cc1b13f4cd..0b91194255 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/DeleteBadMediaCovers.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/DeleteBadMediaCovers.cs @@ -54,7 +54,7 @@ public void Clean() } catch (Exception e) { - _logger.Error(e, "Couldn't validate image " + image.RelativePath); + _logger.Error(e, "Couldn't validate image {0}", image.RelativePath); } } } diff --git a/src/NzbDrone.Core/Housekeeping/HousekeepingService.cs b/src/NzbDrone.Core/Housekeeping/HousekeepingService.cs index c36ace89da..573087a84e 100644 --- a/src/NzbDrone.Core/Housekeeping/HousekeepingService.cs +++ b/src/NzbDrone.Core/Housekeeping/HousekeepingService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using NLog; using NzbDrone.Core.Messaging.Commands; @@ -34,7 +34,7 @@ private void Clean() } catch (Exception ex) { - _logger.Error(ex, "Error running housekeeping task: " + housekeeper.GetType().Name); + _logger.Error(ex, "Error running housekeeping task: {0}", housekeeper.GetType().Name); } } diff --git a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs index 24b12a5ea8..40d8d7166b 100644 --- a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs @@ -90,7 +90,7 @@ private List Dispatch(Func> } catch (Exception e) { - _logger.Error(e, "Error while searching for " + criteriaBase); + _logger.Error(e, "Error while searching for {0}", criteriaBase); } }).LogExceptions()); } diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 9251ffc6e4..843897d3c6 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -244,11 +244,11 @@ protected virtual IList FetchReleases(IndexerPageableRequestChain p var message = string.Format("{0} - {1}", ex.Message, url); _logger.Warn(ex, message); } - catch (Exception feedEx) + catch (Exception ex) { _indexerStatusService.RecordFailure(Definition.Id); - feedEx.Data.Add("FeedUrl", url); - _logger.Error(feedEx, "An error occurred while processing feed. " + url); + ex.Data.Add("FeedUrl", url); + _logger.Error(ex, "An error occurred while processing feed. {0}", url); } return CleanupReleases(releases); diff --git a/src/NzbDrone.Core/Indexers/RssParser.cs b/src/NzbDrone.Core/Indexers/RssParser.cs index 3116861bc7..e8df17d4ca 100644 --- a/src/NzbDrone.Core/Indexers/RssParser.cs +++ b/src/NzbDrone.Core/Indexers/RssParser.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -66,7 +66,7 @@ public virtual IList ParseResponse(IndexerResponse indexerResponse) catch (Exception itemEx) { itemEx.Data.Add("Item", item.Title()); - _logger.Error(itemEx, "An error occurred while processing feed item from " + indexerResponse.Request.Url); + _logger.Error(itemEx, "An error occurred while processing feed item from {0}", indexerResponse.Request.Url); } } diff --git a/src/NzbDrone.Core/MediaCover/MediaCoverService.cs b/src/NzbDrone.Core/MediaCover/MediaCoverService.cs index 3a65b7d1a2..1f16732e40 100644 --- a/src/NzbDrone.Core/MediaCover/MediaCoverService.cs +++ b/src/NzbDrone.Core/MediaCover/MediaCoverService.cs @@ -130,7 +130,7 @@ private void EnsureCovers(Movie movie, int retried = 0) } catch (Exception e) { - _logger.Error(e, "Couldn't download media cover for " + movie); + _logger.Error(e, "Couldn't download media cover for {0}", movie); } EnsureResizedCovers(movie, cover, !alreadyExists); diff --git a/src/NzbDrone.Core/MediaFiles/MovieFileMovingService.cs b/src/NzbDrone.Core/MediaFiles/MovieFileMovingService.cs index 38f44d5e30..deb37c3e4e 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieFileMovingService.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieFileMovingService.cs @@ -224,7 +224,7 @@ private void CreateFolder(string directoryName) } catch (IOException ex) { - _logger.Error(ex, "Unable to create directory: " + directoryName); + _logger.Error(ex, "Unable to create directory: {0}", directoryName); } _mediaFileAttributeService.SetFolderPermissions(directoryName); diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/ImportDecisionMaker.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/ImportDecisionMaker.cs index 610e61f7b1..1322c27f34 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/ImportDecisionMaker.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/ImportDecisionMaker.cs @@ -169,7 +169,7 @@ private ImportDecision GetDecision(string file, Movie movie, DownloadClientItem } catch (Exception e) { - _logger.Error(e, "Couldn't import file. " + file); + _logger.Error(e, "Couldn't import file. {0}", file); var localMovie = new LocalMovie { Path = file }; decision = new ImportDecision(localMovie, new Rejection("Unexpected error processing file")); @@ -210,7 +210,7 @@ private Rejection EvaluateSpec(IImportDecisionEngineSpecification spec, LocalMov { //e.Data.Add("report", remoteEpisode.Report.ToJson()); //e.Data.Add("parsed", remoteEpisode.ParsedEpisodeInfo.ToJson()); - _logger.Error(e, "Couldn't evaluate decision on " + localMovie.Path); + _logger.Error(e, "Couldn't evaluate decision on {0}", localMovie.Path); return new Rejection(string.Format("{0}: {1}", spec.GetType().Name, e.Message)); } diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Specifications/FreeSpaceSpecification.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Specifications/FreeSpaceSpecification.cs index 6b484c4c3f..573e4a7ca6 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Specifications/FreeSpaceSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Specifications/FreeSpaceSpecification.cs @@ -55,11 +55,11 @@ public Decision IsSatisfiedBy(LocalMovie localMovie, DownloadClientItem download } catch (DirectoryNotFoundException ex) { - _logger.Error("Unable to check free disk space while importing. " + ex.Message); + _logger.Error(ex, "Unable to check free disk space while importing."); } catch (Exception ex) { - _logger.Error(ex, "Unable to check free disk space while importing: " + localMovie.Path); + _logger.Error(ex, "Unable to check free disk space while importing: {0}", localMovie.Path); } return Decision.Accept(); diff --git a/src/NzbDrone.Core/MediaFiles/RenameMovieFileService.cs b/src/NzbDrone.Core/MediaFiles/RenameMovieFileService.cs index dd2e751f14..762ad1eb29 100644 --- a/src/NzbDrone.Core/MediaFiles/RenameMovieFileService.cs +++ b/src/NzbDrone.Core/MediaFiles/RenameMovieFileService.cs @@ -126,7 +126,7 @@ private void RenameFiles(List movieFiles, Movie movie, string oldMovi } catch (Exception ex) { - _logger.Error(ex, "Failed to rename file: " + oldMovieFilePath); + _logger.Error(ex, "Failed to rename file: {0}", oldMovieFilePath); } } diff --git a/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs b/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs index bd02b00c9a..a0fdae0d8f 100644 --- a/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs +++ b/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs @@ -44,18 +44,18 @@ private void ExecuteCommands() } catch (Exception ex) { - _logger.Error(ex, "Error occurred while executing task " + command.Name); + _logger.Error(ex, "Error occurred while executing task {0}", command.Name); } } } catch (ThreadAbortException ex) { - _logger.Error(ex, "Thread aborted: " + ex.Message); + _logger.Error(ex, "Thread aborted"); Thread.ResetAbort(); } catch (Exception ex) { - _logger.Error(ex, "Unknown error in thread: " + ex.Message); + _logger.Error(ex, "Unknown error in thread"); } } diff --git a/src/NzbDrone.Core/Movies/RefreshMovieService.cs b/src/NzbDrone.Core/Movies/RefreshMovieService.cs index fb62f23a86..d8c5b68c14 100644 --- a/src/NzbDrone.Core/Movies/RefreshMovieService.cs +++ b/src/NzbDrone.Core/Movies/RefreshMovieService.cs @@ -180,7 +180,7 @@ public void Execute(RefreshMovieCommand message) } catch (Exception e) { - _logger.Error(e, "Couldn't refresh info for {0}".Inject(movie)); + _logger.Error(e, "Couldn't refresh info for {0}", movie); } } @@ -194,7 +194,7 @@ public void Execute(RefreshMovieCommand message) } catch (Exception e) { - _logger.Error(e, "Couldn't rescan movie {0}".Inject(movie)); + _logger.Error(e, "Couldn't rescan movie {0}", movie); } } } diff --git a/src/NzbDrone.Core/NetImport/HttpNetImportBase.cs b/src/NzbDrone.Core/NetImport/HttpNetImportBase.cs index 7564c448ee..07b8321b03 100644 --- a/src/NzbDrone.Core/NetImport/HttpNetImportBase.cs +++ b/src/NzbDrone.Core/NetImport/HttpNetImportBase.cs @@ -102,7 +102,7 @@ protected virtual NetImportFetchResult FetchMovies(NetImportPageableRequestChain { anyFailure = true; feedEx.Data.Add("FeedUrl", url); - _logger.Error(feedEx, "An error occurred while processing feed. " + url); + _logger.Error(feedEx, "An error occurred while processing feed. {0}", url); } return new NetImportFetchResult {Movies = movies, AnyFailure = anyFailure}; diff --git a/src/NzbDrone.Core/NetImport/RSSImport/RSSImportParser.cs b/src/NzbDrone.Core/NetImport/RSSImport/RSSImportParser.cs index 6dd0dadf40..e0727bb12d 100644 --- a/src/NzbDrone.Core/NetImport/RSSImport/RSSImportParser.cs +++ b/src/NzbDrone.Core/NetImport/RSSImport/RSSImportParser.cs @@ -54,7 +54,7 @@ public virtual IList ParseResponse(NetImportResponse importResponse) catch (Exception itemEx) { //itemEx.Data.Add("Item", item.Title()); - _logger.Error(itemEx, "An error occurred while processing feed item from " + importResponse.Request.Url); + _logger.Error(itemEx, "An error occurred while processing feed item from {0}", importResponse.Request.Url); } } diff --git a/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs b/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs index 8d26a883be..29ec52c210 100644 --- a/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs +++ b/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs @@ -52,16 +52,16 @@ public ValidationFailure Test(BoxcarSettings settings) { if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) { - _logger.Error(ex, "Access Token is invalid: " + ex.Message); + _logger.Error(ex, "Access Token is invalid: {0}", ex.Message); return new ValidationFailure("Token", "Access Token is invalid"); } - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("Token", "Unable to send test message"); } catch (Exception ex) { - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("", "Unable to send test message"); } } @@ -84,7 +84,7 @@ private void SendNotification(string title, string message, RestRequest request, { if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) { - _logger.Error(ex, "Access Token is invalid: " + ex.Message); + _logger.Error(ex, "Access Token is invalid: {0}", ex.Message); throw; } diff --git a/src/NzbDrone.Core/Notifications/Email/EmailService.cs b/src/NzbDrone.Core/Notifications/Email/EmailService.cs index 84d1ed2987..7886be4a3e 100644 --- a/src/NzbDrone.Core/Notifications/Email/EmailService.cs +++ b/src/NzbDrone.Core/Notifications/Email/EmailService.cs @@ -68,7 +68,7 @@ public ValidationFailure Test(EmailSettings settings) } catch (Exception ex) { - _logger.Error(ex, "Unable to send test email: " + ex.Message); + _logger.Error(ex, "Unable to send test email: {0}", ex.Message); return new ValidationFailure("Server", "Unable to send test email"); } diff --git a/src/NzbDrone.Core/Notifications/Growl/GrowlService.cs b/src/NzbDrone.Core/Notifications/Growl/GrowlService.cs index e62af4dc04..b17fc0ad0a 100644 --- a/src/NzbDrone.Core/Notifications/Growl/GrowlService.cs +++ b/src/NzbDrone.Core/Notifications/Growl/GrowlService.cs @@ -151,7 +151,7 @@ public ValidationFailure Test(GrowlSettings settings) } catch (Exception ex) { - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("Host", "Unable to send test message"); } diff --git a/src/NzbDrone.Core/Notifications/MediaBrowser/MediaBrowserService.cs b/src/NzbDrone.Core/Notifications/MediaBrowser/MediaBrowserService.cs index d1fc67ca9e..2a0048472d 100644 --- a/src/NzbDrone.Core/Notifications/MediaBrowser/MediaBrowserService.cs +++ b/src/NzbDrone.Core/Notifications/MediaBrowser/MediaBrowserService.cs @@ -53,7 +53,7 @@ public ValidationFailure Test(MediaBrowserSettings settings) } catch (Exception ex) { - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("Host", "Unable to send test message: " + ex.Message); } diff --git a/src/NzbDrone.Core/Notifications/NotificationService.cs b/src/NzbDrone.Core/Notifications/NotificationService.cs index 2809bcac7b..8938fe1c27 100644 --- a/src/NzbDrone.Core/Notifications/NotificationService.cs +++ b/src/NzbDrone.Core/Notifications/NotificationService.cs @@ -87,7 +87,7 @@ public void Handle(MovieGrabbedEvent message) catch (Exception ex) { - _logger.Error(ex, "Unable to send OnGrab notification to: " + notification.Definition.Name); + _logger.Error(ex, "Unable to send OnGrab notification to: {0}", notification.Definition.Name); } } } diff --git a/src/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidProxy.cs b/src/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidProxy.cs index d983c96c4d..526a74cfa1 100644 --- a/src/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidProxy.cs +++ b/src/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidProxy.cs @@ -75,7 +75,7 @@ public ValidationFailure Test(NotifyMyAndroidSettings settings) } catch (Exception ex) { - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("ApiKey", "Unable to send test message"); } diff --git a/src/NzbDrone.Core/Notifications/Plex/PlexClientService.cs b/src/NzbDrone.Core/Notifications/Plex/PlexClientService.cs index 76a6a6a0d7..ba838344be 100644 --- a/src/NzbDrone.Core/Notifications/Plex/PlexClientService.cs +++ b/src/NzbDrone.Core/Notifications/Plex/PlexClientService.cs @@ -63,7 +63,7 @@ public ValidationFailure Test(PlexClientSettings settings) } catch (Exception ex) { - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("Host", "Unable to send test message"); } diff --git a/src/NzbDrone.Core/Notifications/Plex/PlexServerService.cs b/src/NzbDrone.Core/Notifications/Plex/PlexServerService.cs index dff45d2243..2f34a573f7 100644 --- a/src/NzbDrone.Core/Notifications/Plex/PlexServerService.cs +++ b/src/NzbDrone.Core/Notifications/Plex/PlexServerService.cs @@ -175,12 +175,12 @@ public ValidationFailure Test(PlexServerSettings settings) } catch(PlexAuthenticationException ex) { - _logger.Error(ex, "Unable to connect to Plex Server: " + ex.Message); + _logger.Error(ex, "Unable to connect to Plex Server: {0}", ex.Message); return new ValidationFailure("Username", "Incorrect username or password"); } catch (Exception ex) { - _logger.Error(ex, "Unable to connect to Plex Server: " + ex.Message); + _logger.Error(ex, "Unable to connect to Plex Server: {0}", ex.Message); return new ValidationFailure("Host", "Unable to connect to Plex Server"); } diff --git a/src/NzbDrone.Core/Notifications/Prowl/ProwlService.cs b/src/NzbDrone.Core/Notifications/Prowl/ProwlService.cs index 91827524dd..308db88d2a 100644 --- a/src/NzbDrone.Core/Notifications/Prowl/ProwlService.cs +++ b/src/NzbDrone.Core/Notifications/Prowl/ProwlService.cs @@ -94,7 +94,7 @@ public ValidationFailure Test(ProwlSettings settings) } catch (Exception ex) { - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("ApiKey", "Unable to send test message"); } diff --git a/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs b/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs index ad3f23c9d5..d1fe2dd014 100644 --- a/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs +++ b/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs @@ -42,7 +42,7 @@ public void SendNotification(string title, string message, PushBulletSettings se } catch (PushBulletException ex) { - _logger.Error(ex, "Unable to send test message to: " + channelTag); + _logger.Error(ex, "Unable to send test message to: {0}", channelTag); error = true; } } @@ -61,7 +61,7 @@ public void SendNotification(string title, string message, PushBulletSettings se } catch (PushBulletException ex) { - _logger.Error(ex, "Unable to send test message to: " + deviceId); + _logger.Error(ex, "Unable to send test message to: {0}", deviceId); error = true; } } @@ -101,16 +101,16 @@ public ValidationFailure Test(PushBulletSettings settings) { if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) { - _logger.Error(ex, "API Key is invalid: " + ex.Message); + _logger.Error(ex, "API Key is invalid: {0}", ex.Message); return new ValidationFailure("ApiKey", "API Key is invalid"); } - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("ApiKey", "Unable to send test message"); } catch (Exception ex) { - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("", "Unable to send test message"); } @@ -165,7 +165,7 @@ private void SendNotification(string title, string message, RestRequest request, { if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) { - _logger.Error(ex, "API Key is invalid: " + ex.Message); + _logger.Error(ex, "API Key is invalid: {0}", ex.Message); throw; } diff --git a/src/NzbDrone.Core/Notifications/Pushalot/PushalotProxy.cs b/src/NzbDrone.Core/Notifications/Pushalot/PushalotProxy.cs index 40cdfb2355..73a05c4eed 100644 --- a/src/NzbDrone.Core/Notifications/Pushalot/PushalotProxy.cs +++ b/src/NzbDrone.Core/Notifications/Pushalot/PushalotProxy.cs @@ -73,30 +73,30 @@ public ValidationFailure Test(PushalotSettings settings) { if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) { - _logger.Error(ex, "Authentication Token is invalid: " + ex.Message); + _logger.Error(ex, "Authentication Token is invalid: {0}", ex.Message); return new ValidationFailure("AuthToken", "Authentication Token is invalid"); } if (ex.Response.StatusCode == HttpStatusCode.NotAcceptable) { - _logger.Error(ex, "Message limit reached: " + ex.Message); + _logger.Error(ex, "Message limit reached: {0}", ex.Message); return new ValidationFailure("AuthToken", "Message limit reached"); } if (ex.Response.StatusCode == HttpStatusCode.Gone) { - _logger.Error(ex, "Authorization Token is no longer valid: " + ex.Message); + _logger.Error(ex, "Authorization Token is no longer valid: {0}", ex.Message); return new ValidationFailure("AuthToken", "Authorization Token is no longer valid, please use a new one."); } var response = Json.Deserialize(ex.Response.Content); - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("AuthToken", response.Description); } catch (Exception ex) { - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("", "Unable to send test message"); } diff --git a/src/NzbDrone.Core/Notifications/Pushover/PushoverService.cs b/src/NzbDrone.Core/Notifications/Pushover/PushoverService.cs index 9960bc18a3..25bdc806a1 100644 --- a/src/NzbDrone.Core/Notifications/Pushover/PushoverService.cs +++ b/src/NzbDrone.Core/Notifications/Pushover/PushoverService.cs @@ -59,7 +59,7 @@ public ValidationFailure Test(PushoverSettings settings) } catch (Exception ex) { - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("ApiKey", "Unable to send test message"); } diff --git a/src/NzbDrone.Core/Notifications/Telegram/TelegramService.cs b/src/NzbDrone.Core/Notifications/Telegram/TelegramService.cs index 81e59322a1..068e7ca324 100644 --- a/src/NzbDrone.Core/Notifications/Telegram/TelegramService.cs +++ b/src/NzbDrone.Core/Notifications/Telegram/TelegramService.cs @@ -51,7 +51,7 @@ public ValidationFailure Test(TelegramSettings settings) } catch (Exception ex) { - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); var restException = ex as RestException; diff --git a/src/NzbDrone.Core/Notifications/Twitter/TwitterService.cs b/src/NzbDrone.Core/Notifications/Twitter/TwitterService.cs index f6e334194b..5c898310f0 100644 --- a/src/NzbDrone.Core/Notifications/Twitter/TwitterService.cs +++ b/src/NzbDrone.Core/Notifications/Twitter/TwitterService.cs @@ -131,7 +131,7 @@ public ValidationFailure Test(TwitterSettings settings) } catch (Exception ex) { - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("Host", "Unable to send test message"); } return null; diff --git a/src/NzbDrone.Core/Notifications/Xbmc/XbmcService.cs b/src/NzbDrone.Core/Notifications/Xbmc/XbmcService.cs index d3c2bbbea6..4ecc1a7f12 100644 --- a/src/NzbDrone.Core/Notifications/Xbmc/XbmcService.cs +++ b/src/NzbDrone.Core/Notifications/Xbmc/XbmcService.cs @@ -63,7 +63,7 @@ private XbmcVersion GetJsonVersion(XbmcSettings settings) { var response = _proxy.GetJsonVersion(settings); - _logger.Debug("Getting version from response: " + response); + _logger.Debug("Getting version from response: {0}", response); var result = Json.Deserialize>(response); var versionObject = result.Result.Property("version"); @@ -115,7 +115,7 @@ public ValidationFailure Test(XbmcSettings settings, string message) } catch (Exception ex) { - _logger.Error(ex, "Unable to send test message: " + ex.Message); + _logger.Error(ex, "Unable to send test message: {0}", ex.Message); return new ValidationFailure("Host", "Unable to send test message"); } diff --git a/src/NzbDrone.Core/Parser/Parser.cs b/src/NzbDrone.Core/Parser/Parser.cs index ddc7c75e79..1a8cae9579 100644 --- a/src/NzbDrone.Core/Parser/Parser.cs +++ b/src/NzbDrone.Core/Parser/Parser.cs @@ -253,7 +253,7 @@ public static ParsedMovieInfo ParseMovieTitle(string title, bool isLenient, bool catch (Exception e) { if (!title.ToLower().Contains("password") && !title.ToLower().Contains("yenc")) - Logger.Error(e, "An error has occurred while trying to parse " + title); + Logger.Error(e, "An error has occurred while trying to parse {0}", title); } Logger.Debug("Unable to parse {0}", title); diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 9f7c08b54c..7d4c992f99 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -4,9 +4,11 @@ using NLog; using NzbDrone.Common.Composition; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; using NzbDrone.Common.Processes; using NzbDrone.Common.Security; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Instrumentation; namespace Radarr.Host @@ -49,6 +51,10 @@ public static void Start(StartupContext startupContext, IUserAlert userAlert, Ac SpinToExit(appMode); } } + catch (InvalidConfigFileException ex) + { + throw new RadarrStartupException(ex); + } catch (TerminateApplicationException e) { Logger.Info(e.Message); diff --git a/src/NzbDrone.Host/BrowserService.cs b/src/NzbDrone.Host/BrowserService.cs index cf0a3a313c..14a3f0ce6f 100644 --- a/src/NzbDrone.Host/BrowserService.cs +++ b/src/NzbDrone.Host/BrowserService.cs @@ -43,7 +43,7 @@ public void LaunchWebUI() } catch (Exception e) { - _logger.Error(e, "Couldn't open default browser to " + url); + _logger.Error(e, "Couldn't open default browser to {0}", url); } } }