Fixed the cleanup of the log files generated by the auto processes (Backup, Update and Shutdown/Restart)

Added new Log settings which allow you to turn if on/off and set the number of days/files to retain
Language file updates
This commit is contained in:
Brett Hewitson 2021-12-18 21:31:36 +10:00
parent f582e1e72a
commit dace70a37c
29 changed files with 821 additions and 431 deletions

View file

@ -535,7 +535,7 @@
<value>500</value>
</setting>
<setting name="UpdateDirectoryPermissions" serializeAs="String">
<value>True</value>
<value>False</value>
</setting>
<setting name="AutoUpdate_VerifyServerAfterUpdate" serializeAs="String">
<value>False</value>
@ -632,6 +632,15 @@
<setting name="DiscordBotAllowAllBots" serializeAs="String">
<value>False</value>
</setting>
<setting name="LoggingEnabled" serializeAs="String">
<value>True</value>
</setting>
<setting name="LoggingMaxArchiveFiles" serializeAs="String">
<value>30</value>
</setting>
<setting name="LoggingMaxArchiveDays" serializeAs="String">
<value>30</value>
</setting>
</ServerManagerTool.Config>
</userSettings>
</configuration>

View file

@ -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()}");
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -492,7 +492,7 @@
<Value Profile="(Default)">500</Value>
</Setting>
<Setting Name="UpdateDirectoryPermissions" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="AutoUpdate_VerifyServerAfterUpdate" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
@ -606,5 +606,14 @@
<Setting Name="DiscordBotAllowAllBots" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="LoggingEnabled" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="LoggingMaxArchiveFiles" Type="System.Int32" Scope="User">
<Value Profile="(Default)">30</Value>
</Setting>
<Setting Name="LoggingMaxArchiveDays" Type="System.Int32" Scope="User">
<Value Profile="(Default)">30</Value>
</Setting>
</Settings>
</SettingsFile>

View file

@ -79,6 +79,7 @@
<sys:String x:Key="SliderUnits_Minutes">minutes</sys:String>
<sys:String x:Key="SliderUnits_Hours">hours</sys:String>
<sys:String x:Key="SliderUnits_Days">days</sys:String>
<sys:String x:Key="SliderUnits_Files">files</sys:String>
<sys:String x:Key="SliderUnits_Items">items</sys:String>
<sys:String x:Key="SliderUnits_XP">xp</sys:String>
<sys:String x:Key="SliderUnits_Players">players</sys:String>
@ -735,6 +736,12 @@
<sys:String x:Key="GlobalSettings_VerifyServerAfterUpdateTooltip">If enabled, after the server has been updated from the cache, it will perform a server verification using steamcmd.</sys:String>
<sys:String x:Key="GlobalSettings_UpdateDirectoryPermissionsLabel">Update Directory Permissions on Save</sys:String>
<sys:String x:Key="GlobalSettings_UpdateDirectoryPermissionsTooltip">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.</sys:String>
<sys:String x:Key="GlobalSettings_EnableLoggingLabel">Enable Logging</sys:String>
<sys:String x:Key="GlobalSettings_EnableLoggingTooltip">If enabled, all logging will be enabled.</sys:String>
<sys:String x:Key="GlobalSettings_LoggingMaxArchiveDaysLabel">Delete Logs After</sys:String>
<sys:String x:Key="GlobalSettings_LoggingMaxArchiveDaysTooltip">How old the log files must be to be deleted in days.</sys:String>
<sys:String x:Key="GlobalSettings_LoggingMaxArchiveFilesLabel">Max Number of Logs</sys:String>
<sys:String x:Key="GlobalSettings_LoggingMaxArchiveFilesTooltip">The maximum number of log files that will be kept.</sys:String>
<sys:String x:Key="GlobalSettings_AutoUpdateLabel">Enable Auto Update</sys:String>
<sys:String x:Key="GlobalSettings_AutoUpdate_GameServerLabel">Game Server</sys:String>

View file

