서버구축 (WEB,DB)

Grafana Loki 통한 로그 수집 통합 모니터링 및 알람 시스템 구성

날으는물고기 2024. 9. 28. 00:37

Loki는 로그 수집, 저장, 조회를 위한 오픈 소스 로그 집계 시스템입니다. Grafana Labs에서 개발하였으며, 특히 대규모 로그 데이터를 효율적으로 관리하고 분석하기 위해 설계되었습니다. Loki는 Prometheus와 유사한 방식으로 작동하지만, 메트릭 대신 로그를 처리합니다. 주요 특징은 다음과 같습니다.

  1. 효율성: Loki는 인덱스를 최소화하고, 로그 데이터를 압축하여 저장합니다. 이를 통해 디스크 사용량과 검색 속도를 최적화합니다.
  2. 고가용성 및 확장성: 클러스터링을 지원하여, 대규모 환경에서도 높은 가용성과 확장성을 제공합니다.
  3. 간편한 통합: Prometheus 및 Grafana와 쉽게 통합할 수 있으며, 로그와 메트릭을 하나의 대시보드에서 함께 분석할 수 있습니다.
  4. 다양한 입력 소스 지원: Fluentd, Promtail, Logstash 등 다양한 로그 수집기를 통해 데이터를 수집할 수 있습니다.
  5. 라벨 기반 검색: 라벨을 사용한 강력한 검색 기능을 제공하여, 특정 조건의 로그를 빠르게 찾을 수 있습니다.

Loki 구성 요소

  1. Promtail: 로그 수집기로, 다양한 소스로부터 로그를 수집하여 Loki에 전달합니다.
  2. Loki 서버: 로그를 저장하고, 검색 요청을 처리합니다.
  3. Grafana: Loki와 통합되어 로그 데이터를 시각화하고, 분석할 수 있는 대시보드를 제공합니다.

설치 및 기본 설정

