diff --git a/src/ARKServerManager/App.config b/src/ARKServerManager/App.config index 83ff6ff9..383dba97 100644 --- a/src/ARKServerManager/App.config +++ b/src/ARKServerManager/App.config @@ -239,7 +239,7 @@ 5 - + http://arkservermanager.freeforums.net/board/22/plugins @@ -564,9 +564,6 @@ False - - - True @@ -600,7 +597,7 @@ False - + @@ -715,7 +712,7 @@ 500 - True + False True @@ -866,6 +863,15 @@ False + + True + + + 30 + + + 30 + diff --git a/src/ARKServerManager/App.xaml.cs b/src/ARKServerManager/App.xaml.cs index c89867ed..cdcd030b 100644 --- a/src/ARKServerManager/App.xaml.cs +++ b/src/ARKServerManager/App.xaml.cs @@ -50,9 +50,9 @@ namespace ServerManagerTool public App() { - if (string.IsNullOrWhiteSpace(Config.Default.ASMUniqueKey)) + if (string.IsNullOrWhiteSpace(Config.Default.ServerManagerUniqueKey)) { - Config.Default.ASMUniqueKey = Guid.NewGuid().ToString(); + Config.Default.ServerManagerUniqueKey = Guid.NewGuid().ToString(); } if (!string.IsNullOrWhiteSpace(Config.Default.DataDir)) @@ -233,27 +233,30 @@ namespace ServerManagerTool public static string GetProfileLogFolder(string profileId) => IOUtils.NormalizePath(Path.Combine(Config.Default.DataDir, Config.Default.LogsDir, profileId.ToLower())); - public static Logger GetProfileLogger(string profileId, string name, LogLevel minLevel, LogLevel maxLevel) + public static Logger GetProfileLogger(string profileId, string logName, LogLevel minLevel, LogLevel maxLevel) { - if (string.IsNullOrWhiteSpace(profileId) || string.IsNullOrWhiteSpace(name)) + if (string.IsNullOrWhiteSpace(profileId) || string.IsNullOrWhiteSpace(logName)) return null; - var loggerName = $"{profileId.ToLower()}_{name}".Replace(" ", "_"); + var loggerName = $"{profileId.ToLower()}_{logName}".Replace(" ", "_"); if (LogManager.Configuration.FindTargetByName(loggerName) == null) - { + { var logFilePath = GetProfileLogFolder(profileId); if (!System.IO.Directory.Exists(logFilePath)) System.IO.Directory.CreateDirectory(logFilePath); var logFile = new FileTarget(loggerName) { - FileName = Path.Combine(logFilePath, $"{name}.log"), - Layout = "${time} ${message}", - ArchiveFileName = Path.Combine(logFilePath, $"{name}.{{#}}.log"), + FileName = Path.Combine(logFilePath, $"{logName}.log"), + Layout = "${time} [${level:uppercase=true}] ${message}", + ArchiveFileName = Path.Combine(logFilePath, $"{logName}.{{#}}.log"), ArchiveNumbering = ArchiveNumberingMode.DateAndSequence, ArchiveEvery = FileArchivePeriod.Day, - ArchiveDateFormat = "yyyyMMdd" + ArchiveDateFormat = "yyyyMMdd", + ArchiveOldFileOnStartup = true, + MaxArchiveFiles = Config.Default.LoggingMaxArchiveFiles, + MaxArchiveDays = Config.Default.LoggingMaxArchiveDays, }; LogManager.Configuration.AddTarget(loggerName, logFile); @@ -291,12 +294,6 @@ namespace ServerManagerTool SettingsUtils.MigrateSettings(Config.Default, settingsFile); Config.Default.UpgradeConfig = false; Config.Default.Save(); - - if (string.IsNullOrWhiteSpace(CommonConfig.Default.SteamAPIKey)) - { - CommonConfig.Default.SteamAPIKey = Config.Default.SteamAPIKey; - CommonConfig.Default.Save(); - } } if (!Config.Default.DiscordBotPrefixFixed) { @@ -370,14 +367,14 @@ namespace ServerManagerTool PluginHelper.Instance.SetFetchProfileCallback(DiscordPluginHelper.FetchProfiles); OnResourceDictionaryChanged(Thread.CurrentThread.CurrentCulture.Name); - // check if we are starting ASM for the old server restart - no longer supported + // check if we are starting server manager for the old server restart - no longer supported if (e.Args.Any(a => a.StartsWith(Constants.ARG_AUTORESTART, StringComparison.OrdinalIgnoreCase))) { // just exit Environment.Exit(0); } - // check if we are starting ASM for server shutdown + // check if we are starting server manager for server shutdown if (e.Args.Any(a => a.StartsWith(Constants.ARG_AUTOSHUTDOWN1, StringComparison.OrdinalIgnoreCase))) { var arg = e.Args.FirstOrDefault(a => a.StartsWith(Constants.ARG_AUTOSHUTDOWN1, StringComparison.OrdinalIgnoreCase)); @@ -387,7 +384,7 @@ namespace ServerManagerTool Environment.Exit(exitCode); } - // check if we are starting ASM for server shutdown + // check if we are starting server manager for server shutdown if (e.Args.Any(a => a.StartsWith(Constants.ARG_AUTOSHUTDOWN2, StringComparison.OrdinalIgnoreCase))) { var arg = e.Args.FirstOrDefault(a => a.StartsWith(Constants.ARG_AUTOSHUTDOWN2, StringComparison.OrdinalIgnoreCase)); @@ -397,7 +394,7 @@ namespace ServerManagerTool Environment.Exit(exitCode); } - // check if we are starting ASM for server updating + // check if we are starting server manager for server updating if (e.Args.Any(a => a.Equals(Constants.ARG_AUTOUPDATE, StringComparison.OrdinalIgnoreCase))) { var exitCode = ServerApp.PerformAutoUpdate(); @@ -406,7 +403,7 @@ namespace ServerManagerTool Environment.Exit(exitCode); } - // check if we are starting ASM for server backups + // check if we are starting server manager for server backups if (e.Args.Any(a => a.Equals(Constants.ARG_AUTOBACKUP, StringComparison.OrdinalIgnoreCase))) { var exitCode = ServerApp.PerformAutoBackup(); @@ -469,7 +466,7 @@ namespace ServerManagerTool var restartRequired = false; if (string.IsNullOrWhiteSpace(Config.Default.DataDir)) - { + { var dataDirectoryWindow = new DataDirectoryWindow(); dataDirectoryWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen; var result = dataDirectoryWindow.ShowDialog(); @@ -479,7 +476,7 @@ namespace ServerManagerTool Environment.Exit(0); } - restartRequired = true; + restartRequired = true; } Config.Default.ConfigDirectory = Path.Combine(Config.Default.DataDir, Config.Default.ProfilesDir); @@ -533,8 +530,10 @@ namespace ServerManagerTool } public static void ReconfigureLogging() - { - string logDir = Path.Combine(Config.Default.DataDir, Config.Default.LogsDir); + { + UpdateLoggingStatus(); + + var logDir = Path.Combine(Config.Default.DataDir, Config.Default.LogsDir); if (!System.IO.Directory.Exists(logDir)) System.IO.Directory.CreateDirectory(logDir); @@ -546,10 +545,31 @@ namespace ServerManagerTool var fileName = Path.GetFileNameWithoutExtension(fileTarget.FileName.ToString()); fileTarget.FileName = Path.Combine(logDir, $"{fileName}.log"); fileTarget.ArchiveFileName = Path.Combine(logDir, $"{fileName}.{{#}}.log"); + fileTarget.MaxArchiveFiles = Config.Default.LoggingMaxArchiveFiles; + fileTarget.MaxArchiveDays = Config.Default.LoggingMaxArchiveDays; } LogManager.ReconfigExistingLoggers(); - } + } + + public static void SaveConfigFiles(bool includeBackup = true) + { + Config.Default.Save(); + CommonConfig.Default.Save(); + + Config.Default.Reload(); + CommonConfig.Default.Reload(); + + var installFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + var backupFolder = includeBackup + ? string.IsNullOrWhiteSpace(Config.Default.BackupPath) + ? Path.Combine(Config.Default.DataDir, Config.Default.BackupDir) + : Path.Combine(Config.Default.BackupPath) + : null; + + SettingsUtils.BackupUserConfigSettings(Config.Default, "userconfig.json", installFolder, backupFolder); + SettingsUtils.BackupUserConfigSettings(CommonConfig.Default, "commonconfig.json", installFolder, backupFolder); + } private void ShutDownApplication() { @@ -572,29 +592,12 @@ namespace ServerManagerTool } PluginHelper.Instance?.Dispose(); + LogManager.Flush(); + LogManager.Shutdown(); ApplicationStarted = false; } - public static void SaveConfigFiles(bool includeBackup = true) - { - Config.Default.Save(); - CommonConfig.Default.Save(); - - Config.Default.Reload(); - CommonConfig.Default.Reload(); - - var installFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - var backupFolder = includeBackup - ? string.IsNullOrWhiteSpace(Config.Default.BackupPath) - ? Path.Combine(Config.Default.DataDir, Config.Default.BackupDir) - : Path.Combine(Config.Default.BackupPath) - : null; - - SettingsUtils.BackupUserConfigSettings(Config.Default, "userconfig.json", installFolder, backupFolder); - SettingsUtils.BackupUserConfigSettings(CommonConfig.Default, "commonconfig.json", installFolder, backupFolder); - } - public void StartDiscordBot() { if (_tokenSourceDiscordBot != null) @@ -610,6 +613,8 @@ namespace ServerManagerTool var config = new DiscordBotConfig { LogLevel = Config.Default.DiscordBotLogLevel, + MaxArchiveFiles = Config.Default.LoggingMaxArchiveFiles, + MaxArchiveDays = Config.Default.LoggingMaxArchiveDays, DiscordToken = Config.Default.DiscordBotToken, CommandPrefix = Config.Default.DiscordBotPrefix, DataDirectory = Config.Default.DataDir, @@ -656,5 +661,21 @@ namespace ServerManagerTool _tokenSourceDiscordBot.Cancel(); } } + + public static void UpdateLoggingStatus() + { + if (Config.Default.LoggingEnabled) + { + while (!LogManager.IsLoggingEnabled()) + LogManager.EnableLogging(); + } + else + { + while (LogManager.IsLoggingEnabled()) + LogManager.DisableLogging(); + } + + Debug.WriteLine($"Logging Enabled: {LogManager.IsLoggingEnabled()}"); + } } } diff --git a/src/ARKServerManager/Config.Designer.cs b/src/ARKServerManager/Config.Designer.cs index 59e049e6..a3cf728c 100644 --- a/src/ARKServerManager/Config.Designer.cs +++ b/src/ARKServerManager/Config.Designer.cs @@ -1451,18 +1451,6 @@ namespace ServerManagerTool { } } - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string SteamAPIKey { - get { - return ((string)(this["SteamAPIKey"])); - } - set { - this["SteamAPIKey"] = value; - } - } - [global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("https://steamcommunity.com/dev/apikey")] @@ -1635,12 +1623,12 @@ namespace ServerManagerTool { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("")] - public string ASMUniqueKey { + public string ServerManagerUniqueKey { get { - return ((string)(this["ASMUniqueKey"])); + return ((string)(this["ServerManagerUniqueKey"])); } set { - this["ASMUniqueKey"] = value; + this["ServerManagerUniqueKey"] = value; } } @@ -1803,9 +1791,9 @@ namespace ServerManagerTool { [global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("http://arkservermanager.freeforums.net/board/22/plugins")] - public string ASMPluginUrl { + public string ServerManagerPluginUrl { get { - return ((string)(this["ASMPluginUrl"])); + return ((string)(this["ServerManagerPluginUrl"])); } } @@ -2374,7 +2362,7 @@ namespace ServerManagerTool { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("True")] + [global::System.Configuration.DefaultSettingValueAttribute("False")] public bool UpdateDirectoryPermissions { get { return ((bool)(this["UpdateDirectoryPermissions"])); @@ -3044,5 +3032,41 @@ namespace ServerManagerTool { this["DiscordBotAllowAllBots"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool LoggingEnabled { + get { + return ((bool)(this["LoggingEnabled"])); + } + set { + this["LoggingEnabled"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("30")] + public int LoggingMaxArchiveFiles { + get { + return ((int)(this["LoggingMaxArchiveFiles"])); + } + set { + this["LoggingMaxArchiveFiles"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("30")] + public int LoggingMaxArchiveDays { + get { + return ((int)(this["LoggingMaxArchiveDays"])); + } + set { + this["LoggingMaxArchiveDays"] = value; + } + } } } diff --git a/src/ARKServerManager/Config.settings b/src/ARKServerManager/Config.settings index c70bfa64..afbea840 100644 --- a/src/ARKServerManager/Config.settings +++ b/src/ARKServerManager/Config.settings @@ -410,9 +410,6 @@ False - - - https://steamcommunity.com/dev/apikey @@ -458,7 +455,7 @@ False - + @@ -500,7 +497,7 @@ Mod updates have been detected: - + http://arkservermanager.freeforums.net/board/22/plugins @@ -666,7 +663,7 @@ 500 - True + False True @@ -840,5 +837,14 @@ False + + True + + + 30 + + + 30 + \ No newline at end of file diff --git a/src/ARKServerManager/Globalization/en-US/en-US.xaml b/src/ARKServerManager/Globalization/en-US/en-US.xaml index ca44537c..70b26f4e 100644 --- a/src/ARKServerManager/Globalization/en-US/en-US.xaml +++ b/src/ARKServerManager/Globalization/en-US/en-US.xaml @@ -691,6 +691,12 @@ If enabled, after the server has been updated from the cache, it will perform a server verification using steamcmd. Update Directory Permissions on Save If enabled, when a save is performed, all folders under the server directory will be have the permissions check and if necessary fixed. WARNING: Disabling could prevent your server from running properly. + Enable Logging + If enabled, all logging will be enabled. + Delete Logs After + How old the log files must be to be deleted in days. + Max Number of Logs + The maximum number of log files that will be kept. Confirm Settings Reset Action Click 'Yes' to confirm you want to perform the settings reset. @@ -848,6 +854,7 @@ hours days dinos + files items xp players @@ -1896,7 +1903,7 @@ If enabled, will remove the prerequisites needed to unlock the engram. Auto Unlock If enabled, the engram will be automatically unlocked at the specified level. - Unlock Level + Auto Unlock Level Player level when the engram is automatically unlocked. Auto Unlock must be enabled. Remove this Engram diff --git a/src/ARKServerManager/Globalization/zh-CN/zh-CN.xaml b/src/ARKServerManager/Globalization/zh-CN/zh-CN.xaml index db610027..a7c79f5a 100644 --- a/src/ARKServerManager/Globalization/zh-CN/zh-CN.xaml +++ b/src/ARKServerManager/Globalization/zh-CN/zh-CN.xaml @@ -88,6 +88,15 @@ 正常 最小化 最大化 + + + + 关键的 + 错误 + 警告 + 信息 + 详细调试信息 + 排错 @@ -616,6 +625,32 @@ 显示所有关机消息的关机原因 如果启用,关闭原因将显示所有关闭消息; 否则只会在服务器关机开始时显示。 + 启用Discord(开黑) 机器人 + 如果更改Discord(开黑)机器人的任何设置,则需要重新启动服务器管理器. + 令牌: + 与Discord(开黑)关联的令牌. + 地图配置ID: + 机器人将侦听的Discord(开黑)服务器的id. + 前缀: + 通过Discord(开黑)发送命令时必须使用的前缀. + 日志级别: + 领取令牌... + 帮助... + 允许所有机器人 + 如果启用,服务器管理器机器人将响应所有其他机器人,否则将忽略它们,除非它们在白名单中. + 机器人白名单 + 机器人ID + 要加入白名单的机器人的id. + 添加白名单 + 清除白名单 + 删除白名单 + 如果启用,则可以从discord(开黑)发送备份命令. + 如果启用,可以从discord(开黑)发送重启命令. + 如果启用,可以从discord(开黑)发送关机命令. + 如果启用,则可以从discord(开黑)发送开始命令. + 如果启用,可以从discord(开黑)发送停止命令. + 如果启用,则可以从discord(开黑)发送更新命令. + SMTP 电子邮箱设置 主机: 主机名称或者地址使用SMTP发送. @@ -757,12 +792,18 @@ 启用 启用自动更新计划任务 下次运行时间: + Discord(开黑)机器人: + 开始 + 启动Discord(开黑)机器人 + 停止 + 停止Discord(开黑)机器人 未知 禁用 排队 准备 运行 + 停止 配置文件无法加载 在配置文件 {0} 加载失败. 错误是: {1}\r\n{2} @@ -1182,6 +1223,26 @@ 如果启用,服务器将按照周期,定期自动更新。请参阅自动更新选项的设置. 如果已关闭,则重新启动服务器, 如果启用,即使关闭自动重启和自动更新,服务器也将重新启动。 + + + + Discord(开黑)机器人细节 + 频道ID: + 此配置文件将侦听的Discord(开黑)服务器通道的ID. + 名称: + 在使用Discord(开黑)命令时,可以使用唯一的名称来标识服务器,而不是配置文件id. + 允许备份 + 如果启用,配置文件将侦听来自Discord(开黑)的备份命令. + 允许重新启动 + 如果启用,配置文件将侦听来自Discord(开黑)的重新启动命令. + 允许关机 + 如果启用,配置文件将侦听来自Discord(开黑)的关机命令. + 允许启动 + 如果启用,配置文件将侦听来自Discord(开黑)的启动命令. + 允许停止 + 如果启用,配置文件将侦听来自Discord(开黑)的停止命令. + 允许更新 + 如果启用,配置文件将侦听来自Discord(开黑)的更新命令. @@ -6900,4 +6961,34 @@ 炮塔终端 恐龙洗点卡 + + + Discord(开黑)机器人错误 + Discord(开黑)机器人需要有效的令牌,以便它可以登录到Discord(开黑)服务器。\r\n这可以在全局设置中设置. + Discord(开黑)机器人需要有效的前缀。\r\n这可以在全局设置中设置. + Discord(开黑)机器人前缀包含无效字符。只允许使用字母和数字. + + 命令 '{0}'尚未启用. + 未知命令 '{0}'. + 当前正在处理另一个命令. + 另一个命令 '{0}' 当前正在针对配置文件运行 '{1}'. + 命令 '{0}' 已为配置文件禁用 '{1}'. + + 这个 '{0}' 命令需要配置文件ID或别名。 + 简介 '{0}'找不到或与通道不关联. + 具有多个配置文件 '{0}' 在通道中找到,命令中止. + 简介 '{0}'他处于一种状态'{1}' 无法运行此命令的. + 简介 '{0}' 目前正在更新. + + 对服务器'{0}'的调用失败. + 已发送服务器'{0}'的备份请求. + 已发送服务器'{0}'的重新启动请求. + 已发送服务器'{0}'的关闭请求. + 已发送服务器'{0}'的启动请求. + 已发送服务器'{0}'的停止请求. + 已发送服务器'{0}'的更新请求. + + 总数: + 地图: + diff --git a/src/ARKServerManager/Lib/ServerApp.cs b/src/ARKServerManager/Lib/ServerApp.cs index a2715ef4..3088f837 100644 --- a/src/ARKServerManager/Lib/ServerApp.cs +++ b/src/ARKServerManager/Lib/ServerApp.cs @@ -1,4 +1,8 @@ -using ServerManagerTool.Common; +using NLog; +using NLog.Config; +using NLog.Layouts; +using NLog.Targets; +using ServerManagerTool.Common; using ServerManagerTool.Common.Lib; using ServerManagerTool.Common.Model; using ServerManagerTool.Common.Utils; @@ -74,6 +78,7 @@ namespace ServerManagerTool.Lib // restart code private const int EXITCODE_RESTART_FAILED = 5001; private const int EXITCODE_RESTART_BADLAUNCHER = 5002; + private const int EXITCODE_RESTART_NOSTEAMCLIENT = 5003; public const string LOGPREFIX_AUTOBACKUP = "#AutoBackupLogs"; public const string LOGPREFIX_AUTOSHUTDOWN = "#AutoShutdownLogs"; @@ -81,13 +86,13 @@ namespace ServerManagerTool.Lib private const int DIRECTORIES_PER_LINE = 200; - private static readonly object LockObjectMessage = new object(); - private static readonly object LockObjectBranchMessage = new object(); - private static readonly object LockObjectProfileMessage = new object(); private static DateTime _startTime = DateTime.Now; - private static string _logPrefix = ""; private static Dictionary _profiles = null; + private static Logger _loggerManager; + private Logger _loggerBranch; + private Logger _loggerProfile; + private ServerProfileSnapshot _profile = null; private QueryMaster.Rcon _rconConsole = null; private bool _serverRunning = false; @@ -97,7 +102,7 @@ namespace ServerManagerTool.Lib public bool SendMessages = Config.Default.ServerShutdown_SendShutdownMessages; public bool DeleteOldServerBackupFiles = false; public int ExitCode = EXITCODE_NORMALEXIT; - public bool OutputLogs = true; + public bool OutputLogs = false; public bool SendAlerts = false; public bool SendEmails = false; public string ShutdownReason = null; @@ -123,6 +128,7 @@ namespace ServerManagerTool.Lib } var emailMessage = new StringBuilder(); + LogProfileMessage("------------------------"); LogProfileMessage("Started server backup..."); LogProfileMessage("------------------------"); @@ -477,7 +483,7 @@ namespace ServerManagerTool.Lib var message = string.Empty; if (minutesLeft > 5) { - // check if the we have just started the countdown + // check if we have just started the countdown if (minutesLeft == ShutdownInterval) { message = Config.Default.ServerShutdown_GraceMessage1.Replace("{minutes}", minutesLeft.ToString()); @@ -872,13 +878,13 @@ namespace ServerManagerTool.Lib // check if the mod needs to be downloaded, or force the download. if (Config.Default.ServerUpdate_ForceUpdateMods) { - LogProfileMessage("Forcing mod download - ASM setting is TRUE."); + LogProfileMessage("Forcing mod download - Server Manager setting is TRUE."); } else if (modDetail == null) { if (forceUpdateMods) { - LogProfileMessage("Forcing mod download - Mod details not available and ASM setting is TRUE."); + LogProfileMessage("Forcing mod download - Mod details not available and Server Manager setting is TRUE."); } else { @@ -1003,7 +1009,7 @@ namespace ServerManagerTool.Lib // check if the mod needs to be copied, or force the copy. if (Config.Default.ServerUpdate_ForceCopyMods) { - LogProfileMessage("Forcing mod copy - ASM setting is TRUE."); + LogProfileMessage("Forcing mod copy - Server Manager setting is TRUE."); } else { @@ -1261,18 +1267,19 @@ namespace ServerManagerTool.Lib _profile.LastInstalledVersion = GetServerVersion(GetServerVersionFile()).ToString(); _profile.ServerUpdated = true; - LogProfileMessage("Updated server from cache."); + LogProfileMessage("Updated server from cache. See patch notes."); LogProfileMessage($"Server version: {_profile.LastInstalledVersion}."); - LogProfileMessage("See ARK patch notes."); LogProfileMessage(Config.Default.ArkSE_PatchNotesUrl); if (!string.IsNullOrWhiteSpace(Config.Default.Alert_ServerUpdate)) alertMessage.AppendLine(Config.Default.Alert_ServerUpdate); emailMessage.AppendLine(); - emailMessage.AppendLine("Updated server from cache. See ARK patch notes."); + emailMessage.AppendLine("Updated server from cache. See patch notes."); emailMessage.AppendLine(Config.Default.ArkSE_PatchNotesUrl); + + _profile.ServerUpdated = true; } else { @@ -1621,7 +1628,7 @@ namespace ServerManagerTool.Lib { // failed max limit reached if (Config.Default.SteamCmdRedirectOutput) - LogMessage($"If the mod cache update keeps failing try disabling the '{_globalizer.GetResourceString("GlobalSettings_SteamCmdRedirectOutputLabel")}' option in the ASM settings window."); + LogMessage($"If the mod cache update keeps failing try disabling the '{_globalizer.GetResourceString("GlobalSettings_SteamCmdRedirectOutputLabel")}' option in the Server Manager settings window."); ExitCode = EXITCODE_CACHEMODUPDATEFAILED; return; @@ -1867,7 +1874,8 @@ namespace ServerManagerTool.Lib var comment = new StringBuilder(); comment.AppendLine($"Windows Platform: {Environment.OSVersion.Platform}"); comment.AppendLine($"Windows Version: {Environment.OSVersion.VersionString}"); - comment.AppendLine($"ASM Version: {App.Instance.Version}"); + comment.AppendLine($"Server Manager Version: {App.Instance.Version}"); + comment.AppendLine($"Server Manager Key: {Config.Default.ServerManagerCode}"); comment.AppendLine($"Config Directory: {Config.Default.ConfigDirectory}"); comment.AppendLine($"Server Directory: {_profile.InstallDirectory}"); comment.AppendLine($"Profile Name: {_profile.ProfileName}"); @@ -2017,7 +2025,8 @@ namespace ServerManagerTool.Lib var comment = new StringBuilder(); comment.AppendLine($"Windows Platform: {Environment.OSVersion.Platform}"); comment.AppendLine($"Windows Version: {Environment.OSVersion.VersionString}"); - comment.AppendLine($"ASM Version: {App.Instance.Version}"); + comment.AppendLine($"Server Manager Version: {App.Instance.Version}"); + comment.AppendLine($"Server Manager Key: {Config.Default.ServerManagerCode}"); comment.AppendLine($"Config Directory: {Config.Default.ConfigDirectory}"); comment.AppendLine($"Server Directory: {_profile.InstallDirectory}"); comment.AppendLine($"Profile Name: {_profile.ProfileName}"); @@ -2181,11 +2190,48 @@ namespace ServerManagerTool.Lib public static string GetBranchName(string branchName) => string.IsNullOrWhiteSpace(branchName) ? Config.Default.DefaultServerBranchName : branchName; - public static string GetBranchLogFile(string branchName) => IOUtils.NormalizePath(Path.Combine(App.GetLogFolder(), _logPrefix, $"{_startTime:yyyyMMdd_HHmmss}{(string.IsNullOrWhiteSpace(branchName) ? string.Empty : $"_{branchName}")}.log")); - private string GetLauncherFile() => IOUtils.NormalizePath(Path.Combine(GetProfileServerConfigDir(_profile), Config.Default.LauncherFile)); - private static string GetLogFile() => IOUtils.NormalizePath(Path.Combine(App.GetLogFolder(), _logPrefix, $"{_startTime:yyyyMMdd_HHmmss}.log")); + private static string GetLogFolder(string logType) => IOUtils.NormalizePath(Path.Combine(App.GetLogFolder(), logType)); + + private static Logger GetLogger(string logFilePath, string logType, string logName) + { + return GetLogger(logFilePath, logType, logName ?? string.Empty, LogLevel.Debug, LogLevel.Fatal); + } + + private static Logger GetLogger(string logFilePath, string logType, string logName, LogLevel minLevel, LogLevel maxLevel) + { + if (string.IsNullOrWhiteSpace(logFilePath) || string.IsNullOrWhiteSpace(logType) || string.IsNullOrWhiteSpace(logName)) + return null; + + var loggerName = $"{logType}_{logName}".Replace(" ", "_"); + + if (LogManager.Configuration.FindTargetByName(loggerName) is null) + { + if (!Directory.Exists(logFilePath)) + Directory.CreateDirectory(logFilePath); + + var logFile = new FileTarget(loggerName) + { + FileName = Path.Combine(logFilePath, $"{logName}.log"), + Layout = "${time} [${level:uppercase=true}] ${message}", + ArchiveFileName = Path.Combine(logFilePath, $"{logName}.{{#}}.log"), + ArchiveNumbering = ArchiveNumberingMode.DateAndSequence, + ArchiveEvery = FileArchivePeriod.Day, + ArchiveDateFormat = "yyyyMMdd", + ArchiveOldFileOnStartup = true, + MaxArchiveFiles = Config.Default.LoggingMaxArchiveFiles, + MaxArchiveDays = Config.Default.LoggingMaxArchiveDays, + }; + LogManager.Configuration.AddTarget(loggerName, logFile); + + var rule = new LoggingRule(loggerName, minLevel, maxLevel, logFile); + LogManager.Configuration.LoggingRules.Add(rule); + LogManager.ReconfigExistingLoggers(); + } + + return LogManager.GetLogger(loggerName); + } private List GetModList() { @@ -2238,7 +2284,7 @@ namespace ServerManagerTool.Lib private static string GetProfileFile(ServerProfileSnapshot profile) => IOUtils.NormalizePath(Path.Combine(Config.Default.ConfigDirectory, $"{profile.ProfileId.ToLower()}{Config.Default.ProfileExtension}")); - private string GetProfileLogFile() => _profile != null ? IOUtils.NormalizePath(Path.Combine(App.GetLogFolder(), _profile.ProfileId.ToLower(), _logPrefix, $"{_startTime:yyyyMMdd_HHmmss}.log")) : GetLogFile(); + private string GetProfileLogFolder(string profileId, string logType) => IOUtils.NormalizePath(Path.Combine(App.GetProfileLogFolder(profileId), logType)); public static string GetProfileServerConfigDir(ServerProfile profile) => Path.Combine(profile.InstallDirectory, Config.Default.ServerConfigRelativePath); @@ -2424,36 +2470,18 @@ namespace ServerManagerTool.Lib if (string.IsNullOrWhiteSpace(error)) return; - LogMessage($"***** ERROR: {error}"); + _loggerManager?.Error(error); + + Debug.WriteLine($"[ERROR] {error}"); } private static void LogMessage(string message) { message = message ?? string.Empty; - var logFile = GetLogFile(); - lock (LockObjectMessage) - { - if (!Directory.Exists(Path.GetDirectoryName(logFile))) - Directory.CreateDirectory(Path.GetDirectoryName(logFile)); + _loggerManager?.Info(message); - int retries = 0; - while (retries < 3) - { - try - { - File.AppendAllLines(logFile, new[] { $"{DateTime.Now.ToString("o", CultureInfo.CurrentCulture)}: {message}" }, Encoding.Unicode); - break; - } - catch (IOException) - { - retries++; - Task.Delay(WRITELOG_ERRORRETRYDELAY).Wait(); - } - } - } - - Debug.WriteLine(message); + Debug.WriteLine($"[INFO] {message}"); } private void LogBranchError(string branchName, string error, bool includeProgressCallback = true) @@ -2461,45 +2489,24 @@ namespace ServerManagerTool.Lib if (string.IsNullOrWhiteSpace(error)) return; - LogBranchMessage(branchName, $"***** ERROR: {error}", includeProgressCallback); + _loggerBranch?.Error(error); + + if (includeProgressCallback) + ProgressCallback?.Invoke(0, $"[ERROR] {error}"); + + Debug.WriteLine($"[ERROR] (Branch {GetBranchName(branchName) ?? "unknown"}) {error}"); } private void LogBranchMessage(string branchName, string message, bool includeProgressCallback = true) { message = message ?? string.Empty; - if (OutputLogs) - { - var logFile = GetBranchLogFile(branchName); - lock (LockObjectBranchMessage) - { - if (!Directory.Exists(Path.GetDirectoryName(logFile))) - Directory.CreateDirectory(Path.GetDirectoryName(logFile)); - - int retries = 0; - while (retries < 3) - { - try - { - File.AppendAllLines(logFile, new[] { $"{DateTime.Now.ToString("o", CultureInfo.CurrentCulture)}: {message}" }, Encoding.Unicode); - break; - } - catch (IOException) - { - retries++; - Task.Delay(WRITELOG_ERRORRETRYDELAY).Wait(); - } - } - } - } + _loggerBranch?.Info(message); if (includeProgressCallback) - ProgressCallback?.Invoke(0, message); + ProgressCallback?.Invoke(0, $"[INFO] {message}"); - if (_profile != null) - Debug.WriteLine($"[Branch {GetBranchName(branchName) ?? "unknown"}] {message}"); - else - Debug.WriteLine(message); + Debug.WriteLine($"[INFO] (Branch {GetBranchName(branchName) ?? "unknown"}) {message}"); } private void LogProfileError(string error, bool includeProgressCallback = true) @@ -2507,45 +2514,24 @@ namespace ServerManagerTool.Lib if (string.IsNullOrWhiteSpace(error)) return; - LogProfileMessage($"***** ERROR: {error}", includeProgressCallback); + _loggerProfile?.Error(error); + + if (includeProgressCallback) + ProgressCallback?.Invoke(0, $"[ERROR] {error}"); + + Debug.WriteLine($"[ERROR] (Profile {_profile?.ProfileName ?? "unknown"}) {error}"); } private void LogProfileMessage(string message, bool includeProgressCallback = true) { message = message ?? string.Empty; - if (OutputLogs) - { - var logFile = GetProfileLogFile(); - lock (LockObjectProfileMessage) - { - if (!Directory.Exists(Path.GetDirectoryName(logFile))) - Directory.CreateDirectory(Path.GetDirectoryName(logFile)); - - int retries = 0; - while (retries < 3) - { - try - { - File.AppendAllLines(logFile, new[] { $"{DateTime.Now.ToString("o", CultureInfo.CurrentCulture)}: {message}" }, Encoding.Unicode); - break; - } - catch (IOException) - { - retries++; - Task.Delay(WRITELOG_ERRORRETRYDELAY).Wait(); - } - } - } - } + _loggerProfile?.Info(message); if (includeProgressCallback) - ProgressCallback?.Invoke(0, message); + ProgressCallback?.Invoke(0, $"[INFO] {message}"); - if (_profile != null) - Debug.WriteLine($"[Profile {_profile?.ProfileName ?? "unknown"}] {message}"); - else - Debug.WriteLine(message); + Debug.WriteLine($"[INFO] (Profile {_profile?.ProfileName ?? "unknown"}) {message}"); } private void ProcessAlert(AlertType alertType, string alertMessage) @@ -2579,7 +2565,7 @@ namespace ServerManagerTool.Lib if (_rconConsole == null) { LogProfileMessage($"RCON> {command} - attempt {rconRetries + 1} (a).", false); - LogProfileMessage("RCON connection not created.", false); + LogProfileMessage("RCON connection could not be created.", false); rconRetries++; } else @@ -2596,6 +2582,7 @@ namespace ServerManagerTool.Lib { LogProfileMessage($"RCON> {command} - attempt {retries + 1} (b).", false); LogProfileMessage($"{ex.Message}", false); + LogProfileMessage($"{ex.StackTrace}", false); } retries++; @@ -2648,9 +2635,11 @@ namespace ServerManagerTool.Lib StringBuilder messageBody = new StringBuilder(body); Attachment attachment = null; - if (includeLogFile) + if (includeLogFile && _loggerProfile != null) { - var logFile = GetProfileLogFile(); + var fileTarget = LogManager.Configuration.FindTargetByName(_loggerProfile.Name) as FileTarget; + var fileLayout = fileTarget?.FileName as SimpleLayout; + var logFile = fileLayout?.Text ?? string.Empty; if (!string.IsNullOrWhiteSpace(logFile) && File.Exists(logFile)) { attachment = new Attachment(logFile); @@ -2720,6 +2709,7 @@ namespace ServerManagerTool.Lib { #if DEBUG LogProfileMessage($"ERROR: {nameof(SetupRconConsole)}\r\n{ex.Message}", false); + LogProfileMessage($"ERROR: {nameof(SetupRconConsole)}\r\n{ex.StackTrace}", false); #endif } } @@ -2728,10 +2718,7 @@ namespace ServerManagerTool.Lib { _profile = profile; - if (_profile == null) - return EXITCODE_NORMALEXIT; - - if (_profile.SotFEnabled) + if (_profile == null || _profile.SotFEnabled) return EXITCODE_NORMALEXIT; ExitCode = EXITCODE_NORMALEXIT; @@ -2739,6 +2726,9 @@ namespace ServerManagerTool.Lib Mutex mutex = null; var createdNew = false; + if (OutputLogs) + _loggerProfile = GetLogger(GetProfileLogFolder(profile.ProfileId, LOGPREFIX_AUTOBACKUP), $"{LOGPREFIX_AUTOBACKUP}_{profile.ProfileId}", "Backup"); + try { // try to establish a mutex for the profile. @@ -2804,6 +2794,9 @@ namespace ServerManagerTool.Lib Mutex mutex = null; var createdNew = false; + if (OutputLogs) + _loggerProfile = GetLogger(GetProfileLogFolder(profile.ProfileId, LOGPREFIX_AUTOSHUTDOWN), $"{LOGPREFIX_AUTOSHUTDOWN}_{profile.ProfileId}", "Shutdown"); + try { // check if within the shutdown grace period (only performed when restarting the server) @@ -2889,10 +2882,7 @@ namespace ServerManagerTool.Lib { _profile = profile; - if (_profile == null) - return EXITCODE_NORMALEXIT; - - if (_profile.SotFEnabled) + if (_profile == null || _profile.SotFEnabled) return EXITCODE_NORMALEXIT; ExitCode = EXITCODE_NORMALEXIT; @@ -2900,6 +2890,9 @@ namespace ServerManagerTool.Lib Mutex mutex = null; var createdNew = false; + if (OutputLogs) + _loggerProfile = GetLogger(GetProfileLogFolder(profile.ProfileId, LOGPREFIX_AUTOUPDATE), $"{LOGPREFIX_AUTOUPDATE}_{profile.ProfileId}", "Update"); + try { LogBranchMessage(branch.BranchName, $"[{_profile.ProfileName}] Started server update process."); @@ -2971,6 +2964,9 @@ namespace ServerManagerTool.Lib Mutex mutex = null; var createdNew = false; + if (OutputLogs) + _loggerBranch = GetLogger(GetLogFolder(LOGPREFIX_AUTOUPDATE), $"{LOGPREFIX_AUTOUPDATE}_{branch.BranchName}", GetBranchName(branch.BranchName)); + try { LogBranchMessage(branch.BranchName, $"Started branch update process."); @@ -3007,8 +3003,9 @@ namespace ServerManagerTool.Lib { var app = new ServerApp { - SendAlerts = true, - SendEmails = true, + OutputLogs = OutputLogs, + SendAlerts = SendAlerts, + SendEmails = SendEmails, ServerProcess = ServerProcess, SteamCMDProcessWindowStyle = ProcessWindowStyle.Hidden }; @@ -3026,8 +3023,9 @@ namespace ServerManagerTool.Lib var app = new ServerApp { - SendAlerts = true, - SendEmails = true, + OutputLogs = OutputLogs, + SendAlerts = SendAlerts, + SendEmails = SendEmails, ServerProcess = ServerProcess, SteamCMDProcessWindowStyle = ProcessWindowStyle.Hidden }; @@ -3082,10 +3080,10 @@ namespace ServerManagerTool.Lib public static int PerformAutoBackup() { - _logPrefix = LOGPREFIX_AUTOBACKUP; - int exitCode = EXITCODE_NORMALEXIT; + _loggerManager = GetLogger(GetLogFolder(LOGPREFIX_AUTOBACKUP), LOGPREFIX_AUTOBACKUP, "AutoBackup"); + try { // check if a data directory has been setup. @@ -3101,6 +3099,7 @@ namespace ServerManagerTool.Lib var app = new ServerApp { DeleteOldServerBackupFiles = Config.Default.AutoBackup_DeleteOldFiles, + OutputLogs = true, SendAlerts = true, SendEmails = true, ServerProcess = ServerProcessType.AutoBackup @@ -3130,10 +3129,10 @@ namespace ServerManagerTool.Lib public static int PerformAutoShutdown(string argument, ServerProcessType type) { - _logPrefix = LOGPREFIX_AUTOSHUTDOWN; - int exitCode = EXITCODE_NORMALEXIT; + _loggerManager = GetLogger(GetLogFolder(LOGPREFIX_AUTOSHUTDOWN), LOGPREFIX_AUTOSHUTDOWN, "AutoShutdown"); + try { // check if a data directory has been setup. @@ -3187,6 +3186,7 @@ namespace ServerManagerTool.Lib var app = new ServerApp { + OutputLogs = true, SendAlerts = true, SendEmails = true, ServerProcess = type, @@ -3210,13 +3210,13 @@ namespace ServerManagerTool.Lib public static int PerformAutoUpdate() { - _logPrefix = LOGPREFIX_AUTOUPDATE; - int exitCode = EXITCODE_NORMALEXIT; Mutex mutex = null; bool createdNew = false; + _loggerManager = GetLogger(GetLogFolder(LOGPREFIX_AUTOUPDATE), LOGPREFIX_AUTOUPDATE, "AutoUpdate"); + try { // check if a data directory has been setup. @@ -3258,6 +3258,9 @@ namespace ServerManagerTool.Lib Parallel.ForEach(branches, branch => { app = new ServerApp { + OutputLogs = true, + SendAlerts = true, + SendEmails = true, ServerProcess = ServerProcessType.AutoUpdate, SteamCMDProcessWindowStyle = ProcessWindowStyle.Hidden }; @@ -3276,6 +3279,9 @@ namespace ServerManagerTool.Lib app = new ServerApp { + OutputLogs = true, + SendAlerts = true, + SendEmails = true, ServerProcess = ServerProcessType.AutoUpdate, SteamCMDProcessWindowStyle = ProcessWindowStyle.Hidden }; diff --git a/src/ARKServerManager/Lib/ServerStatusWatcher.cs b/src/ARKServerManager/Lib/ServerStatusWatcher.cs index 3af623df..79cf846d 100644 --- a/src/ARKServerManager/Lib/ServerStatusWatcher.cs +++ b/src/ARKServerManager/Lib/ServerStatusWatcher.cs @@ -72,7 +72,7 @@ namespace ServerManagerTool.Lib { var registration = new ServerStatusUpdateRegistration { - AsmId = Config.Default.ASMUniqueKey, + AsmId = Config.Default.ServerManagerUniqueKey, InstallDirectory = installDirectory, ProfileId = profileId, LocalEndpoint = localEndpoint, diff --git a/src/ARKServerManager/NLog.config b/src/ARKServerManager/NLog.config index 70487eb2..8e2599c8 100644 --- a/src/ARKServerManager/NLog.config +++ b/src/ARKServerManager/NLog.config @@ -15,48 +15,53 @@ /> diff --git a/src/ARKServerManager/UserControls/GlobalSettingsControl.xaml b/src/ARKServerManager/UserControls/GlobalSettingsControl.xaml index b82088fc..a3f4d13b 100644 --- a/src/ARKServerManager/UserControls/GlobalSettingsControl.xaml +++ b/src/ARKServerManager/UserControls/GlobalSettingsControl.xaml @@ -763,6 +763,8 @@ + + @@ -780,7 +782,11 @@ - + + + + + diff --git a/src/ARKServerManager/UserControls/GlobalSettingsControl.xaml.cs b/src/ARKServerManager/UserControls/GlobalSettingsControl.xaml.cs index 87297eea..c3d21503 100644 --- a/src/ARKServerManager/UserControls/GlobalSettingsControl.xaml.cs +++ b/src/ARKServerManager/UserControls/GlobalSettingsControl.xaml.cs @@ -118,6 +118,8 @@ namespace ServerManagerTool Config.DiscordBotWhitelist.Clear(); Config.DiscordBotWhitelist.AddRange(DiscordBotWhitelist.Select(i => i.BotId).ToArray()); + + App.ReconfigureLogging(); } private string GetDeployedVersion() diff --git a/src/ARKServerManager/UserControls/ServerSettingsControl.xaml.cs b/src/ARKServerManager/UserControls/ServerSettingsControl.xaml.cs index 7c198fdb..2db31f2d 100644 --- a/src/ARKServerManager/UserControls/ServerSettingsControl.xaml.cs +++ b/src/ARKServerManager/UserControls/ServerSettingsControl.xaml.cs @@ -848,7 +848,7 @@ namespace ServerManagerTool comment.AppendLine($"Game Server Version: {this.Settings.LastInstalledVersion}"); comment.AppendLine($"Server Manager Version: {App.Instance.Version}"); comment.AppendLine($"Server Manager Code: {Config.Default.ServerManagerCode}"); - comment.AppendLine($"Server Manager Key: {Config.Default.ASMUniqueKey}"); + comment.AppendLine($"Server Manager Key: {Config.Default.ServerManagerUniqueKey}"); comment.AppendLine($"Server Manager Directory: {Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}"); comment.AppendLine($"MachinePublicIP: {Config.Default.MachinePublicIP}"); diff --git a/src/ARKServerManager/VersionFeed.xml b/src/ARKServerManager/VersionFeed.xml index 928c5a32..c31d6035 100644 --- a/src/ARKServerManager/VersionFeed.xml +++ b/src/ARKServerManager/VersionFeed.xml @@ -9,13 +9,18 @@ urn:uuid:3E33DCB2-ECFE-4489-B1A4-56F5D386F9DC - 1.1.413 (1.1.413.10) - 1.1.413.10 + 1.1.413 (1.1.413.11) + 1.1.413.11 2021-12-18T00:00:00Z

