diff --git a/src/BotCatMaxy/Components/Logging/SerilogSinkExtensions.cs b/src/BotCatMaxy/Components/Logging/SerilogSinkExtensions.cs index 9fcee1b..291da23 100644 --- a/src/BotCatMaxy/Components/Logging/SerilogSinkExtensions.cs +++ b/src/BotCatMaxy/Components/Logging/SerilogSinkExtensions.cs @@ -11,10 +11,10 @@ namespace BotCatMaxy.Components.Logging public static class SerilogSinkExtensions { public static LoggerConfiguration TempActionSink( - this LoggerSinkConfiguration loggerConfiguration, DiscordSocketClient client, LogEventLevel minLevel, out TempActionSink.FlushLogDelegate _flush, + this LoggerSinkConfiguration loggerConfiguration, ITextChannel channel, LogEventLevel minLevel, out TempActionSink.FlushLogDelegate _flush, IFormatProvider formatProvider = null) { - var sink = new TempActionSink(client, formatProvider, out var flush); + var sink = new TempActionSink(channel, formatProvider, out var flush); _flush = flush; return loggerConfiguration.Sink(sink, minLevel); } diff --git a/src/BotCatMaxy/Program.cs b/src/BotCatMaxy/Program.cs index f1f366d..f25eeb7 100644 --- a/src/BotCatMaxy/Program.cs +++ b/src/BotCatMaxy/Program.cs @@ -80,7 +80,7 @@ public static async Task Main(string[] args) var mongo = new MongoClient(context.Configuration["DataToken"]); DataManipulator.dbClient = mongo; services.AddSingleton(mongo); - + services.AddSingleton(context.Configuration); services.AddSingleton(); services.AddSingleton(new CommandService(new CommandServiceConfig { diff --git a/src/BotCatMaxy/Properties/Template.ini b/src/BotCatMaxy/Properties/Template.ini index 6026a3f..b87a38a 100644 --- a/src/BotCatMaxy/Properties/Template.ini +++ b/src/BotCatMaxy/Properties/Template.ini @@ -4,6 +4,11 @@ ; Also has possibility for BotCatMaxy.Environment.ini allowing for debug vs release keys - but right ; now only BotCatMaxy.DEBUG.ini is implemented -;Example DataToken=mongodb://localhost -DiscordToken=YOURDISCORDTOKENHERE \ No newline at end of file +DiscordToken=YOURDISCORDTOKENHERE + +;Stuff for TempAction Checks below +;Log channel (verify your bot has access) +ActLogChannel=866833376882589716 +;Minimum minutes between logging in above channel +ActLogFlushTime=10 \ No newline at end of file diff --git a/src/BotCatMaxy/Services/TempActions/TempActionService.cs b/src/BotCatMaxy/Services/TempActions/TempActionService.cs index 9cb7a7a..3274ff2 100644 --- a/src/BotCatMaxy/Services/TempActions/TempActionService.cs +++ b/src/BotCatMaxy/Services/TempActions/TempActionService.cs @@ -10,6 +10,8 @@ using Discord.Addons.Hosting.Util; using Discord.WebSocket; using Humanizer; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Polly; using Serilog; @@ -22,31 +24,50 @@ public class TempActionService : DiscordClientService { public TempActionChecker ActiveChecker { get; private set; } private TempActionSink.FlushLogDelegate _flushLogDelegate; + private readonly IConfiguration _configuration; private readonly DiscordSocketClient _client; private readonly System.Timers.Timer _timer; + private readonly TimeSpan _flushInterval; private CancellationToken _shutdownToken; private Serilog.ILogger _verboseLogger; private DateTime _lastFlush; - public TempActionService(DiscordSocketClient client, ILogger logger) : base(client, logger) + public TempActionService(DiscordSocketClient client, IConfiguration configuration, + ILogger logger) : base(client, logger) { + _configuration = configuration; _client = client; + _timer = new System.Timers.Timer(45000); client.UserJoined += CheckNewUserAsync; _lastFlush = DateTime.Now; + + _flushInterval = TimeSpan.FromMinutes(float + .TryParse(configuration["ActLogFlushTime"], out float flushInterval) ? flushInterval : 10); } protected override async Task ExecuteAsync(CancellationToken shutdownToken) { _shutdownToken = shutdownToken; await _client.WaitForReadyAsync(shutdownToken); - _verboseLogger = new LoggerConfiguration() - .MinimumLevel.Verbose() - .WriteTo.Logger(Log.Logger, LogEventLevel.Warning) - .WriteTo.TempActionSink(_client, LogEventLevel.Verbose, out var flushLogDelegate) - .CreateLogger() - .ForContext("Source", "TempAct"); - _flushLogDelegate = flushLogDelegate; + var verboseLoggerConfig = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.Logger(Log.Logger, LogEventLevel.Warning); + + if (ulong.TryParse(_configuration["ActLogChannel"], out ulong channelId)) + { + verboseLoggerConfig = verboseLoggerConfig.WriteTo.TempActionSink(_client.GetChannel(channelId) as ITextChannel, + LogEventLevel.Verbose, out var flushLogDelegate); + _flushLogDelegate = flushLogDelegate; + } + else + { + LogSeverity.Warning.Log("TempAct", "Log Channel not set, verbose logs will not be sent"); + } + + _verboseLogger = verboseLoggerConfig.CreateLogger() + .ForContext("Source", "TempAct"); + _timer.Elapsed += async (_, _) => await TryActCheckAsync(); _timer.Start(); } @@ -60,7 +81,8 @@ public static async Task CheckNewUserAsync(IGuildUser user) var actions = user.Guild?.LoadFromFile(); //Can be done better and cleaner - if (settings == null || user.Guild?.GetRole(settings.mutedRole) == null || (actions?.tempMutes?.Count is null or 0)) + if (settings == null || user.Guild?.GetRole(settings.mutedRole) == null || + (actions?.tempMutes?.Count is null or 0)) return; if (actions.tempMutes.Any(tempMute => tempMute.User == user.Id)) await user.AddRoleAsync(user.Guild.GetRole(settings.mutedRole)); @@ -90,12 +112,14 @@ public Task ActCheckExecAsync() ActiveChecker = new TempActionChecker(_client, _verboseLogger); CurrentInfo.Checking = true; var start = DateTime.UtcNow; - var timeoutPolicy = Policy.TimeoutAsync(40, Polly.Timeout.TimeoutStrategy.Optimistic, (context, timespan, task) => - { - _verboseLogger.Log(LogEventLevel.Error, "TempAct", - $"TempAct check canceled at {DateTime.UtcNow.Subtract(start).Humanize(2)} and through {CurrentInfo.CheckedGuilds}/{_client.Guilds.Count} guilds"); - return ResetInfo(start); - }); + var timeoutPolicy = Policy.TimeoutAsync(40, Polly.Timeout.TimeoutStrategy.Optimistic, + (context, timespan, task) => + { + _verboseLogger.Log(LogEventLevel.Error, "TempAct", + $"TempAct check canceled at {DateTime.UtcNow.Subtract(start).Humanize(2)} and through {CurrentInfo.CheckedGuilds}/{_client.Guilds.Count} guilds"); + + return ResetInfo(start); + }); return timeoutPolicy.ExecuteAsync(async ct => { @@ -111,7 +135,7 @@ private Task ResetInfo(DateTime start) CachedInfo.LastCheck = DateTime.UtcNow; CurrentInfo.Checking = false; - return (DateTime.Now - _lastFlush > TimeSpan.FromMinutes(10)) ? _flushLogDelegate() : Task.CompletedTask; + return (DateTime.Now - _lastFlush > _flushInterval) ? _flushLogDelegate() : Task.CompletedTask; } } } \ No newline at end of file diff --git a/src/BotCatMaxy/Services/TempActions/TempActionSink.cs b/src/BotCatMaxy/Services/TempActions/TempActionSink.cs index 856de71..3997f99 100644 --- a/src/BotCatMaxy/Services/TempActions/TempActionSink.cs +++ b/src/BotCatMaxy/Services/TempActions/TempActionSink.cs @@ -2,6 +2,7 @@ using System.IO; using System.Text; using System.Threading.Tasks; +using Discord; using Discord.WebSocket; using Serilog.Core; using Serilog.Events; @@ -15,22 +16,19 @@ public class TempActionSink : ILogEventSink { private const string _format = "[{@t:mm:ss.fff} {@l:u3}]{#if IsDefined(GuildID)} {GuildID} {GuildIndex}:{#end} {@m:lj}\n{@x}"; private readonly ITextFormatter _textFormatter; - private readonly DiscordSocketClient _client; - private readonly SocketTextChannel _channel; private readonly MemoryStream _memoryStream; private readonly StreamWriter _streamWriter; + private readonly ITextChannel _channel; private ushort _events = 0; public delegate Task FlushLogDelegate(); - public TempActionSink(DiscordSocketClient client, IFormatProvider formatProvider, out FlushLogDelegate flush) + public TempActionSink(ITextChannel channel, IFormatProvider formatProvider, out FlushLogDelegate flush) { - const ulong logChannel = 866833376882589716; _memoryStream = new MemoryStream(); - _client = client; + _channel = channel; flush = FlushLog; - _channel = _client.GetChannel(logChannel) as SocketTextChannel; _streamWriter = new StreamWriter(_memoryStream, new UTF8Encoding(false)); _textFormatter = new ExpressionTemplate(_format, formatProvider); }