{"version":3,"file":"logging.mjs","names":["createLogger"],"sources":["../../src/modules/logging.ts"],"sourcesContent":["import type {\n  APIRequest,\n  InvalidRequestWarningData,\n  RateLimitData,\n  REST,\n  ResponseLike,\n} from 'discord.js'\nimport env from 'env-var'\nimport { pino as createLogger, type Logger, type LoggerOptions } from 'pino'\nimport { formatUser, type SleetClient, SleetModule } from 'sleetcord'\n\nimport { interactionToString } from '../utils/stringify.ts'\n\nconst NODE_ENV: string = env.get('NODE_ENV').required().asString()\nconst USE_PINO_PRETTY: boolean = env.get('USE_PINO_PRETTY').required().asBool()\nconst LOG_LEVEL_ENV: string | undefined = env.get('LOG_LEVEL').asString()\n\nexport const LOG_LEVEL = LOG_LEVEL_ENV ?? (NODE_ENV === 'development' ? 'debug' : 'info')\n\nconst loggerOptions: LoggerOptions = {\n  level: LOG_LEVEL,\n}\n\nif (USE_PINO_PRETTY) {\n  loggerOptions.transport = {\n    target: 'pino-dev',\n  }\n}\n\nexport const baseLogger: Logger = createLogger(loggerOptions)\nexport const eventLogger: Logger = baseLogger.child({ module: 'event' })\nexport const djsLogger: Logger = baseLogger.child({ module: 'discord.js' })\nconst djsName = { name: 'discord.js' }\n\nexport const logging: SleetModule = new SleetModule(\n  {\n    name: 'logging',\n  },\n  {\n    clientReady(client) {\n      const { application, shard, readyAt } = client\n      eventLogger.info(`Ready at    : ${readyAt.toISOString()}`)\n      eventLogger.info(`Logged in   : ${formatUser(client.user, { markdown: false })}`)\n      eventLogger.info(`Guild Approx: ${application.approximateGuildCount}`)\n\n      if (shard) {\n        eventLogger.info(`Shard Count : ${shard.count}`)\n      }\n\n      djsLogger.info({ djsName, type: 'client-ready' }, 'Client is ready!')\n    },\n    load() {\n      this.client.rest.on('invalidRequestWarning', (...args) =>\n        onInvalidRequestWarning(this.sleet, ...args),\n      )\n      this.client.rest.on('rateLimited', (...args) => onRateLimited(this.sleet, ...args))\n      this.client.rest.on('response', (...args) =>\n        onResponse(this.sleet, this.client.rest, ...args),\n      )\n    },\n    unload() {\n      this.client.rest.off('invalidRequestWarning', (...args) =>\n        onInvalidRequestWarning(this.sleet, ...args),\n      )\n      this.client.rest.off('rateLimited', (...args) => onRateLimited(this.sleet, ...args))\n      this.client.rest.off('response', (...args) =>\n        onResponse(this.sleet, this.client.rest, ...args),\n      )\n    },\n    error(error) {\n      djsLogger.error({ ...moduleName(this.sleet), error, type: 'djs-error' })\n    },\n    warn(warning) {\n      djsLogger.warn({ ...moduleName(this.sleet), type: 'djs-warn' }, warning)\n    },\n    debug(debug) {\n      djsLogger.trace({ ...moduleName(this.sleet), type: 'djs-debug' }, debug)\n    },\n    shardReady(shardId, unavailableGuilds) {\n      const unavailable = unavailableGuilds\n        ? ` with ${unavailableGuilds.size} unavailable guilds`\n        : ''\n      djsLogger.info(\n        { ...djsName, type: 'shard-ready', shardId, unavailableGuilds },\n        `Shard ${shardId} ready${unavailable}`,\n      )\n    },\n    shardDisconnect(closeEvent, shardId) {\n      djsLogger.warn(\n        { ...djsName, type: 'shard-disconnect', shardId, code: closeEvent.code },\n        `Shard ${shardId} disconnected with code ${closeEvent.code}`,\n      )\n    },\n    shardReconnecting(shardId) {\n      djsLogger.info(\n        { ...djsName, type: 'shard-reconnecting', shardId },\n        `Shard ${shardId} reconnecting`,\n      )\n    },\n    shardResume(shardId, replayedEvents) {\n      djsLogger.info(\n        { ...djsName, type: 'shard-resume', shardId, replayedEvents },\n        `Shard ${shardId} resumed with ${replayedEvents} events`,\n      )\n    },\n    shardError(error, shardId) {\n      djsLogger.error(\n        {\n          ...djsName,\n          error: {\n            name: error.name,\n            message: error.message,\n            stack: error.stack,\n          },\n          type: 'shard-error',\n        },\n        `Shard ${shardId} errored: ${error.message}`,\n      )\n    },\n    guildCreate(guild) {\n      const info = [\n        `name: ${guild.name}`,\n        `id: ${guild.id}`,\n        `owner: ${guild.ownerId}`,\n        `members: ${guild.memberCount}`,\n      ].join(', ')\n\n      djsLogger.info(\n        { ...moduleName(this.sleet), type: 'guild-create', guildId: guild.id },\n        `Guild create (${info})`,\n      )\n    },\n    guildDelete(guild) {\n      const info = [\n        `name: ${guild.name}`,\n        `id: ${guild.id}`,\n        `owner: ${guild.ownerId}`,\n        `members: ${guild.memberCount}`,\n      ].join(', ')\n\n      djsLogger.info(\n        { ...moduleName(this.sleet), type: 'guild-delete', guildId: guild.id },\n        `Guild delete (${info})`,\n      )\n    },\n\n    sleetError(message, error) {\n      eventLogger.error(\n        { ...moduleName(this.sleet), type: 'sleet-error', error, message },\n        error instanceof Error ? error.message : String(error),\n      )\n    },\n    sleetWarn(warning, data) {\n      eventLogger.warn({ ...moduleName(this.sleet), type: 'sleet-warn', data, warning }, warning)\n    },\n    sleetDebug(debug, data) {\n      eventLogger.debug({ ...moduleName(this.sleet), type: 'sleet-debug', data, debug }, debug)\n    },\n    applicationInteractionError(module, interaction, error) {\n      eventLogger.error(\n        {\n          name: module.name,\n          commandName: interaction.commandName,\n          type: 'interaction-error',\n          error,\n        },\n        error instanceof Error ? error.message : String(error),\n      )\n    },\n    autocompleteInteractionError(module, interaction, error) {\n      eventLogger.error(\n        {\n          name: module.name,\n          commandName: interaction.commandName,\n          type: 'autocomplete-error',\n          error,\n        },\n        error instanceof Error ? error.message : String(error),\n      )\n    },\n    // interactionCreate(interaction) {\n    //   const str = interactionToString(interaction)\n    //   logger.debug(\n    //     {\n    //       userId: interaction.user.id,\n    //       interactionId: interaction.id,\n    //     },\n    //     `[INTR] ${str}`,\n    //   )\n    // },\n    runModule(module, interaction) {\n      eventLogger.debug(\n        {\n          name: module.name,\n          type: 'run-module',\n          userId: interaction.user.id,\n          interactionId: interaction.id,\n        },\n        interactionToString(interaction),\n      )\n    },\n    loadModule(module, qualifiedName) {\n      eventLogger.info(\n        {\n          name: module.name,\n          type: 'load-module',\n          qualifiedName: qualifiedName,\n        },\n        'Loaded module',\n      )\n    },\n    unloadModule(module, qualifiedName) {\n      eventLogger.info(\n        {\n          name: module.name,\n          type: 'unload-module',\n          qualifiedName: qualifiedName,\n        },\n        'Unloaded module',\n      )\n    },\n  },\n)\n\n/**\n * Regexes to censor tokens from paths\n *\n * Regexes should have 3 capture groups:\n *   1. The path before the token\n *   2. The token itself\n *   3. The path after the token\n */\nconst CENSOR_REGEXES: RegExp[] = [\n  /^((?:https:\\/\\/discord(?:app)?\\.com\\/api\\/v\\d{2})?\\/interactions\\/\\d{17,19}\\/)(.*)(\\/callback.*)/,\n  /^((?:https:\\/\\/discord(?:app)?\\.com\\/api\\/v\\d{2})?\\/webhooks\\/\\d{17,19}\\/)(.*)(\\/messages.*|$)/,\n]\n\n/**\n * Attempts to \"censor\" a path by replacing tokens with :token\n *\n * Though technically not required (at least for interactions, since those tokens\n * expire after a couple seconds/15 mins), it makes logs a lot easier to read and parse\n * @param path The path to censor\n * @returns The censored path\n */\nexport function censorPath(path: string): string {\n  let newPath = path\n\n  for (const regex of CENSOR_REGEXES) {\n    newPath = newPath.replace(regex, '$1:token$3')\n  }\n\n  return newPath\n}\n\n/**\n * Get the name of the currently-running module from the running module store, if available\n *\n * Returned as an object so it can be spread into context objects\n * @returns The name of the currently running module, or undefined if there is none\n */\nfunction moduleName(sleet: SleetClient): { name: string } | undefined {\n  const module = sleet.runningModuleStore.getStore()\n  if (module) {\n    return { name: module.name }\n  }\n  return undefined\n}\n\nfunction onInvalidRequestWarning(\n  sleet: SleetClient,\n  invalidRequestInfo: InvalidRequestWarningData,\n) {\n  djsLogger.warn(\n    { ...moduleName(sleet), type: 'invalid-request', invalidRequest: invalidRequestInfo },\n    'Invalid Request Warning: %o',\n    invalidRequestInfo,\n  )\n}\n\nfunction onRateLimited(sleet: SleetClient, rateLimitInfo: RateLimitData) {\n  djsLogger.warn(\n    { ...moduleName(sleet), type: 'ratelimit', ratelimit: rateLimitInfo },\n    'Ratelimited: %o',\n    rateLimitInfo,\n  )\n}\n\nfunction onResponse(sleet: SleetClient, rest: REST, req: APIRequest, res: ResponseLike) {\n  const path = `${req.method} ${censorPath(req.path)} ${res.status} ${res.statusText}`\n\n  if (res.status === undefined) {\n    djsLogger.debug(\n      {\n        ...moduleName(sleet),\n        type: 'rest',\n        path,\n        globalRemaining: rest.globalRemaining,\n      },\n      `${path} [🌎 ${rest.globalRemaining}]`,\n    )\n    return\n  }\n\n  const ratelimit = {\n    limit: res.headers.get('x-ratelimit-limit'),\n    remaining: res.headers.get('x-ratelimit-remaining'),\n    resetAfter: res.headers.get('x-ratelimit-reset-after'),\n    retryAfter: res.headers.get('retry-after'),\n    bucket: res.headers.get('x-ratelimit-bucket'),\n    global: res.headers.get('x-ratelimit-global'),\n    scope: res.headers.get('x-ratelimit-scope'),\n  }\n\n  const ratelimitLine = ratelimit.remaining\n    ? `[${ratelimit.remaining}/${ratelimit.limit} (${ratelimit.resetAfter}s) ${ratelimit.bucket}${\n        ratelimit.scope ? ` ${ratelimit.scope}` : ''\n      }${ratelimit.global ? '!' : ''}${\n        ratelimit.retryAfter ? ` retry in ${ratelimit.retryAfter}s` : ''\n      }] `\n    : ''\n  let body = ''\n\n  if (res.status >= 400) {\n    const bodyBuilder: string[] = []\n\n    if (req.method !== 'GET') {\n      bodyBuilder.push('\\nRequest:\\n')\n      bodyBuilder.push(JSON.stringify(req.data.body, null, 2))\n\n      if (!res.bodyUsed && res.body !== null) {\n        bodyBuilder.push('\\nResponse:\\n')\n\n        if (res instanceof Response && !res.body.locked) {\n          bodyBuilder.push(JSON.stringify(res.clone().body, null, 2))\n        } else {\n          bodyBuilder.push(JSON.stringify(res.body, null, 2))\n        }\n      }\n    }\n\n    body = bodyBuilder.join('')\n  }\n\n  djsLogger.debug(\n    {\n      ...moduleName(sleet),\n      type: 'rest',\n      path,\n      status: res.status,\n      method: req.method,\n      ratelimit,\n      globalRemaining: rest.globalRemaining,\n    },\n    `${path} ${ratelimitLine}[🌎 ${rest.globalRemaining}]${body}`,\n  )\n}\n"],"mappings":"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"}