๐Ÿ”” Slack์ด ์‹œ๋„๋Ÿฝ๋‹คโ€ฆ ๊ทธ๋ž˜์„œ ๋‹ค์ด์–ดํŠธ ์‹œ์ผœ๋ดค๋‹ค

๋‚˜๋‚˜'s Brainยท2025๋…„ 9์›” 19์ผ

๊ฐœ๋…Study

๋ชฉ๋ก ๋ณด๊ธฐ
25/25
post-thumbnail

๐Ÿšฆ ์‹œ์ž‘: ๋‹จ์ˆœํ•จ์ด ๋ถ€๋ฅธ ํ•จ์ •

์ฒ˜์Œ์—๋Š” โ€œ๊ทธ๋ƒฅ ERROR ์ „๋ถ€ Slack์œผ๋กœ ์˜๋ฉด ๋˜๊ฒ ์ง€?โ€ ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.
Logback์—์„œ Slack Webhook๋งŒ ๋ถ™์ด๋ฉด ๋๋‚  ์ค„ ์•Œ์•˜๋‹ค.

ํ•˜์ง€๋งŒ ๋ง‰์ƒ ๊ตฌํ˜„ํ•ด๋ณด๋‹ˆ ํ•˜๋ฃจ์—๋„ ์ˆ˜์‹ญ, ์ˆ˜๋ฐฑ ๊ฑด์˜ ์•Œ๋ฆผ์ด ์šธ๋ ธ๊ณ , ์ง„์งœ ์ค‘์š”ํ•œ ์—๋Ÿฌ๋Š” ์žก์Œ ์†์— ๋ฌปํ˜€๋ฒ„๋ ธ๋‹ค. ์•Œ๋ฆผ์ด ๋งŽ๋‹ค๋Š” ๊ฑด ์•ˆ์‹ฌ์ด ์•„๋‹ˆ๋ผ, ์˜คํžˆ๋ ค ๋ถˆ์•ˆ์ด์—ˆ๋‹ค. โ€œํ˜น์‹œ ์ง„์งœ ์ค‘์š”ํ•œ ๊ฑธ ๋†“์น˜๊ณ  ์žˆ๋Š” ๊ฑด ์•„๋‹๊นŒ?โ€ ํ•˜๋Š” ์˜์‹ฌ์ด ๊ณ„์† ๋”ฐ๋ผ๋‹ค๋…”๋‹ค.

๊ทธ๋Ÿฌ๋˜ ์ค‘ Kafka์™€ Logstash๋ฅผ ๋ถ™์—ฌ๋ณธ ์ˆœ๊ฐ„, ์‹œ์•ผ๊ฐ€ ๋‹ฌ๋ผ์กŒ๋‹ค.
๐Ÿ‘‰ ๋‹จ์ˆœํžˆ ๋กœ๊ทธ๋ฅผ โ€œ๋ณด๋‚ด๋Š” ๊ฒƒโ€์ด ์•„๋‹ˆ๋ผ, ์–ด๋–ค ๋กœ๊ทธ๋ฅผ ๋ณด๋‚ด์•ผ ํ• ์ง€ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑธ ๊นจ๋‹ฌ์•˜๋‹ค. ํ•„ํ„ฐ๋ง, ์ง‘๊ณ„, ์กฐ๊ฑด๋ถ€ ์ „์†กโ€ฆ ์ด ๋ชจ๋“  ๊ฑธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์•„๋‹Œ ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Logback์—์„œ ์‹œ์ž‘ํ•ด Logstash, Slack, Kibana๊นŒ์ง€ ์ด์–ด์ง€๋Š” ๊ณผ์ •์„ ๊ธฐ๋กํ•˜๋ ค ํ•œ๋‹ค.


๐Ÿงฉ Slack Webhook ๋งŒ๋“ค๊ธฐ, ์ตœ๋Œ€ํ•œ ๊ฐ„๋‹จํ•˜๊ฒŒ

Slack ์•ฑ ๊ด€๋ฆฌ ํŽ˜์ด์ง€์—์„œ From scratch๋กœ ์•ฑ์„ ๋งŒ๋“ค๊ณ  Incoming Webhooks๋ฅผ ์ผฐ๋‹ค. ์ด ๋ฐฉ์‹์€ ์ฑ„๋„ ์—ฐ๊ฒฐ๊ณผ Webhook ๋ฐœ๊ธ‰ ๊ณผ์ •์„ ๋‹จ๊ณ„๋ณ„๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด ์ดˆ๋ฐ˜ ์‹ค์ˆ˜๋ฅผ ์ค„์—ฌ์คฌ๋‹ค.

