Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔊 More consistent logs across the bot #133

Merged
merged 6 commits into from
Jun 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bot/utils/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ async def on_error(self, error, ctx=None):
ctx.guild.name + " | " + ctx.channel.name + "\n" + msg
)
except Exception as exc: # pylint: disable=broad-exception-caught
self.bot.log.warn(f"[on_error] {exc}", exc_info=True)
self.bot.log.warning(f"[on_error] {exc}", exc_info=True)

async def senf_err_msg(self, msg):
"""Sends a message to the error channel"""
Expand Down
4 changes: 3 additions & 1 deletion core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
"""

version = (1, 4)
version_string = '1.4'
version_string = '1.4'

from .logger import *
7 changes: 5 additions & 2 deletions core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,21 @@
import yaml

from LRFutils import color
from LRFutils import logs

from core import setup_logger

accept = ["y", "yes", "yeah", "ye"]
decline = ["n", "no", "nope", "nah"]

_global_config = {}

logger = setup_logger('config')

# Check basic requirements and start this script if something is missing
def check():
if not os.path.isfile("config.yaml"):
print(" ")
logs.warn("⛔ The bot is not correctly setup. Running setup script...")
logger.warning("⛔ The bot is not correctly setup. Running setup script...")
os.system("python3 setup.py")
exit()

Expand Down
100 changes: 100 additions & 0 deletions core/logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import logging
import datetime
import os

from LRFutils import color

__all__ = [
'GipsyLogs',
'setup_logger',
]

# Set the filename at start and create logs folder if needed
if not os.path.isdir('logs'):
os.mkdir('logs')

start = datetime.datetime.now()
default_filename = "logs/{time}.log".format(
time=start.strftime("%d-%m-%Y_%H:%M:%S")
)

# For format reference, see https://strftime.org/
# This format outputs like this : 08/09/2013 at 07:06:05
DATETIME_FORMAT = "%d/%m/%Y at %H:%M:%S"
DATETIME_FORMAT_COLOR = f"{color.fg.blue}%d/%m/%Y{color.stop} at {color.fg.purple}%H:%M:%S{color.stop}"

# Formats and colors depending on the level
LOG_FORMAT = "{date} | [{level}] | {name} | {message}"

LOG_FORMAT_COLOR = "{date} | {color}[{level}]{color_end} | {name} | {message}"
LEVEL_COLORS = {
logging.DEBUG: color.fg.lightblue,
logging.INFO: color.fg.green,
logging.WARNING: color.fg.yellow,
logging.ERROR: color.fg.red,
logging.CRITICAL: color.fg.red + color.bold,
}

class GipsyLogs(logging.Formatter):
"""Custom colored logging formatter."""

def __init__(self, colored: bool = False):
super().__init__()
if colored:
self.log_format = LOG_FORMAT_COLOR
self.datetime_format = DATETIME_FORMAT_COLOR
else:
self.log_format = LOG_FORMAT
self.datetime_format = DATETIME_FORMAT

def format(self, record: logging.LogRecord):
level_color = LEVEL_COLORS.get(record.levelno)
date = datetime.datetime.fromtimestamp(
record.created,
).strftime(self.datetime_format)

return self.log_format.format(
date=date,
name=record.name,
color=level_color,
level=record.levelname,
color_end=color.stop,
message=record.getMessage(),
)


def setup_logger(
name: str,
level=logging.INFO,
filename: str = default_filename,
) -> logging.Logger:
logger = logging.getLogger(name)
logger.setLevel(level)

# Output to the console with color formating
stdout_handler = logging.StreamHandler()
stdout_handler.setLevel(level)
stdout_handler.setFormatter(GipsyLogs(colored=True))

logger.addHandler(stdout_handler)

# Output to a file without colors if needed
if filename is not None:
file_handler = logging.FileHandler(filename)
file_handler.setLevel(level)
file_handler.setFormatter(GipsyLogs(colored=False))

logger.addHandler(file_handler)

return logger

if __name__ == "__main__":
test_logger = setup_logger(__name__, level=logging.DEBUG, filename="logs/tests.log")
Aeris1One marked this conversation as resolved.
Show resolved Hide resolved

import random

test_logger.debug("This is a debug message")
test_logger.info("This is an info message %i", random.randint(0, 10))
test_logger.warning("This is a warning")
test_logger.error("Something is wrong, error")
test_logger.critical("It's the end of the world")
24 changes: 13 additions & 11 deletions plugins/admin/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from utils import Gunibot
from bot import checks
from core import setup_logger


def cleanup_code(content):
Expand All @@ -32,6 +33,7 @@ def cleanup_code(content):
class Admin(commands.Cog):
def __init__(self, bot: Gunibot):
self.bot = bot
self.logger = setup_logger('admin')
self._last_result = None

@commands.group(name="admin", hidden=True)
Expand Down Expand Up @@ -62,7 +64,7 @@ async def gitpull(self, ctx: commands.Context, branch: str = None):
try:
repo.git.checkout(branch)
except GitCommandError as exc:
self.bot.log.exception(exc)
self.logger.exception(exc)
if (
"Your local changes to the following files would be overwritten by checkout"
in str(exc)
Expand Down Expand Up @@ -100,7 +102,7 @@ async def shutdown(self, ctx: commands.Context):
await self.cleanup_workspace()
await msg.edit(content="Bot en voie d'extinction")
await self.bot.change_presence(status=discord.Status("offline"))
self.bot.log.info("Fermeture du bot")
self.logger.info("Fermeture du bot")
await self.bot.close()

async def cleanup_workspace(self):
Expand All @@ -119,7 +121,7 @@ async def restart_bot(self, ctx: commands.Context):
"""Relance le bot"""
await ctx.send(content="Redémarrage en cours...")
await self.cleanup_workspace()
self.bot.log.info("Redémarrage du bot")
self.logger.info("Redémarrage du bot")
os.execl(sys.executable, sys.executable, *sys.argv)

@main_msg.command(name="purge")
Expand Down Expand Up @@ -158,7 +160,7 @@ async def reload_cog(self, ctx: commands.Context, *, cog: str):
await errors_cog.on_error(exc, ctx)
await ctx.send(f"**`ERROR:`** {type(exc).__name__} - {exc}")
else:
self.bot.log.info(f"Module {cog} rechargé")
self.logger.info("Module %s rechargé", cog)
reloaded_cogs.append(cog)
if len(reloaded_cogs) > 0:
await ctx.bot.get_cog("General").count_lines_code()
Expand All @@ -170,19 +172,19 @@ async def reload_cog(self, ctx: commands.Context, *, cog: str):
async def add_cog(self, ctx: commands.Context, name: str):
"""Ajouter un cog au bot"""
try:
await self.bot.load_extension("plugins." + name + '.' + name)
await ctx.send(f"Module '{name}' ajouté !")
self.bot.log.info(f"Module {name} ajouté")
except Exception as exc: # pylint: disable=broad-exception-caught
await self.bot.load_extension("plugins." + name)
await ctx.send("Module '{}' ajouté !".format(name))
self.logger.info("Module %s ajouté", name)
except Exception as exc: #pylint: disable=broad-exception-caught
await ctx.send(str(exc))

@main_msg.command(name="del_cog", aliases=["remove_cog"], hidden=True)
async def rm_cog(self, ctx: commands.Context, name: str):
"""Enlever un cog au bot"""
try:
await self.bot.unload_extension("plugins." + name + '.' + name)
await ctx.send(f"Module '{name}' désactivé !")
self.bot.log.info(f"Module {name} désactivé")
await self.bot.unload_extension("plugins." + name)
await ctx.send("Module '{}' désactivé !".format(name))
self.logger.info("Module %s désactivé", name)
except Exception as exc: # pylint: disable=broad-exception-caught
await ctx.send(str(exc))

Expand Down
12 changes: 7 additions & 5 deletions plugins/antikikoo/antikikoo.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
"""

