diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 8afeb8750e..f73b5b9274 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -10,6 +10,7 @@ true + enable diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index bdf3689f14..ed1acb4e66 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Linq; using System.Net; @@ -21,6 +22,7 @@ using MediaBrowser.Model.Globalization; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Serilog; using Serilog.Extensions.Logging; using SQLitePCL; @@ -35,7 +37,7 @@ namespace Jellyfin.Server { private static readonly CancellationTokenSource _tokenSource = new CancellationTokenSource(); private static readonly ILoggerFactory _loggerFactory = new SerilogLoggerFactory(); - private static ILogger _logger; + private static ILogger _logger = NullLogger.Instance; private static bool _restartOnShutdown; /// @@ -86,6 +88,12 @@ namespace Jellyfin.Server { var stopWatch = new Stopwatch(); stopWatch.Start(); + + // Log all uncaught exceptions to std error + static void UnhandledExceptionToConsole(object sender, UnhandledExceptionEventArgs e) => + Console.Error.WriteLine("Unhandled Exception\n" + e.ExceptionObject.ToString()); + AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionToConsole; + ServerApplicationPaths appPaths = CreateApplicationPaths(options); // $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager @@ -97,6 +105,8 @@ namespace Jellyfin.Server _logger = _loggerFactory.CreateLogger("Main"); + // Log uncaught exceptions to the logging instead of std error + AppDomain.CurrentDomain.UnhandledException -= UnhandledExceptionToConsole; AppDomain.CurrentDomain.UnhandledException += (sender, e) => _logger.LogCritical((Exception)e.ExceptionObject, "Unhandled Exception"); @@ -129,7 +139,7 @@ namespace Jellyfin.Server _logger.LogInformation( "Jellyfin version: {Version}", - Assembly.GetEntryAssembly().GetName().Version.ToString(3)); + Assembly.GetEntryAssembly()!.GetName().Version!.ToString(3)); ApplicationHost.LogEnvironmentInfo(_logger, appPaths); @@ -354,16 +364,25 @@ namespace Jellyfin.Server private static async Task CreateConfiguration(IApplicationPaths appPaths) { + const string ResourcePath = "Jellyfin.Server.Resources.Configuration.logging.json"; string configPath = Path.Combine(appPaths.ConfigurationDirectoryPath, "logging.json"); if (!File.Exists(configPath)) { // For some reason the csproj name is used instead of the assembly name - using (Stream rscstr = typeof(Program).Assembly - .GetManifestResourceStream("Jellyfin.Server.Resources.Configuration.logging.json")) - using (Stream fstr = File.Open(configPath, FileMode.CreateNew)) + using (Stream? resource = typeof(Program).Assembly.GetManifestResourceStream(ResourcePath)) { - await rscstr.CopyToAsync(fstr).ConfigureAwait(false); + if (resource == null) + { + throw new InvalidOperationException( + string.Format( + CultureInfo.InvariantCulture, + "Invalid resource path: '{0}'", + ResourcePath)); + } + + using Stream dst = File.Open(configPath, FileMode.CreateNew); + await resource.CopyToAsync(dst).ConfigureAwait(false); } } @@ -426,7 +445,7 @@ namespace Jellyfin.Server { _logger.LogInformation("Starting new instance"); - string module = options.RestartPath; + var module = options.RestartPath; if (string.IsNullOrWhiteSpace(module)) { @@ -434,7 +453,6 @@ namespace Jellyfin.Server } string commandLineArgsString; - if (options.RestartArgs != null) { commandLineArgsString = options.RestartArgs ?? string.Empty; diff --git a/Jellyfin.Server/StartupOptions.cs b/Jellyfin.Server/StartupOptions.cs index bb0adaf630..1fb1c5af8e 100644 --- a/Jellyfin.Server/StartupOptions.cs +++ b/Jellyfin.Server/StartupOptions.cs @@ -13,39 +13,39 @@ namespace Jellyfin.Server /// /// The path to the data directory. [Option('d', "datadir", Required = false, HelpText = "Path to use for the data folder (database files, etc.).")] - public string DataDir { get; set; } + public string? DataDir { get; set; } /// /// Gets or sets the path to the web directory. /// /// The path to the web directory. [Option('w', "webdir", Required = false, HelpText = "Path to the Jellyfin web UI resources.")] - public string WebDir { get; set; } + public string? WebDir { get; set; } /// /// Gets or sets the path to the cache directory. /// /// The path to the cache directory. [Option('C', "cachedir", Required = false, HelpText = "Path to use for caching.")] - public string CacheDir { get; set; } + public string? CacheDir { get; set; } /// /// Gets or sets the path to the config directory. /// /// The path to the config directory. [Option('c', "configdir", Required = false, HelpText = "Path to use for configuration data (user settings and pictures).")] - public string ConfigDir { get; set; } + public string? ConfigDir { get; set; } /// /// Gets or sets the path to the log directory. /// /// The path to the log directory. [Option('l', "logdir", Required = false, HelpText = "Path to use for writing log files.")] - public string LogDir { get; set; } + public string? LogDir { get; set; } /// [Option("ffmpeg", Required = false, HelpText = "Path to external FFmpeg executable to use in place of default found in PATH.")] - public string FFmpegPath { get; set; } + public string? FFmpegPath { get; set; } /// [Option("service", Required = false, HelpText = "Run as headless service.")] @@ -57,14 +57,14 @@ namespace Jellyfin.Server /// [Option("package-name", Required = false, HelpText = "Used when packaging Jellyfin (example, synology).")] - public string PackageName { get; set; } + public string? PackageName { get; set; } /// [Option("restartpath", Required = false, HelpText = "Path to restart script.")] - public string RestartPath { get; set; } + public string? RestartPath { get; set; } /// [Option("restartargs", Required = false, HelpText = "Arguments for restart script.")] - public string RestartArgs { get; set; } + public string? RestartArgs { get; set; } } } diff --git a/jellyfin.ruleset b/jellyfin.ruleset index 768e6dad6f..75b5573b67 100644 --- a/jellyfin.ruleset +++ b/jellyfin.ruleset @@ -6,6 +6,8 @@ + +