Manifest ๋ฐฉ์‹์€ ๊ตฌ์„ฑ ์ด์‹์— ์ข‹์ง€๋งŒ ์ดˆ๊ธฐ ๋””๋ฒ„๊น… ๋‚œ๋„๊ฐ€ ์˜ฌ๋ผ๊ฐ„๋‹ค. ์ด๋ฒˆ์—” ์ฒซ ์„ค์ •์ด์–ด์„œ ๋‹จ์ˆœํ•œ ๊ธธ์„ ํƒํ–ˆ๋‹ค.

๋ฐœ๊ธ‰๋œ Webhook URL์€ ์ฝ”๋“œ์— ์ง์ ‘ ๋ฐ•์ง€ ์•Š๊ณ  ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ์ˆจ๊ฒผ๋‹ค. SLACK_WEBHOOK_URL=https://hooks.slack.com/services/***** ํ˜•ํƒœ๋กœ ๊ด€๋ฆฌํ–ˆ๋‹ค.


๐Ÿ› ๏ธ ์ฒซ ์‹œ๋„์ธ Logback โ†’ Slack ์ง๊ฒฐ

์ฒ˜์Œ์—๋Š” Logback HttpAppender๋กœ Slack์— ๋ฐ”๋กœ ๋ถ™์˜€๋‹ค.
root ๋กœ๊ฑฐ์— ๊ฑธ์–ด์„œ ERROR๋งŒ ์ „์†กํ•˜๊ฒŒ ํ–ˆ๋‹ค.

<appender name="SLACK" class="net.logstash.logback.appender.HttpAppender">
  <encoder class="net.logstash.logback.encoder.LogstashEncoder" />
  <url>${SLACK_WEBHOOK_URL}</url>
  <connectTimeout>10000</connectTimeout>
  <readTimeout>10000</readTimeout>
  <includeCallerData>true</includeCallerData>
  <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
    <level>ERROR</level>
  </filter>
</appender>

ํ•˜์ง€๋งŒ ์ตœ์‹  ๋ฒ„์ „์—์„œ๋Š” HttpAppender๊ฐ€ ์ œ๊ฑฐ๋˜๊ฑฐ๋‚˜ ๋ถ„๋ฆฌ๋ผ ๋™์ž‘ํ•˜์ง€ ์•Š์•˜๋‹ค.
๊ทธ๋ฆฌ๊ณ  ๋” ์ค‘์š”ํ•œ ๊ฑด, ์„ค๋ น ์ž˜ ๋ถ™๋”๋ผ๋„ ์žฌ์‹œ๋„, Rate Limit, ๋Œ€์ƒ ๋ณ€๊ฒฝ(Slackโ†’Sentry/Discord) ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ ์•ˆ์œผ๋กœ ๋Œ์–ด์˜ค๊ณ  ์‹ถ์ง€ ์•Š์•˜๋‹ค.

์—ฌ๊ธฐ์„œ ๊ฒฐ๋ก ์„ ๋ƒˆ๋‹ค.

๐Ÿ‘‰ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ์ผ์—๋งŒ ์ง‘์ค‘ํ•˜๊ณ ,
๐Ÿ‘‰ ์ˆ˜์ง‘ยท๊ฐ€๊ณตยท์ „์†ก์€ Logstash ๊ฐ™์€ ํŒŒ์ดํ”„๋ผ์ธ์ด ๋‹ด๋‹นํ•ด์•ผ ํ•œ๋‹ค.


๐Ÿ”€ ์ „๋žต ์ „ํ™˜: ์—ญํ• ์„ ๋ถ„๋ฆฌํ•˜๋‹ค

์ตœ์ข… ์„ค๊ณ„๋Š” ์ด๋ ‡๊ฒŒ ์ •๋ฆฌ๋๋‹ค.

