diff --git a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs index e0879d9241..2480b2af8b 100644 --- a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs +++ b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs @@ -26,20 +26,18 @@ namespace MediaBrowser.Api.WebSocket /// /// The _kernel /// - private readonly IApplicationHost _appHost; - private readonly IKernel _kernel; - + private readonly ILogManager _logManager; + /// /// Initializes a new instance of the class. /// /// The logger. - /// The kernel. - public LogFileWebSocketListener(ILogger logger, IApplicationHost host, IKernel kernel) + /// The log manager. + public LogFileWebSocketListener(ILogger logger, ILogManager logManager) : base(logger) { - _appHost = host; - _kernel = kernel; - kernel.LoggerLoaded += kernel_LoggerLoaded; + _logManager = logManager; + _logManager.LoggerLoaded += kernel_LoggerLoaded; } /// @@ -49,9 +47,9 @@ namespace MediaBrowser.Api.WebSocket /// IEnumerable{System.String}. protected override async Task> GetDataToSend(LogFileWebSocketState state) { - if (!string.Equals(_appHost.LogFilePath, state.LastLogFilePath)) + if (!string.Equals(_logManager.LogFilePath, state.LastLogFilePath)) { - state.LastLogFilePath = _appHost.LogFilePath; + state.LastLogFilePath = _logManager.LogFilePath; state.StartLine = 0; } @@ -70,7 +68,7 @@ namespace MediaBrowser.Api.WebSocket { if (dispose) { - _kernel.LoggerLoaded -= kernel_LoggerLoaded; + _logManager.LoggerLoaded -= kernel_LoggerLoaded; } base.Dispose(dispose); } diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index f5855bf753..eeef6225dd 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -1,6 +1,7 @@ using System.IO; using System.Linq; using System.Reflection; +using MediaBrowser.Common.Kernel; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using SimpleInjector; @@ -18,6 +19,18 @@ namespace MediaBrowser.Common.Implementations /// The logger. public ILogger Logger { get; protected set; } + /// + /// Gets or sets the log manager. + /// + /// The log manager. + public ILogManager LogManager { get; protected set; } + + /// + /// Gets the application paths. + /// + /// The application paths. + protected IApplicationPaths ApplicationPaths { get; private set; } + /// /// The container /// @@ -45,6 +58,12 @@ namespace MediaBrowser.Common.Implementations /// protected readonly List DisposableParts = new List(); + /// + /// Gets a value indicating whether this instance is first run. + /// + /// true if this instance is first run; otherwise, false. + public bool IsFirstRun { get; private set; } + /// /// The _protobuf serializer initialized /// @@ -82,6 +101,16 @@ namespace MediaBrowser.Common.Implementations protected BaseApplicationHost() { FailedAssemblies = new List(); + + ApplicationPaths = GetApplicationPaths(); + + LogManager = GetLogManager(); + + Logger = LogManager.GetLogger("App"); + + IsFirstRun = !File.Exists(ApplicationPaths.SystemConfigurationFilePath); + + DiscoverTypes(); } /// @@ -90,6 +119,18 @@ namespace MediaBrowser.Common.Implementations /// IEnumerable{Assembly}. protected abstract IEnumerable GetComposablePartAssemblies(); + /// + /// Gets the log manager. + /// + /// ILogManager. + protected abstract ILogManager GetLogManager(); + + /// + /// Gets the application paths. + /// + /// IApplicationPaths. + protected abstract IApplicationPaths GetApplicationPaths(); + /// /// Discovers the types. /// diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs index ac06f111a2..ea1e8b9382 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs @@ -14,25 +14,32 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks public class ReloadLoggerFileTask : IScheduledTask { /// - /// Gets or sets the kernel. + /// Gets or sets the log manager. /// - /// The kernel. - private IKernel Kernel { get; set; } + /// The log manager. + private ILogManager LogManager { get; set; } /// /// Gets or sets the logger. /// /// The logger. private ILogger Logger { get; set; } + /// + /// Gets or sets the kernel. + /// + /// The kernel. + private IKernel Kernel { get; set; } /// /// Initializes a new instance of the class. /// - /// The kernel. + /// The logManager. /// The logger. - public ReloadLoggerFileTask(IKernel kernel, ILogger logger) + /// The kernel. + public ReloadLoggerFileTask(ILogManager logManager, ILogger logger, IKernel kernel) { - Kernel = kernel; + LogManager = logManager; Logger = logger; + Kernel = kernel; } /// @@ -57,8 +64,8 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks cancellationToken.ThrowIfCancellationRequested(); progress.Report(0); - - return Task.Run(() => Kernel.ReloadLogger()); + + return Task.Run(() => LogManager.ReloadLogger(Kernel.Configuration.EnableDebugLevelLogging ? LogSeverity.Debug : LogSeverity.Info)); } /// diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs index 2ec1dd829d..184cef98b8 100644 --- a/MediaBrowser.Common/Kernel/BaseKernel.cs +++ b/MediaBrowser.Common/Kernel/BaseKernel.cs @@ -42,20 +42,6 @@ namespace MediaBrowser.Common.Kernel } #endregion - #region LoggerLoaded Event - /// - /// Fires whenever the logger is loaded - /// - public event EventHandler LoggerLoaded; - /// - /// Called when [logger loaded]. - /// - private void OnLoggerLoaded() - { - EventHelper.QueueEventIfNotNull(LoggerLoaded, this, EventArgs.Empty, Logger); - } - #endregion - #region ReloadBeginning Event /// /// Fires whenever the kernel begins reloading @@ -277,16 +263,6 @@ namespace MediaBrowser.Common.Kernel return Task.FromResult(null); } - /// - /// Disposes and reloads all loggers - /// - public void ReloadLogger() - { - ApplicationHost.ReloadLogger(); - - OnLoggerLoaded(); - } - /// /// Composes the parts with ioc container. /// diff --git a/MediaBrowser.Common/Kernel/IApplicationHost.cs b/MediaBrowser.Common/Kernel/IApplicationHost.cs index 1f99d10dbc..42ba2fbbb2 100644 --- a/MediaBrowser.Common/Kernel/IApplicationHost.cs +++ b/MediaBrowser.Common/Kernel/IApplicationHost.cs @@ -16,23 +16,12 @@ namespace MediaBrowser.Common.Kernel /// void Restart(); - /// - /// Reloads the logger. - /// - void ReloadLogger(); - /// /// Gets the application version. /// /// The application version. Version ApplicationVersion { get; } - /// - /// Gets the log file path. - /// - /// The log file path. - string LogFilePath { get; } - /// /// Gets or sets a value indicating whether this instance can self update. /// diff --git a/MediaBrowser.Common/Kernel/IKernel.cs b/MediaBrowser.Common/Kernel/IKernel.cs index a28500eca7..0ffd46d027 100644 --- a/MediaBrowser.Common/Kernel/IKernel.cs +++ b/MediaBrowser.Common/Kernel/IKernel.cs @@ -53,11 +53,6 @@ namespace MediaBrowser.Common.Kernel /// SystemInfo. SystemInfo GetSystemInfo(); - /// - /// Reloads the logger. - /// - void ReloadLogger(); - /// /// Called when [application updated]. /// @@ -105,11 +100,6 @@ namespace MediaBrowser.Common.Kernel /// The web socket listeners. IEnumerable WebSocketListeners { get; } - /// - /// Occurs when [logger loaded]. - /// - event EventHandler LoggerLoaded; - /// /// Occurs when [reload completed]. /// diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index ed49d26d86..7cb838e44c 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -531,18 +531,9 @@ namespace MediaBrowser.Controller /// The config. public void UpdateConfiguration(ServerConfiguration config) { - var oldConfiguration = Configuration; - - var reloadLogger = config.ShowLogWindow != oldConfiguration.ShowLogWindow; - Configuration = config; SaveConfiguration(); - if (reloadLogger) - { - ReloadLogger(); - } - // Validate currently executing providers, in the background Task.Run(() => { diff --git a/MediaBrowser.Logging.NLog/NlogManager.cs b/MediaBrowser.Logging.NLog/NlogManager.cs index 4d6aeadd88..fa69b94a01 100644 --- a/MediaBrowser.Logging.NLog/NlogManager.cs +++ b/MediaBrowser.Logging.NLog/NlogManager.cs @@ -1,27 +1,62 @@ -using NLog; +using MediaBrowser.Model.Logging; +using NLog; using NLog.Config; using NLog.Targets; +using System; +using System.IO; +using System.Threading.Tasks; namespace MediaBrowser.Logging.Nlog { /// /// Class NlogManager /// - public static class NlogManager + public class NlogManager : ILogManager { + /// + /// Occurs when [logger loaded]. + /// + public event EventHandler LoggerLoaded; + /// + /// Gets or sets the log directory. + /// + /// The log directory. + private string LogDirectory { get; set; } + /// + /// Gets or sets the log file prefix. + /// + /// The log file prefix. + private string LogFilePrefix { get; set; } + /// + /// Gets the log file path. + /// + /// The log file path. + public string LogFilePath { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The log directory. + /// The log file name prefix. + public NlogManager(string logDirectory, string logFileNamePrefix) + { + LogDirectory = logDirectory; + LogFilePrefix = logFileNamePrefix; + } + /// /// Adds the file target. /// /// The path. - /// if set to true [enable debug logging]. - public static void AddFileTarget(string path, bool enableDebugLogging) + /// The level. + private void AddFileTarget(string path, LogSeverity level) { var logFile = new FileTarget(); logFile.FileName = path; logFile.Layout = "${longdate}, ${level}, ${logger}, ${message}"; - AddLogTarget(logFile, "ApplicationLogFile", enableDebugLogging); + AddLogTarget(logFile, "ApplicationLogFile", level); } /// @@ -29,8 +64,8 @@ namespace MediaBrowser.Logging.Nlog /// /// The target. /// The name. - /// if set to true [enable debug logging]. - private static void AddLogTarget(Target target, string name, bool enableDebugLogging) + /// The level. + private void AddLogTarget(Target target, string name, LogSeverity level) { var config = LogManager.Configuration; @@ -39,12 +74,71 @@ namespace MediaBrowser.Logging.Nlog target.Name = name; config.AddTarget(name, target); - var level = enableDebugLogging ? LogLevel.Debug : LogLevel.Info; - - var rule = new LoggingRule("*", level, target); + var rule = new LoggingRule("*", GetLogLevel(level), target); config.LoggingRules.Add(rule); LogManager.Configuration = config; } + + /// + /// Gets the logger. + /// + /// The name. + /// ILogger. + public ILogger GetLogger(string name) + { + return new NLogger(name); + } + + /// + /// Gets the log level. + /// + /// The severity. + /// LogLevel. + /// Unrecognized LogSeverity + private LogLevel GetLogLevel(LogSeverity severity) + { + switch (severity) + { + case LogSeverity.Debug: + return LogLevel.Debug; + case LogSeverity.Error: + return LogLevel.Error; + case LogSeverity.Fatal: + return LogLevel.Fatal; + case LogSeverity.Info: + return LogLevel.Info; + case LogSeverity.Warn: + return LogLevel.Warn; + default: + throw new ArgumentException("Unrecognized LogSeverity"); + } + } + + /// + /// Reloads the logger. + /// + /// The level. + public void ReloadLogger(LogSeverity level) + { + LogFilePath = Path.Combine(LogDirectory, LogFilePrefix + "-" + DateTime.Now.Ticks + ".log"); + + AddFileTarget(LogFilePath, level); + + if (LoggerLoaded != null) + { + Task.Run(() => + { + try + { + LoggerLoaded(this, EventArgs.Empty); + } + catch (Exception ex) + { + GetLogger("Logger").ErrorException("Error in LoggerLoaded event", ex); + } + }); + } + } } } diff --git a/MediaBrowser.Model/Logging/ILogManager.cs b/MediaBrowser.Model/Logging/ILogManager.cs new file mode 100644 index 0000000000..1d6db2bd83 --- /dev/null +++ b/MediaBrowser.Model/Logging/ILogManager.cs @@ -0,0 +1,33 @@ +using System; + +namespace MediaBrowser.Model.Logging +{ + /// + /// Interface ILogManager + /// + public interface ILogManager + { + /// + /// Gets the logger. + /// + /// The name. + /// ILogger. + ILogger GetLogger(string name); + + /// + /// Reloads the logger. + /// + void ReloadLogger(LogSeverity severity); + + /// + /// Gets the log file path. + /// + /// The log file path. + string LogFilePath { get; } + + /// + /// Occurs when [logger loaded]. + /// + event EventHandler LoggerLoaded; + } +} diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 8e8f88c20e..ba3818160c 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -48,6 +48,7 @@ + diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 07246eded6..2cdb5789b4 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -12,6 +12,7 @@ using MediaBrowser.Controller; using MediaBrowser.IsoMounter; using MediaBrowser.Logging.Nlog; using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.System; @@ -39,12 +40,6 @@ namespace MediaBrowser.ServerApplication /// public class ApplicationHost : BaseApplicationHost, IApplicationHost { - /// - /// Gets or sets the log file path. - /// - /// The log file path. - public string LogFilePath { get; private set; } - /// /// Gets or sets the kernel. /// @@ -62,15 +57,13 @@ namespace MediaBrowser.ServerApplication private readonly IXmlSerializer _xmlSerializer = new XmlSerializer(); /// - /// The _application paths + /// Gets the server application paths. /// - private readonly IServerApplicationPaths _applicationPaths = new ServerApplicationPaths(); - - /// - /// Gets a value indicating whether this instance is first run. - /// - /// true if this instance is first run; otherwise, false. - public bool IsFirstRun { get; private set; } + /// The server application paths. + protected IServerApplicationPaths ServerApplicationPaths + { + get { return (IServerApplicationPaths) ApplicationPaths; } + } /// /// Initializes a new instance of the class. @@ -79,21 +72,15 @@ namespace MediaBrowser.ServerApplication public ApplicationHost() : base() { - IsFirstRun = !File.Exists(_applicationPaths.SystemConfigurationFilePath); - - Logger = new NLogger("App"); - - DiscoverTypes(); - - Kernel = new Kernel(this, _applicationPaths, _xmlSerializer, Logger); + Kernel = new Kernel(this, ServerApplicationPaths, _xmlSerializer, Logger); var networkManager = new NetworkManager(); var serverManager = new ServerManager(this, Kernel, networkManager, _jsonSerializer, Logger); - var taskManager = new TaskManager(_applicationPaths, _jsonSerializer, Logger, serverManager); + var taskManager = new TaskManager(ApplicationPaths, _jsonSerializer, Logger, serverManager); - ReloadLogger(); + LogManager.ReloadLogger(Kernel.Configuration.EnableDebugLevelLogging ? LogSeverity.Debug : LogSeverity.Info); Logger.Info("Version {0} initializing", ApplicationVersion); @@ -104,6 +91,24 @@ namespace MediaBrowser.ServerApplication FindParts(taskManager, httpServer); } + /// + /// Gets the application paths. + /// + /// IApplicationPaths. + protected override IApplicationPaths GetApplicationPaths() + { + return new ServerApplicationPaths(); + } + + /// + /// Gets the log manager. + /// + /// ILogManager. + protected override ILogManager GetLogManager() + { + return new NlogManager(ApplicationPaths.LogDirectoryPath, "Server"); + } + /// /// Registers resources that classes will depend on /// @@ -113,14 +118,15 @@ namespace MediaBrowser.ServerApplication RegisterSingleInstance(Kernel); RegisterSingleInstance(this); + RegisterSingleInstance(LogManager); RegisterSingleInstance(Logger); - RegisterSingleInstance(_applicationPaths); - RegisterSingleInstance(_applicationPaths); + RegisterSingleInstance(ApplicationPaths); + RegisterSingleInstance(ServerApplicationPaths); RegisterSingleInstance(taskManager); RegisterSingleInstance(new PismoIsoManager(Logger)); RegisterSingleInstance(new BdInfoExaminer()); - RegisterSingleInstance(new HttpManager(_applicationPaths, Logger)); + RegisterSingleInstance(new HttpManager(ApplicationPaths, Logger)); RegisterSingleInstance(new DotNetZipClient()); RegisterSingleInstance(() => new AlchemyServer(Logger)); RegisterSingleInstance(_jsonSerializer); @@ -147,23 +153,11 @@ namespace MediaBrowser.ServerApplication /// /// Restarts this instance. /// - /// public void Restart() { App.Instance.Restart(); } - /// - /// Reloads the logger. - /// - /// - public void ReloadLogger() - { - LogFilePath = Path.Combine(_applicationPaths.LogDirectoryPath, "Server-" + DateTime.Now.Ticks + ".log"); - - NlogManager.AddFileTarget(LogFilePath, Kernel.Configuration.EnableDebugLevelLogging); - } - /// /// Gets or sets a value indicating whether this instance can self update. /// @@ -204,7 +198,7 @@ namespace MediaBrowser.ServerApplication // Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that // This will prevent the .dll file from getting locked, and allow us to replace it when needed foreach (var pluginAssembly in Directory - .EnumerateFiles(_applicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly) + .EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly) .Select(LoadAssembly).Where(a => a != null)) { yield return pluginAssembly; diff --git a/MediaBrowser.ServerApplication/MainWindow.xaml.cs b/MediaBrowser.ServerApplication/MainWindow.xaml.cs index fc0f0efc9b..b3b26f57a1 100644 --- a/MediaBrowser.ServerApplication/MainWindow.xaml.cs +++ b/MediaBrowser.ServerApplication/MainWindow.xaml.cs @@ -55,6 +55,11 @@ namespace MediaBrowser.ServerApplication /// private readonly IApplicationHost _appHost; + /// + /// The _log manager + /// + private readonly ILogManager _logManager; + /// /// Initializes a new instance of the class. /// @@ -62,20 +67,21 @@ namespace MediaBrowser.ServerApplication /// The logger. /// The app host. /// logger - public MainWindow(IJsonSerializer jsonSerializer, ILogger logger, IApplicationHost appHost) + public MainWindow(IJsonSerializer jsonSerializer, ILogManager logManager, IApplicationHost appHost) { if (jsonSerializer == null) { throw new ArgumentNullException("jsonSerializer"); } - if (logger == null) + if (logManager == null) { - throw new ArgumentNullException("logger"); + throw new ArgumentNullException("logManager"); } _jsonSerializer = jsonSerializer; - _logger = logger; + _logger = logManager.GetLogger("MainWindow"); _appHost = appHost; + _logManager = logManager; InitializeComponent(); @@ -94,7 +100,7 @@ namespace MediaBrowser.ServerApplication Instance_ConfigurationUpdated(null, EventArgs.Empty); Kernel.Instance.ReloadCompleted += KernelReloadCompleted; - Kernel.Instance.LoggerLoaded += LoadLogWindow; + _logManager.LoggerLoaded += LoadLogWindow; Kernel.Instance.HasPendingRestartChanged += Instance_HasPendingRestartChanged; Kernel.Instance.ConfigurationUpdated += Instance_ConfigurationUpdated; } @@ -115,6 +121,13 @@ namespace MediaBrowser.ServerApplication separatorDeveloperTools.Visibility = developerToolsVisibility; cmdReloadServer.Visibility = developerToolsVisibility; cmOpenExplorer.Visibility = developerToolsVisibility; + + var logWindow = App.Instance.Windows.OfType().FirstOrDefault(); + + if ((logWindow == null && Kernel.Instance.Configuration.ShowLogWindow) || (logWindow != null && !Kernel.Instance.Configuration.ShowLogWindow)) + { + _logManager.ReloadLogger(Kernel.Instance.Configuration.EnableDebugLevelLogging ? LogSeverity.Debug : LogSeverity.Info); + } }); }