# VPS 로그 분석 자동화 — Pandas + AI로 10분 만에 서버 문제 찾기
VPS를 운영하면서 로그 파일, 얼마나 쌓아두고 계신가요? Nginx access log, error log, systemd journal, application log… 매일 수십 MB씩 쌓입니다. 그런데 이걸 언제 분석하시나요? 대부분의 대답은 “문제가 생겼을 때만”입니다. 문제가 터진 후에야 로그를 뒤지느라 정작 중요한 패턴을 놓칩니다.
이 글에서는 VPS 로그를 **Pandas**로 처리하고, **LLM과 연동**해서 자연어로 질문하고, 매일 자동으로 인사이트 리포트를 생성하는 파이프라인을 만드는 방법을 다룹니다. 목표는 로그를 더 이상 “문제가 터졌을 때만 보는 것”에서 “매일 아침 요약받는 것”으로 바꾸는 것입니다.
## 로그를 DataFrame으로 — Pandas 기초
Nginx access log는 기본적으로 이런 형식입니다.
“`
192.168.1.1 – – [11/Jul/2026:14:32:01 +0900] “GET /api/bookmarks HTTP/1.1” 200 1234 “https://example.com/” “Mozilla/5.0…”
“`
사람이 읽기엔 까다롭지만, 정규표현식으로 파싱하면 구조화된 데이터가 됩니다. Python 스크립트를 만들어 봅시다.
“`python
import pandas as pd
import re
LOG_PATTERN = re.compile(
r'(?P
def parse_nginx_log(filepath):
records = []
with open(filepath) as f:
for line in f:
m = LOG_PATTERN.match(line)
if m:
records.append(m.groupdict())
return pd.DataFrame(records)
“`
각 로그 라인이 하나의 row가 되고, IP, 시간, HTTP 메서드, 경로, 상태 코드, 응답 크기 등이 컬럼이 됩니다. 수만 줄의 로그가 깔끔한 표 형태로 변환됩니다.
데이터를 불러왔으니 기본 분석을 해봅니다.
“`python
df = parse_nginx_log(‘/var/log/nginx/access.log’)
# 상태 코드별 요청 수
print(df[‘status’].value_counts())
# 200 45231
# 404 3201
# 500 156
# 가장 많이 접근한 경로 TOP 10
print(df[‘path’].value_counts().head(10))
# 시간대별 트래픽
df[‘time’] = pd.to_datetime(df[‘time’], format=’%d/%b/%Y:%H:%M:%S %z’)
df[‘hour’] = df[‘time’].dt.hour
print(df.groupby(‘hour’).size())
“`
이 몇 줄의 코드로 200 OK가 93%인지 70%인지, 404가 어디서 많이 나는지, 트래픽 피크가 몇 시인지 한눈에 볼 수 있습니다. 엑셀로는 104만 행까지만 표시되지만, Pandas는 메모리만 허락하면 천만 행도 처리합니다.
여기서 중요한 점은 **파싱 정규표현식이 맞는지 검증**하는 것입니다. 파싱 실패한 라인이 있다면 DataFrame에 포함되지 않으니 전체 라인 수와 DataFrame 행 수를 비교합니다. 파싱률이 95% 이하라면 정규표현식을 조정해야 합니다.
## LLM 연동 — 자연어로 데이터 질문하기
Pandas로 기본 통계는 냈지만, 더 복잡한 질문을 하고 싶습니다. “최근 일주일 동안 500 에러가 가장 많이 발생한 시간대와 엔드포인트는?” 같은 질문이죠. 이걸 Pandas 코드로 일일이 작성하려면 시간이 듭니다.
여기서 LLM이 들어갑니다. AI에게 데이터의 **요약 통계와 샘플**을 컨텍스트로 주고, 자연어로 질문합니다. 로컬 LLM(Ollama)을 사용하면 데이터가 외부로 나가지 않으니 보안에 안전합니다.
“`python
import requests
import json
def ask_llm_about_data(df, question):
summary = {
“total_rows”: len(df),
“status_codes”: df[‘status’].value_counts().to_dict(),
“top_paths”: df[‘path’].value_counts().head(20).to_dict(),
“hourly_traffic”: df.groupby(‘hour’).size().to_dict(),
“error_5xx_count”: len(df[df[‘status’].astype(int) >= 500]),
}
prompt = f”””
다음은 Nginx 로그 분석 결과입니다:
{json.dumps(summary, indent=2, ensure_ascii=False)}
질문: {question}
한국어로 답변해주세요.”””
response = requests.post(“http://localhost:11434/api/generate”, json={
“model”: “qwen2.5:14b”,
“prompt”: prompt,
“stream”: False
})
return response.json()[‘response’]
“`
LLM이 데이터를 보고 이렇게 답합니다: “500 에러는 총 156건이며, 새벽 3시~4시 사이에 47건(30%)이 집중되어 있습니다. 주로 `/api/bookmarks/search` 엔드포인트에서 발생했습니다.”
재미있는 점은 LLM이 **단순한 통계를 넘어 가설을 제시**한다는 것입니다. “이 시간대에 배치 작업이 실행되어 데이터베이스 커넥션이 부족했을 가능성이 있습니다”라는 식이죠. 물론 이 가설은 검증이 필요하지만, 어디를 봐야 할지 방향을 잡아준다는 것만으로 가치가 있습니다.
**핵심 주의사항**: 전체 로그를 LLM에 넣지 않습니다. 4GB짜리 로그를 토큰으로 변환하면 수억 토큰이 됩니다. 대신 통계 요약본만 넘깁니다. Pandas가 요약을 만들고, LLM이 해석을 더하는 구조입니다.
## 매일 자동 리포트 — cron + 이메일
이제 이걸 cron에 넣어서 매일 아침 자동으로 리포트를 받아봅니다. 목표는 아침에 커피 마시면서 어제 서버에서 무슨 일이 있었는지 한눈에 보는 것입니다.
“`python
#!/usr/bin/env python3
“””daily_log_report.py — 매일 실행되는 로그 분석 리포트”””
def generate_daily_report():
df = parse_nginx_log(‘/var/log/nginx/access.log’)
yesterday = (datetime.now() – timedelta(days=1)).date()
yesterday_df = df[df[‘time’].dt.date == yesterday]
metrics = {
“total_requests”: len(yesterday_df),
“unique_ips”: yesterday_df[‘ip’].nunique(),
“error_rate”: f”{len(yesterday_df[yesterday_df[‘status’].astype(int) >= 400]) / len(yesterday_df) * 100:.1f}%”,
“peak_hour”: yesterday_df.groupby(‘hour’).size().idxmax(),
}
insight = ask_llm_about_data(yesterday_df, “어제의 트래픽 패턴에서 주목할 점이 있어?”)
send_email(“VPS 일일 로그 리포트”, report, “admin@example.com”)
“`
“`bash
# crontab -e
0 8 * * * /home/user/venv/bin/python /home/user/scripts/daily_log_report.py
“`
매일 아침 8시에 실행되어 전날 로그를 분석하고 핵심 지표와 AI 인사이트를 이메일로 보냅니다. 이메일 대신 Slack webhook이나 Discord 채널로 보내면 팀 채널에서 실시간으로 서버 상태를 공유할 수 있습니다.
**주의**: LLM이 생성하는 인사이트는 참고용으로 보되, 맹신하면 안 됩니다. 가끔 데이터에 없는 사실을 그럴듯하게 말하기도 합니다. “이 시간대에 배치가 돌았을 것 같다”는 분석은 실제 crontab을 확인해서 검증해야 합니다.
## 이상 탐지 — AI가 비정상 패턴 잡아내기
일일 리포트는 좋은데, 문제는 “매일 확인해야” 한다는 것입니다. 더 나아가서 AI가 스스로 비정상을 감지하고 알림을 보내도록 만들 수 있습니다.
이상 탐지의 기본 아이디어는 **과거 데이터의 패턴에서 벗어나면 알림**을 주는 것입니다. 복잡한 머신러닝 모델도 가능하지만, 운영 환경에서는 단순한 통계적 임계값이 더 실용적일 때가 많습니다.
“`python
def detect_anomalies(df):
alerts = []
# 에러율 급증
error_rate = len(df[df[‘status’].astype(int) >= 500]) / len(df) * 100
if error_rate > 5:
alerts.append(f”500 에러율 {error_rate:.1f}% (임계값 5%)”)
# 특정 IP의 비정상적 요청 급증 (DDoS 의심)
ip_counts = df[‘ip’].value_counts()
suspicious = ip_counts[ip_counts > ip_counts.mean() * 50]
if len(suspicious) > 0:
for ip, count in suspicious.items():
alerts.append(f”비정상 트래픽: {ip} ({count}회)”)
# 404 급증 (스캐닝 공격 의심)
if len(df[df[‘status’].astype(int) == 404]) > 1000:
alerts.append(“404 급증 – 스캐닝 공격 의심”)
# LLM으로 종합 판단
if alerts:
response = ask_llm_about_data(df, f”이상 징후: {alerts}
우선순위와 대응 방법을 제안해줘”)
alerts.append(response)
return alerts
“`
이걸 1시간마다 실행되는 모니터링 스크립트로 만들면, 로그를 수동으로 확인하지 않아도 AI가 비정상을 감지하고 알림을 보냅니다. “문제가 터진 후에 로그를 보는” 것에서 “문제가 커지기 전에 AI가 알려주는” 것으로 패러다임이 바뀝니다.
## 정리
핵심은 **Pandas가 데이터를 처리하고, LLM이 의미를 해석하는** 분업 구조입니다. Pandas는 수백만 행을 빠르게 계산하고, LLM은 그 결과를 사람이 이해할 수 있는 인사이트로 바꿉니다. 두 도구를 연결하면 로그 분석이 더 이상 “시간 낭비”가 아니라 **매일 자동으로 들어오는 브리핑**이 됩니다.
처음부터 완벽하게 만들 필요는 없습니다. 먼저 Nginx 로그 하나만 Pandas로 불러와서 `value_counts()`를 해보세요. 거기서부터 시작하면 됩니다.
—
**관련 영상**: 이 글은 유튜브 영상의 보충 자료입니다. 영상에서 실제 데이터 파이프라인 구축 과정을 확인할 수 있습니다.



