๊ตฌ์„ฑ ์š”์†Œ์—ญํ• 
LogbackJSON ๋กœ๊ทธ ์ƒ์„ฑ โ†’ Kafka๋กœ ์ „์†ก
LogstashKafka ์ˆ˜์ง‘ โ†’ ํ•„ํ„ฐ๋งยท์ž„๊ณ„์น˜ ํŒ๋‹จ โ†’ ES ์ƒ‰์ธ + Slack ์•Œ๋ฆผ
SlackLogstash๊ฐ€ ๋ณด๋‚ธ ์š”์•ฝ ์•Œ๋ฆผ๋งŒ ๋ฐ›์Œ
Elasticsearch/Kibana์ „์ฒด ๋กœ๊ทธ ๋ณด๊ด€ + ์‹œ๊ฐํ™”/๋ถ„์„

๊ธฐ์กด ELK ์ถœ๋ ฅ์— Slack http output๋งŒ ์–น๋Š” ๋ฐฉ์‹์ด์—ˆ๊ณ , ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๊น”๋”ํ•˜๊ฒŒ ๋ถ„๋ฆฌ๋๋‹ค.

์›๋ž˜ ELK ์ถœ๋ ฅ์€ ๋‹จ์ˆœํ•˜๊ฒŒ ์ด๋ ‡๊ฒŒ ์‹œ์ž‘ํ–ˆ๋‹ค.

input {
  kafka {
    bootstrap_servers => "kafka:9092"
    topics => ["app-logs"]
    group_id => "logstash-consumer"
    codec => json
  }
}
filter {
  date { match => ["timestamp","ISO8601"] target => "@timestamp" remove_field => ["timestamp"] }
}
output {
  elasticsearch { hosts => ["http://elasticsearch:9200"] index => "app-logs-%{+YYYY.MM.dd}" }
  stdout { codec => json }
}

โœ‚๏ธ Slack์€ ์š”์•ฝ, Kibana๋Š” ๋””๊น…

Slack์— ๋ฌด์ž‘์ • ์ŠคํƒํŠธ๋ ˆ์ด์Šค๋ฅผ ๋‹ค ๋ณด๋‚ผ ์ˆ˜๋Š” ์—†์—ˆ๋‹ค. ๋ฉ”์‹œ์ง€ ๊ธธ์ด ์ œํ•œ๋„ ์žˆ๊ณ , ์†”์งํžˆ ๊ธด ๋กœ๊ทธ๋Š” ์ฝ๋Š” ์ˆœ๊ฐ„ ๋ˆˆ์ด ๋ฏธ๋„๋Ÿฌ์กŒ๋‹ค.

๊ทธ๋ž˜์„œ Slack์—๋Š” ํ•ต์‹ฌ ์š”์•ฝ + ์ƒ์œ„ 3~5์ค„ ์ŠคํƒํŠธ๋ ˆ์ด์Šค + TraceId + Kibana ๋งํฌ๋งŒ ๋ณด๋‚ด๊ณ , ์ „์ฒด ๋กœ๊ทธ๋Š” Kibana์—์„œ ๋ณด๋„๋ก ๋ถ„๋ฆฌํ–ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Slack์€ ๋น ๋ฅธ ๊ฐ์ง€์šฉ, Kibana๋Š” ๊นŠ์€ ๋ถ„์„์šฉ์œผ๋กœ ์—ญํ• ์ด ๋ช…ํ™•ํ•ด์กŒ๋‹ค.


  # stack_trace 5์ค„ ์š”์•ฝ
  if [stack_trace] {
    ruby {
      code => '
        if event.get("stack_trace")
          stack = event.get("stack_trace").split("\n")[0..4].join("\n")
          event.set("stack_trace_short", stack)
        end
      '
    }
  }
  

  # Slack ๋ฉ”์‹œ์ง€ ํ…œํ”Œ๋ฆฟ
  if [level] == "ERROR" {
    mutate {
      add_field => {
        "slack_message" => ":rotating_light: *ERROR ๋ฐœ์ƒ!*%{NEWLINE}*Service:* 
        LogSentry%{NEWLINE}*Message:* %{message}%{NEWLINE}*TraceId:* %
        {traceId}%{NEWLINE}*User:* %{userId}%{NEWLINE}*URI:* %{uri}%
        {NEWLINE}%{stack_trace_short}%{NEWLINE}
        <http://localhost:5601/app/discover#/?_a=(query:
        (language:kuery,query:'traceId:\"%{traceId}\"'))|Kibana์—์„œ ์ „์ฒด ๋กœ๊ทธ ํ™•์ธ>"
      }
    }
  }

}

