Add logging to the host watchdog

This commit is contained in:
Cyberboss
2018-07-20 14:05:57 -04:00
parent 56688ec8b4
commit 02080b2402
7 changed files with 117 additions and 38 deletions
+28 -7
View File
@@ -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);
}
}
}
}
+3 -1
View File
@@ -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);
}
}
+46 -16
View File
@@ -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>());
}
}