diff --git a/src/meta/logger.py b/src/meta/logger.py index b2464088..ffa97f7f 100644 --- a/src/meta/logger.py +++ b/src/meta/logger.py @@ -10,6 +10,7 @@ from io import StringIO from functools import wraps from contextvars import ContextVar +import discord from discord import Webhook, File import aiohttp @@ -304,6 +305,10 @@ class WebHookHandler(logging.StreamHandler): self.webhook = Webhook.from_url(self.webhook_url, session=self.session) async def post(self, record): + if record.context == 'Webhook Logger': + # Don't livelog livelog errors + # Otherwise we recurse and Cloudflare hates us + return log_context.set("Webhook Logger") log_action_stack.set(("Logging",)) log_app.set(record.app) @@ -371,7 +376,7 @@ class WebHookHandler(logging.StreamHandler): except BucketFull: logger.warning( "Can't keep up! " - "Ignoring records on live-logger {self.webhook.id}." + f"Ignoring records on live-logger {self.webhook.id}." ) self.ignored += 1 return @@ -383,16 +388,22 @@ class WebHookHandler(logging.StreamHandler): ) self.ignored = 0 - if as_file or len(message) > 1900: - with StringIO(message) as fp: - fp.seek(0) - await self.webhook.send( - f"{self.prefix}\n`{message.splitlines()[0]}`", - file=File(fp, filename="logs.md"), - username=log_app.get() - ) - else: - await self.webhook.send(self.prefix + '\n' + message, username=log_app.get()) + try: + if as_file or len(message) > 1900: + with StringIO(message) as fp: + fp.seek(0) + await self.webhook.send( + f"{self.prefix}\n`{message.splitlines()[0]}`", + file=File(fp, filename="logs.md"), + username=log_app.get() + ) + else: + await self.webhook.send(self.prefix + '\n' + message, username=log_app.get()) + except discord.HTTPException: + logger.exception( + "Live logger errored. Slowing down live logger." + ) + self.bucket.fill() handlers = [] diff --git a/src/modules/ranks/cog.py b/src/modules/ranks/cog.py index f7878c15..76e615bf 100644 --- a/src/modules/ranks/cog.py +++ b/src/modules/ranks/cog.py @@ -622,7 +622,7 @@ class RankCog(LionCog): error = t(_p( 'rank_refresh|error:unassignable_roles|desc', "I have insufficient permissions to assign the following role(s):\n{roles}" - )).format(roles='\n'.join(role.mention for role in failing)), + )).format(roles='\n'.join(role.mention for role in failing)) await ui.set_error(error) return @@ -707,8 +707,8 @@ class RankCog(LionCog): 'rank_refresh|remove_roles|small_error', "*Could not remove ranks from {member}*" )).format(member=to_remove[index][0].mention) - self.ui.errors.append(error) - if len(self.ui.errors) > 10: + ui.errors.append(error) + if len(ui.errors) > 10: await ui.set_error( t(_p( 'rank_refresh|remove_roles|error:too_many_issues', @@ -742,8 +742,8 @@ class RankCog(LionCog): 'rank_refresh|add_roles|small_error', "*Could not add {role} to {member}*" )).format(member=to_add[index][0].mention, role=to_add[index][1].mention) - self.ui.errors.append(error) - if len(self.ui.errors) > 10: + ui.errors.append(error) + if len(ui.errors) > 10: await ui.set_error( t(_p( 'rank_refresh|add_roles|error:too_many_issues', diff --git a/src/modules/ranks/ui/refresh.py b/src/modules/ranks/ui/refresh.py index b45b3b6e..4b30b256 100644 --- a/src/modules/ranks/ui/refresh.py +++ b/src/modules/ranks/ui/refresh.py @@ -24,6 +24,9 @@ _p = babel._p class RankRefreshUI(MessageUI): + # Cache of live rank UIs, mainly for introspection + _running = set() + def __init__(self, bot: LionBot, guild: discord.Guild, **kwargs): super().__init__(**kwargs) self.bot = bot @@ -66,6 +69,7 @@ class RankRefreshUI(MessageUI): def start(self): self._loop_task = asyncio.create_task(self._refresh_loop(), name='Rank RefreshUI Monitor') + self._running.add(self) async def run(self, *args, **kwargs): await super().run(*args, **kwargs) @@ -74,6 +78,7 @@ class RankRefreshUI(MessageUI): async def cleanup(self): if self._loop_task and not self._loop_task.done(): self._loop_task.cancel() + self._running.discard(self) await super().cleanup() def progress_bar(self, value, minimum, maximum, width=10) -> str: @@ -107,12 +112,13 @@ class RankRefreshUI(MessageUI): # Join all the sections together and return return ''.join(bar) - @log_wrap('refresh ui loop') + @log_wrap(action='refresh ui loop') async def _refresh_loop(self): while True: try: - await asyncio.sleep(1) + await asyncio.sleep(5) await self._wakeup.wait() + self._wakeup.clear() await self.refresh() except asyncio.CancelledError: break diff --git a/src/utils/ratelimits.py b/src/utils/ratelimits.py index 56f25728..4c050e94 100644 --- a/src/utils/ratelimits.py +++ b/src/utils/ratelimits.py @@ -80,6 +80,10 @@ class Bucket: self._last_full = False self._level += 1 + def fill(self): + self._leak() + self._level = max(self._level, self.max_level + 1) + async def wait(self): """ Wait until the bucket has room.