mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-27 23:17:20 +01:00
Add logging to the host watchdog
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Console;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Host.Watchdog;
|
||||
|
||||
namespace Tgstation.Server.Host.Console
|
||||
@@ -13,11 +16,29 @@ namespace Tgstation.Server.Host.Console
|
||||
/// </summary>
|
||||
internal static IWatchdogFactory WatchdogFactory { get; set; } = new WatchdogFactory();
|
||||
|
||||
/// <summary>
|
||||
/// Entrypoint for the application
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments for the <see cref="Program"/></param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation</returns>
|
||||
internal static Task Main(string[] args) => WatchdogFactory.CreateWatchdog().RunAsync(args, default);
|
||||
/// <summary>
|
||||
/// Entrypoint for the application
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments for the <see cref="Program"/></param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation</returns>
|
||||
internal static async Task Main(string[] args)
|
||||
{
|
||||
using (var loggerFactory = new LoggerFactory())
|
||||
{
|
||||
var arguments = new List<string>(args);
|
||||
var trace = arguments.Remove("--trace-host-watchdog");
|
||||
var debug = arguments.Remove("--debug-host-watchdog");
|
||||
|
||||
loggerFactory.AddConsole(trace ? LogLevel.Trace : debug ? LogLevel.Debug : LogLevel.Information, true);
|
||||
|
||||
if (trace && debug)
|
||||
{
|
||||
loggerFactory.CreateLogger(nameof(Program)).LogCritical("Please specify only 1 of --trace-host-watchdog or --debug-host-watchdog!");
|
||||
return;
|
||||
}
|
||||
//default CancellationToken because the Host handles that internally
|
||||
await WatchdogFactory.CreateWatchdog(loggerFactory).RunAsync(arguments.ToArray(), default).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using McMaster.Extensions.CommandLineUtils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Configuration.Install;
|
||||
@@ -97,7 +98,8 @@ namespace Tgstation.Server.Host.Service
|
||||
installer.Uninstall(null);
|
||||
}
|
||||
else
|
||||
ServiceBase.Run(new ServerService(new WatchdogFactory()));
|
||||
using (var loggerFactory = new LoggerFactory())
|
||||
ServiceBase.Run(new ServerService(new WatchdogFactory(), loggerFactory));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.EventLog;
|
||||
using Microsoft.Extensions.Logging.EventLog.Internal;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.ServiceProcess;
|
||||
using System.Threading;
|
||||
@@ -10,7 +14,7 @@ namespace Tgstation.Server.Host.Service
|
||||
/// <summary>
|
||||
/// Represents a <see cref="IWatchdog"/> as a <see cref="ServiceBase"/>
|
||||
/// </summary>
|
||||
sealed class ServerService : ServiceBase
|
||||
sealed class ServerService : ServiceBase, IEventLog
|
||||
{
|
||||
/// <summary>
|
||||
/// The canonical windows service name
|
||||
@@ -20,7 +24,7 @@ namespace Tgstation.Server.Host.Service
|
||||
/// <summary>
|
||||
/// The <see cref="IWatchdog"/> for the <see cref="ServerService"/>
|
||||
/// </summary>
|
||||
IWatchdog watchdog;
|
||||
readonly IWatchdog watchdog;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Task"/> recieved from <see cref="IWatchdog.RunAsync(string[], CancellationToken)"/> of <see cref="watchdog"/>
|
||||
@@ -32,18 +36,33 @@ namespace Tgstation.Server.Host.Service
|
||||
/// </summary>
|
||||
CancellationTokenSource cancellationTokenSource;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="ServerService"/>
|
||||
/// </summary>
|
||||
/// <param name="watchdogFactory">The <see cref="IWatchdogFactory"/> to create <see cref="watchdog"/> with</param>
|
||||
public ServerService(IWatchdogFactory watchdogFactory)
|
||||
/// <summary>
|
||||
/// Construct a <see cref="ServerService"/>
|
||||
/// </summary>
|
||||
/// <param name="watchdogFactory">The <see cref="IWatchdogFactory"/> to create <see cref="watchdog"/> with</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> for <paramref name="watchdogFactory"/></param>
|
||||
public ServerService(IWatchdogFactory watchdogFactory, ILoggerFactory loggerFactory)
|
||||
{
|
||||
if (watchdogFactory == null)
|
||||
throw new ArgumentNullException(nameof(watchdogFactory));
|
||||
if(loggerFactory == null)
|
||||
throw new ArgumentNullException(nameof(loggerFactory));
|
||||
|
||||
loggerFactory.AddEventLog(new EventLogSettings
|
||||
{
|
||||
EventLog = this
|
||||
});
|
||||
|
||||
ServiceName = Name;
|
||||
watchdog = watchdogFactory.CreateWatchdog();
|
||||
watchdog = watchdogFactory.CreateWatchdog(loggerFactory);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int MaxMessageSize => (int)EventLog.MaximumKilobytes * 1024;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void WriteEntry(string message, EventLogEntryType type, int eventID, short category) => EventLog.WriteEntry(message, type, eventID, category);
|
||||
|
||||
/// <inheritdoc />
|
||||
[SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "cancellationTokenSource")]
|
||||
protected override void Dispose(bool disposing)
|
||||
|
||||
@@ -90,7 +90,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils">
|
||||
<Version>2.2.4</Version>
|
||||
<Version>2.2.5</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.EventLog">
|
||||
<Version>2.1.1</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Tgstation.Server.Host.Watchdog
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Tgstation.Server.Host.Watchdog
|
||||
{
|
||||
/// <summary>
|
||||
/// Factory for creating <see cref="IWatchdog"/>s
|
||||
@@ -8,7 +10,8 @@
|
||||
/// <summary>
|
||||
/// Create a <see cref="IWatchdog"/>
|
||||
/// </summary>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to use for error reporting</param>
|
||||
/// <returns>A new <see cref="IWatchdog"/></returns>
|
||||
IWatchdog CreateWatchdog();
|
||||
IWatchdog CreateWatchdog(ILoggerFactory loggerFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -24,38 +25,67 @@ namespace Tgstation.Server.Host.Watchdog
|
||||
/// </summary>
|
||||
readonly IIsolatedAssemblyContextFactory isolatedAssemblyLoader;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILogger"/> for the <see cref="Watchdog"/>
|
||||
/// </summary>
|
||||
readonly ILogger<Watchdog> logger;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="Watchdog"/>
|
||||
/// </summary>
|
||||
/// <param name="initialServerFactory">The value of <see cref="initialServerFactory"/></param>
|
||||
/// <param name="activeAssemblyDeleter">The value of <see cref="activeAssemblyDeleter"/></param>
|
||||
/// <param name="isolatedAssemblyLoader">The value of <see cref="isolatedAssemblyLoader"/></param>
|
||||
public Watchdog(IServerFactory initialServerFactory, IActiveAssemblyDeleter activeAssemblyDeleter, IIsolatedAssemblyContextFactory isolatedAssemblyLoader)
|
||||
/// <param name="logger">The value of <see cref="logger"/></param>
|
||||
public Watchdog(IServerFactory initialServerFactory, IActiveAssemblyDeleter activeAssemblyDeleter, IIsolatedAssemblyContextFactory isolatedAssemblyLoader, ILogger<Watchdog> logger)
|
||||
{
|
||||
this.initialServerFactory = initialServerFactory ?? throw new ArgumentNullException(nameof(initialServerFactory));
|
||||
this.activeAssemblyDeleter = activeAssemblyDeleter ?? throw new ArgumentNullException(nameof(activeAssemblyDeleter));
|
||||
this.isolatedAssemblyLoader = isolatedAssemblyLoader ?? throw new ArgumentNullException(nameof(isolatedAssemblyLoader));
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task RunAsync(string[] args, CancellationToken cancellationToken)
|
||||
{
|
||||
//first run the host we started with
|
||||
var serverFactory = initialServerFactory;
|
||||
var assemblyPath = serverFactory.GetType().Assembly.Location;
|
||||
do
|
||||
{
|
||||
var server = serverFactory.CreateServer(args);
|
||||
await server.RunAsync(cancellationToken).ConfigureAwait(false);
|
||||
logger.LogInformation("Host watchdog starting...");
|
||||
try
|
||||
{
|
||||
//first run the host we started with
|
||||
logger.LogTrace("Running with initial server factory...");
|
||||
var serverFactory = initialServerFactory;
|
||||
logger.LogTrace("Determining location of host assembly...");
|
||||
var assemblyPath = serverFactory.GetType().Assembly.Location;
|
||||
logger.LogDebug("Path to initial host assembly: {0}", assemblyPath);
|
||||
do
|
||||
using (logger.BeginScope("Host invocation"))
|
||||
{
|
||||
var server = serverFactory.CreateServer(args);
|
||||
logger.LogTrace("Running server...");
|
||||
await server.RunAsync(cancellationToken).ConfigureAwait(false);
|
||||
logger.LogInformation("Active host exited.");
|
||||
|
||||
if (server.UpdatePath == null)
|
||||
break;
|
||||
if (server.UpdatePath == null)
|
||||
break;
|
||||
|
||||
activeAssemblyDeleter.DeleteActiveAssembly(assemblyPath);
|
||||
File.Move(server.UpdatePath, assemblyPath);
|
||||
serverFactory = isolatedAssemblyLoader.CreateIsolatedServerFactory(assemblyPath);
|
||||
}
|
||||
while (!cancellationToken.IsCancellationRequested);
|
||||
logger.LogInformation("Update path is set to \"{0}\", attempting host assembly hotswap...", server.UpdatePath);
|
||||
activeAssemblyDeleter.DeleteActiveAssembly(assemblyPath);
|
||||
logger.LogTrace("Moving new host assembly in place...");
|
||||
File.Move(server.UpdatePath, assemblyPath);
|
||||
logger.LogTrace("Atttempting to create new server factory...");
|
||||
serverFactory = isolatedAssemblyLoader.CreateIsolatedServerFactory(assemblyPath);
|
||||
}
|
||||
while (!cancellationToken.IsCancellationRequested);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
logger.LogDebug("Exiting due to cancellation...");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogCritical("Error running host assembly! Exception: {0}", e);
|
||||
}
|
||||
logger.LogInformation("Host watchdog exiting...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Tgstation.Server.Host.Watchdog
|
||||
@@ -8,6 +9,6 @@ namespace Tgstation.Server.Host.Watchdog
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[ExcludeFromCodeCoverage]
|
||||
public IWatchdog CreateWatchdog() => new Watchdog(new ServerFactory(), RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? (IActiveAssemblyDeleter)new WindowsActiveAssemblyDeleter() : new PosixActiveAssemblyDeleter(), new IsolatedAssemblyContextFactory());
|
||||
public IWatchdog CreateWatchdog(ILoggerFactory loggerFactory) => new Watchdog(new ServerFactory(), RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? (IActiveAssemblyDeleter)new WindowsActiveAssemblyDeleter() : new PosixActiveAssemblyDeleter(), new IsolatedAssemblyContextFactory(), loggerFactory.CreateLogger<Watchdog>());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user