Slack์€ ์‹ ์†ํ•œ ๊ฐ์ง€์—, Kibana๋Š” ์ •๋ฐ€ ๋ถ„์„์— ์ตœ์ ํ™”๋˜๊ฒŒ ๋ง์ด๋‹ค.


๐Ÿ“ฆ Logback โ†’ Kafka: JSON ๋กœ๊ทธ ์ „์†ก

Slack ์•Œ๋ฆผ์„ ์š”์•ฝํ–ˆ๋‹ค๋ฉด, ์ด์ œ ์›์ฒœ ๋กœ๊ทธ๋ฅผ ํŠผํŠผํ•˜๊ฒŒ ๋‚จ๊ธธ ์ฐจ๋ก€์˜€๋‹ค.
KafkaAppender๋ฅผ ํ†ตํ•ด Logback์—์„œ JSON ๋กœ๊ทธ๋ฅผ Kafka๋กœ ์ „์†กํ•˜๊ณ , MDC(traceId/spanId)์™€ stack_trace ํ•„๋“œ๋ฅผ ํฌํ•จ์‹œ์ผฐ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Logstash์—์„œ ๋ฉ”์‹œ์ง€๋ฅผ ๊ฐ€๊ณตํ•  ๋•Œ๋„, Kibana์—์„œ ์ „์ฒด ํ๋ฆ„์„ ๋ณผ ๋•Œ๋„ ๋น ์ง์—†์ด ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

<appender name="KAFKA_JSON" class="com.github.danielwegener.logback.kafka.KafkaAppender">
  <topic>app-logs</topic>
  <encoder class="com.github.danielwegener.logback.kafka.encoding.LayoutKafkaMessageEncoder">
    <layout class="net.logstash.logback.layout.LogstashLayout">
      <includeMdc>true</includeMdc>
      <includeException>true</includeException>
      <includeCallerData>false</includeCallerData>
    </layout>
  </encoder>
  <producerConfig>XXXX ์ดํ•˜์ƒ๋žต</producerConfig>
  ...
</appender>

๐Ÿ—‚๏ธ ์ธ๋ฑ์Šค ํ…œํ”Œ๋ฆฟ์—์„œ stack_trace ์ •์˜

Elasticsearch๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋™์  ๋งคํ•‘(dynamic mapping)์œผ๋กœ ์ƒˆ ํ•„๋“œ๋ฅผ ์ž๋™ ์ธ์‹ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ํ•„๋“œ ํƒ€์ž…์ด ์ž˜๋ชป ์žกํžˆ๊ฑฐ๋‚˜, ๊ฒ€์ƒ‰ยท์ง‘๊ณ„๊ฐ€ ๊ผฌ์ผ ์œ„ํ—˜์ด ์žˆ์–ด์„œ ์ธ๋ฑ์Šค ํ…œํ”Œ๋ฆฟ์— stack_trace ํ•„๋“œ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จ์‹œ์ผฐ๋‹ค.

์ด๋ ‡๊ฒŒ ํ…œํ”Œ๋ฆฟ์— ํฌํ•จํ•ด๋‘๋ฉด Kibana Discover์™€ Lens์—์„œ ์•ˆ์ •์ ์œผ๋กœ ์กฐํšŒยทํ•„ํ„ฐ๋งํ•  ์ˆ˜ ์žˆ๋‹ค.

_

โœ… ์‹ค์ œ๋กœ ์—๋Ÿฌ API๋ฅผ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ stack_trace ํ•„๋“œ๊ฐ€ ์ž˜ ๋“ค์–ด์˜ค๋Š” ๊ฒƒ๋„ ํ™•์ธํ–ˆ๋‹ค.


๐Ÿงช Logstash์˜ ํ•„ํ„ฐ๋ง๊ณผ ์ž„๊ณ„์น˜