Loki를 설치하려면 다음과 같은 단계를 따릅니다.

  1. Loki 다운로드 및 설치
    wget https://github.com/grafana/loki/releases/download/v2.5.0/loki-linux-amd64.zip
    unzip loki-linux-amd64.zip
    chmod a+x loki-linux-amd64
  2. Loki 설정 파일 작성
    auth_enabled: false
    
    server:
      http_listen_port: 3100
    
    ingester:
      lifecycler:
        address: 127.0.0.1
        ring:
          kvstore:
            store: inmemory
          replication_factor: 1
        final_sleep: 0s
      chunk_idle_period: 5m
      max_chunk_age: 1h
      chunk_target_size: 1048576
      chunk_retain_period: 30s
      max_transfer_retries: 0
    
    schema_config:
      configs:
        - from: 2020-10-24
          store: boltdb-shipper
          object_store: filesystem
          schema: v11
          index:
            prefix: index_
            period: 168h
    
    storage_config:
      boltdb_shipper:
        active_index_directory: /tmp/loki/boltdb-shipper-active
        cache_location: /tmp/loki/boltdb-shipper-cache
        shared_store: filesystem
      filesystem:
        directory: /tmp/loki/chunks
    
    limits_config:
      enforce_metric_name: false
      reject_old_samples: true
      reject_old_samples_max_age: 168h
    
    chunk_store_config:
      max_look_back_period: 0s
    
    table_manager:
      retention_deletes_enabled: false
      retention_period: 0s
  3. Loki 실행
    ./loki-linux-amd64 -config.file=loki-config.yaml
  4. Promtail 설치 및 설정
    wget https://github.com/grafana/loki/releases/download/v2.5.0/promtail-linux-amd64.zip
    unzip promtail-linux-amd64.zip
    chmod a+x promtail-linux-amd64
    Promtail 설정 파일 promtail-config.yaml
    server:
      http_listen_port: 9080
      grpc_listen_port: 0
    
    positions:
      filename: /tmp/positions.yaml
    
    clients:
      - url: http://localhost:3100/loki/api/v1/push
    
    scrape_configs:
      - job_name: system
        static_configs:
          - targets:
              - localhost
            labels:
              job: varlogs
              __path__: /var/log/*log
  5. Promtail 실행
    ./promtail-linux-amd64 -config.file=promtail-config.yaml

보안 가이드 및 점검 포인트

  1. 로그 접근 제어: Loki 서버에 대한 접근을 제어하고, 인증 및 인가를 설정하여 불필요한 접근을 방지합니다.
  2. 암호화: Loki와 Promtail 간의 통신을 TLS로 암호화하여 로그 데이터의 도청을 방지합니다.
  3. 로그 데이터 보존 정책: 로그 데이터의 보존 기간을 설정하고, 필요시 자동 삭제를 설정하여 저장소의 용량을 효율적으로 관리합니다.
  4. 모니터링 및 경고: Loki의 성능과 상태를 모니터링하고, 문제 발생 시 경고를 받을 수 있도록 설정합니다.

Loki는 대규모 로그 데이터를 효율적으로 관리하고 분석할 수 있는 강력한 도구입니다. 회사의 로그 관리 요구사항에 맞추어 적절히 구성하고 사용하면 큰 도움이 될 것입니다.

Slack에 분석이 필요한 파일을 첨부하고, 해당 파일을 Loki 등 도구를 활용하여 자동으로 관련 정보를 수집 및 분석한 후 결과를 Slack 메시지로 전송하는 시스템을 구성하려면 다음과 같은 단계를 따를 수 있습니다.

1. Slack 설정 및 Webhook 구성

Slack Webhook을 사용하여 메시지를 전송할 수 있도록 설정합니다.

  1. Slack에서 새 앱 생성
    • Slack API 사이트로 이동하여 새 앱을 생성합니다.
    • 앱의 권한을 설정하여 파일 이벤트 및 메시지 전송을 허용합니다.
  2. Incoming Webhook 생성
    • Slack 앱 설정에서 'Incoming Webhooks'를 활성화합니다.
    • Webhook URL을 생성하여 기록해 둡니다.

2. 파일 업로드 이벤트 감지 및 처리

파일 업로드 이벤트를 감지하고, 해당 파일을 다운로드하여 분석합니다. 이 작업은 Slack Events API를 사용하여 구현할 수 있습니다.

  1. Slack 이벤트 설정
    • 앱 설정에서 'Event Subscriptions'을 활성화하고, 요청 URL을 설정합니다.
    • 'File Created' 이벤트를 구독합니다.
  2. 서버 설정
    • Flask와 같은 웹 프레임워크를 사용하여 이벤트를 처리할 서버를 설정합니다.
      from flask import Flask, request, jsonify
      import requests
      
      app = Flask(__name__)
      
      SLACK_BOT_TOKEN = 'xoxb-...'
      SLACK_SIGNING_SECRET = '...'
      
      @app.route('/slack/events', methods=['POST'])
      def slack_events():
          data = request.get_json()
          if 'event' in data and data['event']['type'] == 'file_created':
              file_id = data['event']['file_id']
              handle_file(file_id)
          return jsonify({'status': 'ok'})
      
      def handle_file(file_id):
          url = f"https://slack.com/api/files.info?file={file_id}"
          headers = {"Authorization": f"Bearer {SLACK_BOT_TOKEN}"}
          response = requests.get(url, headers=headers)
          file_info = response.json()
          download_url = file_info['file']['url_private_download']
          download_file(download_url)
      
      def download_file(url):
          headers = {"Authorization": f"Bearer {SLACK_BOT_TOKEN}"}
          response = requests.get(url, headers=headers)
          with open('/path/to/save/file', 'wb') as f:
              f.write(response.content)
          analyze_file('/path/to/save/file')
      
      def analyze_file(filepath):
          # 파일 분석 및 Loki 연동 로직 추가
          pass
      
      if __name__ == "__main__":
          app.run(port=3000)

3. 파일 분석 및 Loki 연동

파일을 분석하고, 필요한 로그 데이터를 Loki에 저장하거나 조회하여 분석합니다.

import subprocess

def analyze_file(filepath):
    # 예시: 특정 키워드를 포함한 로그 라인 추출
    with open(filepath, 'r') as file:
        logs = file.readlines()

    # 분석 로직 (예시: 에러 로그 추출)
    error_logs = [log for log in logs if 'ERROR' in log]

    # 분석 결과를 Loki에 저장 또는 Loki에서 관련 데이터 조회
    loki_push_logs(error_logs)

def loki_push_logs(logs):
    loki_url = "http://localhost:3100/loki/api/v1/push"
    headers = {'Content-Type': 'application/json'}
    data = {
        "streams": [
            {
                "labels": "{job=\"file_analysis\"}",
                "entries": [{"ts": "2024-07-30T14:00:00Z", "line": log} for log in logs]
            }
        ]
    }
    response = requests.post(loki_url, headers=headers, json=data)
    if response.status_code == 204:
        print("Logs pushed to Loki successfully")
    else:
        print("Failed to push logs to Loki")

    # 분석 결과 요약
    summary = f"Analyzed {len(logs)} logs, found {len(error_logs)} errors."
    send_to_slack(summary)

4. 결과 리포팅 및 Slack 메시지 전송

분석 결과를 Slack으로 전송합니다.

def send_to_slack(summary):
    webhook_url = 'https://hooks.slack.com/services/...'
    message = {
        "text": summary
    }
    response = requests.post(webhook_url, json=message)
    if response.status_code == 200:
        print("Message sent to Slack successfully")
    else:
        print("Failed to send message to Slack")

전체 코드 통합

이제 전체 코드를 통합하여 하나의 애플리케이션으로 구성합니다.

from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

SLACK_BOT_TOKEN = 'xoxb-...'
SLACK_SIGNING_SECRET = '...'

@app.route('/slack/events', methods=['POST'])
def slack_events():
    data = request.get_json()
    if 'event' in data and data['event']['type'] == 'file_created':
        file_id = data['event']['file_id']
        handle_file(file_id)
    return jsonify({'status': 'ok'})

def handle_file(file_id):
    url = f"https://slack.com/api/files.info?file={file_id}"
    headers = {"Authorization": f"Bearer {SLACK_BOT_TOKEN}"}
    response = requests.get(url, headers=headers)
    file_info = response.json()
    download_url = file_info['file']['url_private_download']
    download_file(download_url)

def download_file(url):
    headers = {"Authorization": f"Bearer {SLACK_BOT_TOKEN}"}
    response = requests.get(url, headers=headers)
    with open('/path/to/save/file', 'wb') as f:
        f.write(response.content)
    analyze_file('/path/to/save/file')

def analyze_file(filepath):
    with open(filepath, 'r') as file:
        logs = file.readlines()
    error_logs = [log for log in logs if 'ERROR' in log]
    loki_push_logs(error_logs)

def loki_push_logs(logs):
    loki_url = "http://localhost:3100/loki/api/v1/push"
    headers = {'Content-Type': 'application/json'}
    data = {
        "streams": [
            {
                "labels": "{job=\"file_analysis\"}",
                "entries": [{"ts": "2024-07-30T14:00:00Z", "line": log} for log in logs]
            }
        ]
    }
    response = requests.post(loki_url, headers=headers, json=data)
    if response.status_code == 204:
        print("Logs pushed to Loki successfully")
    else:
        print("Failed to push logs to Loki")

    summary = f"Analyzed {len(logs)} logs, found {len(error_logs)} errors."
    send_to_slack(summary)

def send_to_slack(summary):
    webhook_url = 'https://hooks.slack.com/services/...'
    message = {
        "text": summary
    }
    response = requests.post(webhook_url, json=message)
    if response.status_code == 200:
        print("Message sent to Slack successfully")
    else:
        print("Failed to send message to Slack")

if __name__ == "__main__":
    app.run(port=3000)

이와 같이 구성하면, Slack에 파일이 업로드될 때마다 자동으로 파일을 분석하고, 분석 결과를 Slack 메시지로 전송할 수 있습니다. 필요에 따라 파일 분석 로직과 Loki 연동 부분을 추가로 구성하고 최적화할 수 있습니다.

728x90