Add logging sharing in bot channel

This commit is contained in:
BreadTube 2026-05-27 14:56:39 +09:00
commit 48a5fa2285
3 changed files with 38 additions and 6 deletions

View file

@ -60,7 +60,8 @@ class Bot:
log_level: int = logging.INFO): log_level: int = logging.INFO):
self.config: Config = config or Config() self.config: Config = config or Config()
self.guild_id = guild_id self.guild_id = guild_id
self.logger = create_logger('breadtube', log_level, stdout=True) self.logger, self.logger_memory = create_logger(
'breadtube', log_level, self.config.log_buffer_length, stdout=True)
self.version = self._get_code_version() self.version = self._get_code_version()
self.discord_manager = DiscordManager(bot_token=bot_token, bot_version=self.version, logger=self.logger) self.discord_manager = DiscordManager(bot_token=bot_token, bot_version=self.version, logger=self.logger)
@ -91,6 +92,7 @@ class Bot:
self.guild_text_channels: list[TextChannel] = text_channel self.guild_text_channels: list[TextChannel] = text_channel
self.guild_categories: list[ChannelCategory] = categories self.guild_categories: list[ChannelCategory] = categories
self.init_message: Message | None = None self.init_message: Message | None = None
self.init_message_update: float = time.time()
bot_channel: TextChannel | None = None bot_channel: TextChannel | None = None
for _ in range(self.config.bot_channel_init_retries): for _ in range(self.config.bot_channel_init_retries):
@ -392,6 +394,7 @@ class Bot:
# New init message is needed, previous need to be deleted # New init message is needed, previous need to be deleted
if self.init_message is not None and ( if self.init_message is not None and (
new_config is not None or new_subscriptions is not None new_config is not None or new_subscriptions is not None
or self.logger_memory.last_update < self.init_message_update
or self.init_message.content != self.INIT_MESSAGE): or self.init_message.content != self.INIT_MESSAGE):
self.logger.info('Refreshing init message') self.logger.info('Refreshing init message')
immediate_delete[self.init_message.id] = self.init_message immediate_delete[self.init_message.id] = self.init_message
@ -404,8 +407,11 @@ class Bot:
self.bot_channel, {'content': self.INIT_MESSAGE}, request_timeout=self.config.request_timeout, self.bot_channel, {'content': self.INIT_MESSAGE}, request_timeout=self.config.request_timeout,
upload_files=[ upload_files=[
('config.txt', FileMime.TEXT_PLAIN, self.config.to_str().encode()), ('config.txt', FileMime.TEXT_PLAIN, self.config.to_str().encode()),
('subscriptions.csv', FileMime.TEXT_CSV, SubscriptionHelper.generate_text(self._yt_subscriptions)) ('subscriptions.csv', FileMime.TEXT_CSV, SubscriptionHelper.generate_text(self._yt_subscriptions)),
('bot.log', FileMime.TEXT_PLAIN, b'\n'.join([
r.getMessage().encode() for r in self.logger_memory.buffer]))
]) ])
self.init_message_update = self.logger_memory.last_update
for message in immediate_delete.values(): for message in immediate_delete.values():
try: try:

View file

@ -11,6 +11,7 @@ class Config:
bot_channel_init_retries: int = 3 bot_channel_init_retries: int = 3
bot_message_duration: float = 150. bot_message_duration: float = 150.
delete_duplicate_channels: bool = True delete_duplicate_channels: bool = True
log_buffer_length: int = 200
request_timeout: float = 3. request_timeout: float = 3.
unmanaged_categories: str = '' unmanaged_categories: str = ''
youtube_channel_refresh_interval: float = 600 youtube_channel_refresh_interval: float = 600

View file

@ -1,7 +1,27 @@
from collections import deque
from logging import handlers from logging import handlers
import logging import logging
from pathlib import Path from pathlib import Path
import sys import sys
import time
class MemoryHandler(logging.Handler):
def __init__(self, capacity):
"""
Initialize the handler with the buffer size.
"""
logging.Handler.__init__(self)
self.buffer: deque[logging.LogRecord] = deque(maxlen=capacity)
self.last_update = time.time()
def emit(self, record: logging.LogRecord):
self.buffer.append(record)
self.last_update = time.time()
def close(self):
self.buffer.clear()
logging.Handler.close(self)
class ConsoleColor: class ConsoleColor:
@ -34,19 +54,24 @@ class ColoredFormatter(logging.Formatter):
return logging.Formatter.format(self, record) return logging.Formatter.format(self, record)
def create_logger(name: str, level: int, log_dir: Path | None = None, stdout=False) -> logging.Logger: def create_logger(name: str, level: int, buffer_capacity: int, log_dir: Path | None = None,
stdout=False) -> tuple[logging.Logger, MemoryHandler]:
logger = logging.getLogger(name) logger = logging.getLogger(name)
logger.setLevel(level) logger.setLevel(level)
log_formatter = logging.Formatter('%(asctime)s %(levelname)s : %(message)s')
buffer_handler = MemoryHandler(buffer_capacity)
buffer_handler.setFormatter(log_formatter)
buffer_handler.setLevel(level)
logger.addHandler(buffer_handler)
if log_dir is not None: if log_dir is not None:
log_dir.mkdir(parents=True, exist_ok=True) log_dir.mkdir(parents=True, exist_ok=True)
logger.setLevel(level)
file_log_handler = handlers.RotatingFileHandler( file_log_handler = handlers.RotatingFileHandler(
log_dir / f'{name}.log', log_dir / f'{name}.log',
maxBytes=500000, maxBytes=500000,
backupCount=5) backupCount=5)
file_log_handler.setLevel(level) file_log_handler.setLevel(level)
log_formatter = logging.Formatter('%(asctime)s %(levelname)s : %(message)s')
file_log_handler.setFormatter(log_formatter) file_log_handler.setFormatter(log_formatter)
logger.addHandler(file_log_handler) logger.addHandler(file_log_handler)
@ -57,4 +82,4 @@ def create_logger(name: str, level: int, log_dir: Path | None = None, stdout=Fal
terminal_log_handler.setFormatter(colored_log_formatter) terminal_log_handler.setFormatter(colored_log_formatter)
logger.addHandler(terminal_log_handler) logger.addHandler(terminal_log_handler)
return logger return logger, buffer_handler