Skip to content

Commit

Permalink
🔊 feat: more consistent logs across the bot
Browse files Browse the repository at this point in the history
  • Loading branch information
ascpial committed Feb 21, 2023
1 parent be9a69c commit c6f5157
Show file tree
Hide file tree
Showing 17 changed files with 254 additions and 112 deletions.
1 change: 1 addition & 0 deletions core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .logger import *
7 changes: 5 additions & 2 deletions core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@
import os
import importlib
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.warn("⛔ The bot is not correctly setup. Running setup script...")
os.system("python3 setup.py")
exit()

Expand Down
99 changes: 99 additions & 0 deletions core/logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
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):
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__":
logger = setup_logger(__name__, level=logging.DEBUG, filename="logs/tests.log")

import random

logger.debug("This is a debug message")
logger.info("This is an info message %i", random.randint(0, 10))
logger.warning("This is a warning")
logger.error("Something is wrong, error")
logger.critical("It's the end of the world")
26 changes: 15 additions & 11 deletions plugins/admin/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@
de la licence CeCILL diffusée sur le site "http://www.cecill.info".
"""

from utils import Gunibot
from git import Repo, exc
from discord.ext import commands
import discord
from bot import checks
import io
import os
import sys
import textwrap
import traceback
from contextlib import redirect_stdout

from git import Repo, exc
from discord.ext import commands
import discord

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

sys.path.append("./bot")


Expand All @@ -32,6 +35,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 @@ -61,7 +65,7 @@ async def gitpull(self, ctx: commands.Context, branch: str = None):
try:
repo.git.checkout(branch)
except exc.GitCommandError as e:
self.bot.log.exception(e)
self.logger.exception(e)
if (
"Your local changes to the following files would be overwritten by checkout"
in str(e)
Expand Down Expand Up @@ -99,7 +103,7 @@ async def shutdown(self, ctx: commands.Context):
await self.cleanup_workspace()
await m.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 @@ -115,7 +119,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 @@ -154,7 +158,7 @@ async def reload_cog(self, ctx: commands.Context, *, cog: str):
await errors_cog.on_error(e, ctx)
await ctx.send(f"**`ERROR:`** {type(e).__name__} - {e}")
else:
self.bot.log.info("Module {} rechargé".format(cog))
self.logger.info("Module {} rechargé".format(cog))
reloaded_cogs.append(cog)
if len(reloaded_cogs) > 0:
await ctx.bot.get_cog("General").count_lines_code()
Expand All @@ -170,7 +174,7 @@ async def add_cog(self, ctx: commands.Context, name: str):
try:
self.bot.load_extension("plugins." + name)
await ctx.send("Module '{}' ajouté !".format(name))
self.bot.log.info("Module {} ajouté".format(name))
self.logger.info("Module {} ajouté".format(name))
except Exception as e:
await ctx.send(str(e))

Expand All @@ -180,7 +184,7 @@ async def rm_cog(self, ctx: commands.Context, name: str):
try:
self.bot.unload_extension("plugins." + name)
await ctx.send("Module '{}' désactivé !".format(name))
self.bot.log.info("Module {} désactivé".format(name))
self.logger.info("Module {} désactivé".format(name))
except Exception as e:
await ctx.send(str(e))

Expand Down
17 changes: 10 additions & 7 deletions plugins/antikikoo/antikikoo.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
de la licence CeCILL diffusée sur le site "http://www.cecill.info".
"""

from utils import Gunibot, MyContext
import sys

import discord
from discord.ext import commands
from discord.channel import TextChannel
import discord
from bot import checks
import sys

from utils import Gunibot, MyContext
from core import setup_logger

sys.path.append("./bot")

Expand Down Expand Up @@ -38,6 +40,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 @@ -50,7 +53,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(f"{member} ({member.id}) joined the server")
config = self.bot.server_configs[member.guild.id]
# if nothing has been configured
if (
Expand Down Expand Up @@ -94,7 +97,7 @@ async def on_message(self, message: discord.Message):
try:
await message.delete()
except BaseException:
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 @@ -104,7 +107,7 @@ async def on_message(self, message: discord.Message):
else:
await message.author.remove_roles(verif_role)
except BaseException:
self.bot.log.exception(
self.logger.exception(
f"Cannot give or take away verification role from member {message.author}"
)

Expand Down
16 changes: 7 additions & 9 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 @@ -10,27 +10,25 @@
import time
from marshal import dumps, loads
from typing import List, Optional, Union

import sys

sys.path.append("./bot")
import re
import args
import sys

sys.path.append("./bot")
from bot import checks
import discord
import emoji
from discord.ext import commands, tasks

from utils import Gunibot, MyContext
import re
from bot import checks
from core import setup_logger


class Giveaways(commands.Cog):
def __init__(self, bot: Gunibot):
self.bot = bot
self.config_options = ["giveaways_emojis"]
self.internal_task.start()
self.logger = setup_logger('giveways')

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

Expand Down Expand Up @@ -708,7 +706,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(f"Giveaway '{giveaway['name']}' has stopped")
channel: discord.TextChannel = self.bot.get_channel(giveaway["channel"])
if channel is None:
return None
Expand Down
15 changes: 9 additions & 6 deletions plugins/hypesquad/hypesquad.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
from typing import Dict

import discord
from checks import is_roles_manager
from discord.ext import commands, tasks

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


class Hypesquad(commands.Cog):
Expand All @@ -24,6 +26,7 @@ def __init__(self, bot: Gunibot):
"hs_none_role",
]
self.roles_loop.start()
self.logger = setup_logger('hypesquad')

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

Expand Down Expand Up @@ -68,7 +71,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"""
t1 = time.time()
self.bot.log.debug("[hypesquad] Started roles check")
self.logger.debug("Started roles check")
count = 0 # count of edited members
for g in self.bot.guilds:
try:
Expand All @@ -78,12 +81,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 {g.id} ({g.name})"
self.logger.warn(
f"Unable to give roles in guild {g.id} ({g.name})"
)
delta = round(time.time() - t1, 2)
self.bot.log.info(
f"[hypesquad] Finished roles check in {delta}s with {count} editions"
self.logger.info(
f"Finished roles check in {delta}s with {count} editions"
)

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

from typing import Any, Dict, List, Optional, Tuple, Union

import discord
from discord.ext import tasks, commands

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 @@ -158,6 +160,7 @@ def __eq__(self, object: Union[int, str, "Invite", discord.Invite]) -> bool:
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 @@ -263,7 +266,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

0 comments on commit c6f5157

Please sign in to comment.