Split Core modules into separate files
This commit is contained in:
28
PluralKit.Core/Modules/ConfigModule.cs
Normal file
28
PluralKit.Core/Modules/ConfigModule.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Autofac;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace PluralKit.Core
|
||||
{
|
||||
public class ConfigModule<T>: Module where T: new()
|
||||
{
|
||||
private readonly string _submodule;
|
||||
|
||||
public ConfigModule(string submodule = null)
|
||||
{
|
||||
_submodule = submodule;
|
||||
}
|
||||
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
// We're assuming IConfiguration is already available somehow - it comes from various places (auto-injected in ASP, etc)
|
||||
|
||||
// Register the CoreConfig and where to find it
|
||||
builder.Register(c => c.Resolve<IConfiguration>().GetSection("PluralKit").Get<CoreConfig>() ?? new CoreConfig()).SingleInstance();
|
||||
|
||||
// Register the submodule config (BotConfig, etc) if specified
|
||||
if (_submodule != null)
|
||||
builder.Register(c => c.Resolve<IConfiguration>().GetSection("PluralKit").GetSection(_submodule).Get<T>() ?? new T()).SingleInstance();
|
||||
}
|
||||
}
|
||||
}
|
19
PluralKit.Core/Modules/DataStoreModule.cs
Normal file
19
PluralKit.Core/Modules/DataStoreModule.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Autofac;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace PluralKit.Core
|
||||
{
|
||||
public class DataStoreModule: Module
|
||||
{
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterType<DbConnectionCountHolder>().SingleInstance();
|
||||
builder.RegisterType<Database>().As<IDatabase>().SingleInstance();
|
||||
builder.RegisterType<ModelRepository>().AsSelf().SingleInstance();
|
||||
|
||||
builder.Populate(new ServiceCollection().AddMemoryCache());
|
||||
}
|
||||
}
|
||||
}
|
134
PluralKit.Core/Modules/LoggingModule.cs
Normal file
134
PluralKit.Core/Modules/LoggingModule.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
using Autofac;
|
||||
|
||||
using NodaTime;
|
||||
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using Serilog.Formatting.Compact;
|
||||
using Serilog.Sinks.Elasticsearch;
|
||||
using Serilog.Sinks.SystemConsole.Themes;
|
||||
|
||||
namespace PluralKit.Core
|
||||
{
|
||||
public class LoggingModule: Module
|
||||
{
|
||||
private readonly string _component;
|
||||
private readonly Action<LoggerConfiguration> _fn;
|
||||
|
||||
public LoggingModule(string component, Action<LoggerConfiguration> fn = null)
|
||||
{
|
||||
_component = component;
|
||||
_fn = fn ?? (_ => { });
|
||||
}
|
||||
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
builder
|
||||
.Register(c => InitLogger(c.Resolve<CoreConfig>()))
|
||||
.AsSelf()
|
||||
.SingleInstance()
|
||||
// AutoActivate ensures logging is enabled as early as possible in the API startup flow
|
||||
// since we set the Log.Logger global >.>
|
||||
.AutoActivate();
|
||||
|
||||
builder.Register(c => new Microsoft.Extensions.Logging.LoggerFactory().AddSerilog(c.Resolve<ILogger>()))
|
||||
.As<Microsoft.Extensions.Logging.ILoggerFactory>()
|
||||
.SingleInstance();
|
||||
}
|
||||
|
||||
private ILogger InitLogger(CoreConfig config)
|
||||
{
|
||||
var consoleTemplate = "[{Timestamp:HH:mm:ss.fff}] {Level:u3} {Message:lj}{NewLine}{Exception}";
|
||||
var outputTemplate = "[{Timestamp:yyyy-MM-dd HH:mm:ss.ffffff}] {Level:u3} {Message:lj}{NewLine}{Exception}";
|
||||
|
||||
var logCfg = new LoggerConfiguration()
|
||||
.Enrich.FromLogContext()
|
||||
.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb)
|
||||
.Enrich.WithProperty("Component", _component)
|
||||
.MinimumLevel.Is(config.ConsoleLogLevel)
|
||||
|
||||
// Don't want App.Metrics/D#+ spam
|
||||
.MinimumLevel.Override("App.Metrics", LogEventLevel.Information)
|
||||
.MinimumLevel.Override("DSharpPlus", LogEventLevel.Debug)
|
||||
|
||||
// Actual formatting for these is handled in ScalarFormatting
|
||||
.Destructure.AsScalar<SystemId>()
|
||||
.Destructure.AsScalar<MemberId>()
|
||||
.Destructure.AsScalar<GroupId>()
|
||||
.Destructure.AsScalar<SwitchId>()
|
||||
.Destructure.ByTransforming<ProxyTag>(t => new { t.Prefix, t.Suffix })
|
||||
.Destructure.With<PatchObjectDestructuring>()
|
||||
|
||||
.WriteTo.Async(a =>
|
||||
{
|
||||
// Both the same output, except one is raw compact JSON and one is plain text.
|
||||
// Output simultaneously. May remove the JSON formatter later, keeping it just in cast.
|
||||
// Flush interval is 50ms (down from 10s) to make "tail -f" easier. May be too low?
|
||||
a.File(
|
||||
(config.LogDir ?? "logs") + $"/pluralkit.{_component}.log",
|
||||
outputTemplate: outputTemplate,
|
||||
rollingInterval: RollingInterval.Day,
|
||||
flushToDiskInterval: TimeSpan.FromMilliseconds(50),
|
||||
restrictedToMinimumLevel: config.FileLogLevel,
|
||||
formatProvider: new UTCTimestampFormatProvider(),
|
||||
buffered: true);
|
||||
|
||||
a.File(
|
||||
new RenderedCompactJsonFormatter(new ScalarFormatting.JsonValue()),
|
||||
(config.LogDir ?? "logs") + $"/pluralkit.{_component}.json",
|
||||
rollingInterval: RollingInterval.Day,
|
||||
flushToDiskInterval: TimeSpan.FromMilliseconds(50),
|
||||
restrictedToMinimumLevel: config.FileLogLevel,
|
||||
buffered: true);
|
||||
})
|
||||
.WriteTo.Async(a =>
|
||||
a.Console(
|
||||
theme: AnsiConsoleTheme.Code,
|
||||
outputTemplate: consoleTemplate,
|
||||
restrictedToMinimumLevel: config.ConsoleLogLevel));
|
||||
|
||||
if (config.ElasticUrl != null)
|
||||
{
|
||||
var elasticConfig = new ElasticsearchSinkOptions(new Uri(config.ElasticUrl))
|
||||
{
|
||||
AutoRegisterTemplate = true,
|
||||
AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7,
|
||||
MinimumLogEventLevel = LogEventLevel.Verbose,
|
||||
IndexFormat = "pluralkit-logs-{0:yyyy.MM.dd}",
|
||||
CustomFormatter = new ScalarFormatting.Elasticsearch()
|
||||
};
|
||||
|
||||
logCfg.WriteTo
|
||||
.Conditional(e => e.Properties.ContainsKey("Elastic"),
|
||||
c => c.Elasticsearch(elasticConfig));
|
||||
}
|
||||
|
||||
_fn.Invoke(logCfg);
|
||||
return Log.Logger = logCfg.CreateLogger();
|
||||
}
|
||||
}
|
||||
|
||||
// Serilog why is this necessary for such a simple thing >.>
|
||||
public class UTCTimestampFormatProvider: IFormatProvider
|
||||
{
|
||||
public object GetFormat(Type formatType) => new UTCTimestampFormatter();
|
||||
}
|
||||
|
||||
public class UTCTimestampFormatter: ICustomFormatter
|
||||
{
|
||||
public string Format(string format, object arg, IFormatProvider formatProvider)
|
||||
{
|
||||
// Convert offset to UTC and then print
|
||||
// FormatProvider defaults to locale-specific stuff so we force-default to invariant culture
|
||||
// If we pass the given formatProvider it'll conveniently ignore it, for some reason >.>
|
||||
if (arg is DateTimeOffset dto)
|
||||
return dto.ToUniversalTime().ToString(format, CultureInfo.InvariantCulture);
|
||||
if (arg is IFormattable f)
|
||||
return f.ToString(format, CultureInfo.InvariantCulture);
|
||||
return arg.ToString();
|
||||
}
|
||||
}
|
||||
}
|
32
PluralKit.Core/Modules/MetricsModule.cs
Normal file
32
PluralKit.Core/Modules/MetricsModule.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using App.Metrics;
|
||||
|
||||
using Autofac;
|
||||
|
||||
namespace PluralKit.Core
|
||||
{
|
||||
public class MetricsModule: Module
|
||||
{
|
||||
private readonly string _onlyContext;
|
||||
|
||||
public MetricsModule(string onlyContext = null)
|
||||
{
|
||||
_onlyContext = onlyContext;
|
||||
}
|
||||
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
builder.Register(c => InitMetrics(c.Resolve<CoreConfig>()))
|
||||
.AsSelf().As<IMetrics>().SingleInstance();
|
||||
}
|
||||
|
||||
private IMetricsRoot InitMetrics(CoreConfig config)
|
||||
{
|
||||
var builder = AppMetrics.CreateDefaultBuilder();
|
||||
if (config.InfluxUrl != null && config.InfluxDb != null)
|
||||
builder.Report.ToInfluxDb(config.InfluxUrl, config.InfluxDb);
|
||||
if (_onlyContext != null)
|
||||
builder.Filter.ByIncludingOnlyContext(_onlyContext);
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user