ModernUO/Projects/UOContent/Misc/CrashGuard.cs
2025-12-27 16:47:28 -08:00

205 lines
6.1 KiB
C#

using System;
using System.IO;
using Server.Accounting;
using Server.Logging;
using Server.Network;
using Server.Saves;
namespace Server.Misc
{
public static class CrashGuard
{
private static readonly ILogger logger = LogFactory.GetLogger(typeof(CrashGuard));
private static bool Enabled;
private static bool SaveBackup;
private static bool RestartServer; // Disable this if using a daemon/service
private static bool GenerateReport;
public static void Configure()
{
Enabled = ServerConfiguration.GetOrUpdateSetting("crashGuard.enabled", true);
SaveBackup = ServerConfiguration.GetOrUpdateSetting("crashGuard.saveBackup", true);
RestartServer = ServerConfiguration.GetOrUpdateSetting("crashGuard.restartServer", true);
GenerateReport = ServerConfiguration.GetOrUpdateSetting("crashGuard.generateReport", true);
}
public static void Initialize()
{
if (Enabled)
{
EventSink.ServerCrashed += CrashGuard_OnCrash;
}
}
public static void CrashGuard_OnCrash(ServerCrashedEventArgs e)
{
if (GenerateReport)
{
GenerateCrashReport(e);
}
if (SaveBackup)
{
Backup();
}
if (RestartServer)
{
e.Close = true;
Core.Kill(true);
}
else
{
World.WaitForWriteCompletion();
}
}
private static void SendEmail(string filePath)
{
logger.Information("Sending crash email");
Email.SendCrashEmail(filePath);
}
private static void DirectoryCopy(string sourceDirName, string destDirName)
{
// Get the subdirectories for the specified directory.
var dir = new DirectoryInfo(sourceDirName);
var dirs = dir.GetDirectories();
var files = dir.GetFiles();
foreach (var file in files)
{
var tempPath = Path.Combine(destDirName, file.Name);
file.CopyTo(tempPath, false);
}
foreach (var subdir in dirs)
{
var tempPath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, tempPath);
}
}
private static void Backup()
{
logger.Information("Backing up");
try
{
var timeStamp = Utility.GetTimeStamp();
var backupPath = PathUtility.EnsureDirectory(Path.Combine(AutoArchive.BackupPath, "Crashed", timeStamp));
var savePath = World.SavePath;
if (Directory.Exists(savePath))
{
DirectoryCopy(savePath, backupPath);
}
logger.Information("Backup {Status}", "done");
}
catch
{
logger.Error("Backup {Status}", "failed");
}
}
private static void GenerateCrashReport(ServerCrashedEventArgs e)
{
logger.Information("Generating crash report");
try
{
var timeStamp = Utility.GetTimeStamp();
var fileName = $"Crash {timeStamp}.log";
var root = Core.BaseDirectory;
var filePath = Path.Combine(root, fileName);
using (var op = new StreamWriter(filePath))
{
var ver = Core.Version;
op.WriteLine("Server Crash Report");
op.WriteLine("===================");
op.WriteLine();
op.WriteLine($"ModernUO Version {ver.Major}.{ver.Minor}, Build {ver.Build}.{ver.Revision}");
op.WriteLine("Operating System: {0}", Environment.OSVersion);
op.WriteLine(".NET Framework: {0}", Environment.Version);
op.WriteLine("Time: {0}", timeStamp);
try
{
op.WriteLine($"Accounts: {Accounts.Count}");
}
catch
{
// ignored
}
try
{
op.WriteLine($"Mobiles: {World.Mobiles.Count}");
}
catch
{
// ignored
}
try
{
op.WriteLine($"Items: {World.Items.Count}");
}
catch
{
// ignored
}
op.WriteLine($"Exception: {e.Exception}");
op.WriteLine();
op.WriteLine("Clients:");
try
{
var states = NetState.Instances;
op.WriteLine($"- Count: {states.Count}");
foreach (var ns in NetState.Instances)
{
op.Write($"+ {ns}:");
if (ns.Account is Account a)
{
op.Write($" (account = {a.Username})");
}
var m = ns.Mobile;
if (m != null)
{
op.Write($" (mobile = {m.Serial} '{m.Name}')");
}
op.WriteLine();
}
}
catch
{
op.WriteLine("- Failed");
}
}
logger.Information("Crash report generated");
SendEmail(filePath);
}
catch
{
logger.Error("Crash report generation failed");
}
}
}
}