본문 바로가기
프로그램 (PHP,Python)

Python 기반 로그 모니터링 및 Google Sheets 수집 연동 자동화

by 날으는물고기 2024. 12. 22.

Python 기반 로그 모니터링 및 Google Sheets 수집 연동 자동화

여러 로그 파일을 지정하고, 해당 파일에 로그가 적재될 때 자동으로 수집되도록 한 예시코드입니다. 이 코드를 실행하는 데 필요한 Dockerfile도 함께 제공합니다.

Python 코드 (monitor_logs.py)

import os
import re
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from googleapiclient.discovery import build
from google.oauth2.service_account import Credentials

# Google Sheets API 설정
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
SERVICE_ACCOUNT_FILE = '/path/to/credentials.json'  # Google 서비스 계정 JSON 키 파일 경로
SPREADSHEET_ID = 'your_spreadsheet_id'  # Google Sheet의 스프레드시트 ID
SHEET_NAME = 'Sheet1'  # Sheet 이름

creds = Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = build('sheets', 'v4', credentials=creds)

# 도메인과 카운트를 Google Sheets에 업데이트
def update_google_sheets(domain):
    # 시트에서 데이터를 조회
    result = service.spreadsheets().values().get(
        spreadsheetId=SPREADSHEET_ID,
        range=f"{SHEET_NAME}!A:B"
    ).execute()

    values = result.get('values', [])

    # 도메인이 시트에 있는지 확인
    domain_exists = False
    for i, row in enumerate(values):
        if len(row) > 0 and row[0] == domain:
            # 도메인이 이미 있으면 카운트 증가
            current_count = int(row[1]) if len(row) > 1 else 0
            new_count = current_count + 1
            values[i][1] = new_count
            domain_exists = True
            break

    # 도메인이 없으면 새로 추가
    if not domain_exists:
        values.append([domain, 1])

    # Google Sheets에 업데이트
    body = {
        'values': values
    }
    service.spreadsheets().values().update(
        spreadsheetId=SPREADSHEET_ID,
        range=f"{SHEET_NAME}!A1",
        valueInputOption="RAW",
        body=body
    ).execute()

# 로그 파일에서 도메인 이름 추출
def extract_domain_from_log(log_entry):
    # 정규식을 사용해 도메인 이름 추출 (예: "A IN example.com")
    match = re.search(r'IN\s+([a-zA-Z0-9.-]+)', log_entry)
    if match:
        return match.group(1)
    return None

# 파일 변화 감지 핸들러
class LogFileHandler(FileSystemEventHandler):
    def __init__(self, log_file):
        self.log_file = log_file
        # 파일 포인터를 끝으로 이동
        self.file_pointer = open(log_file, 'r')
        self.file_pointer.seek(0, os.SEEK_END)

    def on_modified(self, event):
        if event.src_path == self.log_file:
            while True:
                line = self.file_pointer.readline()
                if not line:
                    break
                log_entry = line.strip()
                domain = extract_domain_from_log(log_entry)  # 도메인 추출
                if domain:
                    update_google_sheets(domain)  # 도메인 카운트 업데이트

def monitor_logs(log_files):
    observers = []
    for log_file in log_files:
        event_handler = LogFileHandler(log_file)
        observer = Observer()
        directory = os.path.dirname(log_file)
        observer.schedule(event_handler, directory, recursive=False)
        observer.start()
        observers.append(observer)
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        for observer in observers:
            observer.stop()
    for observer in observers:
        observer.join()

if __name__ == "__main__":
    # 모니터링할 로그 파일 목록
    log_files = [
        "/var/log/coredns/coredns.log",
        "/path/to/another/log/file.log",
        # 필요에 따라 더 많은 로그 파일 경로 추가
    ]

    monitor_logs(log_files)
  • SERVICE_ACCOUNT_FILE, SPREADSHEET_ID, SHEET_NAME를 실제 값으로 변경해야 합니다.
  • 로그 파일 경로 목록 log_files에 모니터링할 모든 로그 파일의 경로를 추가하세요.

Dockerfile

# 베이스 이미지 선택
FROM python:3.8-slim