์ฒ˜์Œ์—” โ€œ๋ชจ๋“  ERROR๋ฅผ Slack์œผ๋กœ!โ€ ๋ผ๊ณ  ๋‹จ์ˆœํ•˜๊ฒŒ ์ ‘๊ทผํ–ˆ์ง€๋งŒ, ์•Œ๋ฆผ ํญํƒ„์€ ๋‹ต์ด ์•„๋‹ˆ์—ˆ๋‹ค.
Slack์€ ๊ธˆ๋ฐฉ ์‹œ๋„๋Ÿฌ์›Œ์ง€๊ณ , ์ค‘์š”ํ•œ ์—๋Ÿฌ์กฐ์ฐจ ์žก์Œ์— ๋ฌปํ˜€๋ฒ„๋ ธ๋‹ค.

๊ทธ๋ž˜์„œ ์ „๋žต์„ ๋ฐ”๊ฟจ๋‹ค. BizLogger ํ‘œ์ค€ ๋กœ๊น…์— ALERT ๋งˆ์ปค๋ฅผ ๋„์ž…ํ•˜๊ณ , Logstash์—์„œ ์ž„๊ณ„์น˜ ์กฐ๊ฑด์„ ๊ฑธ์–ด ์˜๋ฏธ ์žˆ๋Š” ์ด๋ฒคํŠธ๋งŒ Slack์œผ๋กœ ๋ณด๋‚ด๋„๋ก ํ–ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์ฝ”๋“œ์—์„œ๋Š” ์ด๋ ‡๊ฒŒ ๊ตฌ๋ถ„ํ–ˆ๋‹ค.

// ์ผ๋ฐ˜ ์˜ˆ์™ธ โ†’ Kibana์—์„œ๋งŒ ํ™•์ธ
BizLogger.error("ํšŒ์› ๊ฐ€์ž… ์ค‘ ๋‹‰๋„ค์ž„ ์ค‘๋ณต ๋ฐœ์ƒ: {}", nickname);

// ์ค‘์š”ํ•œ ์˜ˆ์™ธ โ†’ Slack ์•Œ๋ฆผ๊นŒ์ง€ ์ „์†ก
BizLogger.alert("๐Ÿšจ ๊ฒฐ์ œ API ํ˜ธ์ถœ ์‹คํŒจ! ์ฃผ๋ฌธ๋ฒˆํ˜ธ: {}", orderId);

๐Ÿ”Ž Logstash์—์„œ ์ ์šฉํ•œ ๊ทœ์น™

  • ALERT ๋งˆ์ปค๊ฐ€ ์ฐํžŒ ์—๋Ÿฌ๋Š” ์ฆ‰์‹œ Slack ์ „์†ก
  • ๊ฐ™์€ URI์—์„œ 10๋ถ„ ๋™์•ˆ 5ํšŒ ์ด์ƒ ๋ฐ˜๋ณต๋˜๋ฉด Slack ์ „์†ก
  • ๊ฐ™์€ traceId์—์„œ 10๋ถ„ ๋™์•ˆ 3ํšŒ ์ด์ƒ ๋ฐ˜๋ณต๋˜๋ฉด Slack ์ „์†ก

์ฆ‰, ๋‹จ๋ฐœ์„ฑ ์˜ˆ์™ธ๋Š” Kibana์—๋งŒ ๋‚จ๊ธฐ๊ณ , ๋ฐ˜๋ณต๋˜๊ฑฐ๋‚˜ ์น˜๋ช…์ ์ธ ์ด๋ฒคํŠธ๋งŒ Slack์„ ์šธ๋ฆฌ๊ฒŒ ํ–ˆ๋‹ค.

โš™๏ธ Logstash ์„ค์ • ์˜ˆ์‹œ

# ALERT ๋งˆ์ปค ๊ฐ์ง€
if "ALERT" in [tags] {
  mutate { add_field => { "alert_flag" => "true" } }
}

# URI ์ž„๊ณ„์น˜: 10๋ถ„ ๋‚ด 5ํšŒ
aggregate {
  task_id => "%{uri}"
  code => "
    map['count'] ||= 0
    map['count'] += 1
    event.set('error_count_uri_10m', map['count'])
  "
  timeout_task_id_field => "uri"
  timeout => 600
  push_previous_map_as_event => false
  timeout_code => "event.set('error_count_uri_10m', 0)"
}

# traceId ์ž„๊ณ„์น˜: 10๋ถ„ ๋‚ด 3ํšŒ
aggregate {
  task_id => "%{traceId}"
  code => "
    map['count'] ||= 0
    map['count'] += 1
    event.set('error_count_trace_10m', map['count'])
  "
  timeout_task_id_field => "traceId"
  timeout => 600
  push_previous_map_as_event => false
  timeout_code => "event.set('error_count_trace_10m', 0)"
}