@ -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<ServerProfileSnapshot, ServerProfile> _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<bool> ts = new TaskCompletionSource<bool>();
EventHandler handler = (s, e) => ts.TrySetResult(true);
var ts = new TaskCompletionSource<bool>();
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<string> 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<ServerProfileSnapshot, int>();
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
};

View file

@ -15,48 +15,53 @@
/>
<target name="debugFile" xsi:type="File"
fileName="${logDir}/ServerManager_Debug.log"
layout="${time} ${message}"
layout="${time} [${level:uppercase=true}] ${message}"
archiveFileName="${logDir}/ServerManager_Debug.{#}.log"
archiveNumbering="DateAndSequence"
archiveEvery="Day"
archiveDateFormat="yyyyMMdd"
maxArchiveFiles="30"
maxArchiveDays="30"
/>
<target name="errorFile" xsi:type="File"
fileName="${logDir}/ServerManager_Error.log"
layout="${time} ${message}"
layout="${time} [${level:uppercase=true}] ${message}"
archiveFileName="${logDir}/ServerManager_Error.{#}.log"
archiveNumbering="DateAndSequence"
archiveEvery="Day"
archiveDateFormat="yyyyMMdd"
maxArchiveFiles="30"
maxArchiveDays="30"
/>
<target name="scripts" xsi:type="File"
fileName="${logDir}/ServerManager_Scripts.log"
layout="${time} ${message}"
layout="${time} [${level:uppercase=true}] ${message}"
archiveFileName="${logDir}/ServerManager_Scripts.{#}.log"
archiveNumbering="DateAndSequence"
archiveEvery="Day"
archiveDateFormat="yyyyMMdd"
maxArchiveFiles="30"
maxArchiveDays="30"
/>
<target name="statuswatcher" xsi:type="File"
fileName="${logDir}/ServerManager_ServerStatus.log"
layout="${time} ${message}"
layout="${time} [${level:uppercase=true}] ${message}"
archiveFileName="${logDir}/ServerManager_ServerStatus.{#}.log"
archiveNumbering="DateAndSequence"
archiveEvery="Day"
archiveDateFormat="yyyyMMdd"
maxArchiveFiles="30"
maxArchiveDays="30"
/>
<target name="taskscheduler" xsi:type="File"
fileName="${logDir}/ServerManager_TaskScheduler.log"
layout="${time} ${message}"
layout="${time} [${level:uppercase=true}] ${message}"
archiveFileName="${logDir}/ServerManager_TaskScheduler.{#}.log"
archiveNumbering="DateAndSequence"
archiveEvery="Day"
archiveDateFormat="yyyyMMdd"
maxArchiveFiles="30"
maxArchiveDays="30"
/>
</targets>

View file

