Slack을 서버 오류 알림으로 사용해 보자

2022.10.09
6분
댓글

slack api


서버를 운영하다 보면, 예상치 못한 문제에 직면할 때가 많을 것이다.
서버가 죽는다던지, 특정 로직에서 오류가 발생하는 등 하루종일 서버를 관찰하지 않는 이상 즉각적인 대응은 힘들 것이다.

이런 Critical한 Issue를 대응하기 위해 Slack을 모니터링 알림으로 사용해 보고자 한다.

Slack web hook을 이용해야 해서 다음 글을 참고하면 도움이 될 듯 하다.


...

new Error("에러 발생!");

...

예시를 위해 일부러 Error를 throw 했는데, 직접 핸들링 하는 Error가 아니라 코드 에러, DB 에러, 비동기 에러 등 당장 처리할 수 없는 Error에 대해 모니터링 프로세스를 통해 빠른 대응으로 안정적인 서비스를 운영할 수 있어야 한다.


✍️ Error Handling


모니터링 프로세스를 놓던, 로깅을 하던 일단 에러에 대해 Handling 할 수 있어야 한다.

Framework단에서 지원하는 Filter가 있다면 상관없지만, 싱글 스레드로 동작하는 Node.js에겐 Error Handling이 잘 이루어져야 한다.

비동기 로직은 메인 스레드가 아닌 스레드로 돌아가기 때문에 적절한 처리가 안된다면 프로세스가 죽는다.



🤖 슬랙봇을 이용한 Error 모니터링


슬랙봇을 통해 모니터링을 하기 위해서, Error 발생 지점(trace), Error Message, Date time 등이 필요할 텐데, 여기에 마크다운을 이용한 디자인 매핑을 하게 되면, 보기 좋은 에러 알림이 될 것이다.


interface Field {
  title: string;
  value: any;
  short?: boolean;
}

interface Block {
  type: string;
  text: any;
}

class SlackTextBuilder {
  color: string;
  pretext: string;
  fields: Array<Field>;
  blocks: Array<Block>;

  constructor({ color, pretext }: Partial<{ color: string; pretext: string }>) {
    this.color = color || "#2eb886";
    this.pretext = pretext || "";
    this.fields = [];
    this.blocks = [];
  }

  addField(field: Field) {
    if (field.short === undefined) {
      field.short = true;
    }
    this.fields.push(field);
    return this;
  }

  addBlock(block: any) {
    this.blocks.push(block);
    return this;
  }

  toJSON() {
    return {
      as_user: false,
      attachments: [
        {
          color: this.color,
          pretext: this.pretext,
          fields: this.fields,
        },
      ],
      blocks: this.blocks,
    };
  }
}

여기에서 볼 수 있는데, 위 클래스의 toJSON 부분을 이해하는 것이 중요하다!


슬랙 포매팅을 위한 클래스를 제작해 주고, 여기에 필요한 데이터를 넣으면 될 듯하다.

대략 위 코드를 설명하자면 다음과 같다.

  • Field: 자잘한 정보들이 병렬적으로 들어갈 부분
  • Block: Layer 단위로 정보들이 수직적으로 들어갈 부분

슬랙 메세지 포맷에 대한 정보는 다음 사이트에서 찾아볼 수 있다.


const errorFormat = (message: string, stack: string) => {
  const builder = new SlackTextBuilder({});
  builder
    .addField({
      title: "APP_NAME",
      value: `\`Monitering test\``,
    })
    .addField({
      title: "TIME_STAMP",
      value: `\`${new Date().toString()}\``,
    })
    .addBlock({
      type: "header",
      text: {
        type: "plain_text",
        text: message,
        emoji: true,
      },
    })
    .addBlock({
      type: "section",
      text: {
        type: "mrkdwn",
        text: `\`\`\`${stack}\`\`\``,
      },
    });
  return builder.toJSON();
};

export const slackError = async (error: IError) => {
  const body = errorFormat(error);
  await axios.post(env.slackConfig.errorUri, body);
};

위와 같은 방식으로 Slack message formatter 클래스의 인스턴스를 생성한 뒤, JSON 형태로 Body에 담아 앞전에 생성한 Incoming Webhook url에 전송하면 해당 슬랙 채널에 메세지가 전송되게 된다.


monitoring

위와 같은 메세지 포맷을 사용하면 다음과 같이 슬랙에 메세지가 전송될 것이다.


이를 통해 Latency 측정, Error 모니터링 등 상황에 맞게 여러 방면으로 실시간 서버 모니터링이 가능하니, 활용만 잘 하면 될 듯 하다.


📚 참고 자료

Sending messages using Incoming Webhooks


Slack Webhook API 생성하기