167 lines
6.4 KiB
Python
167 lines
6.4 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""
|
|||
|
|
スマホアプリエラー監視ツール: リアルタイムで400エラーを監視
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import subprocess
|
|||
|
|
import re
|
|||
|
|
import time
|
|||
|
|
from datetime import datetime
|
|||
|
|
import json
|
|||
|
|
|
|||
|
|
def monitor_app_errors():
|
|||
|
|
"""
|
|||
|
|
スマホアプリの400エラーをリアルタイム監視
|
|||
|
|
"""
|
|||
|
|
print("🔍 スマホアプリエラー監視開始")
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("Ctrl+C で停止")
|
|||
|
|
print()
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# docker compose logs --follow で継続監視
|
|||
|
|
process = subprocess.Popen(
|
|||
|
|
['docker', 'compose', 'logs', '--follow', 'app'],
|
|||
|
|
stdout=subprocess.PIPE,
|
|||
|
|
stderr=subprocess.PIPE,
|
|||
|
|
text=True,
|
|||
|
|
bufsize=1,
|
|||
|
|
universal_newlines=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
error_patterns = {
|
|||
|
|
'checkin_400': re.compile(r'Bad Request.*checkin_from_rogapp', re.I),
|
|||
|
|
'member_400': re.compile(r'Bad Request.*members', re.I),
|
|||
|
|
'team_400': re.compile(r'Bad Request.*teams', re.I),
|
|||
|
|
'validation_error': re.compile(r'Validation error.*({.*})', re.I),
|
|||
|
|
'checkin_start_error': re.compile(r'Team has not started yet.*team_name: \'([^\']+)\'.*cp_number: (\d+)', re.I),
|
|||
|
|
'dart_request': re.compile(r'Dart/\d+\.\d+.*"([A-Z]+)\s+([^"]+)".*(\d{3})', re.I)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
print(f"🎯 監視対象パターン:")
|
|||
|
|
for name, pattern in error_patterns.items():
|
|||
|
|
print(f" • {name}")
|
|||
|
|
print()
|
|||
|
|
|
|||
|
|
while True:
|
|||
|
|
line = process.stdout.readline()
|
|||
|
|
if not line:
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
timestamp = datetime.now().strftime("%H:%M:%S")
|
|||
|
|
|
|||
|
|
# Dartクライアント(スマホアプリ)のリクエスト監視
|
|||
|
|
dart_match = error_patterns['dart_request'].search(line)
|
|||
|
|
if dart_match and 'Dart/' in line:
|
|||
|
|
method = dart_match.group(1)
|
|||
|
|
path = dart_match.group(2)
|
|||
|
|
status = dart_match.group(3)
|
|||
|
|
|
|||
|
|
if status.startswith('4'): # 4xx エラー
|
|||
|
|
print(f"❌ [{timestamp}] スマホアプリエラー: {method} {path} → HTTP {status}")
|
|||
|
|
elif status.startswith('2'): # 2xx 成功
|
|||
|
|
if any(keyword in path.lower() for keyword in ['checkin', 'teams', 'members']):
|
|||
|
|
print(f"✅ [{timestamp}] スマホアプリ成功: {method} {path} → HTTP {status}")
|
|||
|
|
|
|||
|
|
# チェックインスタートエラー監視
|
|||
|
|
start_error_match = error_patterns['checkin_start_error'].search(line)
|
|||
|
|
if start_error_match:
|
|||
|
|
team_name = start_error_match.group(1)
|
|||
|
|
cp_number = start_error_match.group(2)
|
|||
|
|
print(f"⚠️ [{timestamp}] チェックインエラー: チーム'{team_name}'がCP{cp_number}でスタート前チェックイン試行")
|
|||
|
|
print(f" 💡 解決策: 先にstart_from_rogappでスタート処理が必要")
|
|||
|
|
|
|||
|
|
# バリデーションエラー監視
|
|||
|
|
validation_match = error_patterns['validation_error'].search(line)
|
|||
|
|
if validation_match:
|
|||
|
|
try:
|
|||
|
|
error_details = validation_match.group(1)
|
|||
|
|
print(f"❌ [{timestamp}] バリデーションエラー: {error_details}")
|
|||
|
|
if 'date_of_birth' in error_details:
|
|||
|
|
print(f" 💡 date_of_birthフィールドの問題 - MemberCreationSerializerを確認")
|
|||
|
|
except:
|
|||
|
|
print(f"❌ [{timestamp}] バリデーションエラー詳細を解析できませんでした")
|
|||
|
|
|
|||
|
|
# 一般的な400エラー監視
|
|||
|
|
for pattern_name, pattern in error_patterns.items():
|
|||
|
|
if pattern_name in ['dart_request', 'checkin_start_error', 'validation_error']:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
if pattern.search(line):
|
|||
|
|
print(f"❌ [{timestamp}] {pattern_name}: {line.strip()}")
|
|||
|
|
|
|||
|
|
except KeyboardInterrupt:
|
|||
|
|
print(f"\n\n🛑 監視を停止しました")
|
|||
|
|
process.terminate()
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"❌ 監視エラー: {e}")
|
|||
|
|
if 'process' in locals():
|
|||
|
|
process.terminate()
|
|||
|
|
|
|||
|
|
def analyze_current_issues():
|
|||
|
|
"""
|
|||
|
|
現在の問題を分析
|
|||
|
|
"""
|
|||
|
|
print("📊 現在の問題分析")
|
|||
|
|
print("-" * 40)
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# 最近のエラーログを分析
|
|||
|
|
result = subprocess.run(
|
|||
|
|
['docker', 'compose', 'logs', '--tail=100', 'app'],
|
|||
|
|
capture_output=True,
|
|||
|
|
text=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
lines = result.stdout.split('\n')
|
|||
|
|
|
|||
|
|
# チェックインエラーの分析
|
|||
|
|
checkin_errors = []
|
|||
|
|
validation_errors = []
|
|||
|
|
|
|||
|
|
for line in lines:
|
|||
|
|
if 'Team has not started yet' in line:
|
|||
|
|
match = re.search(r'team_name: \'([^\']+)\'.*cp_number: (\d+)', line)
|
|||
|
|
if match:
|
|||
|
|
checkin_errors.append((match.group(1), match.group(2)))
|
|||
|
|
|
|||
|
|
if 'Validation error' in line and 'date_of_birth' in line:
|
|||
|
|
validation_errors.append(line)
|
|||
|
|
|
|||
|
|
print(f"🔍 分析結果:")
|
|||
|
|
print(f" • チェックインスタートエラー: {len(checkin_errors)}件")
|
|||
|
|
for team, cp in checkin_errors[-3:]: # 最新3件
|
|||
|
|
print(f" - チーム'{team}' → CP{cp}")
|
|||
|
|
|
|||
|
|
print(f" • date_of_birthバリデーションエラー: {len(validation_errors)}件")
|
|||
|
|
|
|||
|
|
if checkin_errors:
|
|||
|
|
print(f"\n💡 推奨対策:")
|
|||
|
|
print(f" 1. スマホアプリでスタート処理を実行")
|
|||
|
|
print(f" 2. start_from_rogapp API の正常動作確認")
|
|||
|
|
|
|||
|
|
if validation_errors:
|
|||
|
|
print(f" 3. MemberCreationSerializerの再確認")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"❌ 分析エラー: {e}")
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
"""
|
|||
|
|
メイン関数
|
|||
|
|
"""
|
|||
|
|
print("📱 スマホアプリエラー監視ツール")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
choice = input("選択してください:\n1. リアルタイム監視\n2. 現在の問題分析\n選択 (1/2): ")
|
|||
|
|
|
|||
|
|
if choice == "1":
|
|||
|
|
monitor_app_errors()
|
|||
|
|
elif choice == "2":
|
|||
|
|
analyze_current_issues()
|
|||
|
|
else:
|
|||
|
|
print("無効な選択です")
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|