import discord
from discord.channel import TextChannel
from discord.ext import commands
from discord.channel import TextChannel

from utils import Gunibot, MyContext
from core import setup_logger

# pylint: disable=line-too-long
WELCOME_MESSAGE = """(FR) Bienvenue sur {server} {user} !
Expand All @@ -36,6 +37,7 @@ def __init__(self, bot: Gunibot):
"verification_info_message",
"verification_role",
]
self.logger = setup_logger("antikikoo")

bot.get_command("config").add_command(self.ak_channel)
bot.get_command("config").add_command(self.ak_msg)
Expand All @@ -48,7 +50,7 @@ def __init__(self, bot: Gunibot):
async def on_member_join(self, member: discord.Member):
"""Called when a member joins a guild
Sends a message in the verification channel to inform new users"""
self.bot.log.info(f"{member} ({member.id}) joined the server")
self.logger.info("%s (%i) joined the server", repr(member), member.id)
config = self.bot.server_configs[member.guild.id]
# if nothing has been configured
if (
Expand Down Expand Up @@ -92,7 +94,7 @@ async def on_message(self, message: discord.Message):
try:
await message.delete()
except (discord.Forbidden, discord.NotFound):
self.bot.log.exception("Cannot delete the verification message")
self.logger.exception("Cannot delete the verification message")
verif_role = message.guild.get_role(config["verification_role"])
if verif_role is None:
return
Expand All @@ -102,8 +104,8 @@ async def on_message(self, message: discord.Message):
else:
await message.author.remove_roles(verif_role)
except (discord.Forbidden, discord.NotFound):
self.bot.log.exception(
f"Cannot give or take away verification role from member {message.author}"
self.logger.exception(
"Cannot give or take away verification role from member %s", repr(message.author),
)

@commands.group(name="antikikoo", aliases=["ak", "antitroll"])
Expand Down
7 changes: 4 additions & 3 deletions plugins/giveaways/giveaways.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""
"""giveways
Ce programme est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
Expand All @@ -16,16 +16,17 @@

