using System; using System.Diagnostics; using System.IO; using System.Linq; using LogentriesNLog; using NLog; using NLog.Config; using NLog.Targets; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Common.Instrumentation.Sentry; namespace NzbDrone.Common.Instrumentation { public static class NzbDroneLogger { private static bool _isConfigured; static NzbDroneLogger() { LogManager.Configuration = new LoggingConfiguration(); } public static void Register(IStartupContext startupContext, bool updateApp, bool inConsole) { if (_isConfigured) { throw new InvalidOperationException("Loggers have already been registered."); } _isConfigured = true; GlobalExceptionHandlers.Register(); var appFolderInfo = new AppFolderInfo(startupContext); if (Debugger.IsAttached) { RegisterDebugger(); } RegisterSentry(updateApp); if (updateApp) { RegisterUpdateFile(appFolderInfo); RegisterLogEntries(); } else { if (inConsole && (OsInfo.IsNotWindows || RuntimeInfo.IsUserInteractive)) { RegisterConsole(); } RegisterAppFile(appFolderInfo); } LogManager.ReconfigExistingLoggers(); } public static void UnRegisterRemoteLoggers() { var sentryRules = LogManager.Configuration.LoggingRules.Where(r => r.Targets.Any(t => t.Name == "sentryTarget")); foreach (var rules in sentryRules) { rules.Targets.Clear(); } LogManager.ReconfigExistingLoggers(); } private static void RegisterLogEntries() { var target = new LogentriesTarget(); target.Name = "logentriesTarget"; target.Token = "d3a83ee9-74fb-4045-ad25-a84c1d4d7c81"; target.LogHostname = true; target.Debug = false; var loggingRule = new LoggingRule("*", LogLevel.Info, target); LogManager.Configuration.AddTarget("logentries", target); LogManager.Configuration.LoggingRules.Add(loggingRule); } private static void RegisterSentry(bool updateClient) { string dsn; if (updateClient) { dsn = RuntimeInfo.IsProduction ? "https://b85aa82c65b84b0e99e3b7c281438357:392b5bc007974147a922c5d841c47cf9@sentry.sonarr.tv/11" : "https://6168f0946aba4e60ac23e469ac08eac5:bd59e8454ccc454ea27a90cff1f814ca@sentry.sonarr.tv/9"; } else { dsn = RuntimeInfo.IsProduction ? "https://a013727b8d224e719894e1e13ff4966b:c95ca1f9ca02418d829db10c2938baf4@sentry.sonarr.tv/8" : "https://4ee3580e01d8407c96a7430fbc953512:5f2d07227a0b4fde99dea07041a3ff93@sentry.sonarr.tv/10"; } var target = new SentryTarget(dsn) { Name = "sentryTarget", Layout = "${message}" }; var loggingRule = new LoggingRule("*", updateClient ? LogLevel.Trace : LogLevel.Warn, target); LogManager.Configuration.AddTarget("sentryTarget", target); LogManager.Configuration.LoggingRules.Add(loggingRule); // Events logged to Sentry go only to Sentry. var loggingRuleSentry = new LoggingRule("Sentry", LogLevel.Debug, target) { Final = true }; LogManager.Configuration.LoggingRules.Insert(0, loggingRuleSentry); } private static void RegisterDebugger() { DebuggerTarget target = new DebuggerTarget(); target.Name = "debuggerLogger"; target.Layout = "[${level}] [${threadid}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}}"; var loggingRule = new LoggingRule("*", LogLevel.Trace, target); LogManager.Configuration.AddTarget("debugger", target); LogManager.Configuration.LoggingRules.Add(loggingRule); } private static void RegisterConsole() { var level = LogLevel.Trace; var coloredConsoleTarget = new ColoredConsoleTarget(); coloredConsoleTarget.Name = "consoleLogger"; coloredConsoleTarget.Layout = "[${level}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}}"; var loggingRule = new LoggingRule("*", level, coloredConsoleTarget); LogManager.Configuration.AddTarget("console", coloredConsoleTarget); LogManager.Configuration.LoggingRules.Add(loggingRule); } private const string FILE_LOG_LAYOUT = @"${date:format=yy-M-d HH\:mm\:ss.f}|${level}|${logger}|${message}${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}}"; private static void RegisterAppFile(IAppFolderInfo appFolderInfo) { RegisterAppFile(appFolderInfo, "appFileInfo", "sonarr.txt", 5, LogLevel.Info); RegisterAppFile(appFolderInfo, "appFileDebug", "sonarr.debug.txt", 50, LogLevel.Off); RegisterAppFile(appFolderInfo, "appFileTrace", "sonarr.trace.txt", 50, LogLevel.Off); } private static void RegisterAppFile(IAppFolderInfo appFolderInfo, string name, string fileName, int maxArchiveFiles, LogLevel minLogLevel) { var fileTarget = new NzbDroneFileTarget(); fileTarget.Name = name; fileTarget.FileName = Path.Combine(appFolderInfo.GetLogFolder(), fileName); fileTarget.AutoFlush = true; fileTarget.KeepFileOpen = false; fileTarget.ConcurrentWrites = false; fileTarget.ConcurrentWriteAttemptDelay = 50; fileTarget.ConcurrentWriteAttempts = 10; fileTarget.ArchiveAboveSize = 1024000; fileTarget.MaxArchiveFiles = maxArchiveFiles; fileTarget.EnableFileDelete = true; fileTarget.ArchiveNumbering = ArchiveNumberingMode.Rolling; fileTarget.Layout = FILE_LOG_LAYOUT; var loggingRule = new LoggingRule("*", minLogLevel, fileTarget); LogManager.Configuration.AddTarget(name, fileTarget); LogManager.Configuration.LoggingRules.Add(loggingRule); } private static void RegisterUpdateFile(IAppFolderInfo appFolderInfo) { var fileTarget = new FileTarget(); fileTarget.Name = "updateFileLogger"; fileTarget.FileName = Path.Combine(appFolderInfo.GetUpdateLogFolder(), DateTime.Now.ToString("yyyy.MM.dd-HH.mm") + ".txt"); fileTarget.AutoFlush = true; fileTarget.KeepFileOpen = false; fileTarget.ConcurrentWrites = false; fileTarget.ConcurrentWriteAttemptDelay = 50; fileTarget.ConcurrentWriteAttempts = 100; fileTarget.Layout = FILE_LOG_LAYOUT; var loggingRule = new LoggingRule("*", LogLevel.Trace, fileTarget); LogManager.Configuration.AddTarget("updateFile", fileTarget); LogManager.Configuration.LoggingRules.Add(loggingRule); } public static Logger GetLogger(Type obj) { return LogManager.GetLogger(obj.Name.Replace("NzbDrone.", "")); } public static Logger GetLogger(object obj) { return GetLogger(obj.GetType()); } } }