Skip to content

[Feature][Logging]#25

Merged
shamikkarkhanis merged 5 commits intomainfrom
feature/logging
Jan 13, 2026
Merged

[Feature][Logging]#25
shamikkarkhanis merged 5 commits intomainfrom
feature/logging

Conversation

@shamikkarkhanis
Copy link
Copy Markdown
Member

@shamikkarkhanis shamikkarkhanis commented Dec 20, 2025

Summary by Sourcery

Introduce a colorized stdout-based logging configuration and integrate structured logging into core Discord command cogs.

New Features:

  • Add a configurable, colorized logging setup that directs log output to stdout using a shared formatter.
  • Introduce a helper to retrieve loggers by name for use across the application.
  • Log invocations and results of the sync and ping commands, including user and guild context.

Enhancements:

  • Simplify command cogs by renaming SyncCog and PingCog to Sync and Ping and adjusting their setup registration.
  • Improve user-facing error responses for sync and ping commands while logging full exceptions server-side.
  • Disable Discord's default log handler when running the bot to avoid duplicate logging.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Dec 20, 2025

Reviewer's Guide

Refactors the logging system to use a colored stdout-based root logger, introduces a reusable logger accessor, and adds structured logging and error handling to the sync and ping cogs while simplifying cog construction and Discord client startup logging behavior.

Sequence diagram for /ping command handling with logging

sequenceDiagram
    actor User
    participant DiscordGateway
    participant BotInstance
    participant PingCog as Ping
    participant LoggingModule
    participant RootLogger
    participant StdoutHandler
    participant ColoredFormatter

    User->>DiscordGateway: /ping command
    DiscordGateway->>BotInstance: InteractionCreate(ping)
    BotInstance->>PingCog: ping(interaction)

    activate PingCog
    PingCog->>PingCog: calculate_latency()
    PingCog->>LoggingModule: get_logger(__name__)
    LoggingModule-->>PingCog: logging_Logger

    PingCog->>RootLogger: info("/ping invoked user: ...")
    RootLogger->>StdoutHandler: emit(LogRecord)
    StdoutHandler->>ColoredFormatter: format(LogRecord)
    ColoredFormatter-->>StdoutHandler: formatted_colored_string
    StdoutHandler-->>RootLogger: write_to_stdout()

    PingCog->>BotInstance: interaction.response.send_message(embed)
    BotInstance->>DiscordGateway: SendMessage(Ping embed)
    DiscordGateway-->>User: Show ping latency
    deactivate PingCog

    Note over PingCog,RootLogger: On exception
    User-->>DiscordGateway: /ping command
    DiscordGateway-->>BotInstance: InteractionCreate(ping)
    BotInstance-->>PingCog: ping(interaction)
    activate PingCog
    PingCog->>RootLogger: exception("/ping attempted user")
    RootLogger->>StdoutHandler: emit(LogRecord)
    StdoutHandler->>ColoredFormatter: format(LogRecord)
    ColoredFormatter-->>StdoutHandler: formatted_colored_string
    StdoutHandler-->>RootLogger: write_to_stdout()
    PingCog-->>BotInstance: interaction.response.send_message(generic_error)
    BotInstance-->>DiscordGateway: SendMessage(Generic error)
    DiscordGateway-->>User: Show generic failure message
    deactivate PingCog
Loading

Class diagram for updated logging and Discord cogs

classDiagram
    direction LR

    class logging_Formatter {
    }

    class ColoredFormatter {
        +level_colors dict
        +name_color str
        +reset str
        +__init__(fmt: str, datefmt: str)
        +format(record: logging_LogRecord) str
    }

    class Sync {
        -logger logging_Logger
        +__init__() None
        +_sync_commands() list
        +sync(ctx: commands_Context) None
        +sync_slash(interaction: discord_Interaction) None
    }

    class Ping {
        -logger logging_Logger
        +__init__() None
        +ping(interaction: discord_Interaction) None
    }

    class LoggingModule {
        +LOG_FORMAT str
        +DATE_FORMAT str
        +get_logger(name: str) logging_Logger
        +setup_logging(level: int) None
    }

    ColoredFormatter --|> logging_Formatter
    Sync ..> LoggingModule : uses_get_logger
    Ping ..> LoggingModule : uses_get_logger
    LoggingModule ..> ColoredFormatter : uses_in_setup_logging
Loading

File-Level Changes

Change Details Files
Replace file-based rotating logging with a colored stdout logger and reusable logger accessor.
  • Define shared LOG_FORMAT and DATE_FORMAT constants for log messages
  • Introduce ColoredFormatter to colorize log level and logger name using ANSI escape codes
  • Change setup_logging to configure the root logger with a StreamHandler to sys.stdout using ColoredFormatter
  • Clear existing root logger handlers before adding the new handler to avoid duplicate Discord logs
  • Add get_logger helper to retrieve named loggers
