Skip to content

tux.handlers.sentry

Classes:

Name Description
SentryHandler

Handles Sentry error tracking and status management for commands and interactions.

Functions:

Name Description
setup

Add the SentryHandler cog to the bot.

Classes

SentryHandler(bot: Tux)

Bases: Cog

Handles Sentry error tracking and status management for commands and interactions.

This cog works with the automatic instrumentation from tracing.py to provide proper error handling and status management for both prefix commands and slash commands. It does not create transactions manually, as that is handled by the automatic instrumentation system.

Initialize the Sentry handler cog.

Parameters:

Name Type Description Default
bot Tux

The bot instance to attach the listeners to

required

Methods:

Name Description
on_command

Set context for a prefix command execution.

on_command_error

Handle errors for prefix commands.

on_interaction

Set context for application command interactions.

on_app_command_error

Handle errors for application commands.

Source code in tux/handlers/sentry.py
Python
def __init__(self, bot: Tux) -> None:
    """Initialize the Sentry handler cog.

    Parameters
    ----------
    bot : Tux
        The bot instance to attach the listeners to
    """
    self.bot = bot
    logger.info("Sentry handler initialized")

Functions

_is_sentry_available() -> bool

Check if Sentry is initialized and available for use.

Returns:

Type Description
bool

True if Sentry is initialized, False otherwise

Source code in tux/handlers/sentry.py
Python
def _is_sentry_available(self) -> bool:
    """Check if Sentry is initialized and available for use.

    Returns
    -------
    bool
        True if Sentry is initialized, False otherwise
    """
    return sentry_sdk.is_initialized()
_set_command_context(ctx: commands.Context[Tux] | discord.Interaction, command_name: str) -> None

Set command context on the current Sentry span.

Parameters:

Name Type Description Default
ctx Union[Context[Tux], Interaction]

The command context or interaction

required
command_name str

The name of the command being executed

required
Source code in tux/handlers/sentry.py
Python
def _set_command_context(self, ctx: commands.Context[Tux] | discord.Interaction, command_name: str) -> None:
    """Set command context on the current Sentry span.

    Parameters
    ----------
    ctx : Union[commands.Context[Tux], discord.Interaction]
        The command context or interaction
    command_name : str
        The name of the command being executed
    """
    if not self._is_sentry_available():
        return

    # Set command-specific tags
    if isinstance(ctx, commands.Context):
        set_span_attributes(
            {
                "discord.command.name": command_name,
                "discord.guild.id": str(ctx.guild.id) if ctx.guild else "DM",
                "discord.channel.id": ctx.channel.id,
                "discord.user.id": ctx.author.id,
                "discord.message.id": ctx.message.id,
                "discord.command.type": "prefix",
            },
        )
    else:  # discord.Interaction
        set_span_attributes(
            {
                "discord.command.name": command_name,
                "discord.guild.id": str(ctx.guild_id) if ctx.guild_id else "DM",
                "discord.channel.id": ctx.channel_id,
                "discord.user.id": ctx.user.id,
                "discord.interaction.id": ctx.id,
                "discord.interaction.type": ctx.type.name,
                "discord.command.type": "slash",
            },
        )
on_command(ctx: commands.Context[Tux]) -> None async

Set context for a prefix command execution.

This works with the automatic instrumentation to add command-specific context to the existing transaction.

Parameters:

Name Type Description Default
ctx Context[Tux]

The command context

required
Source code in tux/handlers/sentry.py
Python
@commands.Cog.listener()
async def on_command(self, ctx: commands.Context[Tux]) -> None:
    """
    Set context for a prefix command execution.

    This works with the automatic instrumentation to add command-specific
    context to the existing transaction.

    Parameters
    ----------
    ctx : commands.Context[Tux]
        The command context
    """
    if command_name := (ctx.command.qualified_name if ctx.command else "Unknown Command"):
        self._set_command_context(ctx, command_name)
        logger.trace(f"Set context for prefix command: {command_name}")