from bot import args
from utils import Gunibot
from core import setup_logger

from .src.view import GiveawayView


class Giveaways(commands.Cog):
"Manage giveaways in your server"

def __init__(self, bot: Gunibot):
self.bot = bot
self.embed_color = 0x9933ff
self.logger = setup_logger('giveways')

async def cog_load(self):
self.internal_task.start() # pylint: disable=no-member
Expand Down Expand Up @@ -578,7 +579,7 @@ async def pick_winners(

async def send_results(self, giveaway: dict, winners: list[discord.Member]):
"""Send the giveaway results in a new embed"""
self.bot.log.info(f"Giveaway '{giveaway['name']}' has stopped")
self.logger.info("Giveaway '%s' has stopped", giveaway['name'])
channel: discord.TextChannel = self.bot.get_channel(giveaway["channel"])
if channel is None:
return None
Expand Down
12 changes: 7 additions & 5 deletions plugins/hypesquad/hypesquad.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from bot.checks import is_roles_manager
from utils import Gunibot, MyContext
from core import setup_logger


class Hypesquad(commands.Cog):
Expand All @@ -27,6 +28,7 @@ def __init__(self, bot: Gunibot):
"hs_none_role",
]
self.roles_loop.start() # pylint: disable=no-member
self.logger = setup_logger('hypesquad')

bot.get_command("config").add_command(self.hs_main)

Expand Down Expand Up @@ -71,7 +73,7 @@ async def hs_role(self, ctx: MyContext, house: str, *, role: discord.Role = None
async def roles_loop(self):
"""Check every 12h the members roles"""
start = time.time()
self.bot.log.debug("[hypesquad] Started roles check")
self.logger.debug("Started roles check")
count = 0 # count of edited members
for guild in self.bot.guilds:
try:
Expand All @@ -81,12 +83,12 @@ async def roles_loop(self):
count += await self.edit_roles(member, roles)
except discord.Forbidden:
# missing a perm
self.bot.log.warn(
f"[hypesquad] Unable to give roles in guild {guild.id} ({guild.name})"
self.logger.warning(
"Unable to give roles in guild %i (%s)", guild.id, guild.name,
)
delta = round(time.time() - start, 2)
self.bot.log.info(
f"[hypesquad] Finished roles check in {delta}s with {count} editions"
self.logger.info(
"Finished roles check in %f s with %i editions", delta, count,
)

@roles_loop.before_loop
Expand Down
5 changes: 3 additions & 2 deletions plugins/inviteTracker/inviteTracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from utils import Gunibot, MyContext
from bot import checks

from core import setup_logger

class DatabaseInvite:
"""Represent a database invitation object"""
Expand Down Expand Up @@ -162,6 +162,7 @@ class Invite(commands.Cog):

def __init__(self, bot: Gunibot):
self.bot = bot
self.logger = setup_logger('invitetracker')
self.config_options = ["invite_log"]
bot.get_command("config").add_command(self.invite_log)

Expand Down Expand Up @@ -267,7 +268,7 @@ async def on_ready(self) -> None:
for guild in self.bot.guilds:
if guild.me.guild_permissions.manage_guild:
await self.check_invites(guild)
self.bot.log.info("Invitations successfully synced")
self.logger.info("Invitations successfully synced")

async def check_invites(self, guild: discord.Guild) -> List[DatabaseInvite]:
"""Check for all guild invite and changes
Expand Down
Loading