capy_discord/logging.py
Add structured logging and friendlier error responses in the Sync cog, and simplify its construction.
  • Rename SyncCog to Sync and update setup to construct it without a bot parameter
  • Add init that initializes a per-cog logger via get_logger
  • Log successful sync operations and command invocations for both prefix and slash sync commands, including user and guild identifiers
  • Replace raw exception messages to users with generic failure messages while logging full stack traces via logger.exception
capy_discord/exts/tools/sync.py
Add logging and error handling to the Ping cog and simplify its construction.
  • Rename PingCog to Ping and update setup to construct it without a bot parameter
  • Add init that initializes a per-cog logger via get_logger
  • Enhance ping command to compute latency, log invocations with user and guild identifiers, and wrap logic in a try/except that logs exceptions and returns a generic failure message to users
capy_discord/exts/tools/ping.py
Adjust bot startup to rely on the new logging configuration instead of Discord’s default log handler.
  • Call setup_logging before Bot instantiation remains unchanged but now configures the new stdout logger
  • Disable Discord.py’s default log handler by passing log_handler=None to instance.run
capy_discord/__main__.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues, and left some high level feedback:

  • In setup_logging, the logs directory is still created but no file handler writes to it anymore, so either reintroduce a file/rotating handler or remove the directory creation to avoid dead code.
  • For the new logging calls, prefer logger argument interpolation (e.g. self.logger.info("/ping invoked user: %s guild: %s", interaction.user.id, interaction.guild_id)) instead of f-strings so that formatting cost is only incurred when the message is actually emitted.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `setup_logging`, the `logs` directory is still created but no file handler writes to it anymore, so either reintroduce a file/rotating handler or remove the directory creation to avoid dead code.
- For the new logging calls, prefer logger argument interpolation (e.g. `self.logger.info("/ping invoked user: %s guild: %s", interaction.user.id, interaction.guild_id)`) instead of f-strings so that formatting cost is only incurred when the message is actually emitted.

## Individual Comments

### Comment 1
<location> `capy_discord/logging.py:64-66` </location>
<code_context>
+    formatter = ColoredFormatter(LOG_FORMAT, datefmt=DATE_FORMAT)
+    handler.setFormatter(formatter)
+
+    # Create a log directory if it doesn't exist
     log_dir = Path("logs")
     log_dir.mkdir(exist_ok=True)

-    # Root logger
</code_context>

<issue_to_address>
**suggestion:** The `logs` directory is created but never used now that file logging has been removed.

Consider either removing this block or adding a file handler that writes to `log_dir` so the directory creation isn’t dead code and doesn’t confuse future readers.
</issue_to_address>

### Comment 2
<location> `capy_discord/logging.py:68` </location>
<code_context>
-    )
-    file_handler.setFormatter(logging.Formatter(log_format))
-    logger.addHandler(file_handler)
+    # Removing previous handlers to avoid duplicate logs from discord after setup_logging invokation
+    if root_logger.hasHandlers():
+        root_logger.handlers.clear()
</code_context>

<issue_to_address>
**nitpick (typo):** Fix minor typo in the comment describing handler removal.

Please change "invokation" to "invocation" to keep the comment professional and clear.

```suggestion
    # Removing previous handlers to avoid duplicate logs from discord after setup_logging invocation
```
</issue_to_address>

### Comment 3
<location> `capy_discord/exts/tools/ping.py:27-29` </location>
<code_context>
+
+            await interaction.response.send_message(embed=embed)
+
+        except Exception:
+            self.logger.exception("/ping attempted user")
+            await interaction.response.send_message("We're sorry, this interaction failed. Please contact an admin.")


</code_context>

<issue_to_address>
**suggestion:** Align the error log message with the successful path by adding more context.

Right now the success path for `/ping` logs the invoking user and guild, but the exception path logs only a static string. Please include `interaction.user.id` and `interaction.guild_id` in the exception message (while still using `logger.exception` for the traceback) so failures can be tied to specific servers and users.

```suggestion
        except Exception:
            self.logger.exception(
                f"/ping failed user: {interaction.user.id} guild: {interaction.guild_id}"
            )
            await interaction.response.send_message(
                "We're sorry, this interaction failed. Please contact an admin."
            )
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread capy_discord/logging.py
Comment thread capy_discord/logging.py Outdated
@shamikkarkhanis shamikkarkhanis merged commit d3fc831 into main Jan 13, 2026
4 checks passed
@shamikkarkhanis shamikkarkhanis deleted the feature/logging branch January 13, 2026 04:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant