mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-25 05:56:58 +01:00
Use async console logging with Serilog
This commit is contained in:
@@ -64,7 +64,7 @@ namespace Tgstation.Server.Host.Core
|
||||
public Application(
|
||||
IConfiguration configuration,
|
||||
IWebHostEnvironment hostingEnvironment)
|
||||
: base(configuration, hostingEnvironment)
|
||||
: base(configuration)
|
||||
{
|
||||
this.hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
|
||||
}
|
||||
@@ -97,63 +97,52 @@ namespace Tgstation.Server.Host.Core
|
||||
// enable options which give us config reloading
|
||||
services.AddOptions();
|
||||
|
||||
// setup file logging via serilog
|
||||
services.AddLogging(builder =>
|
||||
{
|
||||
if (postSetupServices.FileLoggingConfiguration.Disable)
|
||||
return;
|
||||
static LogEventLevel? ConvertSeriLogLevel(LogLevel logLevel) =>
|
||||
logLevel switch
|
||||
{
|
||||
LogLevel.Critical => LogEventLevel.Fatal,
|
||||
LogLevel.Debug => LogEventLevel.Debug,
|
||||
LogLevel.Error => LogEventLevel.Error,
|
||||
LogLevel.Information => LogEventLevel.Information,
|
||||
LogLevel.Trace => LogEventLevel.Verbose,
|
||||
LogLevel.Warning => LogEventLevel.Warning,
|
||||
LogLevel.None => null,
|
||||
_ => throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid log level {0}", logLevel)),
|
||||
};
|
||||
|
||||
// common app data is C:/ProgramData on windows, else /usr/share
|
||||
var logPath = !String.IsNullOrEmpty(postSetupServices.FileLoggingConfiguration.Directory)
|
||||
? postSetupServices.FileLoggingConfiguration.Directory
|
||||
: IOManager.ConcatPath(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
|
||||
"tgstation-server",
|
||||
"Logs");
|
||||
var microsoftEventLevel = ConvertSeriLogLevel(postSetupServices.FileLoggingConfiguration.MicrosoftLogLevel);
|
||||
services.SetupLogging(
|
||||
config =>
|
||||
{
|
||||
if (microsoftEventLevel.HasValue)
|
||||
config.MinimumLevel.Override("Microsoft", microsoftEventLevel.Value);
|
||||
},
|
||||
sinkConfig =>
|
||||
{
|
||||
if (postSetupServices.FileLoggingConfiguration.Disable)
|
||||
return;
|
||||
|
||||
logPath = IOManager.ConcatPath(logPath, "tgs-{Date}.log");
|
||||
// common app data is C:/ProgramData on windows, else /usr/share
|
||||
var logPath = !String.IsNullOrEmpty(postSetupServices.FileLoggingConfiguration.Directory)
|
||||
? postSetupServices.FileLoggingConfiguration.Directory
|
||||
: IOManager.ConcatPath(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
|
||||
AssemblyInformationProvider.VersionPrefix,
|
||||
"Logs");
|
||||
|
||||
static LogEventLevel? ConvertLogLevel(LogLevel logLevel) =>
|
||||
logLevel switch
|
||||
{
|
||||
LogLevel.Critical => LogEventLevel.Fatal,
|
||||
LogLevel.Debug => LogEventLevel.Debug,
|
||||
LogLevel.Error => LogEventLevel.Error,
|
||||
LogLevel.Information => LogEventLevel.Information,
|
||||
LogLevel.Trace => LogEventLevel.Verbose,
|
||||
LogLevel.Warning => LogEventLevel.Warning,
|
||||
LogLevel.None => null,
|
||||
_ => throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid log level {0}", logLevel)),
|
||||
};
|
||||
var logEventLevel = ConvertSeriLogLevel(postSetupServices.FileLoggingConfiguration.LogLevel);
|
||||
|
||||
var logEventLevel = ConvertLogLevel(postSetupServices.FileLoggingConfiguration.LogLevel);
|
||||
var microsoftEventLevel = ConvertLogLevel(postSetupServices.FileLoggingConfiguration.MicrosoftLogLevel);
|
||||
var formatter = new MessageTemplateTextFormatter(
|
||||
"{Timestamp:o} {RequestId,13} [{Level:u3}] {SourceContext:l}: {Message} ({EventId:x8}){NewLine}{Exception}",
|
||||
null);
|
||||
|
||||
var formatter = new MessageTemplateTextFormatter(
|
||||
"{Timestamp:o} {RequestId,13} [{Level:u3}] {SourceContext:l}: {Message} ({EventId:x8}){NewLine}{Exception}",
|
||||
null);
|
||||
|
||||
var configuration = new LoggerConfiguration()
|
||||
.Enrich
|
||||
.FromLogContext()
|
||||
.WriteTo
|
||||
.Async(
|
||||
w => w.RollingFile(
|
||||
formatter,
|
||||
logPath,
|
||||
shared: true,
|
||||
flushToDiskInterval: TimeSpan.FromSeconds(2)));
|
||||
|
||||
if (logEventLevel.HasValue)
|
||||
configuration.MinimumLevel.Is(logEventLevel.Value);
|
||||
|
||||
if (microsoftEventLevel.HasValue)
|
||||
configuration.MinimumLevel.Override("Microsoft", microsoftEventLevel.Value);
|
||||
|
||||
builder.AddSerilog(configuration.CreateLogger(), true);
|
||||
});
|
||||
|
||||
services.RemoveEventLogging();
|
||||
logPath = IOManager.ConcatPath(logPath, "tgs-{Date}.log");
|
||||
var rollingFileConfig = sinkConfig.RollingFile(
|
||||
formatter,
|
||||
logPath,
|
||||
logEventLevel ?? LogEventLevel.Verbose,
|
||||
flushToDiskInterval: TimeSpan.FromSeconds(2));
|
||||
});
|
||||
|
||||
// configure bearer token validation
|
||||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(jwtBearerOptions =>
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Tgstation.Server.Host.Extensions
|
||||
|
||||
return builder.ConfigureServices((context, services) =>
|
||||
{
|
||||
var setupApplication = new SetupApplication(context.Configuration, context.HostingEnvironment);
|
||||
var setupApplication = new SetupApplication(context.Configuration);
|
||||
setupApplication.ConfigureServices(services);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging.EventLog;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Serilog;
|
||||
using Serilog.Configuration;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
|
||||
namespace Tgstation.Server.Host.Extensions
|
||||
@@ -44,24 +45,40 @@ namespace Tgstation.Server.Host.Extensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the <see cref="EventLogLoggerProvider"/> from a given <paramref name="serviceCollection"/>.
|
||||
/// Clear previous providers and configure logging.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to remove the <see cref="EventLogLoggerProvider"/> from.</param>
|
||||
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to configure.</param>
|
||||
/// <param name="configurationAction">Additional configuration for a given <see cref="LoggerConfiguration"/>.</param>
|
||||
/// <param name="sinkConfigurationAction">Additional configuration for a given <see cref="LoggerSinkConfiguration"/>.</param>
|
||||
/// <returns>The updated <paramref name="serviceCollection"/>.</returns>
|
||||
public static IServiceCollection RemoveEventLogging(this IServiceCollection serviceCollection)
|
||||
{
|
||||
if (serviceCollection == null)
|
||||
throw new ArgumentNullException(nameof(serviceCollection));
|
||||
public static IServiceCollection SetupLogging(
|
||||
this IServiceCollection serviceCollection,
|
||||
Action<LoggerConfiguration> configurationAction,
|
||||
Action<LoggerSinkConfiguration> sinkConfigurationAction = null)
|
||||
=> serviceCollection.AddLogging(builder =>
|
||||
{
|
||||
builder.ClearProviders();
|
||||
|
||||
// IMPORTANT: Remove the event log provider, it's shitty and causes issues
|
||||
var eventLogDescriptor =
|
||||
serviceCollection.FirstOrDefault(
|
||||
descriptor => descriptor.ImplementationType == typeof(EventLogLoggerProvider));
|
||||
var configuration = new LoggerConfiguration()
|
||||
.MinimumLevel
|
||||
.Verbose();
|
||||
|
||||
if (eventLogDescriptor != default)
|
||||
serviceCollection.Remove(eventLogDescriptor);
|
||||
configurationAction?.Invoke(configuration);
|
||||
|
||||
return serviceCollection;
|
||||
}
|
||||
configuration
|
||||
.WriteTo
|
||||
.Async(sinkConfiguration =>
|
||||
{
|
||||
sinkConfiguration.Console(
|
||||
outputTemplate: "[{Timestamp:HH:mm:ss}] {Level:w3}: {SourceContext:l}{NewLine} {Message:lj}{NewLine}{Exception}");
|
||||
sinkConfigurationAction?.Invoke(sinkConfiguration);
|
||||
});
|
||||
|
||||
builder.AddSerilog(configuration.CreateLogger(), true);
|
||||
|
||||
#if DEBUG
|
||||
builder.AddDebug();
|
||||
#endif
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
},
|
||||
"Docker": {
|
||||
"commandName": "Docker",
|
||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
|
||||
"publishAllPorts": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,7 @@ namespace Tgstation.Server.Host
|
||||
IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args)
|
||||
.ConfigureAppConfiguration((context, configuration) => configuration
|
||||
.SetBasePath(
|
||||
IOManager.ResolvePath()))
|
||||
.ConfigureServices(services => services.RemoveEventLogging());
|
||||
IOManager.ResolvePath()));
|
||||
|
||||
var setupWizardHostBuilder = CreateDefaultBuilder()
|
||||
.UseSetupApplication();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.Core;
|
||||
@@ -31,22 +32,13 @@ namespace Tgstation.Server.Host.Setup
|
||||
/// </summary>
|
||||
protected IConfiguration Configuration { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IHostEnvironment"/> for the <see cref="SetupApplication"/>
|
||||
/// </summary>
|
||||
readonly IHostEnvironment hostingEnvironment;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SetupApplication"/> <see langword="class"/>.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The value of <see cref="Configuration"/>.</param>
|
||||
/// <param name="hostingEnvironment">The value of <see cref="hostingEnvironment"/>.</param>
|
||||
public SetupApplication(
|
||||
IConfiguration configuration,
|
||||
IHostEnvironment hostingEnvironment)
|
||||
public SetupApplication(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
||||
this.hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -58,7 +50,7 @@ namespace Tgstation.Server.Host.Setup
|
||||
if (services == null)
|
||||
throw new ArgumentNullException(nameof(services));
|
||||
|
||||
services.RemoveEventLogging();
|
||||
services.SetupLogging(config => config.MinimumLevel.Override("Microsoft", LogEventLevel.Warning));
|
||||
|
||||
services.AddSingleton(IOManager);
|
||||
services.AddSingleton(AssemblyInformationProvider);
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
<!-- If this is updated, be sure to update the reference in the README.md -->
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||
<PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
Reference in New Issue
Block a user