Skip to content

tux.handlers.sentry

Classes:

Name Description
SentryHandler

Handles Sentry transaction tracking for commands and interactions.

Functions:

Name Description
setup

Add the SentryHandler cog to the bot.

Classes

SentryHandler(bot: Tux)

Bases: Cog

Handles Sentry transaction tracking for commands and interactions.

This cog listens for Discord events to create and complete Sentry transactions, providing performance monitoring and error context for both prefix commands and slash commands.

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

Start a Sentry transaction for a prefix command.

on_command_completion

Finish the Sentry transaction for a completed prefix command.

on_interaction

Start a Sentry transaction for application command interactions.

on_app_command_completion

Finish the Sentry transaction for a completed application command.

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()
_create_transaction(operation: str, name: str, description: str, tags: dict[str, Any]) -> Any | None

Create a Sentry transaction with the given parameters.

Parameters:

Name Type Description Default
operation str

The operation type (e.g., "discord.command")

required
name str

The name of the transaction

required
description str

A description of the transaction

required
tags dict[str, Any]

Tags to attach to the transaction

required

Returns:

Type Description
Optional[Any]

The created transaction or None if Sentry is not initialized

Source code in tux/handlers/sentry.py
Python
def _create_transaction(
    self,
    operation: str,
    name: str,
    description: str,
    tags: dict[str, Any],
) -> Any | None:
    """Create a Sentry transaction with the given parameters.

    Parameters
    ----------
    operation : str
        The operation type (e.g., "discord.command")
    name : str
        The name of the transaction
    description : str
        A description of the transaction
    tags : dict[str, Any]
        Tags to attach to the transaction

    Returns
    -------
    Optional[Any]
        The created transaction or None if Sentry is not initialized
    """
    if not self._is_sentry_available():
        return None

    try:
        transaction = sentry_sdk.start_transaction(op=operation, name=name, description=description)

        # Add all tags to the transaction
        for key, value in tags.items():
            transaction.set_tag(key, value)
    except Exception as e:
        logger.error(f"Error creating Sentry transaction: {e}")
        sentry_sdk.capture_exception(e)
        return None
    else:
        return transaction
_finish_transaction(object_id: int, status: str = STATUS['OK']) -> None

Finish a stored transaction with the given status.

Parameters:

Name Type Description Default
object_id int

The ID of the interaction or message

required
status str

The status to set on the transaction

STATUS['OK']
Source code in tux/handlers/sentry.py
Python
def _finish_transaction(self, object_id: int, status: str = STATUS["OK"]) -> None:
    """Finish a stored transaction with the given status.

    Parameters
    ----------
    object_id : int
        The ID of the interaction or message
    status : str
        The status to set on the transaction
    """
    if not self._is_sentry_available():
        return

    if transaction := self.bot.active_sentry_transactions.pop(object_id, None):
        transaction.set_status(status)
        transaction.finish()
        logger.trace(f"Finished Sentry transaction ({status}) for {transaction.name}")
on_command(ctx: commands.Context[Tux]) -> None async

Start a Sentry transaction for a prefix command.

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:
    """
    Start a Sentry transaction for a prefix command.

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

    if command_name := (ctx.command.qualified_name if ctx.command else "Unknown Command"):
        tags = {
            "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",
        }

        if transaction := self._create_transaction(
            operation="discord.command",
            name=command_name,
            description=ctx.message.content,
            tags=tags,
        ):
            self.bot.active_sentry_transactions[ctx.message.id] = transaction
            logger.trace(f"Started transaction for prefix command: {command_name}")
on_command_completion(ctx: commands.Context[Tux]) -> None async

Finish the Sentry transaction for a completed prefix command.

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_completion(self, ctx: commands.Context[Tux]) -> None:
    """
    Finish the Sentry transaction for a completed prefix command.

    Parameters
    ----------
    ctx : commands.Context[Tux]
        The command context
    """
    self._finish_transaction(ctx.message.id, self.STATUS["OK"])
on_interaction(interaction: discord.Interaction) -> None async

Start a Sentry transaction for application command interactions.

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:
    """
    Start a Sentry transaction for application command interactions.

    Parameters
    ----------
    interaction : discord.Interaction
        The interaction object
    """
    if not self._is_sentry_available() or interaction.type != discord.InteractionType.application_command:
        return

    if command_name := (interaction.command.qualified_name if interaction.command else "Unknown App Command"):
        tags = {
            "discord.command.name": command_name,
            "discord.guild.id": str(interaction.guild_id) if interaction.guild_id else "DM",
            "discord.channel.id": interaction.channel_id,
            "discord.user.id": interaction.user.id,
            "discord.interaction.id": interaction.id,
            "discord.interaction.type": interaction.type.name,
            "discord.command.type": "slash",
        }

        if transaction := self._create_transaction(
            operation="discord.app_command",
            name=command_name,
            description=f"/{command_name}",
            tags=tags,
        ):
            self.bot.active_sentry_transactions[interaction.id] = transaction
            logger.trace(f"Started transaction for app command: {command_name}")
on_app_command_completion(interaction: discord.Interaction, command: CommandObject) -> None async

Finish the Sentry transaction for a completed application command.

Parameters:

Name Type Description Default
interaction Interaction

The interaction object

required
command CommandObject

The command that was completed

required
Source code in tux/handlers/sentry.py
Python
@commands.Cog.listener()
async def on_app_command_completion(self, interaction: discord.Interaction, command: CommandObject) -> None:
    """
    Finish the Sentry transaction for a completed application command.

    Parameters
    ----------
    interaction : discord.Interaction
        The interaction object
    command : CommandObject
        The command that was completed
    """
    self._finish_transaction(interaction.id, self.STATUS["OK"])

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))