import util from 'util'; import got from 'got'; import { MessageAttachment } from '@slack/types'; enum ERecordLevel { trace = 10, debug = 20, info = 30, warn = 40, error = 50, fatal = 60, } const noop = () => {}; function defaultFormatter( record: T, levelName: keyof typeof ERecordLevel ) { return { text: util.format('[%s] %s', levelName.toUpperCase(), record.msg), }; } export default class BunyanSlack { webhookUrl: string; channel?: string; username?: string; iconUrl?: string; iconEmoji?: string; customFormatter: ( record: T, levelName: keyof typeof ERecordLevel ) => { text: string } | { attachments: MessageAttachment[] }; onError: (err: unknown) => void; constructor( options: Omit, 'write' | 'customFormatter' | 'onError'> & { customFormatter?: BunyanSlack['customFormatter']; onError?: BunyanSlack['onError']; } ) { if (!options.webhookUrl) { throw new Error('Webhook url required'); } this.webhookUrl = options.webhookUrl; this.channel = options.channel; this.username = options.username; this.iconUrl = options.iconUrl; this.iconEmoji = options.iconEmoji; this.customFormatter = options.customFormatter || defaultFormatter; this.onError = options.onError || noop; } async write(record: Object) { try { const parsedRecord = typeof record === 'string' ? (JSON.parse(record) as T) : (record as T); const levelName = ERecordLevel[parsedRecord.level] as keyof typeof ERecordLevel; const message = this.customFormatter(parsedRecord, levelName); const body = { channel: this.channel, username: this.username, icon_url: this.iconUrl, icon_emoji: this.iconEmoji, ...message, }; await got.post(this.webhookUrl, { json: body }); } catch (err) { this.onError(err); } } }