diff options
author | Eric Bailey <git@esb.lol> | 2025-02-28 12:09:36 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-28 12:09:36 -0600 |
commit | 7c36ea115855050f319be19bb74d6f7fd80f8eed (patch) | |
tree | ed32d674b1b74dca813ad9cac44a621313431270 /src/logger/transports/sentry.ts | |
parent | 9e9ffd5c6e9e5c672f60aa10d60c6628a15ae783 (diff) | |
download | voidsky-7c36ea115855050f319be19bb74d6f7fd80f8eed.tar.zst |
Logger improvements (#7729)
* Remove enablement * Refactor context and filtering * Fix imports, simplify transports config * Migrate usages of debug context * Re-org, add colors and grouping to console logging * Remove temp default context * Remove manual prefix * Move colorizing out of console transport body * Reduce reuse * Pass through context * Ensure bitdrift is enabled in dev * Enable Sentry on web only * Clean up types * Docs * Format * Update tests * Clean up tests * No positional args * Revert Sentry changes * Clean up context, use it, pass metadata through to Bitdrift * Fix up debugging * Clean up metadata before passing to Bitdrift * Correct transports * Reserve context prop on metadata and include in transports * Update tests
Diffstat (limited to 'src/logger/transports/sentry.ts')
-rw-r--r-- | src/logger/transports/sentry.ts | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/logger/transports/sentry.ts b/src/logger/transports/sentry.ts new file mode 100644 index 000000000..890918d67 --- /dev/null +++ b/src/logger/transports/sentry.ts @@ -0,0 +1,102 @@ +import {isNetworkError} from '#/lib/strings/errors' +import {Sentry} from '#/logger/sentry/lib' +import {LogLevel, Transport} from '#/logger/types' +import {prepareMetadata} from '#/logger/util' + +export const sentryTransport: Transport = ( + level, + context, + message, + {type, tags, ...metadata}, + timestamp, +) => { + const meta = { + // match Bitdrift payload + context, + ...prepareMetadata(metadata), + } + let _tags = tags || {} + _tags = { + // use `category` to match breadcrumbs + category: context, + ...tags, + } + + /** + * If a string, report a breadcrumb + */ + if (typeof message === 'string') { + const severity = ( + { + [LogLevel.Debug]: 'debug', + [LogLevel.Info]: 'info', + [LogLevel.Log]: 'log', // Sentry value here is undefined + [LogLevel.Warn]: 'warning', + [LogLevel.Error]: 'error', + } as const + )[level] + + Sentry.addBreadcrumb({ + category: context, + message, + data: meta, + type: type || 'default', + level: severity, + timestamp: timestamp / 1000, // Sentry expects seconds + }) + + // We don't want to send any network errors to sentry + if (isNetworkError(message)) { + return + } + + /** + * Send all higher levels with `captureMessage`, with appropriate severity + * level + */ + if (level === 'error' || level === 'warn' || level === 'log') { + // Defer non-critical messages so they're sent in a batch + queueMessageForSentry(message, { + level: severity, + tags: _tags, + extra: meta, + }) + } + } else { + /** + * It's otherwise an Error and should be reported with captureException + */ + Sentry.captureException(message, { + tags: _tags, + extra: meta, + }) + } +} + +const queuedMessages: [string, Parameters<typeof Sentry.captureMessage>[1]][] = + [] +let sentrySendTimeout: ReturnType<typeof setTimeout> | null = null + +function queueMessageForSentry( + message: string, + captureContext: Parameters<typeof Sentry.captureMessage>[1], +) { + queuedMessages.push([message, captureContext]) + if (!sentrySendTimeout) { + // Throttle sending messages with a leading delay + // so that we can get Sentry out of the critical path. + sentrySendTimeout = setTimeout(() => { + sentrySendTimeout = null + sendQueuedMessages() + }, 7000) + } +} + +function sendQueuedMessages() { + while (queuedMessages.length > 0) { + const record = queuedMessages.shift() + if (record) { + Sentry.captureMessage(record[0], record[1]) + } + } +} |