Logs: add support for batching multiple log messages into 1

This commit is contained in:
Dragory 2019-02-16 11:47:15 +02:00
parent aec251aa34
commit 6cc6528599

View file

@ -11,7 +11,7 @@ import {
formatTemplateString, formatTemplateString,
noop, noop,
stripObjectToScalars, stripObjectToScalars,
useMediaUrls useMediaUrls,
} from "../utils"; } from "../utils";
import DefaultLogMessages from "../data/DefaultLogMessages.json"; import DefaultLogMessages from "../data/DefaultLogMessages.json";
import moment from "moment-timezone"; import moment from "moment-timezone";
@ -26,6 +26,8 @@ import { GuildCases } from "../data/GuildCases";
interface ILogChannel { interface ILogChannel {
include?: string[]; include?: string[];
exclude?: string[]; exclude?: string[];
batched?: boolean;
batch_time?: number;
} }
interface ILogChannelMap { interface ILogChannelMap {
@ -35,7 +37,7 @@ interface ILogChannelMap {
const unknownUser = { const unknownUser = {
id: 0, id: 0,
username: "Unknown", username: "Unknown",
discriminator: "0000" discriminator: "0000",
}; };
export class LogsPlugin extends Plugin { export class LogsPlugin extends Plugin {
@ -48,6 +50,8 @@ export class LogsPlugin extends Plugin {
protected logListener; protected logListener;
protected batches: Map<string, string[]>;
private onMessageDeleteFn; private onMessageDeleteFn;
private onMessageDeleteBulkFn; private onMessageDeleteBulkFn;
private onMessageUpdateFn; private onMessageUpdateFn;
@ -58,9 +62,9 @@ export class LogsPlugin extends Plugin {
channels: {}, channels: {},
format: { format: {
timestamp: "YYYY-MM-DD HH:mm:ss", timestamp: "YYYY-MM-DD HH:mm:ss",
...DefaultLogMessages ...DefaultLogMessages,
} },
} },
}; };
} }
@ -73,6 +77,8 @@ export class LogsPlugin extends Plugin {
this.logListener = ({ type, data }) => this.log(type, data); this.logListener = ({ type, data }) => this.log(type, data);
this.guildLogs.on("log", this.logListener); this.guildLogs.on("log", this.logListener);
this.batches = new Map();
this.onMessageDeleteFn = this.onMessageDelete.bind(this); this.onMessageDeleteFn = this.onMessageDelete.bind(this);
this.savedMessages.events.on("delete", this.onMessageDeleteFn); this.savedMessages.events.on("delete", this.onMessageDeleteFn);
@ -101,7 +107,24 @@ export class LogsPlugin extends Plugin {
if ((opts.include && opts.include.includes(typeStr)) || (opts.exclude && !opts.exclude.includes(typeStr))) { if ((opts.include && opts.include.includes(typeStr)) || (opts.exclude && !opts.exclude.includes(typeStr))) {
const message = this.getLogMessage(type, data); const message = this.getLogMessage(type, data);
if (message) await createChunkedMessage(channel, message).catch(noop); if (message) {
if (opts.batched) {
// If we're batching log messages, gather all log messages within the set batch_time into a single message
if (!this.batches.has(channel.id)) {
this.batches.set(channel.id, []);
setTimeout(async () => {
const batchedMessage = this.batches.get(channel.id).join("\n");
this.batches.delete(channel.id);
createChunkedMessage(channel, batchedMessage).catch(noop);
}, opts.batch_time || 2000);
}
this.batches.get(channel.id).push(message);
} else {
// If we're not batching log messages, just send them immediately
await createChunkedMessage(channel, message).catch(noop);
}
}
} }
} }
} }
@ -126,13 +149,13 @@ export class LogsPlugin extends Plugin {
const newThreshold = moment().valueOf() - 1000 * 60 * 60; const newThreshold = moment().valueOf() - 1000 * 60 * 60;
const accountAge = humanizeDuration(moment().valueOf() - member.createdAt, { const accountAge = humanizeDuration(moment().valueOf() - member.createdAt, {
largest: 2, largest: 2,
round: true round: true,
}); });
this.guildLogs.log(LogType.MEMBER_JOIN, { this.guildLogs.log(LogType.MEMBER_JOIN, {
member: stripObjectToScalars(member, ["user"]), member: stripObjectToScalars(member, ["user"]),
new: member.createdAt >= newThreshold ? " :new:" : "", new: member.createdAt >= newThreshold ? " :new:" : "",
account_age: accountAge account_age: accountAge,
}); });
const cases = (await this.cases.with("notes").getByUserId(member.id)).filter(c => !c.is_hidden); const cases = (await this.cases.with("notes").getByUserId(member.id)).filter(c => !c.is_hidden);
@ -157,7 +180,7 @@ export class LogsPlugin extends Plugin {
this.guildLogs.log(LogType.MEMBER_JOIN_WITH_PRIOR_RECORDS, { this.guildLogs.log(LogType.MEMBER_JOIN_WITH_PRIOR_RECORDS, {
member: stripObjectToScalars(member, ["user"]), member: stripObjectToScalars(member, ["user"]),
recentCaseSummary recentCaseSummary,
}); });
} }
} }
@ -165,7 +188,7 @@ export class LogsPlugin extends Plugin {
@d.event("guildMemberRemove") @d.event("guildMemberRemove")
onMemberLeave(_, member) { onMemberLeave(_, member) {
this.guildLogs.log(LogType.MEMBER_LEAVE, { this.guildLogs.log(LogType.MEMBER_LEAVE, {
member: stripObjectToScalars(member, ["user"]) member: stripObjectToScalars(member, ["user"]),
}); });
} }
@ -175,7 +198,7 @@ export class LogsPlugin extends Plugin {
const relevantAuditLogEntry = await findRelevantAuditLogEntry( const relevantAuditLogEntry = await findRelevantAuditLogEntry(
this.guild, this.guild,
ErisConstants.AuditLogActions.MEMBER_BAN_ADD, ErisConstants.AuditLogActions.MEMBER_BAN_ADD,
user.id user.id,
); );
const mod = relevantAuditLogEntry ? relevantAuditLogEntry.user : unknownUser; const mod = relevantAuditLogEntry ? relevantAuditLogEntry.user : unknownUser;
@ -183,9 +206,9 @@ export class LogsPlugin extends Plugin {
LogType.MEMBER_BAN, LogType.MEMBER_BAN,
{ {
user: stripObjectToScalars(user), user: stripObjectToScalars(user),
mod: stripObjectToScalars(mod) mod: stripObjectToScalars(mod),
}, },
user.id user.id,
); );
} }
@ -195,7 +218,7 @@ export class LogsPlugin extends Plugin {
const relevantAuditLogEntry = await findRelevantAuditLogEntry( const relevantAuditLogEntry = await findRelevantAuditLogEntry(
this.guild, this.guild,
ErisConstants.AuditLogActions.MEMBER_BAN_REMOVE, ErisConstants.AuditLogActions.MEMBER_BAN_REMOVE,
user.id user.id,
); );
const mod = relevantAuditLogEntry ? relevantAuditLogEntry.user : unknownUser; const mod = relevantAuditLogEntry ? relevantAuditLogEntry.user : unknownUser;
@ -203,9 +226,9 @@ export class LogsPlugin extends Plugin {
LogType.MEMBER_UNBAN, LogType.MEMBER_UNBAN,
{ {
mod: stripObjectToScalars(mod), mod: stripObjectToScalars(mod),
userId: user.id userId: user.id,
}, },
user.id user.id,
); );
} }
@ -218,7 +241,7 @@ export class LogsPlugin extends Plugin {
this.guildLogs.log(LogType.MEMBER_NICK_CHANGE, { this.guildLogs.log(LogType.MEMBER_NICK_CHANGE, {
member, member,
oldNick: oldMember.nick != null ? oldMember.nick : "<none>", oldNick: oldMember.nick != null ? oldMember.nick : "<none>",
newNick: member.nick != null ? member.nick : "<none>" newNick: member.nick != null ? member.nick : "<none>",
}); });
} }
@ -229,7 +252,7 @@ export class LogsPlugin extends Plugin {
const relevantAuditLogEntry = await findRelevantAuditLogEntry( const relevantAuditLogEntry = await findRelevantAuditLogEntry(
this.guild, this.guild,
ErisConstants.AuditLogActions.MEMBER_ROLE_UPDATE, ErisConstants.AuditLogActions.MEMBER_ROLE_UPDATE,
member.id member.id,
); );
const mod = relevantAuditLogEntry ? relevantAuditLogEntry.user : unknownUser; const mod = relevantAuditLogEntry ? relevantAuditLogEntry.user : unknownUser;
@ -239,9 +262,9 @@ export class LogsPlugin extends Plugin {
{ {
member, member,
role: this.guild.roles.get(addedRoles[0]), role: this.guild.roles.get(addedRoles[0]),
mod: stripObjectToScalars(mod) mod: stripObjectToScalars(mod),
}, },
member.id member.id,
); );
} else if (removedRoles.length) { } else if (removedRoles.length) {
this.guildLogs.log( this.guildLogs.log(
@ -249,9 +272,9 @@ export class LogsPlugin extends Plugin {
{ {
member, member,
role: this.guild.roles.get(removedRoles[0]), role: this.guild.roles.get(removedRoles[0]),
mod: stripObjectToScalars(mod) mod: stripObjectToScalars(mod),
}, },
member.id member.id,
); );
} }
} }
@ -266,7 +289,7 @@ export class LogsPlugin extends Plugin {
this.guildLogs.log(LogType.MEMBER_USERNAME_CHANGE, { this.guildLogs.log(LogType.MEMBER_USERNAME_CHANGE, {
member: stripObjectToScalars(member, ["user"]), member: stripObjectToScalars(member, ["user"]),
oldName: `${oldUser.username}#${oldUser.discriminator}`, oldName: `${oldUser.username}#${oldUser.discriminator}`,
newName: `${user.username}#${user.discriminator}` newName: `${user.username}#${user.discriminator}`,
}); });
} }
} }
@ -274,28 +297,28 @@ export class LogsPlugin extends Plugin {
@d.event("channelCreate") @d.event("channelCreate")
onChannelCreate(channel) { onChannelCreate(channel) {
this.guildLogs.log(LogType.CHANNEL_CREATE, { this.guildLogs.log(LogType.CHANNEL_CREATE, {
channel: stripObjectToScalars(channel) channel: stripObjectToScalars(channel),
}); });
} }
@d.event("channelDelete") @d.event("channelDelete")
onChannelDelete(channel) { onChannelDelete(channel) {
this.guildLogs.log(LogType.CHANNEL_DELETE, { this.guildLogs.log(LogType.CHANNEL_DELETE, {
channel: stripObjectToScalars(channel) channel: stripObjectToScalars(channel),
}); });
} }
@d.event("guildRoleCreate") @d.event("guildRoleCreate")
onRoleCreate(_, role) { onRoleCreate(_, role) {
this.guildLogs.log(LogType.ROLE_CREATE, { this.guildLogs.log(LogType.ROLE_CREATE, {
role: stripObjectToScalars(role) role: stripObjectToScalars(role),
}); });
} }
@d.event("guildRoleDelete") @d.event("guildRoleDelete")
onRoleDelete(_, role) { onRoleDelete(_, role) {
this.guildLogs.log(LogType.ROLE_DELETE, { this.guildLogs.log(LogType.ROLE_DELETE, {
role: stripObjectToScalars(role) role: stripObjectToScalars(role),
}); });
} }
@ -318,7 +341,7 @@ export class LogsPlugin extends Plugin {
member: stripObjectToScalars(member, ["user"]), member: stripObjectToScalars(member, ["user"]),
channel: stripObjectToScalars(channel), channel: stripObjectToScalars(channel),
before, before,
after after,
}); });
} }
@ -342,18 +365,18 @@ export class LogsPlugin extends Plugin {
channel: stripObjectToScalars(channel), channel: stripObjectToScalars(channel),
messageText: disableCodeBlocks(deactivateMentions(savedMessage.data.content || "<no text content>")), messageText: disableCodeBlocks(deactivateMentions(savedMessage.data.content || "<no text content>")),
messageDate: moment(savedMessage.data.timestamp, "x").format(this.configValue("format.timestamp")), messageDate: moment(savedMessage.data.timestamp, "x").format(this.configValue("format.timestamp")),
attachments: disableLinkPreviews(useMediaUrls(attachments)) attachments: disableLinkPreviews(useMediaUrls(attachments)),
}, },
savedMessage.id savedMessage.id,
); );
} else { } else {
this.guildLogs.log( this.guildLogs.log(
LogType.MESSAGE_DELETE_BARE, LogType.MESSAGE_DELETE_BARE,
{ {
messageId: savedMessage.id, messageId: savedMessage.id,
channel: stripObjectToScalars(channel) channel: stripObjectToScalars(channel),
}, },
savedMessage.id savedMessage.id,
); );
} }
} }
@ -369,9 +392,9 @@ export class LogsPlugin extends Plugin {
{ {
count: savedMessages.length, count: savedMessages.length,
channel, channel,
archiveUrl archiveUrl,
}, },
savedMessages[0].id savedMessages[0].id,
); );
} }
@ -379,7 +402,7 @@ export class LogsPlugin extends Plugin {
onVoiceChannelJoin(member: Member, channel: Channel) { onVoiceChannelJoin(member: Member, channel: Channel) {
this.guildLogs.log(LogType.VOICE_CHANNEL_JOIN, { this.guildLogs.log(LogType.VOICE_CHANNEL_JOIN, {
member: stripObjectToScalars(member, ["user"]), member: stripObjectToScalars(member, ["user"]),
channel: stripObjectToScalars(channel) channel: stripObjectToScalars(channel),
}); });
} }
@ -387,7 +410,7 @@ export class LogsPlugin extends Plugin {
onVoiceChannelLeave(member: Member, channel: Channel) { onVoiceChannelLeave(member: Member, channel: Channel) {
this.guildLogs.log(LogType.VOICE_CHANNEL_LEAVE, { this.guildLogs.log(LogType.VOICE_CHANNEL_LEAVE, {
member: stripObjectToScalars(member, ["user"]), member: stripObjectToScalars(member, ["user"]),
channel: stripObjectToScalars(channel) channel: stripObjectToScalars(channel),
}); });
} }
@ -396,7 +419,7 @@ export class LogsPlugin extends Plugin {
this.guildLogs.log(LogType.VOICE_CHANNEL_MOVE, { this.guildLogs.log(LogType.VOICE_CHANNEL_MOVE, {
member: stripObjectToScalars(member, ["user"]), member: stripObjectToScalars(member, ["user"]),
oldChannel: stripObjectToScalars(oldChannel), oldChannel: stripObjectToScalars(oldChannel),
newChannel: stripObjectToScalars(newChannel) newChannel: stripObjectToScalars(newChannel),
}); });
} }
} }