@ -711,6 +711,8 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
@ -728,7 +730,11 @@
<CheckBox Grid.Row="3" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_SteamCmdRemoveQuitLabel}" IsChecked="{Binding CommonConfig.SteamCmdRemoveQuit, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_SteamCmdRemoveQuitTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="3" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_UpdateDirectoryPermissionsLabel}" IsChecked="{Binding Config.UpdateDirectoryPermissions, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_UpdateDirectoryPermissionsTooltip}" HorizontalAlignment="Left"/>
<cctl:AnnotatedSlider Grid.Row="4" Grid.Column="0" Margin="1" Label="{DynamicResource GlobalSettings_WorldSaveDelayLabel}" Value="{Binding Config.ServerShutdown_WorldSaveDelay, Converter={cc:IntRangeValueConverter 10, 300}}" Minimum="10" Maximum="300" SmallChange="10" LargeChange="50" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Seconds}" ToolTip="{DynamicResource GlobalSettings_WorldSaveDelayTooltip}"/>
<CheckBox Grid.Row="4" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EnableLoggingLabel}" IsChecked="{Binding Config.LoggingEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_EnableLoggingTooltip}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<cctl:AnnotatedSlider Grid.Row="4" Grid.Column="1" Margin="0" Label="{DynamicResource GlobalSettings_WorldSaveDelayLabel}" Value="{Binding Config.ServerShutdown_WorldSaveDelay, Converter={cc:IntRangeValueConverter 10, 300}}" Minimum="10" Maximum="300" SmallChange="10" LargeChange="50" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Seconds}" ToolTip="{DynamicResource GlobalSettings_WorldSaveDelayTooltip}"/>
<cctl:AnnotatedSlider Grid.Row="5" Grid.Column="0" Margin="0" Label="{DynamicResource GlobalSettings_LoggingMaxArchiveDaysLabel}" Value="{Binding Config.LoggingMaxArchiveDays}" Minimum="1" Maximum="365" SmallChange="1" LargeChange="5" TickFrequency="5" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" SuffixRelativeMinWidth="40" Suffix="{DynamicResource SliderUnits_Days}" ToolTip="{DynamicResource GlobalSettings_LoggingMaxArchiveDaysTooltip}" IsEnabled="{Binding Config.LoggingEnabled}"/>
<cctl:AnnotatedSlider Grid.Row="6" Grid.Column="0" Margin="0" Label="{DynamicResource GlobalSettings_LoggingMaxArchiveFilesLabel}" Value="{Binding Config.LoggingMaxArchiveFiles}" Minimum="1" Maximum="1000" SmallChange="1" LargeChange="5" TickFrequency="5" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" SuffixRelativeMinWidth="40" Suffix="{DynamicResource SliderUnits_Files}" ToolTip="{DynamicResource GlobalSettings_LoggingMaxArchiveFilesTooltip}" IsEnabled="{Binding Config.LoggingEnabled}"/>
</Grid>
</GroupBox>

View file

@ -116,6 +116,8 @@ namespace ServerManagerTool
Config.DiscordBotWhitelist.Clear();
Config.DiscordBotWhitelist.AddRange(DiscordBotWhitelist.Select(i => i.BotId).ToArray());
App.ReconfigureLogging();
}
private string GetDeployedVersion()

View file

@ -9,13 +9,18 @@
<entry>
<id>urn:uuid:19B09A66-43F2-4D5F-AF33-5C77D7EA9A6B</id>
<title>1.1.58 (1.1.58.10)</title>
<summary>1.1.58.10</summary>
<title>1.1.58 (1.1.58.11)</title>
<summary>1.1.58.11</summary>
<link href="" />
<updated>2021-12-18T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed the cleanup of the log files generated by the auto processes (Backup, Update and Shutdown/Restart).<br/>NOTE: It will not cleanup the existing files, you need to do that manually.</li>
</ul>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
@ -23,6 +28,7 @@
<li>Global Settings - Discord Bot section - Added a log level droplist.</li>
<li>Global Settings - Discord Bot section - Added a checkbox to allow all bots.</li>
<li>Global Settings - Discord Bot section - Added a whitelist to allow bots to send commands to the server manager.</li>
<li>Global Settings - Added new Log settings which allow you to turn if on/off and set the number of days/files to retain.</li>
<li>Server Settings - Discord Bot section - Added an alias that can be used with the discord command instead of the profile id.</li>
</ul>
<u style="font-size: .9em;">CHANGE</u>

View file

@ -7,6 +7,34 @@
<link href="http://servermanagers.freeforums.net/" />
<updated>2021-12-17T00:00:00Z</updated>
<entry>
<id>urn:uuid:40905243-2E97-4FCD-ACEA-53C9D42E69F0</id>
<title>1.1.58 (1.1.58.11)</title>
<summary>1.1.58.11</summary>
<link href="" />
<updated>2021-12-18T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed the cleanup of the log files generated by the auto processes (Backup, Update and Shutdown/Restart).<br/>NOTE: It will not cleanup the existing files, you need to do that manually.</li>
</ul>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>Global Settings - Added new Log settings which allow you to turn if on/off and set the number of days/files to retain.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:6EF11E7A-65D0-481E-A712-71CDB6C3F23F</id>
<title>1.1.58 (1.1.58.10)</title>