import 'dart:convert'; import 'dart:developer' as developer; import 'package:flutter/foundation.dart'; /// 디버깅을 위한 고급 로거 클래스 class DebugLogger { static const String _separator = '=================================================='; // 50개의 '=' /// 디버그 모드에서만 로그 출력 static void log( String message, { String? tag, Object? data, StackTrace? stackTrace, bool isError = false, }) { if (!kDebugMode) return; final timestamp = DateTime.now().toIso8601String(); final logTag = tag ?? 'DEBUG'; developer.log( ''' $_separator [$logTag] $timestamp $message ${data != null ? '\nData: ${_formatData(data)}' : ''} ${stackTrace != null ? '\nStackTrace:\n$stackTrace' : ''} $_separator ''', name: logTag, error: isError ? data : null, stackTrace: isError ? stackTrace : null, time: DateTime.now(), ); } /// API 요청 로깅 static void logApiRequest({ required String method, required String url, Map? headers, dynamic data, }) { log( 'API 요청', tag: 'API_REQUEST', data: { 'method': method, 'url': url, 'headers': headers, 'data': data, }, ); } /// API 응답 로깅 static void logApiResponse({ required String url, required int? statusCode, Map? headers, dynamic data, }) { log( 'API 응답', tag: 'API_RESPONSE', data: { 'url': url, 'statusCode': statusCode, 'headers': headers, 'data': data, }, ); } /// 에러 로깅 static void logError( String message, { Object? error, StackTrace? stackTrace, Map? additionalData, }) { log( '에러 발생: $message', tag: 'ERROR', data: { 'error': error?.toString(), 'additionalData': additionalData, }, stackTrace: stackTrace, isError: true, ); } /// 로그인 프로세스 전용 로깅 static void logLogin(String step, {Map? data}) { log( '로그인 프로세스: $step', tag: 'LOGIN', data: data, ); } /// 데이터 포맷팅 static String _formatData(Object data) { try { if (data is Map || data is List) { return const JsonEncoder.withIndent(' ').convert(data); } return data.toString(); } catch (e) { return data.toString(); } } /// 디버그 모드 확인 static bool get isDebugMode => kDebugMode; /// Assert를 사용한 런타임 검증 (디버그 모드에서만) static void assertValid( bool condition, String message, { Map? data, }) { assert(() { if (!condition) { logError('Assertion failed: $message', additionalData: data); } return condition; }(), message); } /// JSON 파싱 검증 및 로깅 static T? parseJsonWithLogging( dynamic json, T Function(Map) parser, { required String objectName, }) { try { if (json == null) { logError('$objectName 파싱 실패: JSON이 null입니다'); return null; } if (json is! Map) { logError( '$objectName 파싱 실패: 잘못된 JSON 형식', additionalData: { 'actualType': json.runtimeType.toString(), 'expectedType': 'Map', }, ); return null; } log( '$objectName 파싱 시작', tag: 'JSON_PARSE', data: json, ); final result = parser(json); log( '$objectName 파싱 성공', tag: 'JSON_PARSE', ); return result; } catch (e, stackTrace) { logError( '$objectName 파싱 중 예외 발생', error: e, stackTrace: stackTrace, additionalData: { 'json': json, }, ); return null; } } /// 응답 데이터 구조 검증 static bool validateResponseStructure( Map response, List requiredFields, { String? responseName, }) { final missing = []; for (final field in requiredFields) { if (!response.containsKey(field)) { missing.add(field); } } if (missing.isNotEmpty) { logError( '${responseName ?? 'Response'} 구조 검증 실패', additionalData: { 'missingFields': missing, 'actualFields': response.keys.toList(), }, ); return false; } log( '${responseName ?? 'Response'} 구조 검증 성공', tag: 'VALIDATION', ); return true; } }