diff --git a/analyze_nginx_logs.py b/analyze_nginx_logs.py new file mode 100644 index 0000000..391e69d --- /dev/null +++ b/analyze_nginx_logs.py @@ -0,0 +1,219 @@ +#!/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()