+ BUGFIX +
+

    +
  • Fixed the cleanup of the log files generated by the auto processes (Backup, Update and Shutdown/Restart).
    NOTE: It will not cleanup the existing files, you need to do that manually.
  • +
NEW
    @@ -23,6 +28,7 @@
  • Global Settings - Discord Bot section - Added a log level droplist.
  • Global Settings - Discord Bot section - Added a checkbox to allow all bots.
  • Global Settings - Discord Bot section - Added a whitelist to allow bots to send commands to the server manager.
  • +
  • Global Settings - Added new Log settings which allow you to turn if on/off and set the number of days/files to retain.
  • Server Settings - Discord Bot section - Added an alias that can be used with the discord command instead of the profile id.
CHANGE diff --git a/src/ARKServerManager/VersionFeedBeta.xml b/src/ARKServerManager/VersionFeedBeta.xml index b9dc08e5..a7bef2dc 100644 --- a/src/ARKServerManager/VersionFeedBeta.xml +++ b/src/ARKServerManager/VersionFeedBeta.xml @@ -7,6 +7,39 @@ 2021-12-16T00:00:00Z + + urn:uuid:A652172B-F29A-4050-8A0C-8A34F6DDF1FA + 1.1.413 (1.1.413.11) + 1.1.413.11 + + 2021-12-18T00:00:00Z + +
+

