import 'package:dio/dio.dart'; import 'package:firebase_crashlytics/firebase_crashlytics.dart'; class CrashlyticsInterceptor extends Interceptor { @override void onError(DioException err, ErrorInterceptorHandler handler) { FirebaseCrashlytics.instance.recordError( err, err.stackTrace, reason: _getErrorReason(err), information: _getErrorInformation(err), fatal: false, ); super.onError(err, handler); } String _getErrorReason(DioException err) { final statusCode = err.response?.statusCode; if (statusCode != null) { return 'HTTP $statusCode Error: ${err.requestOptions.uri.path}'; } switch (err.type) { case DioExceptionType.connectionTimeout: return 'Connection Timeout'; case DioExceptionType.sendTimeout: return 'Send Timeout'; case DioExceptionType.receiveTimeout: return 'Receive Timeout'; case DioExceptionType.connectionError: return 'Connection Error'; case DioExceptionType.cancel: return 'Request Cancelled'; default: return 'Network Error: ${err.type.name}'; } } List _getErrorInformation(DioException err) { return [ 'URL: ${err.requestOptions.uri}', 'Method: ${err.requestOptions.method}', 'Status Code: ${err.response?.statusCode ?? 'N/A'}', 'Error Type: ${err.type.name}', 'Message: ${err.message ?? 'No message'}', // Tambahan 'Request Data: ${_sanitizeData(err.requestOptions.data)}', 'Response Body: ${err.response?.data ?? 'No response'}', 'Headers: ${err.requestOptions.headers.entries.where((e) => e.key.toLowerCase() != 'authorization').toList()}', ]; } /// Hindari log data sensitif dynamic _sanitizeData(dynamic data) { if (data == null) return 'No data'; if (data is Map) { final sanitized = Map.from(data); const sensitiveKeys = [ 'password', 'token', 'secret', 'pin', 'card_number', ]; for (final key in sensitiveKeys) { if (sanitized.containsKey(key)) { sanitized[key] = '***'; } } return sanitized; } return data; } }