rewrite: Analytic snapshots.
This commit is contained in:
@@ -1,6 +1,14 @@
|
||||
from meta import LionCog, LionBot, LionContext
|
||||
import logging
|
||||
|
||||
import discord
|
||||
from discord.ext.commands import Bot, Cog, HybridCommand, HybridCommandError
|
||||
from discord.ext.commands.errors import CommandInvokeError, CheckFailure
|
||||
from discord.app_commands.errors import CommandInvokeError as appCommandInvokeError
|
||||
|
||||
from meta import LionCog, LionBot, LionContext
|
||||
from meta.app import shard_talk, appname
|
||||
from meta.errors import HandledException, SafeCancellation
|
||||
from meta.logger import log_wrap
|
||||
from utils.lib import utc_now
|
||||
|
||||
from .data import AnalyticsData
|
||||
@@ -9,6 +17,9 @@ from .events import (
|
||||
GuildAction, GuildEvent, guild_event_handler,
|
||||
VoiceAction, VoiceEvent, voice_event_handler
|
||||
)
|
||||
from .snapshot import shard_snapshot
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# TODO: Client side might be better handled as a single connection fed by a queue?
|
||||
@@ -26,10 +37,35 @@ class Analytics(LionCog):
|
||||
self.talk_guild_event = guild_event_handler.bind(shard_talk).route
|
||||
self.talk_voice_event = voice_event_handler.bind(shard_talk).route
|
||||
|
||||
self.talk_shard_snapshot = shard_talk.register_route()(shard_snapshot)
|
||||
|
||||
async def cog_load(self):
|
||||
await self.data.init()
|
||||
|
||||
@LionCog.listener()
|
||||
@log_wrap(action='AnEvent')
|
||||
async def on_voice_state_update(self, member, before, after):
|
||||
if not before.channel and after.channel:
|
||||
# Member joined channel
|
||||
action = VoiceAction.JOINED
|
||||
elif before.channel and not after.channel:
|
||||
# Member left channel
|
||||
action = VoiceAction.LEFT
|
||||
|
||||
event = VoiceEvent(
|
||||
appname=appname,
|
||||
userid=member.id,
|
||||
guildid=member.guild.id,
|
||||
action=action,
|
||||
created_at=utc_now()
|
||||
)
|
||||
if self.an_app not in shard_talk.peers:
|
||||
logger.warning(f"Analytics peer not found, discarding event: {event}")
|
||||
else:
|
||||
await self.talk_voice_event(event).send(self.an_app, wait_for_reply=False)
|
||||
|
||||
@LionCog.listener()
|
||||
@log_wrap(action='AnEvent')
|
||||
async def on_guild_join(self, guild):
|
||||
"""
|
||||
Send guild join event.
|
||||
@@ -40,10 +76,14 @@ class Analytics(LionCog):
|
||||
action=GuildAction.JOINED,
|
||||
created_at=utc_now()
|
||||
)
|
||||
await self.talk_guild_event(event).send(self.an_app, wait_for_reply=False)
|
||||
if self.an_app not in shard_talk.peers:
|
||||
logger.warning(f"Analytics peer not found, discarding event: {event}")
|
||||
else:
|
||||
await self.talk_guild_event(event).send(self.an_app, wait_for_reply=False)
|
||||
|
||||
@LionCog.listener()
|
||||
async def on_guild_leave(self, guild):
|
||||
@log_wrap(action='AnEvent')
|
||||
async def on_guild_remove(self, guild):
|
||||
"""
|
||||
Send guild leave event
|
||||
"""
|
||||
@@ -53,13 +93,18 @@ class Analytics(LionCog):
|
||||
action=GuildAction.LEFT,
|
||||
created_at=utc_now()
|
||||
)
|
||||
await self.talk_guild_event(event).send(self.an_app, wait_for_reply=False)
|
||||
if self.an_app not in shard_talk.peers:
|
||||
logger.warning(f"Analytics peer not found, discarding event: {event}")
|
||||
else:
|
||||
await self.talk_guild_event(event).send(self.an_app, wait_for_reply=False)
|
||||
|
||||
@LionCog.listener()
|
||||
@log_wrap(action='AnEvent')
|
||||
async def on_command_completion(self, ctx: LionContext):
|
||||
"""
|
||||
Send command completed successfully.
|
||||
"""
|
||||
duration = utc_now() - ctx.message.created_at
|
||||
event = CommandEvent(
|
||||
appname=appname,
|
||||
cmdname=ctx.command.name if ctx.command else 'Unknown',
|
||||
@@ -67,16 +112,63 @@ class Analytics(LionCog):
|
||||
userid=ctx.author.id,
|
||||
created_at=utc_now(),
|
||||
status=CommandStatus.COMPLETED,
|
||||
execution_time=0,
|
||||
execution_time=duration.total_seconds(),
|
||||
guildid=ctx.guild.id if ctx.guild else None,
|
||||
ctxid=ctx.message.id
|
||||
)
|
||||
await self.talk_command_event(event).send(self.an_app, wait_for_reply=False)
|
||||
if self.an_app not in shard_talk.peers:
|
||||
logger.warning(f"Analytics peer not found, discarding event: {event}")
|
||||
else:
|
||||
await self.talk_command_event(event).send(self.an_app, wait_for_reply=False)
|
||||
|
||||
@LionCog.listener()
|
||||
@log_wrap(action='AnEvent')
|
||||
async def on_command_error(self, ctx: LionContext, error):
|
||||
"""
|
||||
Send command failed.
|
||||
"""
|
||||
# TODO: Add command error field?
|
||||
...
|
||||
duration = utc_now() - ctx.message.created_at
|
||||
status = CommandStatus.FAILED
|
||||
err_type = None
|
||||
try:
|
||||
err_type = repr(error)
|
||||
raise error
|
||||
except (HybridCommandError, CommandInvokeError, appCommandInvokeError):
|
||||
original = error.original
|
||||
try:
|
||||
err_type = repr(original)
|
||||
if isinstance(original, (HybridCommandError, CommandInvokeError, appCommandInvokeError)):
|
||||
raise original.original
|
||||
else:
|
||||
raise original
|
||||
except HandledException:
|
||||
status = CommandStatus.CANCELLED
|
||||
except SafeCancellation:
|
||||
status = CommandStatus.CANCELLED
|
||||
except discord.Forbidden:
|
||||
status = CommandStatus.CANCELLED
|
||||
except discord.HTTPException:
|
||||
status = CommandStatus.CANCELLED
|
||||
except Exception:
|
||||
status = CommandStatus.FAILED
|
||||
except CheckFailure:
|
||||
status = CommandStatus.CANCELLED
|
||||
except Exception:
|
||||
status = CommandStatus.FAILED
|
||||
|
||||
event = CommandEvent(
|
||||
appname=appname,
|
||||
cmdname=ctx.command.name if ctx.command else 'Unknown',
|
||||
cogname=ctx.cog.qualified_name if ctx.cog else None,
|
||||
userid=ctx.author.id,
|
||||
created_at=utc_now(),
|
||||
status=status,
|
||||
error=err_type,
|
||||
execution_time=duration.total_seconds(),
|
||||
guildid=ctx.guild.id if ctx.guild else None,
|
||||
ctxid=ctx.message.id
|
||||
)
|
||||
if self.an_app not in shard_talk.peers:
|
||||
logger.warning(f"Analytics peer not found, discarding event: {event}")
|
||||
else:
|
||||
await self.talk_command_event(event).send(self.an_app, wait_for_reply=False)
|
||||
|
||||
Reference in New Issue
Block a user