aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Matteo Bertucci <[email protected]>2021-10-15 09:20:20 +0000
committerGravatar GitHub <[email protected]>2021-10-15 09:21:08 +0000
commit5408b78bdf61e6109aaad940757497cae02eaab6 (patch)
tree3f55f0dca6f878973b355492047ad458d95abbe1
parentActions: do not check licenses of dev packages (diff)
parentMerge pull request #1874 from python-discord/fix-bot-1869 (diff)
Merge remote-tracking branch 'origin/main' into experiments/isort
-rw-r--r--bot/__main__.py6
-rw-r--r--bot/api.py5
-rw-r--r--bot/bot.py4
-rw-r--r--bot/constants.py12
-rw-r--r--bot/converters.py4
-rw-r--r--bot/decorators.py4
-rw-r--r--bot/exts/backend/branding/_cog.py4
-rw-r--r--bot/exts/backend/branding/_repository.py4
-rw-r--r--bot/exts/backend/config_verifier.py5
-rw-r--r--bot/exts/backend/error_handler.py4
-rw-r--r--bot/exts/backend/logging.py5
-rw-r--r--bot/exts/backend/sync/_cog.py4
-rw-r--r--bot/exts/backend/sync/_syncers.py4
-rw-r--r--bot/exts/events/code_jams/_channels.py4
-rw-r--r--bot/exts/events/code_jams/_cog.py4
-rw-r--r--bot/exts/filters/antimalware.py4
-rw-r--r--bot/exts/filters/antispam.py4
-rw-r--r--bot/exts/filters/filter_lists.py4
-rw-r--r--bot/exts/filters/filtering.py4
-rw-r--r--bot/exts/filters/security.py5
-rw-r--r--bot/exts/filters/token_remover.py4
-rw-r--r--bot/exts/filters/webhook_remover.py4
-rw-r--r--bot/exts/fun/duck_pond.py4
-rw-r--r--bot/exts/fun/off_topic_names.py4
-rw-r--r--bot/exts/help_channels/__init__.py5
-rw-r--r--bot/exts/help_channels/_channel.py4
-rw-r--r--bot/exts/help_channels/_cog.py4
-rw-r--r--bot/exts/help_channels/_message.py4
-rw-r--r--bot/exts/help_channels/_name.py4
-rw-r--r--bot/exts/help_channels/_stats.py5
-rw-r--r--bot/exts/info/code_snippets.py3
-rw-r--r--bot/exts/info/codeblock/_cog.py4
-rw-r--r--bot/exts/info/codeblock/_instructions.py4
-rw-r--r--bot/exts/info/codeblock/_parsing.py4
-rw-r--r--bot/exts/info/doc/_batch_parser.py4
-rw-r--r--bot/exts/info/doc/_cog.py4
-rw-r--r--bot/exts/info/doc/_html.py5
-rw-r--r--bot/exts/info/doc/_inventory_parser.py4
-rw-r--r--bot/exts/info/doc/_parsing.py4
-rw-r--r--bot/exts/info/help.py4
-rw-r--r--bot/exts/info/information.py4
-rw-r--r--bot/exts/info/pep.py4
-rw-r--r--bot/exts/info/pypi.py4
-rw-r--r--bot/exts/info/python_news.py4
-rw-r--r--bot/exts/info/site.py5
-rw-r--r--bot/exts/info/tags.py4
-rw-r--r--bot/exts/moderation/defcon.py28
-rw-r--r--bot/exts/moderation/dm_relay.py5
-rw-r--r--bot/exts/moderation/incidents.py4
-rw-r--r--bot/exts/moderation/infraction/_scheduler.py18
-rw-r--r--bot/exts/moderation/infraction/_utils.py4
-rw-r--r--bot/exts/moderation/infraction/infractions.py4
-rw-r--r--bot/exts/moderation/infraction/management.py11
-rw-r--r--bot/exts/moderation/infraction/superstarify.py4
-rw-r--r--bot/exts/moderation/metabase.py4
-rw-r--r--bot/exts/moderation/modlog.py4
-rw-r--r--bot/exts/moderation/modpings.py4
-rw-r--r--bot/exts/moderation/silence.py4
-rw-r--r--bot/exts/moderation/slowmode.py4
-rw-r--r--bot/exts/moderation/stream.py4
-rw-r--r--bot/exts/moderation/verification.py4
-rw-r--r--bot/exts/moderation/voice_gate.py4
-rw-r--r--bot/exts/moderation/watchchannels/_watchchannel.py6
-rw-r--r--bot/exts/moderation/watchchannels/bigbrother.py12
-rw-r--r--bot/exts/recruitment/talentpool/_cog.py4
-rw-r--r--bot/exts/recruitment/talentpool/_review.py4
-rw-r--r--bot/exts/utils/bot.py4
-rw-r--r--bot/exts/utils/clean.py4
-rw-r--r--bot/exts/utils/extensions.py4
-rw-r--r--bot/exts/utils/internal.py4
-rw-r--r--bot/exts/utils/reminders.py6
-rw-r--r--bot/exts/utils/snekbox.py4
-rw-r--r--bot/exts/utils/utils.py4
-rw-r--r--bot/log.py65
-rw-r--r--bot/monkey_patches.py5
-rw-r--r--bot/pagination.py4
-rw-r--r--bot/resources/tags/contribute.md12
-rw-r--r--bot/utils/channel.py5
-rw-r--r--bot/utils/checks.py4
-rw-r--r--bot/utils/function.py5
-rw-r--r--bot/utils/lock.py4
-rw-r--r--bot/utils/members.py5
-rw-r--r--bot/utils/messages.py4
-rw-r--r--bot/utils/scheduling.py7
-rw-r--r--bot/utils/services.py4
-rw-r--r--bot/utils/webhooks.py4
-rw-r--r--tests/__init__.py4
-rw-r--r--tests/base.py3
-rw-r--r--tests/test_base.py10
89 files changed, 277 insertions, 235 deletions
diff --git a/bot/__main__.py b/bot/__main__.py
index 9317563c8..0d3fce180 100644
--- a/bot/__main__.py
+++ b/bot/__main__.py
@@ -1,11 +1,9 @@
-import logging
-
import aiohttp
import bot
from bot import constants
from bot.bot import Bot, StartupError
-from bot.log import setup_sentry
+from bot.log import get_logger, setup_sentry
setup_sentry()
@@ -21,7 +19,7 @@ except StartupError as e:
message = "Could not connect to Redis. Is it running?"
# The exception is logged with an empty message so the actual message is visible at the bottom
- log = logging.getLogger("bot")
+ log = get_logger("bot")
log.fatal("", exc_info=e.exception)
log.fatal(message)
diff --git a/bot/api.py b/bot/api.py
index 6ce9481f4..856f7c865 100644
--- a/bot/api.py
+++ b/bot/api.py
@@ -1,13 +1,14 @@
import asyncio
-import logging
from typing import Optional
from urllib.parse import quote as quote_url
import aiohttp
+from bot.log import get_logger
+
from .constants import Keys, URLs
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class ResponseCodeError(ValueError):
diff --git a/bot/bot.py b/bot/bot.py
index db3d651a3..94783a466 100644
--- a/bot/bot.py
+++ b/bot/bot.py
@@ -1,5 +1,4 @@
import asyncio
-import logging
import socket
import warnings
from collections import defaultdict
@@ -14,8 +13,9 @@ from sentry_sdk import push_scope
from bot import api, constants
from bot.async_stats import AsyncStatsClient
+from bot.log import get_logger
-log = logging.getLogger('bot')
+log = get_logger('bot')
LOCALHOST = "127.0.0.1"
diff --git a/bot/constants.py b/bot/constants.py
index f99913b17..f704c9e6a 100644
--- a/bot/constants.py
+++ b/bot/constants.py
@@ -9,8 +9,6 @@ the custom configuration. Any settings left
out in the custom user configuration will stay
their default values from `config-default.yml`.
"""
-
-import logging
import os
from collections.abc import Mapping
from enum import Enum
@@ -25,8 +23,6 @@ try:
except ModuleNotFoundError:
pass
-log = logging.getLogger(__name__)
-
def _env_var_constructor(loader, node):
"""
@@ -104,7 +100,7 @@ def _recursive_update(original, new):
if Path("config.yml").exists():
- log.info("Found `config.yml` file, loading constants from it.")
+ print("Found `config.yml` file, loading constants from it.")
with open("config.yml", encoding="UTF-8") as f:
user_config = yaml.safe_load(f)
_recursive_update(_CONFIG_YAML, user_config)
@@ -123,11 +119,10 @@ def check_required_keys(keys):
if lookup is None:
raise KeyError(key)
except KeyError:
- log.critical(
+ raise KeyError(
f"A configuration for `{key_path}` is required, but was not found. "
"Please set it in `config.yml` or setup an environment variable and try again."
)
- raise
try:
@@ -186,8 +181,7 @@ class YAMLGetter(type):
(cls.section, cls.subsection, name)
if cls.subsection is not None else (cls.section, name)
)
- # Only an INFO log since this can be caught through `hasattr` or `getattr`.
- log.info(f"Tried accessing configuration variable at `{dotted_path}`, but it could not be found.")
+ print(f"Tried accessing configuration variable at `{dotted_path}`, but it could not be found.")
raise AttributeError(repr(name)) from e
def __getitem__(cls, name):
diff --git a/bot/converters.py b/bot/converters.py
index 7f6aa9c52..4d019691e 100644
--- a/bot/converters.py
+++ b/bot/converters.py
@@ -1,6 +1,5 @@
from __future__ import annotations
-import logging
import re
import typing as t
from datetime import datetime
@@ -19,6 +18,7 @@ from bot.api import ResponseCodeError
from bot.constants import URLs
from bot.errors import InvalidInfraction
from bot.exts.info.doc import _inventory_parser
+from bot.log import get_logger
from bot.utils.extensions import EXTENSIONS, unqualify
from bot.utils.regex import INVITE_RE
from bot.utils.time import parse_duration_string
@@ -26,7 +26,7 @@ from bot.utils.time import parse_duration_string
if t.TYPE_CHECKING:
from bot.exts.info.source import SourceType
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
DISCORD_EPOCH_DT = datetime.utcfromtimestamp(DISCORD_EPOCH / 1000)
RE_USER_MENTION = re.compile(r"<@!?([0-9]+)>$")
diff --git a/bot/decorators.py b/bot/decorators.py
index ee210be26..048a2a09a 100644
--- a/bot/decorators.py
+++ b/bot/decorators.py
@@ -1,6 +1,5 @@
import asyncio
import functools
-import logging
import types
import typing as t
from contextlib import suppress
@@ -10,11 +9,12 @@ from discord.ext import commands
from discord.ext.commands import Cog, Context
from bot.constants import Channels, DEBUG_MODE, RedirectOutput
+from bot.log import get_logger
from bot.utils import function, scheduling
from bot.utils.checks import ContextCheckFailure, in_whitelist_check
from bot.utils.function import command_wraps
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
def in_whitelist(
diff --git a/bot/exts/backend/branding/_cog.py b/bot/exts/backend/branding/_cog.py
index ab0a761ff..9c5bdbb4e 100644
--- a/bot/exts/backend/branding/_cog.py
+++ b/bot/exts/backend/branding/_cog.py
@@ -1,6 +1,5 @@
import asyncio
import contextlib
-import logging
import random
import typing as t
from datetime import timedelta
@@ -17,9 +16,10 @@ from bot.bot import Bot
from bot.constants import Branding as BrandingConfig, Channels, Colours, Guild, MODERATION_ROLES
from bot.decorators import mock_in_debug
from bot.exts.backend.branding._repository import BrandingRepository, Event, RemoteObject
+from bot.log import get_logger
from bot.utils import scheduling
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class AssetType(Enum):
diff --git a/bot/exts/backend/branding/_repository.py b/bot/exts/backend/branding/_repository.py
index 7b09d4641..d88ea67f3 100644
--- a/bot/exts/backend/branding/_repository.py
+++ b/bot/exts/backend/branding/_repository.py
@@ -1,4 +1,3 @@
-import logging
import typing as t
from datetime import date, datetime
@@ -7,6 +6,7 @@ import frontmatter
from bot.bot import Bot
from bot.constants import Keys
from bot.errors import BrandingMisconfiguration
+from bot.log import get_logger
# Base URL for requests into the branding repository.
BRANDING_URL = "https://api.github.com/repos/python-discord/branding/contents"
@@ -25,7 +25,7 @@ ARBITRARY_YEAR = 2020
# Format used to parse date strings after we inject `ARBITRARY_YEAR` at the end.
DATE_FMT = "%B %d %Y" # Ex: July 10 2020
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class RemoteObject:
diff --git a/bot/exts/backend/config_verifier.py b/bot/exts/backend/config_verifier.py
index c24cb324f..dc85a65a2 100644
--- a/bot/exts/backend/config_verifier.py
+++ b/bot/exts/backend/config_verifier.py
@@ -1,12 +1,11 @@
-import logging
-
from discord.ext.commands import Cog
from bot import constants
from bot.bot import Bot
+from bot.log import get_logger
from bot.utils import scheduling
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class ConfigVerifier(Cog):
diff --git a/bot/exts/backend/error_handler.py b/bot/exts/backend/error_handler.py
index 578c372c3..7644b93ae 100644
--- a/bot/exts/backend/error_handler.py
+++ b/bot/exts/backend/error_handler.py
@@ -1,5 +1,4 @@
import difflib
-import logging
import typing as t
from discord import Embed
@@ -11,9 +10,10 @@ from bot.bot import Bot
from bot.constants import Colours, Icons, MODERATION_ROLES
from bot.converters import TagNameConverter
from bot.errors import InvalidInfractedUserError, LockedResourceError
+from bot.log import get_logger
from bot.utils.checks import ContextCheckFailure
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class ErrorHandler(Cog):
diff --git a/bot/exts/backend/logging.py b/bot/exts/backend/logging.py
index 8f1b8026f..2d03cd580 100644
--- a/bot/exts/backend/logging.py
+++ b/bot/exts/backend/logging.py
@@ -1,13 +1,12 @@
-import logging
-
from discord import Embed
from discord.ext.commands import Cog
from bot.bot import Bot
from bot.constants import Channels, DEBUG_MODE
+from bot.log import get_logger
from bot.utils import scheduling
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class Logging(Cog):
diff --git a/bot/exts/backend/sync/_cog.py b/bot/exts/backend/sync/_cog.py
index f88dcf538..80f5750bc 100644
--- a/bot/exts/backend/sync/_cog.py
+++ b/bot/exts/backend/sync/_cog.py
@@ -1,4 +1,3 @@
-import logging
from typing import Any, Dict
from discord import Member, Role, User
@@ -9,9 +8,10 @@ from bot import constants
from bot.api import ResponseCodeError
from bot.bot import Bot
from bot.exts.backend.sync import _syncers
+from bot.log import get_logger
from bot.utils import scheduling
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class Sync(Cog):
diff --git a/bot/exts/backend/sync/_syncers.py b/bot/exts/backend/sync/_syncers.py
index 50016df0c..45301b098 100644
--- a/bot/exts/backend/sync/_syncers.py
+++ b/bot/exts/backend/sync/_syncers.py
@@ -1,5 +1,4 @@
import abc
-import logging
import typing as t
from collections import namedtuple
@@ -9,9 +8,10 @@ from more_itertools import chunked
import bot
from bot.api import ResponseCodeError
+from bot.log import get_logger
from bot.utils.members import get_or_fetch_member
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
CHUNK_SIZE = 1000
diff --git a/bot/exts/events/code_jams/_channels.py b/bot/exts/events/code_jams/_channels.py
index 34ff0ad41..e8cf5f7bf 100644
--- a/bot/exts/events/code_jams/_channels.py
+++ b/bot/exts/events/code_jams/_channels.py
@@ -1,11 +1,11 @@
-import logging
import typing as t
import discord
from bot.constants import Categories, Channels, Roles
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
MAX_CHANNELS = 50
CATEGORY_NAME = "Code Jam"
diff --git a/bot/exts/events/code_jams/_cog.py b/bot/exts/events/code_jams/_cog.py
index 7b0831ab4..b31d628d5 100644
--- a/bot/exts/events/code_jams/_cog.py
+++ b/bot/exts/events/code_jams/_cog.py
@@ -1,6 +1,5 @@
import asyncio
import csv
-import logging
import typing as t
from collections import defaultdict
@@ -11,10 +10,11 @@ from discord.ext import commands
from bot.bot import Bot
from bot.constants import Emojis, Roles
from bot.exts.events.code_jams import _channels
+from bot.log import get_logger
from bot.utils.members import get_or_fetch_member
from bot.utils.services import send_to_paste_service
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
TEAM_LEADERS_COLOUR = 0x11806a
DELETION_REACTION = "\U0001f4a5"
diff --git a/bot/exts/filters/antimalware.py b/bot/exts/filters/antimalware.py
index e708e5149..d727f7940 100644
--- a/bot/exts/filters/antimalware.py
+++ b/bot/exts/filters/antimalware.py
@@ -1,4 +1,3 @@
-import logging
import typing as t
from os.path import splitext
@@ -8,8 +7,9 @@ from discord.ext.commands import Cog
from bot.bot import Bot
from bot.constants import Channels, Filter, URLs
from bot.exts.events.code_jams._channels import CATEGORY_NAME as JAM_CATEGORY_NAME
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
PY_EMBED_DESCRIPTION = (
"It looks like you tried to attach a Python file - "
diff --git a/bot/exts/filters/antispam.py b/bot/exts/filters/antispam.py
index 94aec6684..78ad57b48 100644
--- a/bot/exts/filters/antispam.py
+++ b/bot/exts/filters/antispam.py
@@ -1,5 +1,4 @@
import asyncio
-import logging
from collections import defaultdict
from collections.abc import Mapping
from dataclasses import dataclass, field
@@ -19,11 +18,12 @@ from bot.constants import (
from bot.converters import Duration
from bot.exts.events.code_jams._channels import CATEGORY_NAME as JAM_CATEGORY_NAME
from bot.exts.moderation.modlog import ModLog
+from bot.log import get_logger
from bot.utils import lock, scheduling
from bot.utils.message_cache import MessageCache
from bot.utils.messages import format_user, send_attachments
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
RULE_FUNCTION_MAPPING = {
'attachments': rules.apply_attachments,
diff --git a/bot/exts/filters/filter_lists.py b/bot/exts/filters/filter_lists.py
index a06437f3d..4b5200684 100644
--- a/bot/exts/filters/filter_lists.py
+++ b/bot/exts/filters/filter_lists.py
@@ -1,4 +1,3 @@
-import logging
from typing import Optional
from discord import Colour, Embed
@@ -8,10 +7,11 @@ from bot import constants
from bot.api import ResponseCodeError
from bot.bot import Bot
from bot.converters import ValidDiscordServerInvite, ValidFilterListType
+from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils import scheduling
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class FilterLists(Cog):
diff --git a/bot/exts/filters/filtering.py b/bot/exts/filters/filtering.py
index 916e3efff..78b7a8d94 100644
--- a/bot/exts/filters/filtering.py
+++ b/bot/exts/filters/filtering.py
@@ -1,5 +1,4 @@
import asyncio
-import logging
import re
from datetime import datetime, timedelta
from typing import Any, Dict, List, Mapping, NamedTuple, Optional, Tuple, Union
@@ -18,11 +17,12 @@ from bot.bot import Bot
from bot.constants import Channels, Colours, Filter, Guild, Icons, URLs
from bot.exts.events.code_jams._channels import CATEGORY_NAME as JAM_CATEGORY_NAME
from bot.exts.moderation.modlog import ModLog
+from bot.log import get_logger
from bot.utils import scheduling
from bot.utils.messages import format_user
from bot.utils.regex import INVITE_RE
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
# Regular expressions
CODE_BLOCK_RE = re.compile(
diff --git a/bot/exts/filters/security.py b/bot/exts/filters/security.py
index c680c5e27..fe3918423 100644
--- a/bot/exts/filters/security.py
+++ b/bot/exts/filters/security.py
@@ -1,10 +1,9 @@
-import logging
-
from discord.ext.commands import Cog, Context, NoPrivateMessage
from bot.bot import Bot
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class Security(Cog):
diff --git a/bot/exts/filters/token_remover.py b/bot/exts/filters/token_remover.py
index 6c86ff849..f68d4b987 100644
--- a/bot/exts/filters/token_remover.py
+++ b/bot/exts/filters/token_remover.py
@@ -1,6 +1,5 @@
import base64
import binascii
-import logging
import re
import typing as t
@@ -11,10 +10,11 @@ from bot import utils
from bot.bot import Bot
from bot.constants import Channels, Colours, Event, Icons
from bot.exts.moderation.modlog import ModLog
+from bot.log import get_logger
from bot.utils.members import get_or_fetch_member
from bot.utils.messages import format_user
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
LOG_MESSAGE = (
"Censored a seemingly valid token sent by {author} in {channel}, "
diff --git a/bot/exts/filters/webhook_remover.py b/bot/exts/filters/webhook_remover.py
index 25e267426..40cb4e141 100644
--- a/bot/exts/filters/webhook_remover.py
+++ b/bot/exts/filters/webhook_remover.py
@@ -1,4 +1,3 @@
-import logging
import re
from discord import Colour, Message, NotFound
@@ -7,6 +6,7 @@ from discord.ext.commands import Cog
from bot.bot import Bot
from bot.constants import Channels, Colours, Event, Icons
from bot.exts.moderation.modlog import ModLog
+from bot.log import get_logger
from bot.utils.messages import format_user
WEBHOOK_URL_RE = re.compile(
@@ -21,7 +21,7 @@ ALERT_MESSAGE_TEMPLATE = (
"mistake, please let us know."
)
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class WebhookRemover(Cog):
diff --git a/bot/exts/fun/duck_pond.py b/bot/exts/fun/duck_pond.py
index 8ced6922c..2b5592530 100644
--- a/bot/exts/fun/duck_pond.py
+++ b/bot/exts/fun/duck_pond.py
@@ -1,5 +1,4 @@
import asyncio
-import logging
from typing import Union
import discord
@@ -9,12 +8,13 @@ from discord.ext.commands import Cog, Context, command
from bot import constants
from bot.bot import Bot
from bot.converters import MemberOrUser
+from bot.log import get_logger
from bot.utils import scheduling
from bot.utils.checks import has_any_role
from bot.utils.messages import count_unique_users_reaction, send_attachments
from bot.utils.webhooks import send_webhook
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class DuckPond(Cog):
diff --git a/bot/exts/fun/off_topic_names.py b/bot/exts/fun/off_topic_names.py
index 2f56aa5ba..427667c66 100644
--- a/bot/exts/fun/off_topic_names.py
+++ b/bot/exts/fun/off_topic_names.py
@@ -1,5 +1,4 @@
import difflib
-import logging
from datetime import datetime, timedelta
from discord import Colour, Embed
@@ -10,11 +9,12 @@ from bot.api import ResponseCodeError
from bot.bot import Bot
from bot.constants import Channels, MODERATION_ROLES
from bot.converters import OffTopicName
+from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils import scheduling
CHANNELS = (Channels.off_topic_0, Channels.off_topic_1, Channels.off_topic_2)
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
async def update_names(bot: Bot) -> None:
diff --git a/bot/exts/help_channels/__init__.py b/bot/exts/help_channels/__init__.py
index 781f40449..beba18aa6 100644
--- a/bot/exts/help_channels/__init__.py
+++ b/bot/exts/help_channels/__init__.py
@@ -1,10 +1,9 @@
-import logging
-
from bot import constants
from bot.bot import Bot
from bot.exts.help_channels._channel import MAX_CHANNELS_PER_CATEGORY
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
def validate_config() -> None:
diff --git a/bot/exts/help_channels/_channel.py b/bot/exts/help_channels/_channel.py
index f1bcea171..e43c1e789 100644
--- a/bot/exts/help_channels/_channel.py
+++ b/bot/exts/help_channels/_channel.py
@@ -1,4 +1,3 @@
-import logging
import typing as t
from datetime import timedelta
from enum import Enum
@@ -10,9 +9,10 @@ from arrow import Arrow
import bot
from bot import constants
from bot.exts.help_channels import _caches, _message
+from bot.log import get_logger
from bot.utils.channel import get_or_fetch_channel
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
MAX_CHANNELS_PER_CATEGORY = 50
EXCLUDED_CHANNELS = (constants.Channels.cooldown,)
diff --git a/bot/exts/help_channels/_cog.py b/bot/exts/help_channels/_cog.py
index 7c39bc132..498305b47 100644
--- a/bot/exts/help_channels/_cog.py
+++ b/bot/exts/help_channels/_cog.py
@@ -1,5 +1,4 @@
import asyncio
-import logging
import random
import typing as t
from datetime import timedelta
@@ -14,9 +13,10 @@ from bot import constants
from bot.bot import Bot
from bot.constants import Channels, RedirectOutput
from bot.exts.help_channels import _caches, _channel, _message, _name, _stats
+from bot.log import get_logger
from bot.utils import channel as channel_utils, lock, members, scheduling
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
NAMESPACE = "help"
HELP_CHANNEL_TOPIC = """
diff --git a/bot/exts/help_channels/_message.py b/bot/exts/help_channels/_message.py
index 077b20b47..a52c67570 100644
--- a/bot/exts/help_channels/_message.py
+++ b/bot/exts/help_channels/_message.py
@@ -1,4 +1,3 @@
-import logging
import textwrap
import typing as t
@@ -9,8 +8,9 @@ from arrow import Arrow
import bot
from bot import constants
from bot.exts.help_channels import _caches
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
ASKING_GUIDE_URL = "https://pythondiscord.com/pages/asking-good-questions/"
diff --git a/bot/exts/help_channels/_name.py b/bot/exts/help_channels/_name.py
index 061f855ae..a9d9b2df1 100644
--- a/bot/exts/help_channels/_name.py
+++ b/bot/exts/help_channels/_name.py
@@ -1,5 +1,4 @@
import json
-import logging
import typing as t
from collections import deque
from pathlib import Path
@@ -8,8 +7,9 @@ import discord
from bot import constants
from bot.exts.help_channels._channel import MAX_CHANNELS_PER_CATEGORY, get_category_channels
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
def create_name_queue(*categories: discord.CategoryChannel) -> deque:
diff --git a/bot/exts/help_channels/_stats.py b/bot/exts/help_channels/_stats.py
index eb34e75e1..4698c26de 100644
--- a/bot/exts/help_channels/_stats.py
+++ b/bot/exts/help_channels/_stats.py
@@ -1,12 +1,11 @@
-import logging
-
from more_itertools import ilen
import bot
from bot import constants
from bot.exts.help_channels import _caches, _channel
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
def report_counts() -> None:
diff --git a/bot/exts/info/code_snippets.py b/bot/exts/info/code_snippets.py
index 4a90a0668..07b1b8a2d 100644
--- a/bot/exts/info/code_snippets.py
+++ b/bot/exts/info/code_snippets.py
@@ -10,9 +10,10 @@ from discord.ext.commands import Cog
from bot.bot import Bot
from bot.constants import Channels
+from bot.log import get_logger
from bot.utils.messages import wait_for_deletion
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
GITHUB_RE = re.compile(
r'https://github\.com/(?P<repo>[a-zA-Z0-9-]+/[\w.-]+)/blob/'
diff --git a/bot/exts/info/codeblock/_cog.py b/bot/exts/info/codeblock/_cog.py
index f63a459ff..a859d8cef 100644
--- a/bot/exts/info/codeblock/_cog.py
+++ b/bot/exts/info/codeblock/_cog.py
@@ -1,4 +1,3 @@
-import logging
import time
from typing import Optional
@@ -11,11 +10,12 @@ from bot.bot import Bot
from bot.exts.filters.token_remover import TokenRemover
from bot.exts.filters.webhook_remover import WEBHOOK_URL_RE
from bot.exts.info.codeblock._instructions import get_instructions
+from bot.log import get_logger
from bot.utils import has_lines, scheduling
from bot.utils.channel import is_help_channel
from bot.utils.messages import wait_for_deletion
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class CodeBlockCog(Cog, name="Code Block"):
diff --git a/bot/exts/info/codeblock/_instructions.py b/bot/exts/info/codeblock/_instructions.py
index dadb5e1ef..8fcadeec2 100644
--- a/bot/exts/info/codeblock/_instructions.py
+++ b/bot/exts/info/codeblock/_instructions.py
@@ -1,11 +1,11 @@
"""This module generates and formats instructional messages about fixing Markdown code blocks."""
-import logging
from typing import Optional
from bot.exts.info.codeblock import _parsing
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
_EXAMPLE_PY = "{lang}\nprint('Hello, world!')" # Make sure to escape any Markdown symbols here.
_EXAMPLE_CODE_BLOCKS = (
diff --git a/bot/exts/info/codeblock/_parsing.py b/bot/exts/info/codeblock/_parsing.py
index 73fd11b94..3c193d6c5 100644
--- a/bot/exts/info/codeblock/_parsing.py
+++ b/bot/exts/info/codeblock/_parsing.py
@@ -1,15 +1,15 @@
"""This module provides functions for parsing Markdown code blocks."""
import ast
-import logging
import re
import textwrap
from typing import NamedTuple, Optional, Sequence
from bot import constants
+from bot.log import get_logger
from bot.utils import has_lines
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
BACKTICK = "`"
PY_LANG_CODES = ("python-repl", "python", "pycon", "py") # Order is important; "py" is last cause it's a subset.
diff --git a/bot/exts/info/doc/_batch_parser.py b/bot/exts/info/doc/_batch_parser.py
index c8e542ce7..92f814c9d 100644
--- a/bot/exts/info/doc/_batch_parser.py
+++ b/bot/exts/info/doc/_batch_parser.py
@@ -2,7 +2,6 @@ from __future__ import annotations
import asyncio
import collections
-import logging
from collections import defaultdict
from contextlib import suppress
from operator import attrgetter
@@ -13,12 +12,13 @@ from bs4 import BeautifulSoup
import bot
from bot.constants import Channels
+from bot.log import get_logger
from bot.utils import scheduling
from . import _cog, doc_cache
from ._parsing import get_symbol_markdown
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class StaleInventoryNotifier:
diff --git a/bot/exts/info/doc/_cog.py b/bot/exts/info/doc/_cog.py
index 5a8aa8841..fbbcd4a10 100644
--- a/bot/exts/info/doc/_cog.py
+++ b/bot/exts/info/doc/_cog.py
@@ -1,7 +1,6 @@
from __future__ import annotations
import asyncio
-import logging
import sys
import textwrap
from collections import defaultdict
@@ -17,6 +16,7 @@ from bot.api import ResponseCodeError
from bot.bot import Bot
from bot.constants import MODERATION_ROLES, RedirectOutput
from bot.converters import Inventory, PackageName, ValidURL, allowed_strings
+from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils import scheduling
from bot.utils.lock import SharedEvent, lock
@@ -26,7 +26,7 @@ from bot.utils.scheduling import Scheduler
from . import NAMESPACE, PRIORITY_PACKAGES, _batch_parser, doc_cache
from ._inventory_parser import InvalidHeaderError, InventoryDict, fetch_inventory
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
# symbols with a group contained here will get the group prefixed on duplicates
FORCE_PREFIX_GROUPS = (
diff --git a/bot/exts/info/doc/_html.py b/bot/exts/info/doc/_html.py
index 94efd81b7..ca0a0ac4a 100644
--- a/bot/exts/info/doc/_html.py
+++ b/bot/exts/info/doc/_html.py
@@ -1,4 +1,3 @@
-import logging
import re
from functools import partial
from typing import Callable, Container, Iterable, List, Union
@@ -6,9 +5,11 @@ from typing import Callable, Container, Iterable, List, Union
from bs4 import BeautifulSoup
from bs4.element import NavigableString, PageElement, SoupStrainer, Tag
+from bot.log import get_logger
+
from . import MAX_SIGNATURE_AMOUNT
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
_UNWANTED_SIGNATURE_SYMBOLS_RE = re.compile(r"\[source]|\\\\|¶")
_SEARCH_END_TAG_ATTRS = (
diff --git a/bot/exts/info/doc/_inventory_parser.py b/bot/exts/info/doc/_inventory_parser.py
index 61924d070..e69246d47 100644
--- a/bot/exts/info/doc/_inventory_parser.py
+++ b/bot/exts/info/doc/_inventory_parser.py
@@ -1,4 +1,3 @@
-import logging
import re
import zlib
from collections import defaultdict
@@ -7,8 +6,9 @@ from typing import AsyncIterator, DefaultDict, List, Optional, Tuple
import aiohttp
import bot
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
FAILED_REQUEST_ATTEMPTS = 3
_V2_LINE_RE = re.compile(r'(?x)(.+?)\s+(\S*:\S*)\s+(-?\d+)\s+?(\S*)\s+(.*)')
diff --git a/bot/exts/info/doc/_parsing.py b/bot/exts/info/doc/_parsing.py
index a1bf33de9..6ab38eb3d 100644
--- a/bot/exts/info/doc/_parsing.py
+++ b/bot/exts/info/doc/_parsing.py
@@ -1,6 +1,5 @@
from __future__ import annotations
-import logging
import re
import string
import textwrap
@@ -10,6 +9,7 @@ from typing import Collection, Iterable, Iterator, List, Optional, TYPE_CHECKING
from bs4 import BeautifulSoup
from bs4.element import NavigableString, Tag
+from bot.log import get_logger
from bot.utils.helpers import find_nth_occurrence
from . import MAX_SIGNATURE_AMOUNT
@@ -19,7 +19,7 @@ from ._markdown import DocMarkdownConverter
if TYPE_CHECKING:
from ._cog import DocItem
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
_WHITESPACE_AFTER_NEWLINES_RE = re.compile(r"(?<=\n\n)(\s+)")
_PARAMETERS_RE = re.compile(r"\((.+)\)")
diff --git a/bot/exts/info/help.py b/bot/exts/info/help.py
index 21a6cf752..f413caded 100644
--- a/bot/exts/info/help.py
+++ b/bot/exts/info/help.py
@@ -1,5 +1,4 @@
import itertools
-import logging
from collections import namedtuple
from contextlib import suppress
from typing import List, Union
@@ -12,10 +11,11 @@ from rapidfuzz.utils import default_process
from bot import constants
from bot.constants import Channels, STAFF_PARTNERS_COMMUNITY_ROLES
from bot.decorators import redirect_output
+from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils.messages import wait_for_deletion
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
COMMANDS_PER_PAGE = 8
PREFIX = constants.Bot.prefix
diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py
index c60fd2127..f27483af8 100644
--- a/bot/exts/info/information.py
+++ b/bot/exts/info/information.py
@@ -1,5 +1,4 @@
import colorsys
-import logging
import pprint
import textwrap
from collections import defaultdict
@@ -16,13 +15,14 @@ from bot.bot import Bot
from bot.converters import MemberOrUser
from bot.decorators import in_whitelist
from bot.errors import NonExistentRoleError
+from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils.channel import is_mod_channel, is_staff_channel
from bot.utils.checks import cooldown_with_role_bypass, has_no_roles_check, in_whitelist_check
from bot.utils.members import get_or_fetch_member
from bot.utils.time import TimestampFormats, discord_timestamp, humanize_delta
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class Information(Cog):
diff --git a/bot/exts/info/pep.py b/bot/exts/info/pep.py
index bbd112911..259095b50 100644
--- a/bot/exts/info/pep.py
+++ b/bot/exts/info/pep.py
@@ -1,4 +1,3 @@
-import logging
from datetime import datetime, timedelta
from email.parser import HeaderParser
from io import StringIO
@@ -9,10 +8,11 @@ from discord.ext.commands import Cog, Context, command
from bot.bot import Bot
from bot.constants import Keys
+from bot.log import get_logger
from bot.utils import scheduling
from bot.utils.caching import AsyncCache
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
ICON_URL = "https://www.python.org/static/opengraph-icon-200x200.png"
BASE_PEP_URL = "http://www.python.org/dev/peps/pep-"
diff --git a/bot/exts/info/pypi.py b/bot/exts/info/pypi.py
index 62498ce0b..c3d2e2a3c 100644
--- a/bot/exts/info/pypi.py
+++ b/bot/exts/info/pypi.py
@@ -1,5 +1,4 @@
import itertools
-import logging
import random
import re
from contextlib import suppress
@@ -10,6 +9,7 @@ from discord.utils import escape_markdown
from bot.bot import Bot
from bot.constants import Colours, NEGATIVE_REPLIES, RedirectOutput
+from bot.log import get_logger
from bot.utils.messages import wait_for_deletion
URL = "https://pypi.org/pypi/{package}/json"
@@ -20,7 +20,7 @@ PYPI_COLOURS = itertools.cycle((Colours.yellow, Colours.blue, Colours.white))
ILLEGAL_CHARACTERS = re.compile(r"[^-_.a-zA-Z0-9]+")
INVALID_INPUT_DELETE_DELAY = RedirectOutput.delete_delay
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class PyPi(Cog):
diff --git a/bot/exts/info/python_news.py b/bot/exts/info/python_news.py
index 2a8b64f32..2fad9d2ab 100644
--- a/bot/exts/info/python_news.py
+++ b/bot/exts/info/python_news.py
@@ -1,4 +1,3 @@
-import logging
import re
import typing as t
from datetime import date, datetime
@@ -11,6 +10,7 @@ from discord.ext.tasks import loop
from bot import constants
from bot.bot import Bot
+from bot.log import get_logger
from bot.utils import scheduling
from bot.utils.webhooks import send_webhook
@@ -31,7 +31,7 @@ MARKDOWN_REGEX = re.compile(
re.DOTALL # required to support multi-line codeblocks
)
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class PythonNews(Cog):
diff --git a/bot/exts/info/site.py b/bot/exts/info/site.py
index 28eb558a6..e1f2f5153 100644
--- a/bot/exts/info/site.py
+++ b/bot/exts/info/site.py
@@ -1,13 +1,12 @@
-import logging
-
from discord import Colour, Embed
from discord.ext.commands import Cog, Context, Greedy, group
from bot.bot import Bot
from bot.constants import URLs
+from bot.log import get_logger
from bot.pagination import LinePaginator
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
BASE_URL = f"{URLs.site_schema}{URLs.site}"
diff --git a/bot/exts/info/tags.py b/bot/exts/info/tags.py
index bb91a8563..842647555 100644
--- a/bot/exts/info/tags.py
+++ b/bot/exts/info/tags.py
@@ -1,4 +1,3 @@
-import logging
import re
import time
from pathlib import Path
@@ -10,10 +9,11 @@ from discord.ext.commands import Cog, Context, group
from bot import constants
from bot.bot import Bot
from bot.converters import TagNameConverter
+from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils.messages import wait_for_deletion
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
TEST_CHANNELS = (
constants.Channels.bot_commands,
diff --git a/bot/exts/moderation/defcon.py b/bot/exts/moderation/defcon.py
index ac813d6ba..56051d0e5 100644
--- a/bot/exts/moderation/defcon.py
+++ b/bot/exts/moderation/defcon.py
@@ -1,4 +1,3 @@
-import logging
import traceback
from collections import namedtuple
from datetime import datetime
@@ -8,7 +7,7 @@ from typing import Optional, Union
from aioredis import RedisError
from async_rediscache import RedisCache
from dateutil.relativedelta import relativedelta
-from discord import Colour, Embed, Forbidden, Member, User
+from discord import Colour, Embed, Forbidden, Member, TextChannel, User
from discord.ext import tasks
from discord.ext.commands import Cog, Context, group, has_any_role
@@ -16,6 +15,7 @@ from bot.bot import Bot
from bot.constants import Channels, Colours, Emojis, Event, Icons, MODERATION_ROLES, Roles
from bot.converters import DurationDelta, Expiry
from bot.exts.moderation.modlog import ModLog
+from bot.log import get_logger
from bot.utils import scheduling
from bot.utils.messages import format_user
from bot.utils.scheduling import Scheduler
@@ -23,7 +23,7 @@ from bot.utils.time import (
TimestampFormats, discord_timestamp, humanize_delta, parse_duration_string, relativedelta_to_timedelta
)
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
REJECTION_MESSAGE = """
Hi, {user} - Thanks for your interest in our server!
@@ -176,7 +176,7 @@ class Defcon(Cog):
"""
if isinstance(threshold, int):
threshold = relativedelta(days=threshold)
- await self._update_threshold(ctx.author, threshold=threshold, expiry=expiry)
+ await self._update_threshold(ctx.author, ctx.channel, threshold, expiry)
@defcon_group.command()
@has_any_role(Roles.admins)
@@ -208,7 +208,13 @@ class Defcon(Cog):
scheduling.create_task(self.channel.edit(topic=new_topic))
@defcon_settings.atomic_transaction
- async def _update_threshold(self, author: User, threshold: relativedelta, expiry: Optional[Expiry] = None) -> None:
+ async def _update_threshold(
+ self,
+ author: User,
+ channel: TextChannel,
+ threshold: relativedelta,
+ expiry: Optional[Expiry] = None
+ ) -> None:
"""Update the new threshold in the cog, cache, defcon channel, and logs, and additionally schedule expiry."""
self.threshold = threshold
if threshold == relativedelta(days=0): # If the threshold is 0, we don't need to schedule anything
@@ -248,9 +254,13 @@ class Defcon(Cog):
else:
channel_message = "removed"
- await self.channel.send(
- f"{action.value.emoji} DEFCON threshold {channel_message}{error}."
- )
+ message = f"{action.value.emoji} DEFCON threshold {channel_message}{error}."
+ await self.channel.send(message)
+
+ # If invoked outside of #defcon send to `ctx.channel` too
+ if channel != self.channel:
+ await channel.send(message)
+
await self._send_defcon_log(action, author)
self._update_channel_topic()
@@ -258,7 +268,7 @@ class Defcon(Cog):
async def _remove_threshold(self) -> None:
"""Resets the threshold back to 0."""
- await self._update_threshold(self.bot.user, relativedelta(days=0))
+ await self._update_threshold(self.bot.user, self.channel, relativedelta(days=0))
@staticmethod
def _stringify_relativedelta(delta: relativedelta) -> str:
diff --git a/bot/exts/moderation/dm_relay.py b/bot/exts/moderation/dm_relay.py
index 0051db82f..566422e29 100644
--- a/bot/exts/moderation/dm_relay.py
+++ b/bot/exts/moderation/dm_relay.py
@@ -1,14 +1,13 @@
-import logging
-
import discord
from discord.ext.commands import Cog, Context, command, has_any_role
from bot.bot import Bot
from bot.constants import Emojis, MODERATION_ROLES
+from bot.log import get_logger
from bot.utils.channel import is_mod_channel
from bot.utils.services import send_to_paste_service
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class DMRelay(Cog):
diff --git a/bot/exts/moderation/incidents.py b/bot/exts/moderation/incidents.py
index a3d90e3fe..4470b6dd6 100644
--- a/bot/exts/moderation/incidents.py
+++ b/bot/exts/moderation/incidents.py
@@ -1,5 +1,4 @@
import asyncio
-import logging
import typing as t
from datetime import datetime
from enum import Enum
@@ -9,10 +8,11 @@ from discord.ext.commands import Cog
from bot.bot import Bot
from bot.constants import Channels, Colours, Emojis, Guild, Webhooks
+from bot.log import get_logger
from bot.utils import scheduling
from bot.utils.messages import sub_clyde
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
# Amount of messages for `crawl_task` to process at most on start-up - limited to 50
# as in practice, there should never be this many messages, and if there are,
diff --git a/bot/exts/moderation/infraction/_scheduler.py b/bot/exts/moderation/infraction/_scheduler.py
index 8e844822d..2a1ccb9d4 100644
--- a/bot/exts/moderation/infraction/_scheduler.py
+++ b/bot/exts/moderation/infraction/_scheduler.py
@@ -1,4 +1,3 @@
-import logging
import textwrap
import typing as t
from abc import abstractmethod
@@ -16,10 +15,11 @@ from bot.constants import Colours
from bot.converters import MemberOrUser
from bot.exts.moderation.infraction import _utils
from bot.exts.moderation.modlog import ModLog
+from bot.log import get_logger
from bot.utils import messages, scheduling, time
from bot.utils.channel import is_mod_channel
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class InfractionScheduler:
@@ -161,11 +161,11 @@ class InfractionScheduler:
# send DMs to user that it doesn't share a guild with. If we were to
# apply kick/ban infractions first, this would mean that we'd make it
# impossible for us to deliver a DM. See python-discord/bot#982.
- if not infraction["hidden"]:
+ if not infraction["hidden"] and infr_type in {"ban", "kick"}:
dm_result = f"{constants.Emojis.failmail} "
dm_log_text = "\nDM: **Failed**"
- # Accordingly display whether the user was successfully notified via DM.
+ # Accordingly update whether the user was successfully notified via DM.
if await _utils.notify_infraction(user, infr_type.replace("_", " ").title(), expiry, user_reason, icon):
dm_result = ":incoming_envelope: "
dm_log_text = "\nDM: Sent"
@@ -228,6 +228,16 @@ class InfractionScheduler:
else:
infr_message = f" **{purge}{' '.join(infr_type.split('_'))}** to {user.mention}{expiry_msg}{end_msg}"
+ # If we need to DM and haven't already tried to
+ if not infraction["hidden"] and infr_type not in {"ban", "kick"}:
+ dm_result = f"{constants.Emojis.failmail} "
+ dm_log_text = "\nDM: **Failed**"
+
+ # Accordingly update whether the user was successfully notified via DM.
+ if await _utils.notify_infraction(user, infr_type.replace("_", " ").title(), expiry, user_reason, icon):
+ dm_result = ":incoming_envelope: "
+ dm_log_text = "\nDM: Sent"
+
# Send a confirmation message to the invoking context.
log.trace(f"Sending infraction #{id_} confirmation message.")
await ctx.send(f"{dm_result}{confirm_msg}{infr_message}.")
diff --git a/bot/exts/moderation/infraction/_utils.py b/bot/exts/moderation/infraction/_utils.py
index b20ef1d06..89718c857 100644
--- a/bot/exts/moderation/infraction/_utils.py
+++ b/bot/exts/moderation/infraction/_utils.py
@@ -1,4 +1,3 @@
-import logging
import typing as t
from datetime import datetime
@@ -9,8 +8,9 @@ from bot.api import ResponseCodeError
from bot.constants import Colours, Icons
from bot.converters import MemberOrUser
from bot.errors import InvalidInfractedUserError
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
# apply icon, pardon icon
INFRACTION_ICONS = {
diff --git a/bot/exts/moderation/infraction/infractions.py b/bot/exts/moderation/infraction/infractions.py
index a7f7dcb7f..e495a94b3 100644
--- a/bot/exts/moderation/infraction/infractions.py
+++ b/bot/exts/moderation/infraction/infractions.py
@@ -1,4 +1,3 @@
-import logging
import textwrap
import typing as t
@@ -14,10 +13,11 @@ from bot.converters import Duration, Expiry, MemberOrUser, UnambiguousMemberOrUs
from bot.decorators import respect_role_hierarchy
from bot.exts.moderation.infraction import _utils
from bot.exts.moderation.infraction._scheduler import InfractionScheduler
+from bot.log import get_logger
from bot.utils.members import get_or_fetch_member
from bot.utils.messages import format_user
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class Infractions(InfractionScheduler, commands.Cog):
diff --git a/bot/exts/moderation/infraction/management.py b/bot/exts/moderation/infraction/management.py
index 0cb2a8b60..a50339ee2 100644
--- a/bot/exts/moderation/infraction/management.py
+++ b/bot/exts/moderation/infraction/management.py
@@ -1,4 +1,3 @@
-import logging
import textwrap
import typing as t
from datetime import datetime
@@ -16,13 +15,14 @@ from bot.converters import Expiry, Infraction, MemberOrUser, Snowflake, Unambigu
from bot.errors import InvalidInfraction
from bot.exts.moderation.infraction.infractions import Infractions
from bot.exts.moderation.modlog import ModLog
+from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils import messages, time
from bot.utils.channel import is_mod_channel
from bot.utils.members import get_or_fetch_member
from bot.utils.time import humanize_delta, until_expiration
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class ModManagement(commands.Cog):
@@ -141,10 +141,11 @@ class ModManagement(commands.Cog):
log_text = ""
if duration is not None and not infraction['active']:
- if reason is None:
+ if (infr_type := infraction['type']) in ('note', 'warning'):
+ await ctx.send(f":x: Cannot edit the expiration of a {infr_type}.")
+ else:
await ctx.send(":x: Cannot edit the expiration of an expired infraction.")
- return
- confirm_messages.append("expiry unchanged (infraction already expired)")
+ return
elif isinstance(duration, str):
request_data['expires_at'] = None
confirm_messages.append("marked as permanent")
diff --git a/bot/exts/moderation/infraction/superstarify.py b/bot/exts/moderation/infraction/superstarify.py
index 17cde68f6..08c92b8f3 100644
--- a/bot/exts/moderation/infraction/superstarify.py
+++ b/bot/exts/moderation/infraction/superstarify.py
@@ -1,5 +1,4 @@
import json
-import logging
import random
import textwrap
import typing as t
@@ -14,11 +13,12 @@ from bot.bot import Bot
from bot.converters import Duration, Expiry
from bot.exts.moderation.infraction import _utils
from bot.exts.moderation.infraction._scheduler import InfractionScheduler
+from bot.log import get_logger
from bot.utils.members import get_or_fetch_member
from bot.utils.messages import format_user
from bot.utils.time import format_infraction
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
NICKNAME_POLICY_URL = "https://pythondiscord.com/pages/rules/#nickname-policy"
SUPERSTARIFY_DEFAULT_DURATION = "1h"
diff --git a/bot/exts/moderation/metabase.py b/bot/exts/moderation/metabase.py
index 6eadd4bad..ce9c220b3 100644
--- a/bot/exts/moderation/metabase.py
+++ b/bot/exts/moderation/metabase.py
@@ -1,6 +1,5 @@
import csv
import json
-import logging
from datetime import timedelta
from io import StringIO
from typing import Dict, List, Optional
@@ -14,11 +13,12 @@ from discord.ext.commands import Cog, Context, group, has_any_role
from bot.bot import Bot
from bot.constants import Metabase as MetabaseConfig, Roles
from bot.converters import allowed_strings
+from bot.log import get_logger
from bot.utils import scheduling, send_to_paste_service
from bot.utils.channel import is_mod_channel
from bot.utils.scheduling import Scheduler
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
BASE_HEADERS = {
"Content-Type": "application/json"
diff --git a/bot/exts/moderation/modlog.py b/bot/exts/moderation/modlog.py
index be2245650..fbb3684e7 100644
--- a/bot/exts/moderation/modlog.py
+++ b/bot/exts/moderation/modlog.py
@@ -1,7 +1,6 @@
import asyncio
import difflib
import itertools
-import logging
import typing as t
from datetime import datetime
from itertools import zip_longest
@@ -16,10 +15,11 @@ from discord.utils import escape_markdown
from bot.bot import Bot
from bot.constants import Categories, Channels, Colours, Emojis, Event, Guild as GuildConstant, Icons, Roles, URLs
+from bot.log import get_logger
from bot.utils.messages import format_user
from bot.utils.time import humanize_delta
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
GUILD_CHANNEL = t.Union[discord.CategoryChannel, discord.TextChannel, discord.VoiceChannel]
diff --git a/bot/exts/moderation/modpings.py b/bot/exts/moderation/modpings.py
index d775cdedf..a7ccb8162 100644
--- a/bot/exts/moderation/modpings.py
+++ b/bot/exts/moderation/modpings.py
@@ -1,5 +1,4 @@
import datetime
-import logging
from async_rediscache import RedisCache
from dateutil.parser import isoparse
@@ -9,10 +8,11 @@ from discord.ext.commands import Cog, Context, group, has_any_role
from bot.bot import Bot
from bot.constants import Colours, Emojis, Guild, Icons, MODERATION_ROLES, Roles
from bot.converters import Expiry
+from bot.log import get_logger
from bot.utils import scheduling
from bot.utils.scheduling import Scheduler
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class ModPings(Cog):
diff --git a/bot/exts/moderation/silence.py b/bot/exts/moderation/silence.py
index 2ee6496df..133ebaba5 100644
--- a/bot/exts/moderation/silence.py
+++ b/bot/exts/moderation/silence.py
@@ -1,5 +1,4 @@
import json
-import logging
import typing
from contextlib import suppress
from datetime import datetime, timedelta, timezone
@@ -13,11 +12,12 @@ from discord.ext.commands import Context
from bot import constants
from bot.bot import Bot
from bot.converters import HushDurationConverter
+from bot.log import get_logger
from bot.utils import scheduling
from bot.utils.lock import LockedResourceError, lock, lock_arg
from bot.utils.scheduling import Scheduler
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
LOCK_NAMESPACE = "silence"
diff --git a/bot/exts/moderation/slowmode.py b/bot/exts/moderation/slowmode.py
index d8baff76a..9583597e0 100644
--- a/bot/exts/moderation/slowmode.py
+++ b/bot/exts/moderation/slowmode.py
@@ -1,4 +1,3 @@
-import logging
from typing import Optional
from dateutil.relativedelta import relativedelta
@@ -8,9 +7,10 @@ from discord.ext.commands import Cog, Context, group, has_any_role
from bot.bot import Bot
from bot.constants import Channels, Emojis, MODERATION_ROLES
from bot.converters import DurationDelta
+from bot.log import get_logger
from bot.utils import time
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
SLOWMODE_MAX_DELAY = 21600 # seconds
diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py
index 735cd21da..99bbd8721 100644
--- a/bot/exts/moderation/stream.py
+++ b/bot/exts/moderation/stream.py
@@ -1,4 +1,3 @@
-import logging
from datetime import timedelta, timezone
from operator import itemgetter
@@ -13,12 +12,13 @@ from bot.constants import (
Colours, Emojis, Guild, MODERATION_ROLES, Roles, STAFF_PARTNERS_COMMUNITY_ROLES, VideoPermission
)
from bot.converters import Expiry
+from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils import scheduling
from bot.utils.members import get_or_fetch_member
from bot.utils.time import discord_timestamp, format_infraction_with_duration
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class Stream(commands.Cog):
diff --git a/bot/exts/moderation/verification.py b/bot/exts/moderation/verification.py
index bfe9b74b4..ed5571d2a 100644
--- a/bot/exts/moderation/verification.py
+++ b/bot/exts/moderation/verification.py
@@ -1,4 +1,3 @@
-import logging
import typing as t
import discord
@@ -7,9 +6,10 @@ from discord.ext.commands import Cog, Context, command, has_any_role
from bot import constants
from bot.bot import Bot
from bot.decorators import in_whitelist
+from bot.log import get_logger
from bot.utils.checks import InWhitelistCheckFailure
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
# Sent via DMs once user joins the guild
ON_JOIN_MESSAGE = """
diff --git a/bot/exts/moderation/voice_gate.py b/bot/exts/moderation/voice_gate.py
index 2e8e8513a..88733176f 100644
--- a/bot/exts/moderation/voice_gate.py
+++ b/bot/exts/moderation/voice_gate.py
@@ -1,5 +1,4 @@
import asyncio
-import logging
from contextlib import suppress
from datetime import datetime, timedelta
@@ -13,9 +12,10 @@ from bot.bot import Bot
from bot.constants import Channels, Event, MODERATION_ROLES, Roles, VoiceGate as GateConf
from bot.decorators import has_no_roles, in_whitelist
from bot.exts.moderation.modlog import ModLog
+from bot.log import get_logger
from bot.utils.checks import InWhitelistCheckFailure
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
# Flag written to the cog's RedisCache as a value when the Member's (key) notification
# was already removed ~ this signals both that no further notifications should be sent,
diff --git a/bot/exts/moderation/watchchannels/_watchchannel.py b/bot/exts/moderation/watchchannels/_watchchannel.py
index 3fafd097b..8a64e83ff 100644
--- a/bot/exts/moderation/watchchannels/_watchchannel.py
+++ b/bot/exts/moderation/watchchannels/_watchchannel.py
@@ -1,5 +1,4 @@
import asyncio
-import logging
import re
import textwrap
from abc import abstractmethod
@@ -17,12 +16,13 @@ from bot.constants import BigBrother as BigBrotherConfig, Guild as GuildConfig,
from bot.exts.filters.token_remover import TokenRemover
from bot.exts.filters.webhook_remover import WEBHOOK_URL_RE
from bot.exts.moderation.modlog import ModLog
+from bot.log import CustomLogger, get_logger
from bot.pagination import LinePaginator
from bot.utils import CogABCMeta, messages, scheduling
from bot.utils.members import get_or_fetch_member
from bot.utils.time import get_time_delta
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
URL_RE = re.compile(r"(https?://[^\s]+)")
@@ -47,7 +47,7 @@ class WatchChannel(metaclass=CogABCMeta):
webhook_id: int,
api_endpoint: str,
api_default_params: dict,
- logger: logging.Logger,
+ logger: CustomLogger,
*,
disable_header: bool = False
) -> None:
diff --git a/bot/exts/moderation/watchchannels/bigbrother.py b/bot/exts/moderation/watchchannels/bigbrother.py
index 3aa253fea..ab37b1b80 100644
--- a/bot/exts/moderation/watchchannels/bigbrother.py
+++ b/bot/exts/moderation/watchchannels/bigbrother.py
@@ -1,4 +1,3 @@
-import logging
import textwrap
from collections import ChainMap
@@ -9,8 +8,9 @@ from bot.constants import Channels, MODERATION_ROLES, Webhooks
from bot.converters import MemberOrUser
from bot.exts.moderation.infraction._utils import post_infraction
from bot.exts.moderation.watchchannels._watchchannel import WatchChannel
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class BigBrother(WatchChannel, Cog, name="Big Brother"):
@@ -87,11 +87,11 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"):
return
if not await self.fetch_user_cache():
- await ctx.send(f":x: Updating the user cache failed, can't watch user {user}")
+ await ctx.send(f":x: Updating the user cache failed, can't watch user {user.mention}")
return
if user.id in self.watched_users:
- await ctx.send(f":x: {user} is already being watched.")
+ await ctx.send(f":x: {user.mention} is already being watched.")
return
# discord.User instances don't have a roles attribute
@@ -103,7 +103,7 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"):
if response is not None:
self.watched_users[user.id] = response
- msg = f":white_check_mark: Messages sent by {user} will now be relayed to Big Brother."
+ msg = f":white_check_mark: Messages sent by {user.mention} will now be relayed to Big Brother."
history = await self.bot.api_client.get(
self.api_endpoint,
@@ -156,7 +156,7 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"):
log.debug(f"Perma-banned user {user} was unwatched.")
return
log.trace("User is not banned. Sending message to channel")
- message = f":white_check_mark: Messages sent by {user} will no longer be relayed."
+ message = f":white_check_mark: Messages sent by {user.mention} will no longer be relayed."
else:
log.trace("No active watches found for user.")
diff --git a/bot/exts/recruitment/talentpool/_cog.py b/bot/exts/recruitment/talentpool/_cog.py
index f9c836bbd..2fafaec97 100644
--- a/bot/exts/recruitment/talentpool/_cog.py
+++ b/bot/exts/recruitment/talentpool/_cog.py
@@ -1,4 +1,3 @@
-import logging
import textwrap
from collections import ChainMap, defaultdict
from io import StringIO
@@ -14,6 +13,7 @@ from bot.bot import Bot
from bot.constants import Channels, Emojis, Guild, MODERATION_ROLES, Roles, STAFF_ROLES
from bot.converters import MemberOrUser, UnambiguousMemberOrUser
from bot.exts.recruitment.talentpool._review import Reviewer
+from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils import scheduling, time
from bot.utils.members import get_or_fetch_member
@@ -22,7 +22,7 @@ from bot.utils.time import get_time_delta
AUTOREVIEW_ENABLED_KEY = "autoreview_enabled"
REASON_MAX_CHARS = 1000
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class TalentPool(Cog, name="Talentpool"):
diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py
index 14a8dd4c0..dcf73c2cb 100644
--- a/bot/exts/recruitment/talentpool/_review.py
+++ b/bot/exts/recruitment/talentpool/_review.py
@@ -1,6 +1,5 @@
import asyncio
import contextlib
-import logging
import random
import re
import textwrap
@@ -16,6 +15,7 @@ from discord.ext.commands import Context
from bot.api import ResponseCodeError
from bot.bot import Bot
from bot.constants import Channels, Colours, Emojis, Guild
+from bot.log import get_logger
from bot.utils.members import get_or_fetch_member
from bot.utils.messages import count_unique_users_reaction, pin_no_system_message
from bot.utils.scheduling import Scheduler
@@ -24,7 +24,7 @@ from bot.utils.time import get_time_delta, time_since
if typing.TYPE_CHECKING:
from bot.exts.recruitment.talentpool._cog import TalentPool
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
# Maximum amount of days before an automatic review is posted.
MAX_DAYS_IN_POOL = 30
diff --git a/bot/exts/utils/bot.py b/bot/exts/utils/bot.py
index d84709616..8f0094bc9 100644
--- a/bot/exts/utils/bot.py
+++ b/bot/exts/utils/bot.py
@@ -1,4 +1,3 @@
-import logging
from typing import Optional
from discord import Embed, TextChannel
@@ -6,8 +5,9 @@ from discord.ext.commands import Cog, Context, command, group, has_any_role
from bot.bot import Bot
from bot.constants import Guild, MODERATION_ROLES, URLs
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class BotCog(Cog, name="Bot"):
diff --git a/bot/exts/utils/clean.py b/bot/exts/utils/clean.py
index 764ebca15..fa9b7e219 100644
--- a/bot/exts/utils/clean.py
+++ b/bot/exts/utils/clean.py
@@ -1,4 +1,3 @@
-import logging
import random
import re
from typing import Iterable, Optional
@@ -10,8 +9,9 @@ from discord.ext.commands import Cog, Context, group, has_any_role
from bot.bot import Bot
from bot.constants import Channels, CleanMessages, Colours, Event, Icons, MODERATION_ROLES, NEGATIVE_REPLIES
from bot.exts.moderation.modlog import ModLog
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class Clean(Cog):
diff --git a/bot/exts/utils/extensions.py b/bot/exts/utils/extensions.py
index 309126d0e..fa5d38917 100644
--- a/bot/exts/utils/extensions.py
+++ b/bot/exts/utils/extensions.py
@@ -1,5 +1,4 @@
import functools
-import logging
import typing as t
from enum import Enum
@@ -11,10 +10,11 @@ from bot import exts
from bot.bot import Bot
from bot.constants import Emojis, MODERATION_ROLES, Roles, URLs
from bot.converters import Extension
+from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils.extensions import EXTENSIONS
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
UNLOAD_BLACKLIST = {f"{exts.__name__}.utils.extensions", f"{exts.__name__}.moderation.modlog"}
diff --git a/bot/exts/utils/internal.py b/bot/exts/utils/internal.py
index 5d2cd7611..879735945 100644
--- a/bot/exts/utils/internal.py
+++ b/bot/exts/utils/internal.py
@@ -1,6 +1,5 @@
import contextlib
import inspect
-import logging
import pprint
import re
import textwrap
@@ -15,9 +14,10 @@ from discord.ext.commands import Cog, Context, group, has_any_role, is_owner
from bot.bot import Bot
from bot.constants import DEBUG_MODE, Roles
+from bot.log import get_logger
from bot.utils import find_nth_occurrence, send_to_paste_service
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class Internal(Cog):
diff --git a/bot/exts/utils/reminders.py b/bot/exts/utils/reminders.py
index bf4fdf96b..3cb9307a9 100644
--- a/bot/exts/utils/reminders.py
+++ b/bot/exts/utils/reminders.py
@@ -1,4 +1,3 @@
-import logging
import random
import textwrap
import typing as t
@@ -12,6 +11,7 @@ from discord.ext.commands import Cog, Context, Greedy, group
from bot.bot import Bot
from bot.constants import Guild, Icons, MODERATION_ROLES, POSITIVE_REPLIES, Roles, STAFF_PARTNERS_COMMUNITY_ROLES
from bot.converters import Duration, UnambiguousUser
+from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils import scheduling
from bot.utils.checks import has_any_role_check, has_no_roles_check
@@ -21,7 +21,7 @@ from bot.utils.messages import send_denial
from bot.utils.scheduling import Scheduler
from bot.utils.time import TimestampFormats, discord_timestamp
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
LOCK_NAMESPACE = "reminder"
WHITELISTED_CHANNELS = Guild.reminder_whitelist
@@ -115,7 +115,7 @@ class Reminders(Cog):
if await has_no_roles_check(ctx, *STAFF_PARTNERS_COMMUNITY_ROLES):
return False, "members/roles"
elif await has_no_roles_check(ctx, *MODERATION_ROLES):
- return all(isinstance(mention, discord.Member) for mention in mentions), "roles"
+ return all(isinstance(mention, (discord.User, discord.Member)) for mention in mentions), "roles"
else:
return True, ""
diff --git a/bot/exts/utils/snekbox.py b/bot/exts/utils/snekbox.py
index 5fb10a25b..fbfc58d0b 100644
--- a/bot/exts/utils/snekbox.py
+++ b/bot/exts/utils/snekbox.py
@@ -1,7 +1,6 @@
import asyncio
import contextlib
import datetime
-import logging
import re
import textwrap
from functools import partial
@@ -14,10 +13,11 @@ from discord.ext.commands import Cog, Context, command, guild_only
from bot.bot import Bot
from bot.constants import Categories, Channels, Roles, URLs
from bot.decorators import redirect_output
+from bot.log import get_logger
from bot.utils import scheduling, send_to_paste_service
from bot.utils.messages import wait_for_deletion
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
ESCAPE_REGEX = re.compile("[`\u202E\u200B]{3,}")
FORMATTED_CODE_REGEX = re.compile(
diff --git a/bot/exts/utils/utils.py b/bot/exts/utils/utils.py
index 0139a6ad3..f69bab781 100644
--- a/bot/exts/utils/utils.py
+++ b/bot/exts/utils/utils.py
@@ -1,5 +1,4 @@
import difflib
-import logging
import re
import unicodedata
from typing import Tuple, Union
@@ -12,11 +11,12 @@ from bot.bot import Bot
from bot.constants import Channels, MODERATION_ROLES, Roles, STAFF_PARTNERS_COMMUNITY_ROLES
from bot.converters import Snowflake
from bot.decorators import in_whitelist
+from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils import messages
from bot.utils.time import time_since
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
ZEN_OF_PYTHON = """\
Beautiful is better than ugly.
diff --git a/bot/log.py b/bot/log.py
index 4e20c005e..b3cecdcf2 100644
--- a/bot/log.py
+++ b/bot/log.py
@@ -3,6 +3,7 @@ import os
import sys
from logging import Logger, handlers
from pathlib import Path
+from typing import Optional, TYPE_CHECKING, cast
import coloredlogs
import sentry_sdk
@@ -14,11 +15,38 @@ from bot import constants
TRACE_LEVEL = 5
+if TYPE_CHECKING:
+ LoggerClass = Logger
+else:
+ LoggerClass = logging.getLoggerClass()
+
+
+class CustomLogger(LoggerClass):
+ """Custom implementation of the `Logger` class with an added `trace` method."""
+
+ def trace(self, msg: str, *args, **kwargs) -> None:
+ """
+ Log 'msg % args' with severity 'TRACE'.
+
+ To pass exception information, use the keyword argument exc_info with
+ a true value, e.g.
+
+ logger.trace("Houston, we have an %s", "interesting problem", exc_info=1)
+ """
+ if self.isEnabledFor(TRACE_LEVEL):
+ self.log(TRACE_LEVEL, msg, *args, **kwargs)
+
+
+def get_logger(name: Optional[str] = None) -> CustomLogger:
+ """Utility to make mypy recognise that logger is of type `CustomLogger`."""
+ return cast(CustomLogger, logging.getLogger(name))
+
+
def setup() -> None:
"""Set up loggers."""
logging.TRACE = TRACE_LEVEL
logging.addLevelName(TRACE_LEVEL, "TRACE")
- Logger.trace = _monkeypatch_trace
+ logging.setLoggerClass(CustomLogger)
format_string = "%(asctime)s | %(name)s | %(levelname)s | %(message)s"
log_format = logging.Formatter(format_string)
@@ -28,7 +56,7 @@ def setup() -> None:
file_handler = handlers.RotatingFileHandler(log_file, maxBytes=5242880, backupCount=7, encoding="utf8")
file_handler.setFormatter(log_format)
- root_log = logging.getLogger()
+ root_log = get_logger()
root_log.addHandler(file_handler)
if "COLOREDLOGS_LEVEL_STYLES" not in os.environ:
@@ -42,16 +70,16 @@ def setup() -> None:
if "COLOREDLOGS_LOG_FORMAT" not in os.environ:
coloredlogs.DEFAULT_LOG_FORMAT = format_string
- coloredlogs.install(level=logging.TRACE, logger=root_log, stream=sys.stdout)
+ coloredlogs.install(level=TRACE_LEVEL, logger=root_log, stream=sys.stdout)
root_log.setLevel(logging.DEBUG if constants.DEBUG_MODE else logging.INFO)
- logging.getLogger("discord").setLevel(logging.WARNING)
- logging.getLogger("websockets").setLevel(logging.WARNING)
- logging.getLogger("chardet").setLevel(logging.WARNING)
- logging.getLogger("async_rediscache").setLevel(logging.WARNING)
+ get_logger("discord").setLevel(logging.WARNING)
+ get_logger("websockets").setLevel(logging.WARNING)
+ get_logger("chardet").setLevel(logging.WARNING)
+ get_logger("async_rediscache").setLevel(logging.WARNING)
# Set back to the default of INFO even if asyncio's debug mode is enabled.
- logging.getLogger("asyncio").setLevel(logging.INFO)
+ get_logger("asyncio").setLevel(logging.INFO)
_set_trace_loggers()
@@ -73,19 +101,6 @@ def setup_sentry() -> None:
)
-def _monkeypatch_trace(self: logging.Logger, msg: str, *args, **kwargs) -> None:
- """
- Log 'msg % args' with severity 'TRACE'.
-
- To pass exception information, use the keyword argument exc_info with
- a true value, e.g.
-
- logger.trace("Houston, we have an %s", "interesting problem", exc_info=1)
- """
- if self.isEnabledFor(TRACE_LEVEL):
- self._log(TRACE_LEVEL, msg, args, **kwargs)
-
-
def _set_trace_loggers() -> None:
"""
Set loggers to the trace level according to the value from the BOT_TRACE_LOGGERS env var.
@@ -101,13 +116,13 @@ def _set_trace_loggers() -> None:
level_filter = constants.Bot.trace_loggers
if level_filter:
if level_filter.startswith("*"):
- logging.getLogger().setLevel(logging.TRACE)
+ get_logger().setLevel(TRACE_LEVEL)
elif level_filter.startswith("!"):
- logging.getLogger().setLevel(logging.TRACE)
+ get_logger().setLevel(TRACE_LEVEL)
for logger_name in level_filter.strip("!,").split(","):
- logging.getLogger(logger_name).setLevel(logging.DEBUG)
+ get_logger(logger_name).setLevel(logging.DEBUG)
else:
for logger_name in level_filter.strip(",").split(","):
- logging.getLogger(logger_name).setLevel(logging.TRACE)
+ get_logger(logger_name).setLevel(TRACE_LEVEL)
diff --git a/bot/monkey_patches.py b/bot/monkey_patches.py
index 4dbdb5eab..e56a19da2 100644
--- a/bot/monkey_patches.py
+++ b/bot/monkey_patches.py
@@ -1,10 +1,11 @@
-import logging
from datetime import datetime, timedelta
from discord import Forbidden, http
from discord.ext import commands
-log = logging.getLogger(__name__)
+from bot.log import get_logger
+
+log = get_logger(__name__)
class Command(commands.Command):
diff --git a/bot/pagination.py b/bot/pagination.py
index 26caa7db0..8f4353eb1 100644
--- a/bot/pagination.py
+++ b/bot/pagination.py
@@ -1,5 +1,4 @@
import asyncio
-import logging
import typing as t
from contextlib import suppress
from functools import partial
@@ -9,6 +8,7 @@ from discord.abc import User
from discord.ext.commands import Context, Paginator
from bot import constants
+from bot.log import get_logger
from bot.utils import messages
FIRST_EMOJI = "\u23EE" # [:track_previous:]
@@ -19,7 +19,7 @@ DELETE_EMOJI = constants.Emojis.trashcan # [:trashcan:]
PAGINATION_EMOJI = (FIRST_EMOJI, LEFT_EMOJI, RIGHT_EMOJI, LAST_EMOJI, DELETE_EMOJI)
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class EmptyPaginatorEmbedError(Exception):
diff --git a/bot/resources/tags/contribute.md b/bot/resources/tags/contribute.md
new file mode 100644
index 000000000..070975646
--- /dev/null
+++ b/bot/resources/tags/contribute.md
@@ -0,0 +1,12 @@
+**Contribute to Python Discord's Open Source Projects**
+Looking to contribute to Open Source Projects for the first time? Want to add a feature or fix a bug on the bots on this server? We have on-going projects that people can contribute to, even if you've never contributed to open source before!
+
+**Projects to Contribute to**
+• [Sir Lancebot](https://github.com/python-discord/sir-lancebot) - our fun, beginner-friendly bot
+• [Python](https://github.com/python-discord/bot) - our utility & moderation bot
+• [Site](https://github.com/python-discord/site) - resources, guides, and more
+
+**Where to start**
+1. Read our [contributing guidelines](https://pythondiscord.com/pages/guides/pydis-guides/contributing/)
+2. Chat with us in <#635950537262759947> if you're ready to jump in or have any questions
+3. Open an issue or ask to be assigned to an issue to work on
diff --git a/bot/utils/channel.py b/bot/utils/channel.py
index 6d2356679..b9e234857 100644
--- a/bot/utils/channel.py
+++ b/bot/utils/channel.py
@@ -1,12 +1,11 @@
-import logging
-
import discord
import bot
from bot import constants
from bot.constants import Categories
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
def is_help_channel(channel: discord.TextChannel) -> bool:
diff --git a/bot/utils/checks.py b/bot/utils/checks.py
index ff311010e..972a5ef38 100644
--- a/bot/utils/checks.py
+++ b/bot/utils/checks.py
@@ -1,5 +1,4 @@
import datetime
-import logging
from typing import Callable, Container, Iterable, Optional, Union
from discord.ext.commands import (
@@ -8,8 +7,9 @@ from discord.ext.commands import (
)
from bot import constants
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
class ContextCheckFailure(CheckFailure):
diff --git a/bot/utils/function.py b/bot/utils/function.py
index 9bc44e753..55115d7d3 100644
--- a/bot/utils/function.py
+++ b/bot/utils/function.py
@@ -2,11 +2,12 @@
import functools
import inspect
-import logging
import types
import typing as t
-log = logging.getLogger(__name__)
+from bot.log import get_logger
+
+log = get_logger(__name__)
Argument = t.Union[int, str]
BoundArgs = t.OrderedDict[str, t.Any]
diff --git a/bot/utils/lock.py b/bot/utils/lock.py
index ec6f92cd4..c039a4f25 100644
--- a/bot/utils/lock.py
+++ b/bot/utils/lock.py
@@ -1,6 +1,5 @@
import asyncio
import inspect
-import logging
import types
from collections import defaultdict
from functools import partial
@@ -8,10 +7,11 @@ from typing import Any, Awaitable, Callable, Hashable, Union
from weakref import WeakValueDictionary
from bot.errors import LockedResourceError
+from bot.log import get_logger
from bot.utils import function
from bot.utils.function import command_wraps
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
__lock_dicts = defaultdict(WeakValueDictionary)
_IdCallableReturn = Union[Hashable, Awaitable[Hashable]]
diff --git a/bot/utils/members.py b/bot/utils/members.py
index 302fe6d63..77ddf1696 100644
--- a/bot/utils/members.py
+++ b/bot/utils/members.py
@@ -1,9 +1,10 @@
-import logging
import typing as t
import discord
-log = logging.getLogger(__name__)
+from bot.log import get_logger
+
+log = get_logger(__name__)
async def get_or_fetch_member(guild: discord.Guild, member_id: int) -> t.Optional[discord.Member]:
diff --git a/bot/utils/messages.py b/bot/utils/messages.py
index abeb04021..053750cc3 100644
--- a/bot/utils/messages.py
+++ b/bot/utils/messages.py
@@ -1,5 +1,4 @@
import asyncio
-import logging
import random
import re
from functools import partial
@@ -11,9 +10,10 @@ from discord.ext.commands import Context
import bot
from bot.constants import Emojis, MODERATION_ROLES, NEGATIVE_REPLIES
+from bot.log import get_logger
from bot.utils import scheduling
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
def reaction_check(
diff --git a/bot/utils/scheduling.py b/bot/utils/scheduling.py
index bb83b5c0d..7b4c8e2de 100644
--- a/bot/utils/scheduling.py
+++ b/bot/utils/scheduling.py
@@ -1,11 +1,12 @@
import asyncio
import contextlib
import inspect
-import logging
import typing as t
from datetime import datetime
from functools import partial
+from bot.log import get_logger
+
class Scheduler:
"""
@@ -27,7 +28,7 @@ class Scheduler:
def __init__(self, name: str):
self.name = name
- self._log = logging.getLogger(f"{__name__}.{name}")
+ self._log = get_logger(f"{__name__}.{name}")
self._scheduled_tasks: t.Dict[t.Hashable, asyncio.Task] = {}
def __contains__(self, task_id: t.Hashable) -> bool:
@@ -187,5 +188,5 @@ def _log_task_exception(task: asyncio.Task, *, suppressed_exceptions: t.Tuple[t.
exception = task.exception()
# Log the exception if one exists.
if exception and not isinstance(exception, suppressed_exceptions):
- log = logging.getLogger(__name__)
+ log = get_logger(__name__)
log.error(f"Error in task {task.get_name()} {id(task)}!", exc_info=exception)
diff --git a/bot/utils/services.py b/bot/utils/services.py
index db9c93d0f..439c8d500 100644
--- a/bot/utils/services.py
+++ b/bot/utils/services.py
@@ -1,12 +1,12 @@
-import logging
from typing import Optional
from aiohttp import ClientConnectorError
import bot
from bot.constants import URLs
+from bot.log import get_logger
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
FAILED_REQUEST_ATTEMPTS = 3
diff --git a/bot/utils/webhooks.py b/bot/utils/webhooks.py
index 66f82ec66..9c916b63a 100644
--- a/bot/utils/webhooks.py
+++ b/bot/utils/webhooks.py
@@ -1,12 +1,12 @@
-import logging
from typing import Optional
import discord
from discord import Embed
+from bot.log import get_logger
from bot.utils.messages import sub_clyde
-log = logging.getLogger(__name__)
+log = get_logger(__name__)
async def send_webhook(
diff --git a/tests/__init__.py b/tests/__init__.py
index f5b83a261..c2b9d12dc 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,4 +1,6 @@
import logging
-log = logging.getLogger()
+from bot.log import get_logger
+
+log = get_logger()
log.setLevel(logging.CRITICAL)
diff --git a/tests/base.py b/tests/base.py
index d99b9ac31..ab9287e9a 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -6,6 +6,7 @@ from typing import Dict
import discord
from discord.ext import commands
+from bot.log import get_logger
from tests import helpers
@@ -42,7 +43,7 @@ class LoggingTestsMixin:
manager when we're testing under the assumption that no log records will be emitted.
"""
if not isinstance(logger, logging.Logger):
- logger = logging.getLogger(logger)
+ logger = get_logger(logger)
if level:
level = logging._nameToLevel.get(level, level)
diff --git a/tests/test_base.py b/tests/test_base.py
index 7dd5dfac4..365805a71 100644
--- a/tests/test_base.py
+++ b/tests/test_base.py
@@ -1,7 +1,7 @@
import logging
-import unittest
import unittest.mock
+from bot.log import get_logger
from tests.base import LoggingTestsMixin, _CaptureLogHandler
@@ -14,7 +14,7 @@ class LoggingTestCaseTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
- cls.log = logging.getLogger(__name__)
+ cls.log = get_logger(__name__)
def test_assert_not_logs_does_not_raise_with_no_logs(self):
"""Test if LoggingTestCase.assertNotLogs does not raise when no logs were emitted."""
@@ -55,15 +55,15 @@ class LoggingTestCaseTests(unittest.TestCase):
def test_logging_test_case_works_with_logger_instance(self):
"""Test if the LoggingTestCase captures logging for provided logger."""
- log = logging.getLogger("new_logger")
+ log = get_logger("new_logger")
with self.assertRaises(AssertionError):
with LoggingTestCase.assertNotLogs(self, logger=log):
log.info("Hello, this should raise an AssertionError")
def test_logging_test_case_respects_alternative_logger(self):
"""Test if LoggingTestCase only checks the provided logger."""
- log_one = logging.getLogger("log one")
- log_two = logging.getLogger("log two")
+ log_one = get_logger("log one")
+ log_two = get_logger("log two")
with LoggingTestCase.assertNotLogs(self, logger=log_one):
log_two.info("Hello, this should not raise an AssertionError")