on_command_error(ctx: commands.Context[Tux], error: commands.CommandError) -> None async

Handle errors for prefix commands.

This captures command errors and sets the appropriate status on the current transaction.

Parameters:

Name Type Description Default
ctx Context[Tux]

The command context

required
error CommandError

The error that occurred

required
Source code in tux/handlers/sentry.py
Python
@commands.Cog.listener()
async def on_command_error(self, ctx: commands.Context[Tux], error: commands.CommandError) -> None:
    """
    Handle errors for prefix commands.

    This captures command errors and sets the appropriate status on the
    current transaction.

    Parameters
    ----------
    ctx : commands.Context[Tux]
        The command context
    error : commands.CommandError
        The error that occurred
    """
    if not self._is_sentry_available():
        return

    # Capture the error in the current span
    capture_span_exception(error, command_name=ctx.command.qualified_name if ctx.command else "Unknown")

    # Set appropriate status based on error type
    if isinstance(error, commands.CommandNotFound):
        set_span_status("NOT_FOUND")
    elif isinstance(error, commands.MissingPermissions):
        set_span_status("PERMISSION_DENIED")
    elif isinstance(error, commands.BadArgument):
        set_span_status("INVALID_ARGUMENT")
    else:
        set_span_status("ERROR")

    logger.debug(f"Captured error for prefix command: {error}")
on_interaction(interaction: discord.Interaction) -> None async

Set context for application command interactions.

This works with the automatic instrumentation to add command-specific context to the existing transaction.

Parameters:

Name Type Description Default
interaction Interaction

The interaction object

required
Source code in tux/handlers/sentry.py
Python
@commands.Cog.listener()
async def on_interaction(self, interaction: discord.Interaction) -> None:
    """
    Set context for application command interactions.

    This works with the automatic instrumentation to add command-specific
    context to the existing transaction.

    Parameters
    ----------
    interaction : discord.Interaction
        The interaction object
    """
    if interaction.type != discord.InteractionType.application_command:
        return

    if command_name := (interaction.command.qualified_name if interaction.command else "Unknown App Command"):
        self._set_command_context(interaction, command_name)
        logger.trace(f"Set context for app command: {command_name}")
on_app_command_error(interaction: discord.Interaction, error: discord.app_commands.AppCommandError) -> None async

Handle errors for application commands.

This captures command errors and sets the appropriate status on the current transaction.

Parameters:

Name Type Description Default
interaction Interaction

The interaction object

required
error AppCommandError

The error that occurred

required
Source code in tux/handlers/sentry.py
Python
@commands.Cog.listener()
async def on_app_command_error(
    self,
    interaction: discord.Interaction,
    error: discord.app_commands.AppCommandError,
) -> None:
    """
    Handle errors for application commands.

    This captures command errors and sets the appropriate status on the
    current transaction.

    Parameters
    ----------
    interaction : discord.Interaction
        The interaction object
    error : discord.app_commands.AppCommandError
        The error that occurred
    """
    if not self._is_sentry_available():
        return

    # Capture the error in the current span
    command_name = interaction.command.qualified_name if interaction.command else "Unknown"
    capture_span_exception(error, command_name=command_name)

    # Set appropriate status based on error type
    if isinstance(error, discord.app_commands.CommandNotFound):
        set_span_status("NOT_FOUND")
    elif isinstance(error, discord.app_commands.MissingPermissions):
        set_span_status("PERMISSION_DENIED")
    else:
        set_span_status("ERROR")

    logger.debug(f"Captured error for app command: {error}")

Functions

setup(bot: Tux) -> None async

Add the SentryHandler cog to the bot.

Source code in tux/handlers/sentry.py
Python
async def setup(bot: Tux) -> None:
    """Add the SentryHandler cog to the bot."""
    await bot.add_cog(SentryHandler(bot))