qualitybath/bunyan-slack

View on GitHub
src/index.ts

Summary

Maintainability
A
0 mins
Test Coverage
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<T extends { msg: string; level: ERecordLevel }>(
  record: T,
  levelName: keyof typeof ERecordLevel
) {
  return {
    text: util.format('[%s] %s', levelName.toUpperCase(), record.msg),
  };
}

export default class BunyanSlack<T extends { msg: string; level: ERecordLevel }> {
  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<BunyanSlack<T>, 'write' | 'customFormatter' | 'onError'> & {
      customFormatter?: BunyanSlack<T>['customFormatter'];
      onError?: BunyanSlack<T>['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);
    }
  }
}