# 필요한 시스템 패키지 설치
RUN apt-get update && apt-get install -y \
    build-essential \
    && rm -rf /var/lib/apt/lists/*

# 작업 디렉토리 설정
WORKDIR /app

# 필요한 Python 패키지 설치
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

# 애플리케이션 코드 복사
COPY . /app

# 실행 명령 설정
CMD ["python", "monitor_logs.py"]

requirements.txt

watchdog
google-api-python-client
google-auth
google-auth-httplib2
google-auth-oauthlib

사용 방법

  1. 코드 및 파일 준비
    • 위의 monitor_logs.py, Dockerfile, requirements.txt 파일을 동일한 디렉토리에 저장합니다.
    • monitor_logs.py에서 필요한 부분 (SERVICE_ACCOUNT_FILE, SPREADSHEET_ID, SHEET_NAME)을 실제 값으로 수정합니다.
    • credentials.json 파일을 준비하고, monitor_logs.py에서 지정한 경로에 위치시킵니다.
  2. Docker 이미지 빌드
    docker build -t log-monitor .
  3. Docker 컨테이너 실행
    docker run -d \
      -v /path/to/your/logs:/var/log/coredns \  # 로그 파일 디렉토리 마운트
      -v /path/to/credentials.json:/path/to/credentials.json \  # 크레덴셜 파일 마운트
      log-monitor
    • 위 명령에서 /path/to/your/logs는 호스트의 로그 파일 디렉토리 경로입니다.
    • /path/to/credentials.json은 호스트의 서비스 계정 JSON 키 파일 경로입니다.

참고사항

  • 보안상의 이유로, credentials.json 파일을 Docker 이미지에 직접 포함하지 않고, 컨테이너 실행 시 볼륨 마운트를 통해 제공하는 것이 좋습니다.
  • 로그 파일 디렉토리도 마찬가지로 컨테이너 내부에서 접근할 수 있도록 볼륨 마운트를 사용해야 합니다.
  • monitor_logs.py에서 지정한 로그 파일 경로가 컨테이너 내부의 경로와 일치하는지 확인하세요.

추가 설명

  • 여러 로그 파일 모니터링: 수정된 코드는 log_files 리스트에 지정된 모든 로그 파일을 동시에 모니터링합니다.
  • Docker 환경에서 파일 접근: Docker 컨테이너는 기본적으로 호스트의 파일 시스템에 접근할 수 없으므로, 필요한 파일 및 디렉토리를 볼륨 마운트를 통해 컨테이너 내부에 연결해야 합니다.
  • 의존성 관리: requirements.txt 파일을 사용하여 필요한 Python 패키지를 설치합니다.

 

이렇게 구성하면 다양한 로그 파일을 지정하고, 해당 파일에 로그가 적재될 때 자동으로 수집하여 Google Sheets에 업데이트할 수 있습니다. 아래는 다양한 옵션을 제공하도록 개선된 코드와 업데이트된 Dockerfile입니다. 이 코드는 명령줄 인자와 환경 변수를 통해 설정을 유연하게 변경할 수 있도록 하였으며, 로깅 기능과 에러 처리를 강화하였습니다.

개선된 Python 코드 (monitor_logs.py)

import os
import re
import time
import argparse
import logging
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from googleapiclient.discovery import build
from google.oauth2.service_account import Credentials

# 로깅 설정
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 명령줄 인자 파서 설정
def parse_arguments():
    parser = argparse.ArgumentParser(description='Log Monitor Script')
    parser.add_argument('--log-files', nargs='+', required=True, help='모니터링할 로그 파일들의 경로를 공백으로 구분하여 입력')
    parser.add_argument('--credentials', required=True, help='Google 서비스 계정 JSON 키 파일 경로')
    parser.add_argument('--spreadsheet-id', required=True, help='Google Sheets의 스프레드시트 ID')
    parser.add_argument('--sheet-name', default='Sheet1', help='Google Sheets의 시트 이름')
    parser.add_argument('--regex', default=r'IN\s+([a-zA-Z0-9.-]+)', help='도메인 추출을 위한 정규 표현식')
    parser.add_argument('--log-level', default='INFO', help='로깅 레벨 (DEBUG, INFO, WARNING, ERROR, CRITICAL)')
    return parser.parse_args()

# Google Sheets API 설정
def initialize_google_sheets(credentials_path, scopes):
    creds = Credentials.from_service_account_file(credentials_path, scopes=scopes)
    service = build('sheets', 'v4', credentials=creds)
    return service

# 도메인과 카운트를 Google Sheets에 업데이트
def update_google_sheets(service, spreadsheet_id, sheet_name, domain):
    try:
        # 시트에서 데이터를 조회
        result = service.spreadsheets().values().get(
            spreadsheetId=spreadsheet_id,
            range=f"{sheet_name}!A:B"
        ).execute()

        values = result.get('values', [])

        # 도메인이 시트에 있는지 확인
        domain_exists = False
        for i, row in enumerate(values):
            if len(row) > 0 and row[0] == domain:
                # 도메인이 이미 있으면 카운트 증가
                current_count = int(row[1]) if len(row) > 1 else 0
                new_count = current_count + 1
                values[i][1] = new_count
                domain_exists = True
                break

        # 도메인이 없으면 새로 추가
        if not domain_exists:
            values.append([domain, 1])

        # Google Sheets에 업데이트
        body = {
            'values': values
        }
        service.spreadsheets().values().update(
            spreadsheetId=spreadsheet_id,
            range=f"{sheet_name}!A1",
            valueInputOption="RAW",
            body=body
        ).execute()
        logging.debug(f"Updated Google Sheets with domain: {domain}")
    except Exception as e:
        logging.error(f"Failed to update Google Sheets: {e}")

# 로그 파일에서 도메인 이름 추출
def extract_domain_from_log(log_entry, regex_pattern):
    match = re.search(regex_pattern, log_entry)
    if match:
        return match.group(1)
    return None

# 파일 변화 감지 핸들러
class LogFileHandler(FileSystemEventHandler):
    def __init__(self, log_file, regex_pattern, service, spreadsheet_id, sheet_name):
        self.log_file = log_file
        self.regex_pattern = regex_pattern
        self.service = service
        self.spreadsheet_id = spreadsheet_id
        self.sheet_name = sheet_name
        try:
            self.file_pointer = open(log_file, 'r')
            self.file_pointer.seek(0, os.SEEK_END)
        except Exception as e:
            logging.error(f"Failed to open log file {log_file}: {e}")

    def on_modified(self, event):
        if event.src_path == self.log_file:
            while True:
                line = self.file_pointer.readline()
                if not line:
                    break
                log_entry = line.strip()
                domain = extract_domain_from_log(log_entry, self.regex_pattern)  # 도메인 추출
                if domain:
                    update_google_sheets(self.service, self.spreadsheet_id, self.sheet_name, domain)  # 도메인 카운트 업데이트

def monitor_logs(log_files, regex_pattern, service, spreadsheet_id, sheet_name):
    observers = []
    for log_file in log_files:
        event_handler = LogFileHandler(log_file, regex_pattern, service, spreadsheet_id, sheet_name)
        observer = Observer()
        directory = os.path.dirname(log_file)
        observer.schedule(event_handler, directory, recursive=False)
        observer.start()
        observers.append(observer)
        logging.info(f"Started monitoring {log_file}")
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        for observer in observers:
            observer.stop()
            logging.info("Stopping observer")
    for observer in observers:
        observer.join()

if __name__ == "__main__":
    args = parse_arguments()

    # 로깅 레벨 설정
    numeric_level = getattr(logging, args.log_level.upper(), None)
    if isinstance(numeric_level, int):
        logging.getLogger().setLevel(numeric_level)
    else:
        logging.error(f"Invalid log level: {args.log_level}")

    SCOPES = ['https://www.googleapis.com/auth/spreadsheets']

    # Google Sheets 서비스 초기화
    service = initialize_google_sheets(args.credentials, SCOPES)

    # 모니터링 시작
    monitor_logs(args.log_files, args.regex, service, args.spreadsheet_id, args.sheet_name)
  • 명령줄 인자 지원 (argparse 사용)
    • --log-files: 모니터링할 로그 파일들의 경로를 공백으로 구분하여 입력합니다.
    • --credentials: Google 서비스 계정 JSON 키 파일 경로를 지정합니다.
    • --spreadsheet-id: 업데이트할 Google Sheets의 스프레드시트 ID를 지정합니다.
    • --sheet-name: 업데이트할 시트의 이름을 지정합니다.
    • --regex: 도메인 추출을 위한 정규 표현식을 지정합니다.
    • --log-level: 로깅 레벨을 설정합니다 (DEBUG, INFO, WARNING, ERROR, CRITICAL).
  • 로깅 추가 (logging 모듈 사용)
    • 스크립트의 동작 상태를 로그로 출력하여 모니터링 및 디버깅을 용이하게 합니다.
    • --log-level 인자를 통해 로깅 레벨을 조정할 수 있습니다.
  • 에러 처리 강화
    • 예외 처리를 통해 발생할 수 있는 오류를 캡처하고 로그에 기록합니다.
    • 로그 파일을 열지 못하는 경우와 Google Sheets 업데이트 실패 시 에러를 로그로 출력합니다.
  • 유연성 향상
    • 정규 표현식을 명령줄 인자로 받아 다양한 로그 형식에 대응할 수 있도록 하였습니다.
    • 로깅 레벨을 조정하여 필요에 따라 상세한 정보를 얻을 수 있습니다.

업데이트된 Dockerfile

# 베이스 이미지 선택
FROM python:3.8-slim

# 필요한 시스템 패키지 설치
RUN apt-get update && apt-get install -y \
    build-essential \
    && rm -rf /var/lib/apt/lists/*

# 작업 디렉토리 설정
WORKDIR /app

# 필요한 Python 패키지 설치
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

# 애플리케이션 코드 복사
COPY monitor_logs.py /app/

# 실행 명령 설정 (명령줄 인자는 ENTRYPOINT로 처리)
ENTRYPOINT ["python", "monitor_logs.py"]

requirements.txt

watchdog
google-api-python-client
google-auth
google-auth-httplib2
google-auth-oauthlib

참고: argparse는 표준 라이브러리이므로 requirements.txt에 추가할 필요가 없습니다.

추가 옵션 및 유의사항

  • 환경 변수 지원: 필요에 따라 코드를 수정하여 환경 변수를 통해 설정을 제공할 수 있습니다.
  • 로그 레벨 조정: --log-level 인자를 통해 로깅 레벨을 조정할 수 있습니다. 디버깅이 필요한 경우 DEBUG로 설정하면 상세한 로그를 확인할 수 있습니다.
  • 정규 표현식 커스터마이징: --regex 인자를 통해 로그 파일 형식에 맞는 정규 표현식을 지정할 수 있습니다. 예를 들어, 로그 형식이 다를 경우 이에 맞는 정규 표현식을 입력하면 됩니다.
  • 에러 로깅 및 알림: 더 강화된 에러 처리를 통해 문제가 발생할 경우 이메일이나 슬랙으로 알림을 보내도록 코드를 확장할 수 있습니다.
  • 환경 변수 사용 예시: Docker 실행 시 -e 옵션을 사용하여 환경 변수를 전달하고, 코드에서 os.environ.get('ENV_VAR_NAME')으로 가져올 수 있습니다.

 

이렇게 개선된 코드는 사용자가 다양한 옵션을 통해 설정을 유연하게 변경할 수 있도록 하였으며, 로깅과 에러 처리를 통해 안정성을 높였습니다. Docker 환경에서도 쉽게 설정을 변경하여 사용할 수 있도록 명령줄 인자와 볼륨 마운트를 활용하였습니다. 필요에 따라 코드를 더 확장하여 환경 변수 지원이나 알림 기능 등을 추가할 수 있습니다.

 

추가로, Python 데몬으로 실행되도록 개선된 코드와 업데이트된 Dockerfile입니다. 이 코드는 python-daemon 모듈을 사용하여 백그라운드에서 데몬으로 실행되며, 필요한 경우 로그 파일을 통해 상태를 모니터링할 수 있습니다.

개선된 Python 코드 (monitor_logs.py)

import os
import re
import time
import argparse
import logging
import signal
import sys
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from googleapiclient.discovery import build
from google.oauth2.service_account import Credentials

# 데몬 라이브러리 임포트
import daemon
from daemon import pidfile

# 로깅 설정
def setup_logging(log_file=None, log_level=logging.INFO):
    logging.basicConfig(
        level=log_level,
        format='%(asctime)s - %(levelname)s - %(message)s',
        filename=log_file,
        filemode='a'
    )

# 명령줄 인자 파서 설정
def parse_arguments():
    parser = argparse.ArgumentParser(description='Log Monitor Daemon Script')
    parser.add_argument('--log-files', nargs='+', required=True, help='모니터링할 로그 파일들의 경로를 공백으로 구분하여 입력')
    parser.add_argument('--credentials', required=True, help='Google 서비스 계정 JSON 키 파일 경로')
    parser.add_argument('--spreadsheet-id', required=True, help='Google Sheets의 스프레드시트 ID')
    parser.add_argument('--sheet-name', default='Sheet1', help='Google Sheets의 시트 이름')
    parser.add_argument('--regex', default=r'IN\s+([a-zA-Z0-9.-]+)', help='도메인 추출을 위한 정규 표현식')
    parser.add_argument('--log-level', default='INFO', help='로깅 레벨 (DEBUG, INFO, WARNING, ERROR, CRITICAL)')
    parser.add_argument('--daemon-log-file', default='/var/log/monitor_logs_daemon.log', help='데몬 로깅 파일 경로')
    parser.add_argument('--pid-file', default='/var/run/monitor_logs.pid', help='데몬 PID 파일 경로')
    return parser.parse_args()

# Google Sheets API 설정
def initialize_google_sheets(credentials_path, scopes):
    creds = Credentials.from_service_account_file(credentials_path, scopes=scopes)
    service = build('sheets', 'v4', credentials=creds)
    return service

# 도메인과 카운트를 Google Sheets에 업데이트
def update_google_sheets(service, spreadsheet_id, sheet_name, domain):
    try:
        # 시트에서 데이터를 조회
        result = service.spreadsheets().values().get(
            spreadsheetId=spreadsheet_id,
            range=f"{sheet_name}!A:B"
        ).execute()

        values = result.get('values', [])

        # 도메인이 시트에 있는지 확인
        domain_exists = False
        for i, row in enumerate(values):
            if len(row) > 0 and row[0] == domain:
                # 도메인이 이미 있으면 카운트 증가
                current_count = int(row[1]) if len(row) > 1 else 0
                new_count = current_count + 1
                values[i][1] = new_count
                domain_exists = True
                break

        # 도메인이 없으면 새로 추가
        if not domain_exists:
            values.append([domain, 1])

        # Google Sheets에 업데이트
        body = {
            'values': values
        }
        service.spreadsheets().values().update(
            spreadsheetId=spreadsheet_id,
            range=f"{sheet_name}!A1",
            valueInputOption="RAW",
            body=body
        ).execute()
        logging.debug(f"Updated Google Sheets with domain: {domain}")
    except Exception as e:
        logging.error(f"Failed to update Google Sheets: {e}")

# 로그 파일에서 도메인 이름 추출
def extract_domain_from_log(log_entry, regex_pattern):
    match = re.search(regex_pattern, log_entry)
    if match:
        return match.group(1)
    return None

# 파일 변화 감지 핸들러
class LogFileHandler(FileSystemEventHandler):
    def __init__(self, log_file, regex_pattern, service, spreadsheet_id, sheet_name):
        self.log_file = log_file
        self.regex_pattern = regex_pattern
        self.service = service
        self.spreadsheet_id = spreadsheet_id
        self.sheet_name = sheet_name
        try:
            self.file_pointer = open(log_file, 'r')
            self.file_pointer.seek(0, os.SEEK_END)
        except Exception as e:
            logging.error(f"Failed to open log file {log_file}: {e}")

    def on_modified(self, event):
        if event.src_path == self.log_file:
            while True:
                line = self.file_pointer.readline()
                if not line:
                    break
                log_entry = line.strip()
                domain = extract_domain_from_log(log_entry, self.regex_pattern)  # 도메인 추출
                if domain:
                    update_google_sheets(self.service, self.spreadsheet_id, self.sheet_name, domain)  # 도메인 카운트 업데이트

def monitor_logs(log_files, regex_pattern, service, spreadsheet_id, sheet_name):
    observers = []
    for log_file in log_files:
        event_handler = LogFileHandler(log_file, regex_pattern, service, spreadsheet_id, sheet_name)
        observer = Observer()
        directory = os.path.dirname(log_file)
        observer.schedule(event_handler, directory, recursive=False)
        observer.start()
        observers.append(observer)
        logging.info(f"Started monitoring {log_file}")

    # 신호 처리 설정
    def graceful_exit(signum, frame):
        logging.info("Received termination signal, stopping observers...")
        for observer in observers:
            observer.stop()
        sys.exit(0)

    signal.signal(signal.SIGTERM, graceful_exit)
    signal.signal(signal.SIGINT, graceful_exit)

    while True:
        time.sleep(1)

def main():
    args = parse_arguments()

    # 로깅 레벨 설정
    numeric_level = getattr(logging, args.log_level.upper(), None)
    if not isinstance(numeric_level, int):
        logging.error(f"Invalid log level: {args.log_level}")
        numeric_level = logging.INFO

    setup_logging(log_file=args.daemon_log_file, log_level=numeric_level)

    SCOPES = ['https://www.googleapis.com/auth/spreadsheets']

    # Google Sheets 서비스 초기화
    service = initialize_google_sheets(args.credentials, SCOPES)

    # 모니터링 시작
    monitor_logs(args.log_files, args.regex, service, args.spreadsheet_id, args.sheet_name)

if __name__ == "__main__":
    args = parse_arguments()

    # 데몬 컨텍스트 설정
    with daemon.DaemonContext(
        working_directory='/',
        umask=0o002,
        pidfile=pidfile.TimeoutPIDLockFile(args.pid_file),
        stdout=sys.stdout,
        stderr=sys.stderr,
    ):
        main()
  • 데몬 모듈 사용 (python-daemon): daemon 모듈을 사용하여 스크립트를 데몬으로 실행합니다.
  • PID 파일 관리: --pid-file 인자를 추가하여 데몬의 PID 파일 경로를 지정할 수 있습니다.
  • 데몬 로그 파일 설정: --daemon-log-file 인자를 통해 데몬의 로그 출력 경로를 지정합니다.
  • 신호 처리 추가: SIGTERMSIGINT 신호를 처리하여 안전하게 종료할 수 있도록 하였습니다.
  • 로깅 설정 개선: setup_logging 함수를 통해 로깅 설정을 파일로 출력하도록 수정하였습니다.

업데이트된 Dockerfile

# 베이스 이미지 선택
FROM python:3.8-slim

# 필요한 시스템 패키지 설치
RUN apt-get update && apt-get install -y \
    build-essential \
    && rm -rf /var/lib/apt/lists/*

# 작업 디렉토리 설정
WORKDIR /app

# 필요한 Python 패키지 설치
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

# 애플리케이션 코드 복사
COPY monitor_logs.py /app/

# 로그 디렉토리 생성
RUN mkdir -p /var/log

# 실행 명령 설정
CMD ["python", "monitor_logs.py"]

requirements.txt

watchdog
google-api-python-client
google-auth
google-auth-httplib2
google-auth-oauthlib
python-daemon

주의: python-daemon 패키지를 추가하여 데몬 기능을 지원합니다.

사용 방법

  1. 코드 및 파일 준비
    • monitor_logs.py, Dockerfile, requirements.txt 파일을 동일한 디렉토리에 저장합니다.
    • credentials.json 파일을 준비하고 적절한 위치에 저장합니다.
  2. Docker 이미지 빌드
    docker build -t log-monitor-daemon .
  3. Docker 컨테이너 실행 설명
    docker run -d \
      -v /path/to/your/logs:/logs \  # 로그 파일 디렉토리 마운트
      -v /path/to/credentials.json:/app/credentials.json \  # 크레덴셜 파일 마운트
      -v /var/log/monitor_logs_daemon.log:/var/log/monitor_logs_daemon.log \  # 데몬 로그 파일 마운트
      -v /var/run/monitor_logs.pid:/var/run/monitor_logs.pid \  # PID 파일 마운트
      log-monitor-daemon \
      --log-files /logs/coredns.log /logs/another.log \  # 모니터링할 로그 파일 지정
      --credentials /app/credentials.json \  # 컨테이너 내에서의 크레덴셜 파일 경로
      --spreadsheet-id your_spreadsheet_id \  # 실제 스프레드시트 ID로 변경
      --sheet-name Sheet1 \  # 시트 이름 지정
      --regex 'IN\s+([a-zA-Z0-9.-]+)' \  # 필요에 따라 정규 표현식 변경
      --log-level INFO \  # 로깅 레벨 설정
      --daemon-log-file /var/log/monitor_logs_daemon.log \  # 데몬 로그 파일 경로
      --pid-file /var/run/monitor_logs.pid  # PID 파일 경로
    • -v /path/to/your/logs:/logs: 호스트의 로그 파일 디렉토리를 컨테이너의 /logs 디렉토리에 마운트합니다.
    • -v /path/to/credentials.json:/app/credentials.json: 호스트의 크레덴셜 파일을 컨테이너의 /app/credentials.json에 마운트합니다.
    • -v /var/log/monitor_logs_daemon.log:/var/log/monitor_logs_daemon.log: 데몬의 로그 파일을 호스트에서 접근할 수 있도록 마운트합니다.
    • -v /var/run/monitor_logs.pid:/var/run/monitor_logs.pid: PID 파일을 호스트에서 접근할 수 있도록 마운트합니다.
    • --daemon-log-file, --pid-file: 데몬의 로그 파일과 PID 파일의 경로를 지정합니다.

추가 설명

  • 데몬으로 실행되는 이유: 데몬으로 실행하면 프로세스가 백그라운드에서 독립적으로 동작하며, 시스템 재시작 시 자동으로 시작하도록 설정할 수 있습니다.
  • 신호 처리: SIGTERMSIGINT 신호를 처리하여 데몬이 종료될 때 리소스를 적절히 정리합니다.
  • 로그 파일 관리: 데몬의 로그 출력을 파일로 지정하여 백그라운드에서 실행되는 동안 발생하는 이벤트를 추적할 수 있습니다.
  • PID 파일: PID 파일을 생성하여 데몬의 프로세스 ID를 추적하고, 중복 실행을 방지하거나 프로세스를 제어하는 데 사용할 수 있습니다.

유의사항

  • Docker에서 데몬 실행 고려사항: 일반적으로 Docker 컨테이너는 하나의 포그라운드 프로세스를 실행하도록 설계되었습니다. 따라서 컨테이너 내부에서 데몬을 실행하는 것은 권장되지 않을 수 있습니다. 그러나 사용자가 특별히 데몬으로 실행되기를 원하는 경우 위와 같이 구성할 수 있습니다.
  • 시스템 데몬으로 실행: 만약 Docker를 사용하지 않고 시스템 데몬으로 실행하고자 한다면, 이 스크립트를 서비스로 등록하여 사용하면 됩니다.
  • 권한 문제: 로그 파일이나 PID 파일의 경로가 시스템에 따라 접근 권한 문제가 발생할 수 있으므로, 필요에 따라 경로나 권한을 조정해야 합니다.
  • 보안: 크레덴셜 파일과 로그 파일이 외부에 노출되지 않도록 권한 관리에 유의해야 합니다.

 

이렇게 개선된 코드는 Python 데몬으로 동작하며, 다양한 옵션을 제공하여 사용자의 요구에 맞게 설정할 수 있습니다. 데몬으로 실행됨에 따라 시스템 리소스를 효율적으로 사용하고, 백그라운드에서 안정적으로 로그를 모니터링할 수 있습니다.

 

필요에 따라 코드를 더 확장하여 서비스 관리 도구(systemd 등)와 연동하거나 모니터링 및 알림 기능을 강화할 수 있습니다.

728x90

댓글