+ BUGFIX +
+

    +
  • Fixed the cleanup of the log files generated by the auto processes (Backup, Update and Shutdown/Restart).
    NOTE: It will not cleanup the existing files, you need to do that manually.
  • +
+ NEW +
+
    +
  • Global Settings - Added new Log settings which allow you to turn if on/off and set the number of days/files to retain.
  • +
+ CHANGE +
+
    +
  • zh-CN Translation file updated.
  • +
+

+
+
+ + bletch + bletch1971@hotmail.com + +
+ urn:uuid:D1CFECED-7968-47FD-B1DE-2FECD7878BDA 1.1.413 (1.1.413.10) diff --git a/src/ARKServerManager/Windows/PluginsWindow.xaml.cs b/src/ARKServerManager/Windows/PluginsWindow.xaml.cs index da75048c..b2a0c208 100644 --- a/src/ARKServerManager/Windows/PluginsWindow.xaml.cs +++ b/src/ARKServerManager/Windows/PluginsWindow.xaml.cs @@ -102,7 +102,7 @@ namespace ServerManagerTool private void PluginsForum_Click(object sender, RoutedEventArgs e) { - Process.Start(Config.Default.ASMPluginUrl); + Process.Start(Config.Default.ServerManagerPluginUrl); } private void RemovePlugin_Click(object sender, RoutedEventArgs e) diff --git a/src/ConanServerManager/App.config b/src/ConanServerManager/App.config index 465f210b..f49f98e8 100644 --- a/src/ConanServerManager/App.config +++ b/src/ConanServerManager/App.config @@ -535,7 +535,7 @@ 500 - True + False False @@ -632,6 +632,15 @@ False + + True + + + 30 + + + 30 + \ No newline at end of file diff --git a/src/ConanServerManager/App.xaml.cs b/src/ConanServerManager/App.xaml.cs index 7d5fc685..89ccfed5 100644 --- a/src/ConanServerManager/App.xaml.cs +++ b/src/ConanServerManager/App.xaml.cs @@ -232,12 +232,12 @@ namespace ServerManagerTool public static string GetProfileLogFolder(string profileId) => IOUtils.NormalizePath(Path.Combine(Config.Default.DataPath, Config.Default.LogsRelativePath, profileId.ToLower())); - public static Logger GetProfileLogger(string profileId, string name, LogLevel minLevel, LogLevel maxLevel) + public static Logger GetProfileLogger(string profileId, string logName, LogLevel minLevel, LogLevel maxLevel) { - if (string.IsNullOrWhiteSpace(profileId) || string.IsNullOrWhiteSpace(name)) + if (string.IsNullOrWhiteSpace(profileId) || string.IsNullOrWhiteSpace(logName)) return null; - var loggerName = $"{profileId.ToLower()}_{name}".Replace(" ", "_"); + var loggerName = $"{profileId.ToLower()}_{logName}".Replace(" ", "_"); if (LogManager.Configuration.FindTargetByName(loggerName) == null) { @@ -247,12 +247,15 @@ namespace ServerManagerTool var logFile = new FileTarget(loggerName) { - FileName = Path.Combine(logFilePath, $"{name}.log"), - Layout = "${time} ${message}", - ArchiveFileName = Path.Combine(logFilePath, $"{name}.{{#}}.log"), + FileName = Path.Combine(logFilePath, $"{logName}.log"), + Layout = "${time} [${level:uppercase=true}] ${message}", + ArchiveFileName = Path.Combine(logFilePath, $"{logName}.{{#}}.log"), ArchiveNumbering = ArchiveNumberingMode.DateAndSequence, ArchiveEvery = FileArchivePeriod.Day, - ArchiveDateFormat = "yyyyMMdd" + ArchiveDateFormat = "yyyyMMdd", + ArchiveOldFileOnStartup = true, + MaxArchiveFiles = Config.Default.LoggingMaxArchiveFiles, + MaxArchiveDays = Config.Default.LoggingMaxArchiveDays, }; LogManager.Configuration.AddTarget(loggerName, logFile); @@ -334,12 +337,12 @@ namespace ServerManagerTool TaskSchedulerUtils.TaskFolder = Config.Default.ScheduledTaskFolder; - this.Args = string.Join(" ", e.Args); + Args = string.Join(" ", e.Args); // check if we are starting server manager in BETA/TEST mode if (e.Args.Any(a => a.Equals(Constants.ARG_BETA, StringComparison.OrdinalIgnoreCase) || a.Equals(Constants.ARG_TEST, StringComparison.OrdinalIgnoreCase))) { - this.BetaVersion = true; + BetaVersion = true; } // check if we need to set the title @@ -406,12 +409,14 @@ namespace ServerManagerTool var result = MessageBox.Show(_globalizer.GetResourceString("Application_RunAsAdministratorLabel"), _globalizer.GetResourceString("Application_RunAsAdministratorTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question); if (result == MessageBoxResult.Yes) { - var processInfo = new ProcessStartInfo(Assembly.GetEntryAssembly().CodeBase); + var processInfo = new ProcessStartInfo(Assembly.GetExecutingAssembly().CodeBase) + { - // The following properties run the new process as administrator - processInfo.UseShellExecute = true; - processInfo.Verb = "runas"; - processInfo.Arguments = string.Join(" ", e.Args); + // The following properties run the new process as administrator + UseShellExecute = true, + Verb = "runas", + Arguments = string.Join(" ", e.Args) + }; // Start the new process try @@ -449,7 +454,7 @@ namespace ServerManagerTool } } - this.ApplicationStarted = true; + ApplicationStarted = true; var restartRequired = false; if (string.IsNullOrWhiteSpace(Config.Default.DataPath)) @@ -515,7 +520,9 @@ namespace ServerManagerTool public static void ReconfigureLogging() { - string logDir = Path.Combine(Config.Default.DataPath, Config.Default.LogsRelativePath); + UpdateLoggingStatus(); + + var logDir = Path.Combine(Config.Default.DataPath, Config.Default.LogsRelativePath); if (!System.IO.Directory.Exists(logDir)) System.IO.Directory.CreateDirectory(logDir); @@ -527,36 +534,13 @@ namespace ServerManagerTool var fileName = Path.GetFileNameWithoutExtension(fileTarget.FileName.ToString()); fileTarget.FileName = Path.Combine(logDir, $"{fileName}.log"); fileTarget.ArchiveFileName = Path.Combine(logDir, $"{fileName}.{{#}}.log"); + fileTarget.MaxArchiveFiles = Config.Default.LoggingMaxArchiveFiles; + fileTarget.MaxArchiveDays = Config.Default.LoggingMaxArchiveDays; } LogManager.ReconfigExistingLoggers(); } - private void ShutDownApplication() - { - StopDiscordBot(); - - if (this.ApplicationStarted) - { - foreach (var server in ServerManager.Instance.Servers) - { - try - { - server.Profile.Save(false, false, null); - } - catch (Exception ex) - { - MessageBox.Show(String.Format(_globalizer.GetResourceString("Application_Profile_SaveFailedLabel"), server.Profile.ProfileName, ex.Message, ex.StackTrace), _globalizer.GetResourceString("Application_Profile_SaveFailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error); - } - } - App.SaveConfigFiles(); - } - - PluginHelper.Instance?.Dispose(); - - this.ApplicationStarted = false; - } - public static void SaveConfigFiles(bool includeBackup = true) { Config.Default.Save(); @@ -576,6 +560,33 @@ namespace ServerManagerTool SettingsUtils.BackupUserConfigSettings(CommonConfig.Default, "commonconfig.json", installFolder, backupFolder); } + private void ShutDownApplication() + { + StopDiscordBot(); + + if (ApplicationStarted) + { + foreach (var server in ServerManager.Instance.Servers) + { + try + { + server.Profile.Save(false, false, null); + } + catch (Exception ex) + { + MessageBox.Show(String.Format(_globalizer.GetResourceString("Application_Profile_SaveFailedLabel"), server.Profile.ProfileName, ex.Message, ex.StackTrace), _globalizer.GetResourceString("Application_Profile_SaveFailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + } + } + SaveConfigFiles(); + } + + PluginHelper.Instance?.Dispose(); + LogManager.Flush(); + LogManager.Shutdown(); + + ApplicationStarted = false; + } + public void StartDiscordBot() { if (_tokenSourceDiscordBot != null) @@ -591,6 +602,8 @@ namespace ServerManagerTool var config = new DiscordBotConfig { LogLevel = Config.Default.DiscordBotLogLevel, + MaxArchiveFiles = Config.Default.LoggingMaxArchiveFiles, + MaxArchiveDays = Config.Default.LoggingMaxArchiveDays, DiscordToken = Config.Default.DiscordBotToken, CommandPrefix = Config.Default.DiscordBotPrefix, DataDirectory = Config.Default.DataPath, @@ -602,7 +615,7 @@ namespace ServerManagerTool } await ServerManagerBotFactory.GetServerManagerBot().RunAsync(config, DiscordBotHelper.HandleDiscordCommand, DiscordBotHelper.HandleTranslation, _tokenSourceDiscordBot.Token); - + if (_tokenSourceDiscordBot != null) { // cleanup the token @@ -637,5 +650,21 @@ namespace ServerManagerTool _tokenSourceDiscordBot.Cancel(); } } + + public static void UpdateLoggingStatus() + { + if (Config.Default.LoggingEnabled) + { + while (!LogManager.IsLoggingEnabled()) + LogManager.EnableLogging(); + } + else + { + while (LogManager.IsLoggingEnabled()) + LogManager.DisableLogging(); + } + + Debug.WriteLine($"Logging Enabled: {LogManager.IsLoggingEnabled()}"); + } } } diff --git a/src/ConanServerManager/Config.Designer.cs b/src/ConanServerManager/Config.Designer.cs index af7664f6..ad92febf 100644 --- a/src/ConanServerManager/Config.Designer.cs +++ b/src/ConanServerManager/Config.Designer.cs @@ -1761,7 +1761,7 @@ namespace ServerManagerTool { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("True")] + [global::System.Configuration.DefaultSettingValueAttribute("False")] public bool UpdateDirectoryPermissions { get { return ((bool)(this["UpdateDirectoryPermissions"])); @@ -2197,5 +2197,41 @@ namespace ServerManagerTool { this["DiscordBotAllowAllBots"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool LoggingEnabled { + get { + return ((bool)(this["LoggingEnabled"])); + } + set { + this["LoggingEnabled"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("30")] + public int LoggingMaxArchiveFiles { + get { + return ((int)(this["LoggingMaxArchiveFiles"])); + } + set { + this["LoggingMaxArchiveFiles"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("30")] + public int LoggingMaxArchiveDays { + get { + return ((int)(this["LoggingMaxArchiveDays"])); + } + set { + this["LoggingMaxArchiveDays"] = value; + } + } } } diff --git a/src/ConanServerManager/Config.settings b/src/ConanServerManager/Config.settings index dfa830fb..b0d69914 100644 --- a/src/ConanServerManager/Config.settings +++ b/src/ConanServerManager/Config.settings @@ -492,7 +492,7 @@ 500 - True + False False @@ -606,5 +606,14 @@ False + + True + + + 30 + + + 30 + \ No newline at end of file diff --git a/src/ConanServerManager/Globalization/en-US/en-US.xaml b/src/ConanServerManager/Globalization/en-US/en-US.xaml index e9f34170..c2a28659 100644 --- a/src/ConanServerManager/Globalization/en-US/en-US.xaml +++ b/src/ConanServerManager/Globalization/en-US/en-US.xaml @@ -79,6 +79,7 @@ minutes hours days + files items xp players @@ -735,6 +736,12 @@ If enabled, after the server has been updated from the cache, it will perform a server verification using steamcmd. Update Directory Permissions on Save If enabled, when a save is performed, all folders under the server directory will be have the permissions check and if necessary fixed. WARNING: Disabling could prevent your server from running properly. + Enable Logging + If enabled, all logging will be enabled. + Delete Logs After + How old the log files must be to be deleted in days. + Max Number of Logs + The maximum number of log files that will be kept. Enable Auto Update Game Server diff --git a/src/ConanServerManager/Lib/ServerApp.cs b/src/ConanServerManager/Lib/ServerApp.cs index acfdd0e3..f76efbed 100644 --- a/src/ConanServerManager/Lib/ServerApp.cs +++ b/src/ConanServerManager/Lib/ServerApp.cs @@ -1,4 +1,7 @@ -using ConanData; +using NLog; +using NLog.Config; +using NLog.Layouts; +using NLog.Targets; using ServerManagerTool.Common; using ServerManagerTool.Common.Lib; using ServerManagerTool.Common.Model; @@ -30,7 +33,6 @@ namespace ServerManagerTool.Lib private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance; private readonly PluginHelper _pluginHelper = PluginHelper.Instance; - public const int MUTEX_TIMEOUT = 5; // 5 minutes public const int MUTEX_ATTEMPTDELAY = 5000; // 5 seconds private const int WRITELOG_ERRORRETRYDELAY = 2000; // 2 seconds @@ -84,13 +86,13 @@ namespace ServerManagerTool.Lib private const int DIRECTORIES_PER_LINE = 200; - private static readonly object LockObjectMessage = new object(); - private static readonly object LockObjectBranchMessage = new object(); - private static readonly object LockObjectProfileMessage = new object(); private static DateTime _startTime = DateTime.Now; - private static string _logPrefix = ""; private static Dictionary _profiles = null; + private static Logger _loggerManager; + private Logger _loggerBranch; + private Logger _loggerProfile; + private ServerProfileSnapshot _profile = null; private QueryMaster.Rcon _rconConsole = null; private bool _serverRunning = false; @@ -100,7 +102,7 @@ namespace ServerManagerTool.Lib public bool SendMessages = Config.Default.ServerShutdown_SendShutdownMessages; public bool DeleteOldServerBackupFiles = false; public int ExitCode = EXITCODE_NORMALEXIT; - public bool OutputLogs = true; + public bool OutputLogs = false; public bool SendAlerts = false; public bool SendEmails = false; public string ShutdownReason = null; @@ -156,7 +158,7 @@ namespace ServerManagerTool.Lib if (!string.IsNullOrWhiteSpace(Config.Default.ServerBackup_WorldSaveMessage)) { ProcessAlert(AlertType.Backup, Config.Default.ServerBackup_WorldSaveMessage); - sent = SendMessageAsync(Config.Default.ServerBackup_WorldSaveMessage, CancellationToken.None).Result; + sent = SendMessageAsync(Config.Default.ServerBackup_WorldSaveMessage, cancellationToken).Result; if (sent) { emailMessage.AppendLine("sent server save message."); @@ -172,8 +174,6 @@ namespace ServerManagerTool.Lib } catch (Exception ex) { - CloseRconConsole(); - Debug.WriteLine($"RCON> {Config.Default.ServerSaveCommand} command.\r\n{ex.Message}"); } } @@ -442,7 +442,7 @@ namespace ServerManagerTool.Lib if (!string.IsNullOrWhiteSpace(Config.Default.ServerShutdown_CancelMessage)) { ProcessAlert(AlertType.Shutdown, Config.Default.ServerShutdown_CancelMessage); - SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, CancellationToken.None).Wait(); + SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, cancellationToken).Wait(); } ExitCode = EXITCODE_CANCELLED; @@ -503,7 +503,6 @@ namespace ServerManagerTool.Lib } else if (minutesLeft > 1) { - message = string.Empty; message = Config.Default.ServerShutdown_GraceMessage1.Replace("{minutes}", minutesLeft.ToString()); if (!string.IsNullOrWhiteSpace(UpdateReason)) message += $"\n\n{UpdateReason}"; @@ -525,7 +524,7 @@ namespace ServerManagerTool.Lib { ProcessAlert(AlertType.ShutdownReason, ShutdownReason); - message = $"{message} {ShutdownReason}"; + message = $"{message}\r\n{ShutdownReason}"; } sent = SendMessageAsync(message, cancellationToken).Result; @@ -534,7 +533,7 @@ namespace ServerManagerTool.Lib minutesLeft--; try { - var delay = 60000; + var delay = sent ? 60000 - Config.Default.SendMessageDelay : 60000; Task.Delay(delay, cancellationToken).Wait(cancellationToken); } catch { } @@ -576,7 +575,7 @@ namespace ServerManagerTool.Lib if (!string.IsNullOrWhiteSpace(Config.Default.ServerShutdown_CancelMessage)) { ProcessAlert(AlertType.Shutdown, Config.Default.ServerShutdown_CancelMessage); - SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, CancellationToken.None).Wait(); + SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, cancellationToken).Wait(); } ExitCode = EXITCODE_CANCELLED; @@ -594,7 +593,7 @@ namespace ServerManagerTool.Lib { ProcessAlert(AlertType.ShutdownReason, ShutdownReason); - message = $"{message} {ShutdownReason}"; + message = $"{message}\r\n{ShutdownReason}"; } SendMessageAsync(message, cancellationToken).Wait(); @@ -613,7 +612,7 @@ namespace ServerManagerTool.Lib if (!string.IsNullOrWhiteSpace(Config.Default.ServerShutdown_CancelMessage)) { ProcessAlert(AlertType.Shutdown, Config.Default.ServerShutdown_CancelMessage); - SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, CancellationToken.None).Wait(); + SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, cancellationToken).Wait(); } ExitCode = EXITCODE_CANCELLED; @@ -627,8 +626,8 @@ namespace ServerManagerTool.Lib LogProfileMessage("Stopping server..."); ProcessAlert(AlertType.Shutdown, Config.Default.Alert_ServerShutdownMessage); - TaskCompletionSource ts = new TaskCompletionSource(); - EventHandler handler = (s, e) => ts.TrySetResult(true); + var ts = new TaskCompletionSource(); + void handler(object s, EventArgs e) => ts.TrySetResult(true); if (process != null && !process.HasExited) { @@ -723,7 +722,7 @@ namespace ServerManagerTool.Lib LogProfileMessage("Updating server from steam.\r\n"); downloadSuccessful = !Config.Default.SteamCmdRedirectOutput; - DataReceivedEventHandler serverOutputHandler = (s, e) => + void serverOutputHandler(object s, DataReceivedEventArgs e) { var dataValue = e.Data ?? string.Empty; LogProfileMessage(dataValue); @@ -735,7 +734,7 @@ namespace ServerManagerTool.Lib { downloadSuccessful = true; } - }; + } var steamCmdInstallServerArgsFormat = Config.Default.SteamCmdInstallServerArgsFormat; var steamCmdArgs = SteamUtils.BuildSteamCmdArguments(steamCmdRemoveQuit, steamCmdInstallServerArgsFormat, Config.Default.SteamCmd_AnonymousUsername, _profile.InstallDirectory, string.Empty, Config.Default.AppIdServer, string.Empty, validate ? "validate" : string.Empty); @@ -744,7 +743,7 @@ namespace ServerManagerTool.Lib if (steamCmdRemoveQuit) SteamCMDProcessWindowStyle = ProcessWindowStyle.Normal; - success = ServerUpdater.UpgradeServerAsync(steamCmdFile, steamCmdArgs, workingDirectory, null, null, _profile.InstallDirectory, Config.Default.SteamCmdRedirectOutput ? serverOutputHandler : null, cancellationToken, SteamCMDProcessWindowStyle).Result; + success = ServerUpdater.UpgradeServerAsync(steamCmdFile, steamCmdArgs, workingDirectory, null, null, _profile.InstallDirectory, Config.Default.SteamCmdRedirectOutput ? (DataReceivedEventHandler)serverOutputHandler : null, cancellationToken, SteamCMDProcessWindowStyle).Result; if (success && downloadSuccessful) { LogProfileMessage("Finished server update."); @@ -773,6 +772,7 @@ namespace ServerManagerTool.Lib ExitCode = EXITCODE_SERVERUPDATEFAILED; } + // check if we need to update the mods if (updateMods) { if (success) @@ -1730,18 +1730,16 @@ namespace ServerManagerTool.Lib public void CreateProfileBackupArchiveFile(ServerProfileSnapshot profile = null) { + // do nothing if profile is null + if (profile == null) + return; + var oldProfile = _profile; try { - if (profile != null) - _profile = profile; + _profile = profile; - if (_profile == null) - { - ExitCode = EXITCODE_BADPROFILE; - return; - } // create the backup file. try @@ -1859,18 +1857,15 @@ namespace ServerManagerTool.Lib public void CreateServerBackupArchiveFile(StringBuilder emailMessage, ServerProfileSnapshot profile = null) { + // do nothing if profile is null + if (profile == null) + return; + var oldProfile = _profile; try { - if (profile != null) - _profile = profile; - - if (_profile == null) - { - ExitCode = EXITCODE_BADPROFILE; - return; - } + _profile = profile; // check if the servers save folder exists var saveFolder = GetServerSaveFolder(); @@ -2046,7 +2041,7 @@ namespace ServerManagerTool.Lib continue; // destination file does not exist, or is older. Override with the source file. - while(true) + while (true) { var retries = 0; try @@ -2066,11 +2061,48 @@ namespace ServerManagerTool.Lib public static string GetBranchName(string branchName) => string.IsNullOrWhiteSpace(branchName) ? Config.Default.DefaultServerBranchName : branchName; - public static string GetBranchLogFile(string branchName) => IOUtils.NormalizePath(Path.Combine(App.GetLogFolder(), _logPrefix, $"{_startTime:yyyyMMdd_HHmmss}{(string.IsNullOrWhiteSpace(branchName) ? string.Empty : $"_{branchName}")}.log")); - private string GetLauncherFile() => IOUtils.NormalizePath(Path.Combine(GetProfileServerConfigDir(_profile), Config.Default.LauncherFile)); - private static string GetLogFile() => IOUtils.NormalizePath(Path.Combine(App.GetLogFolder(), _logPrefix, $"{_startTime:yyyyMMdd_HHmmss}.log")); + private static string GetLogFolder(string logType) => IOUtils.NormalizePath(Path.Combine(App.GetLogFolder(), logType)); + + private static Logger GetLogger(string logFilePath, string logType, string logName) + { + return GetLogger(logFilePath, logType, logName ?? string.Empty, LogLevel.Debug, LogLevel.Fatal); + } + + private static Logger GetLogger(string logFilePath, string logType, string logName, LogLevel minLevel, LogLevel maxLevel) + { + if (string.IsNullOrWhiteSpace(logFilePath) || string.IsNullOrWhiteSpace(logType) || string.IsNullOrWhiteSpace(logName)) + return null; + + var loggerName = $"{logType}_{logName}".Replace(" ", "_"); + + if (LogManager.Configuration.FindTargetByName(loggerName) is null) + { + if (!Directory.Exists(logFilePath)) + Directory.CreateDirectory(logFilePath); + + var logFile = new FileTarget(loggerName) + { + FileName = Path.Combine(logFilePath, $"{logName}.log"), + Layout = "${time} [${level:uppercase=true}] ${message}", + ArchiveFileName = Path.Combine(logFilePath, $"{logName}.{{#}}.log"), + ArchiveNumbering = ArchiveNumberingMode.DateAndSequence, + ArchiveEvery = FileArchivePeriod.Day, + ArchiveDateFormat = "yyyyMMdd", + ArchiveOldFileOnStartup = true, + MaxArchiveFiles = Config.Default.LoggingMaxArchiveFiles, + MaxArchiveDays = Config.Default.LoggingMaxArchiveDays, + }; + LogManager.Configuration.AddTarget(loggerName, logFile); + + var rule = new LoggingRule(loggerName, minLevel, maxLevel, logFile); + LogManager.Configuration.LoggingRules.Add(rule); + LogManager.ReconfigExistingLoggers(); + } + + return LogManager.GetLogger(loggerName); + } private List GetModList() { @@ -2111,7 +2143,7 @@ namespace ServerManagerTool.Lib private static string GetProfileFile(ServerProfileSnapshot profile) => IOUtils.NormalizePath(Path.Combine(Config.Default.ConfigPath, $"{profile.ProfileId.ToLower()}{Config.Default.ProfileExtension}")); - private string GetProfileLogFile() => _profile != null ? IOUtils.NormalizePath(Path.Combine(App.GetLogFolder(), _profile.ProfileId.ToLower(), _logPrefix, $"{_startTime:yyyyMMdd_HHmmss}.log")) : GetLogFile(); + private string GetProfileLogFolder(string profileId, string logType) => IOUtils.NormalizePath(Path.Combine(App.GetProfileLogFolder(profileId), logType)); public static string GetProfileServerConfigDir(ServerProfile profile) => Path.Combine(profile.InstallDirectory, Config.Default.ServerConfigRelativePath); @@ -2123,7 +2155,7 @@ namespace ServerManagerTool.Lib { StringBuilder builder = new StringBuilder(); - var hashStr = Encoding.UTF8.GetBytes(directory ?? Assembly.GetEntryAssembly().Location); + var hashStr = Encoding.UTF8.GetBytes(directory ?? Assembly.GetExecutingAssembly().Location); var hash = hashAlgo.ComputeHash(hashStr); foreach (var b in hash) { @@ -2281,36 +2313,18 @@ namespace ServerManagerTool.Lib if (string.IsNullOrWhiteSpace(error)) return; - LogMessage($"***** ERROR: {error}"); + _loggerManager?.Error(error); + + Debug.WriteLine($"[ERROR] {error}"); } private static void LogMessage(string message) { message = message ?? string.Empty; - var logFile = GetLogFile(); - lock (LockObjectMessage) - { - if (!Directory.Exists(Path.GetDirectoryName(logFile))) - Directory.CreateDirectory(Path.GetDirectoryName(logFile)); + _loggerManager?.Info(message); - int retries = 0; - while (retries < 3) - { - try - { - File.AppendAllLines(logFile, new[] { $"{DateTime.Now.ToString("o", CultureInfo.CurrentCulture)}: {message}" }, Encoding.Unicode); - break; - } - catch (IOException) - { - retries++; - Task.Delay(WRITELOG_ERRORRETRYDELAY).Wait(); - } - } - } - - Debug.WriteLine(message); + Debug.WriteLine($"[INFO] {message}"); } private void LogBranchError(string branchName, string error, bool includeProgressCallback = true) @@ -2318,45 +2332,24 @@ namespace ServerManagerTool.Lib if (string.IsNullOrWhiteSpace(error)) return; - LogBranchMessage(branchName, $"***** ERROR: {error}", includeProgressCallback); + _loggerBranch?.Error(error); + + if (includeProgressCallback) + ProgressCallback?.Invoke(0, $"[ERROR] {error}"); + + Debug.WriteLine($"[ERROR] (Branch {GetBranchName(branchName) ?? "unknown"}) {error}"); } private void LogBranchMessage(string branchName, string message, bool includeProgressCallback = true) { message = message ?? string.Empty; - if (OutputLogs) - { - var logFile = GetBranchLogFile(branchName); - lock (LockObjectBranchMessage) - { - if (!Directory.Exists(Path.GetDirectoryName(logFile))) - Directory.CreateDirectory(Path.GetDirectoryName(logFile)); - - int retries = 0; - while (retries < 3) - { - try - { - File.AppendAllLines(logFile, new[] { $"{DateTime.Now.ToString("o", CultureInfo.CurrentCulture)}: {message}" }, Encoding.Unicode); - break; - } - catch (IOException) - { - retries++; - Task.Delay(WRITELOG_ERRORRETRYDELAY).Wait(); - } - } - } - } + _loggerBranch?.Info(message); if (includeProgressCallback) - ProgressCallback?.Invoke(0, message); + ProgressCallback?.Invoke(0, $"[INFO] {message}"); - if (_profile != null) - Debug.WriteLine($"[Branch {GetBranchName(branchName) ?? "unknown"}] {message}"); - else - Debug.WriteLine(message); + Debug.WriteLine($"[INFO] (Branch {GetBranchName(branchName) ?? "unknown"}) {message}"); } private void LogProfileError(string error, bool includeProgressCallback = true) @@ -2364,45 +2357,24 @@ namespace ServerManagerTool.Lib if (string.IsNullOrWhiteSpace(error)) return; - LogProfileMessage($"***** ERROR: {error}", includeProgressCallback); + _loggerProfile?.Error(error); + + if (includeProgressCallback) + ProgressCallback?.Invoke(0, $"[ERROR] {error}"); + + Debug.WriteLine($"[ERROR] (Profile {_profile?.ProfileName ?? "unknown"}) {error}"); } private void LogProfileMessage(string message, bool includeProgressCallback = true) { message = message ?? string.Empty; - if (OutputLogs) - { - var logFile = GetProfileLogFile(); - lock (LockObjectProfileMessage) - { - if (!Directory.Exists(Path.GetDirectoryName(logFile))) - Directory.CreateDirectory(Path.GetDirectoryName(logFile)); - - int retries = 0; - while (retries < 3) - { - try - { - File.AppendAllLines(logFile, new[] { $"{DateTime.Now.ToString("o", CultureInfo.CurrentCulture)}: {message}" }, Encoding.Unicode); - break; - } - catch (IOException) - { - retries++; - Task.Delay(WRITELOG_ERRORRETRYDELAY).Wait(); - } - } - } - } + _loggerProfile?.Info(message); if (includeProgressCallback) - ProgressCallback?.Invoke(0, message); + ProgressCallback?.Invoke(0, $"[INFO] {message}"); - if (_profile != null) - Debug.WriteLine($"[Profile {_profile?.ProfileName ?? "unknown"}] {message}"); - else - Debug.WriteLine(message); + Debug.WriteLine($"[INFO] (Profile {_profile?.ProfileName ?? "unknown"}) {message}"); } private void ProcessAlert(AlertType alertType, string alertMessage) @@ -2506,9 +2478,11 @@ namespace ServerManagerTool.Lib StringBuilder messageBody = new StringBuilder(body); Attachment attachment = null; - if (includeLogFile) + if (includeLogFile && _loggerProfile != null) { - var logFile = GetProfileLogFile(); + var fileTarget = LogManager.Configuration.FindTargetByName(_loggerProfile.Name) as FileTarget; + var fileLayout = fileTarget?.FileName as SimpleLayout; + var logFile = fileLayout?.Text ?? string.Empty; if (!string.IsNullOrWhiteSpace(logFile) && File.Exists(logFile)) { attachment = new Attachment(logFile); @@ -2549,9 +2523,9 @@ namespace ServerManagerTool.Lib var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endPoint, sendTimeOut: 10000, receiveTimeOut: 10000); if (server == null) { -//#if DEBUG +#if DEBUG LogProfileMessage($"FAILED: {nameof(SetupRconConsole)} - ServerQuery could not be created.", false); -//#endif +#endif return; } @@ -2564,9 +2538,9 @@ namespace ServerManagerTool.Lib _rconConsole = server.GetControl(_profile.AdminPassword); if (_rconConsole == null) { -//#if DEBUG +#if DEBUG LogProfileMessage($"FAILED: {nameof(SetupRconConsole)} - RconConsole could not be created ({_profile.AdminPassword}).", false); -//#endif +#endif return; } @@ -2576,10 +2550,10 @@ namespace ServerManagerTool.Lib } catch (Exception ex) { -//#if DEBUG +#if DEBUG LogProfileMessage($"ERROR: {nameof(SetupRconConsole)}\r\n{ex.Message}", false); LogProfileMessage($"ERROR: {nameof(SetupRconConsole)}\r\n{ex.StackTrace}", false); -//#endif +#endif } } @@ -2595,6 +2569,9 @@ namespace ServerManagerTool.Lib Mutex mutex = null; var createdNew = false; + if (OutputLogs) + _loggerProfile = GetLogger(GetProfileLogFolder(profile.ProfileId, LOGPREFIX_AUTOBACKUP), $"{LOGPREFIX_AUTOBACKUP}_{profile.ProfileId}", "Backup"); + try { // try to establish a mutex for the profile. @@ -2660,6 +2637,9 @@ namespace ServerManagerTool.Lib Mutex mutex = null; var createdNew = false; + if (OutputLogs) + _loggerProfile = GetLogger(GetProfileLogFolder(profile.ProfileId, LOGPREFIX_AUTOSHUTDOWN), $"{LOGPREFIX_AUTOSHUTDOWN}_{profile.ProfileId}", "Shutdown"); + try { // check if within the shutdown grace period (only performed when restarting the server) @@ -2753,6 +2733,9 @@ namespace ServerManagerTool.Lib Mutex mutex = null; var createdNew = false; + if (OutputLogs) + _loggerProfile = GetLogger(GetProfileLogFolder(profile.ProfileId, LOGPREFIX_AUTOUPDATE), $"{LOGPREFIX_AUTOUPDATE}_{profile.ProfileId}", "Update"); + try { LogBranchMessage(branch.BranchName, $"[{_profile.ProfileName}] Started server update process."); @@ -2824,6 +2807,9 @@ namespace ServerManagerTool.Lib Mutex mutex = null; var createdNew = false; + if (OutputLogs) + _loggerBranch = GetLogger(GetLogFolder(LOGPREFIX_AUTOUPDATE), $"{LOGPREFIX_AUTOUPDATE}_{branch.BranchName}", GetBranchName(branch.BranchName)); + try { LogBranchMessage(branch.BranchName, $"Started branch update process."); @@ -2860,8 +2846,9 @@ namespace ServerManagerTool.Lib { var app = new ServerApp { - SendAlerts = true, - SendEmails = true, + OutputLogs = OutputLogs, + SendAlerts = SendAlerts, + SendEmails = SendEmails, ServerProcess = ServerProcess, SteamCMDProcessWindowStyle = ProcessWindowStyle.Hidden }; @@ -2879,8 +2866,9 @@ namespace ServerManagerTool.Lib var app = new ServerApp { - SendAlerts = true, - SendEmails = true, + OutputLogs = OutputLogs, + SendAlerts = SendAlerts, + SendEmails = SendEmails, ServerProcess = ServerProcess, SteamCMDProcessWindowStyle = ProcessWindowStyle.Hidden }; @@ -2935,10 +2923,10 @@ namespace ServerManagerTool.Lib public static int PerformAutoBackup() { - _logPrefix = LOGPREFIX_AUTOBACKUP; - int exitCode = EXITCODE_NORMALEXIT; + _loggerManager = GetLogger(GetLogFolder(LOGPREFIX_AUTOBACKUP), LOGPREFIX_AUTOBACKUP, "AutoBackup"); + try { // check if a data directory has been setup. @@ -2951,9 +2939,10 @@ namespace ServerManagerTool.Lib var exitCodes = new ConcurrentDictionary(); Parallel.ForEach(_profiles.Keys.Where(p => p.EnableAutoBackup), profile => { - var app = new ServerApp() + var app = new ServerApp { DeleteOldServerBackupFiles = Config.Default.AutoBackup_DeleteOldFiles, + OutputLogs = true, SendAlerts = true, SendEmails = true, ServerProcess = ServerProcessType.AutoBackup @@ -2983,10 +2972,10 @@ namespace ServerManagerTool.Lib public static int PerformAutoShutdown(string argument, ServerProcessType type) { - _logPrefix = LOGPREFIX_AUTOSHUTDOWN; - int exitCode = EXITCODE_NORMALEXIT; + _loggerManager = GetLogger(GetLogFolder(LOGPREFIX_AUTOSHUTDOWN), LOGPREFIX_AUTOSHUTDOWN, "AutoShutdown"); + try { // check if a data directory has been setup. @@ -3038,8 +3027,9 @@ namespace ServerManagerTool.Lib if (!enableAutoShutdown) return EXITCODE_AUTOSHUTDOWNNOTENABLED; - var app = new ServerApp() + var app = new ServerApp { + OutputLogs = true, SendAlerts = true, SendEmails = true, ServerProcess = type, @@ -3063,13 +3053,13 @@ namespace ServerManagerTool.Lib public static int PerformAutoUpdate() { - _logPrefix = LOGPREFIX_AUTOUPDATE; - int exitCode = EXITCODE_NORMALEXIT; Mutex mutex = null; bool createdNew = false; + _loggerManager = GetLogger(GetLogFolder(LOGPREFIX_AUTOUPDATE), LOGPREFIX_AUTOUPDATE, "AutoUpdate"); + try { // check if a data directory has been setup. @@ -3111,6 +3101,9 @@ namespace ServerManagerTool.Lib Parallel.ForEach(branches, branch => { app = new ServerApp { + OutputLogs = true, + SendAlerts = true, + SendEmails = true, ServerProcess = ServerProcessType.AutoUpdate, SteamCMDProcessWindowStyle = ProcessWindowStyle.Hidden }; @@ -3129,6 +3122,9 @@ namespace ServerManagerTool.Lib app = new ServerApp { + OutputLogs = true, + SendAlerts = true, + SendEmails = true, ServerProcess = ServerProcessType.AutoUpdate, SteamCMDProcessWindowStyle = ProcessWindowStyle.Hidden }; diff --git a/src/ConanServerManager/NLog.config b/src/ConanServerManager/NLog.config index 70487eb2..8e2599c8 100644 --- a/src/ConanServerManager/NLog.config +++ b/src/ConanServerManager/NLog.config @@ -15,48 +15,53 @@ /> diff --git a/src/ConanServerManager/UserControls/GlobalSettingsControl.xaml b/src/ConanServerManager/UserControls/GlobalSettingsControl.xaml index 430ccbd6..c9f4600f 100644 --- a/src/ConanServerManager/UserControls/GlobalSettingsControl.xaml +++ b/src/ConanServerManager/UserControls/GlobalSettingsControl.xaml @@ -711,6 +711,8 @@ + + @@ -728,7 +730,11 @@ - + + + + + diff --git a/src/ConanServerManager/UserControls/GlobalSettingsControl.xaml.cs b/src/ConanServerManager/UserControls/GlobalSettingsControl.xaml.cs index a89cbfb1..e99c6e26 100644 --- a/src/ConanServerManager/UserControls/GlobalSettingsControl.xaml.cs +++ b/src/ConanServerManager/UserControls/GlobalSettingsControl.xaml.cs @@ -116,6 +116,8 @@ namespace ServerManagerTool Config.DiscordBotWhitelist.Clear(); Config.DiscordBotWhitelist.AddRange(DiscordBotWhitelist.Select(i => i.BotId).ToArray()); + + App.ReconfigureLogging(); } private string GetDeployedVersion() diff --git a/src/ConanServerManager/VersionFeed.xml b/src/ConanServerManager/VersionFeed.xml index eb6c1b92..a6d98468 100644 --- a/src/ConanServerManager/VersionFeed.xml +++ b/src/ConanServerManager/VersionFeed.xml @@ -9,13 +9,18 @@ urn:uuid:19B09A66-43F2-4D5F-AF33-5C77D7EA9A6B - 1.1.58 (1.1.58.10) - 1.1.58.10 + 1.1.58 (1.1.58.11) + 1.1.58.11 2021-12-18T00:00:00Z

+ BUGFIX +
+

    +
  • Fixed the cleanup of the log files generated by the auto processes (Backup, Update and Shutdown/Restart).
    NOTE: It will not cleanup the existing files, you need to do that manually.
  • +
NEW
    @@ -23,6 +28,7 @@
  • Global Settings - Discord Bot section - Added a log level droplist.
  • Global Settings - Discord Bot section - Added a checkbox to allow all bots.
  • Global Settings - Discord Bot section - Added a whitelist to allow bots to send commands to the server manager.
  • +
  • Global Settings - Added new Log settings which allow you to turn if on/off and set the number of days/files to retain.
  • Server Settings - Discord Bot section - Added an alias that can be used with the discord command instead of the profile id.
CHANGE diff --git a/src/ConanServerManager/VersionFeedBeta.xml b/src/ConanServerManager/VersionFeedBeta.xml index e30a105d..8d6d1b22 100644 --- a/src/ConanServerManager/VersionFeedBeta.xml +++ b/src/ConanServerManager/VersionFeedBeta.xml @@ -7,6 +7,34 @@ 2021-12-17T00:00:00Z + + urn:uuid:40905243-2E97-4FCD-ACEA-53C9D42E69F0 + 1.1.58 (1.1.58.11) + 1.1.58.11 + + 2021-12-18T00:00:00Z + +
+

+ BUGFIX +
+

    +
  • Fixed the cleanup of the log files generated by the auto processes (Backup, Update and Shutdown/Restart).
    NOTE: It will not cleanup the existing files, you need to do that manually.
  • +
+ NEW +
+
    +
  • Global Settings - Added new Log settings which allow you to turn if on/off and set the number of days/files to retain.
  • +
+

+
+
+ + bletch + bletch1971@hotmail.com + +
+ urn:uuid:6EF11E7A-65D0-481E-A712-71CDB6C3F23F 1.1.58 (1.1.58.10) diff --git a/src/ServerManager.Discord/Models/DiscordBotConfig.cs b/src/ServerManager.Discord/Models/DiscordBotConfig.cs index aa783c80..e60c14c7 100644 --- a/src/ServerManager.Discord/Models/DiscordBotConfig.cs +++ b/src/ServerManager.Discord/Models/DiscordBotConfig.cs @@ -7,6 +7,10 @@ namespace ServerManagerTool.DiscordBot.Models { public LogLevel LogLevel { get; set; } = LogLevel.Info; + public int MaxArchiveDays { get; set; } = 30; + + public int MaxArchiveFiles { get; set; } = 30; + public string DiscordToken { get; set; } = string.Empty; public string CommandPrefix { get; set; } = string.Empty; diff --git a/src/ServerManager.Discord/ServerManager.Discord.csproj b/src/ServerManager.Discord/ServerManager.Discord.csproj index 3a28fd00..61b8feca 100644 --- a/src/ServerManager.Discord/ServerManager.Discord.csproj +++ b/src/ServerManager.Discord/ServerManager.Discord.csproj @@ -21,6 +21,7 @@ + diff --git a/src/ServerManager.Discord/Services/LoggingService.cs b/src/ServerManager.Discord/Services/LoggingService.cs index a2e021e0..5922b503 100644 --- a/src/ServerManager.Discord/Services/LoggingService.cs +++ b/src/ServerManager.Discord/Services/LoggingService.cs @@ -1,6 +1,9 @@ using Discord; using Discord.Commands; using Discord.WebSocket; +using NLog; +using NLog.Config; +using NLog.Targets; using ServerManagerTool.DiscordBot.Models; using System; using System.IO; @@ -10,22 +13,21 @@ namespace ServerManagerTool.DiscordBot.Services { public class LoggingService { + private readonly Logger _logger; private readonly DiscordSocketClient _client; private readonly CommandService _commands; private readonly DiscordBotConfig _botConfig; - private string LogDirectory { get; } - private string LogFile => Path.Combine(LogDirectory, $"ServerManager_DiscordBot.{DateTime.Now:yyyyMMdd}.log"); - public LoggingService(DiscordSocketClient client, CommandService commands, DiscordBotConfig botConfig) { _client = client; _commands = commands; _botConfig = botConfig; - // Get the data directory from the config file - var rootDirectory = _botConfig.DataDirectory ?? AppContext.BaseDirectory; - LogDirectory = Path.Combine(rootDirectory, "logs"); + var logFilePath = Path.Combine(_botConfig.DataDirectory ?? AppContext.BaseDirectory, "logs"); + + _logger = GetLogger(logFilePath, "", "ServerManager_DiscordBot", LogLevel.Debug, LogLevel.Fatal, _botConfig.MaxArchiveFiles, _botConfig.MaxArchiveDays); + Console.WriteLine($"{DateTime.Now:HH:mm:ss.ffff} [INFO] Logging Enabled: {LogManager.IsLoggingEnabled()}"); _client.Log += OnLogAsync; _commands.Log += OnLogAsync; @@ -33,25 +35,62 @@ namespace ServerManagerTool.DiscordBot.Services internal async Task OnLogAsync(LogMessage message) { - // Create the log directory if it doesn't exist - if (!Directory.Exists(LogDirectory)) + switch (message.Severity) { - Directory.CreateDirectory(LogDirectory); + case LogSeverity.Critical: + _logger?.Fatal($"{message.Source}: {message.Exception?.ToString() ?? message.Message}"); + break; + case LogSeverity.Error: + _logger?.Error($"{message.Source}: {message.Exception?.ToString() ?? message.Message}"); + break; + case LogSeverity.Warning: + _logger?.Warn($"{message.Source}: {message.Exception?.ToString() ?? message.Message}"); + break; + case LogSeverity.Info: + _logger?.Info($"{message.Source}: {message.Exception?.ToString() ?? message.Message}"); + break; + case LogSeverity.Verbose: + case LogSeverity.Debug: + _logger?.Debug($"{message.Source}: {message.Exception?.ToString() ?? message.Message}"); + break; } - // Create today's log file if it doesn't exist - if (!File.Exists(LogFile)) - { - File.Create(LogFile).Dispose(); - } - - var logText = $"{DateTime.Now:HH:mm:ss:ffff} [{message.Severity}] {message.Source}: {message.Exception?.ToString() ?? message.Message}"; - - // Write the log text to a file - File.AppendAllText(LogFile, logText + "\n"); - // Write the log text to the console - await Console.Out.WriteLineAsync(logText); + await Console.Out.WriteLineAsync($"{DateTime.Now:HH:mm:ss.ffff} [{message.Severity}] {message.Source}: {message.Exception?.ToString() ?? message.Message}"); + } + + private static Logger GetLogger(string logFilePath, string logType, string logName, LogLevel minLevel, LogLevel maxLevel, int maxArchiveFiles, int maxArchiveDays) + { + if (string.IsNullOrWhiteSpace(logFilePath) || string.IsNullOrWhiteSpace(logName)) + return null; + + var loggerName = $"{logType ?? string.Empty}_{logName}".Replace(" ", "_"); + + if (LogManager.Configuration.FindTargetByName(loggerName) is null) + { + if (!Directory.Exists(logFilePath)) + Directory.CreateDirectory(logFilePath); + + var logFile = new FileTarget(loggerName) + { + FileName = Path.Combine(logFilePath, $"{logName}.log"), + Layout = "${time} [${level:uppercase=true}] ${message}", + ArchiveFileName = Path.Combine(logFilePath, $"{logName}.{{#}}.log"), + ArchiveNumbering = ArchiveNumberingMode.Date, + ArchiveEvery = FileArchivePeriod.Day, + ArchiveDateFormat = "yyyyMMdd", + ArchiveOldFileOnStartup = true, + MaxArchiveFiles = maxArchiveFiles, + MaxArchiveDays = maxArchiveDays, + }; + LogManager.Configuration.AddTarget(loggerName, logFile); + + var rule = new LoggingRule(loggerName, minLevel, maxLevel, logFile); + LogManager.Configuration.LoggingRules.Add(rule); + LogManager.ReconfigExistingLoggers(); + } + + return LogManager.GetLogger(loggerName); } } } \ No newline at end of file