Files
rogaining_srv/analyze_nginx_logs.py
2025-09-06 02:29:47 +09:00

220 lines
7.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
nginxログ分析: チェックイン・画像アップロード機能の使用状況を確認
"""
import subprocess
import re
from collections import defaultdict, Counter
from datetime import datetime
def analyze_nginx_logs():
"""
nginxログを分析してチェックイン・画像関連の活動を確認
"""
print("🔍 nginx ログ分析: チェックイン・画像アップロード機能")
print("=" * 70)
# nginxログを取得
try:
result = subprocess.run(
['docker-compose', 'logs', '--tail=500', 'nginx'],
capture_output=True,
text=True,
cwd='/Volumes/PortableSSD1TB/main/GifuTabi/rogaining_srv_exdb-2/rogaining_srv'
)
if result.returncode != 0:
print(f"❌ ログ取得エラー: {result.stderr}")
return
log_lines = result.stdout.split('\n')
except Exception as e:
print(f"❌ 実行エラー: {e}")
return
# 分析用パターン
patterns = {
'checkin_api': re.compile(r'(POST|GET).*/(checkin_from_rogapp|checkin|addCheckin)', re.I),
'image_api': re.compile(r'(POST|GET).*/checkinimage', re.I),
'bulk_upload': re.compile(r'(POST|GET).*/bulk_upload', re.I),
'dart_client': re.compile(r'"Dart/[\d\.]+ \(dart:io\)"'),
'api_access': re.compile(r'"(GET|POST|PUT|PATCH|DELETE) (/api/[^"]+)'),
'status_codes': re.compile(r'" (\d{3}) \d+')
}
# 分析結果
results = {
'checkin_requests': [],
'image_requests': [],
'bulk_upload_requests': [],
'dart_requests': [],
'api_endpoints': Counter(),
'status_codes': Counter(),
'client_ips': Counter()
}
# ログ行の解析
for line in log_lines:
if not line.strip() or 'nginx-1' not in line:
continue
# 各パターンをチェック
if patterns['checkin_api'].search(line):
results['checkin_requests'].append(line)
if patterns['image_api'].search(line):
results['image_requests'].append(line)
if patterns['bulk_upload'].search(line):
results['bulk_upload_requests'].append(line)
if patterns['dart_client'].search(line):
results['dart_requests'].append(line)
# APIエンドポイント集計
api_match = patterns['api_access'].search(line)
if api_match:
method, endpoint = api_match.groups()
results['api_endpoints'][f"{method} {endpoint}"] += 1
# ステータスコード集計
status_match = patterns['status_codes'].search(line)
if status_match:
results['status_codes'][status_match.group(1)] += 1
# クライアントIP集計
ip_match = re.search(r'(\d+\.\d+\.\d+\.\d+) - -', line)
if ip_match:
results['client_ips'][ip_match.group(1)] += 1
# 結果表示
print_analysis_results(results)
def print_analysis_results(results):
"""
分析結果を表示
"""
# 1. チェックインAPI使用状況
print(f"\n📍 チェックインAPI アクセス状況")
print("-" * 50)
if results['checkin_requests']:
print(f"件数: {len(results['checkin_requests'])}")
for req in results['checkin_requests'][-5:]: # 最新5件
print(f" {extract_log_info(req)}")
else:
print("❌ チェックインAPIへのアクセスなし")
# 2. 画像アップロードAPI使用状況
print(f"\n🖼️ 画像アップロードAPI アクセス状況")
print("-" * 50)
if results['image_requests']:
print(f"件数: {len(results['image_requests'])}")
for req in results['image_requests'][-5:]: # 最新5件
print(f" {extract_log_info(req)}")
else:
print("❌ 画像アップロードAPIへのアクセスなし")
# 3. 一括アップロードAPI使用状況
print(f"\n📤 一括アップロードAPI アクセス状況")
print("-" * 50)
if results['bulk_upload_requests']:
print(f"件数: {len(results['bulk_upload_requests'])}")
for req in results['bulk_upload_requests'][-5:]: # 最新5件
print(f" {extract_log_info(req)}")
else:
print("❌ 一括アップロードAPIへのアクセスなし")
# 4. Dartクライアントスマホアプリの活動
print(f"\n📱 スマホアプリDartアクセス状況")
print("-" * 50)
if results['dart_requests']:
print(f"件数: {len(results['dart_requests'])}")
# Dartクライアントが使用しているAPIエンドポイント
dart_endpoints = Counter()
for req in results['dart_requests']:
api_match = re.search(r'"(GET|POST|PUT|PATCH|DELETE) (/api/[^"]+)', req)
if api_match:
method, endpoint = api_match.groups()
dart_endpoints[f"{method} {endpoint}"] += 1
print("主要なAPIエンドポイント:")
for endpoint, count in dart_endpoints.most_common(10):
print(f" {endpoint}: {count}")
else:
print("❌ スマホアプリからのアクセスなし")
# 5. 全体のAPI使用状況Top 10
print(f"\n🌐 API使用状況 (Top 10)")
print("-" * 50)
for endpoint, count in results['api_endpoints'].most_common(10):
print(f" {endpoint}: {count}")
# 6. HTTPステータスコード分布
print(f"\n📊 HTTPステータスコード分布")
print("-" * 50)
for status, count in results['status_codes'].most_common():
status_emoji = get_status_emoji(status)
print(f" {status_emoji} {status}: {count}")
# 7. クライアントIP分布
print(f"\n🌍 アクセス元IP分布")
print("-" * 50)
for ip, count in results['client_ips'].most_common(5):
ip_type = "🏠 ローカル" if ip.startswith(('192.168', '172.', '127.')) else "🌐 外部"
print(f" {ip_type} {ip}: {count}")
def extract_log_info(log_line):
"""
ログ行から重要な情報を抽出
"""
# 時刻を抽出
time_match = re.search(r'\[([^\]]+)\]', log_line)
time_str = time_match.group(1) if time_match else "Unknown"
# メソッドとパスを抽出
method_match = re.search(r'"(GET|POST|PUT|PATCH|DELETE) ([^"]+)', log_line)
method_path = method_match.groups() if method_match else ("Unknown", "Unknown")
# ステータスコードを抽出
status_match = re.search(r'" (\d{3}) \d+', log_line)
status = status_match.group(1) if status_match else "Unknown"
# User Agentを抽出
ua_match = re.search(r'"([^"]+)" "[^"]*"$', log_line)
user_agent = ua_match.group(1) if ua_match else "Unknown"
return f"{time_str} | {method_path[0]} {method_path[1][:50]}... | {status} | {user_agent[:20]}..."
def get_status_emoji(status_code):
"""
HTTPステータスコードに対応する絵文字を返す
"""
if status_code.startswith('2'):
return ''
elif status_code.startswith('3'):
return '🔀'
elif status_code.startswith('4'):
return ''
elif status_code.startswith('5'):
return '💥'
else:
return ''
def main():
try:
analyze_nginx_logs()
print(f"\n✅ 分析完了")
print(f"\n💡 結論:")
print(f" ログから、チェックイン・画像アップロード機能の実際の使用状況を確認できます")
print(f" スマホアプリDartの活動状況も把握可能です")
except Exception as e:
print(f"❌ エラー: {e}")
if __name__ == '__main__':
main()