output {
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    index => "app-logs-%{+YYYY.MM.dd}"
  }

  stdout { codec => json }

  # Slack ์•Œ๋ฆผ ์กฐ๊ฑด
  if (("ALERT" in [tags] or [error_count_uri_10m] >= 5 or [error_count_trace_10m] >= 3) and [level] in ["ERROR", "WARN"]) {
    http {
      url => "${SLACK_WEBHOOK_URL}"
      http_method => "post"
      format => "json"
      mapping => {
        "text" => ":rotating_light: ERROR ์•Œ๋ฆผ (์š”์•ฝ๋ณธ + Kibana ๋งํฌ)"
      }
    }
  }
}

โ€”

์ตœ์ข…์ ์œผ๋กœ ๊ฒฐ๊ณผ๋Š” ์ด๋ ‡๊ฒŒ ๋‚˜์™”๋‹ค.

  • BizLogger.error โ†’ ์ž„๊ณ„์น˜ ํ†ต๊ณผ ์‹œ, Slack ์•Œ๋ฆผ

  • BizLogger.alert โ†’ Slack ์•Œ๋ฆผ + Kibana ๋งํฌ

  • Slack์—์„œ ๋งํฌ ํด๋ฆญ โ†’ Kibana๋กœ ์ด๋™ํ•ด TraceId ๊ธฐ์ค€ ์ „์ฒด ํ๋ฆ„ ์ถ”์ 


๐Ÿง˜ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์• ์ดˆ์— ๋‹จ์ˆœํ•จ์„ ๋ฏฟ๊ณ  Logback ์ง๊ฒฐ์„ ํƒํ–ˆ์ง€๋งŒ, ์šด์˜์€ ๋‹ค๋ฅด๊ฒŒ ๊ตด๋ €๋‹ค.
์•Œ๋ฆผ์€ ๋งŽ๋‹ค๊ณ  ์ข‹์€ ๊ฒŒ ์•„๋‹ˆ๋ผ, ์ œ๋Œ€๋กœ ์˜ค๋Š” ๊ฒŒ ์ค‘์š”ํ•˜๋‹ค๋Š” ๊ฑธ ์ด๋ฒˆ์— ๋А๊ผˆ๋‹ค.

๊ทธ๋ž˜์„œ

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋กœ๊ทธ ์ƒ์„ฑ์—๋งŒ ์ง‘์ค‘ํ•˜๊ฒŒ ํ•˜๊ณ ,
  • Logstash๊ฐ€ ํ•„ํ„ฐ๋งยท์ง‘๊ณ„ยทSlack ์ „์†ก์„ ๋งก๋„๋ก ํ–ˆ๋‹ค.

ALERT ๋งˆ์ปค์™€ ์ž„๊ณ„์น˜๋ฅผ ์–น์œผ๋‹ˆ ์•Œ๋ฆผ์€ ๋œ ์‹œ๋„๋Ÿฝ๊ณ  ๋” ์ •ํ™•ํ•ด์กŒ๊ณ , ์›์ธ ๋ถ„์„์€ Kibana ๋งํฌ๋ฅผ ํ†ตํ•ด ๋” ๋นจ๋ผ์กŒ๋‹ค.

์ด๋ฒˆ ๊ณผ์ •์„ ํ†ตํ•ด ๋ฐฐ์šด ๊ฑด, ๋‹จ์ˆœํžˆ ๊ธฐ์ˆ ์„ ๋ถ™์ด๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์šด์˜์ž์˜ ์‹œ์„ ์—์„œ โ€œ์–ด๋–ค ์•Œ๋ฆผ์ด ์ง„์งœ ํ•„์š”ํ•œ๊ฐ€โ€๋ฅผ ๊ณ ๋ฏผํ•˜๋Š” ๊ฒŒ ๋” ํฐ ์„ค๊ณ„ ํฌ์ธํŠธ๋ผ๋Š” ์ ์ด์—ˆ๋‹ค.

profile
"๋กœ์ปฌ์—์„  ๋ฌธ์ œ์—†์—ˆ๋Š”๋ฐโ€ฆ?"

0๊ฐœ์˜ ๋Œ“๊ธ€