远程遥控开发中
This commit is contained in:
22
lib/core/infrastructure/logging/app_bloc_observer.dart
Normal file
22
lib/core/infrastructure/logging/app_bloc_observer.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../logging/i_logger_service.dart';
|
||||
|
||||
class AppBlocObserver extends BlocObserver {
|
||||
final ILoggerService logger;
|
||||
AppBlocObserver(this.logger);
|
||||
|
||||
@override
|
||||
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
|
||||
super.onError(bloc, error, stackTrace);
|
||||
logger.captureException(error, stackTrace: stackTrace);
|
||||
}
|
||||
|
||||
@override
|
||||
void onChange(BlocBase bloc, Change change) {
|
||||
super.onChange(bloc, change);
|
||||
logger.addBreadcrumb(
|
||||
'Bloc State Change',
|
||||
category: bloc.runtimeType.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
111
lib/core/infrastructure/logging/sentry_logger_impl.dart
Normal file
111
lib/core/infrastructure/logging/sentry_logger_impl.dart
Normal file
@@ -0,0 +1,111 @@
|
||||
// lib/core/infrastructure/logging/sentry_logger_impl.dart
|
||||
import 'dart:io';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
import '../../env/env_config.dart';
|
||||
import '../../logging/i_logger_service.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class SentryLoggerImpl implements ILoggerService {
|
||||
File? _localLogFile;
|
||||
|
||||
@override
|
||||
Future<void> init() async {
|
||||
await SentryFlutter.init((options) {
|
||||
options.dsn = EnvConfig.sentryDsn;
|
||||
options.environment = EnvConfig.environment;
|
||||
// 生产环境只采样 20% 的性能数据,测试环境全开
|
||||
options.tracesSampleRate = EnvConfig.isProduction ? 0.2 : 1.0;
|
||||
});
|
||||
await _collectDeviceInfo();
|
||||
|
||||
await _prepareLocalFile();
|
||||
}
|
||||
|
||||
// 准备本地文件路径
|
||||
Future<void> _prepareLocalFile() async {
|
||||
try {
|
||||
final directory = await getApplicationDocumentsDirectory();
|
||||
// 按天生成文件名,例如: 2024-05-20_logs.txt
|
||||
final fileName =
|
||||
"${DateFormat('yyyy-MM-dd').format(DateTime.now())}_logs.txt";
|
||||
_localLogFile = File('${directory.path}/$fileName');
|
||||
|
||||
if (!await _localLogFile!.exists()) {
|
||||
await _localLogFile!.create(recursive: true);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("无法创建本地日志文件: $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _collectDeviceInfo() async {
|
||||
final deviceInfo = DeviceInfoPlugin();
|
||||
Sentry.configureScope((scope) async {
|
||||
if (Platform.isAndroid) {
|
||||
final android = await deviceInfo.androidInfo;
|
||||
scope.setTag('device_model', android.model);
|
||||
scope.setTag('os_version', android.version.release);
|
||||
} else if (Platform.isIOS) {
|
||||
final ios = await deviceInfo.iosInfo;
|
||||
scope.setTag('device_model', ios.utsname.machine);
|
||||
scope.setTag('os_version', ios.systemVersion);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void captureException(dynamic exception, {dynamic stackTrace}) {
|
||||
Sentry.captureException(exception, stackTrace: stackTrace);
|
||||
}
|
||||
|
||||
@override
|
||||
void log(
|
||||
String message, {
|
||||
bool isWarning = false,
|
||||
Map<String, dynamic>? data,
|
||||
}) {
|
||||
final timestamp = DateTime.now().toIso8601String();
|
||||
final level = isWarning ? 'WARNING' : 'INFO';
|
||||
final logEntry = "[$timestamp] [$level] $message ${data ?? ''}\n";
|
||||
|
||||
// 1.发送日志到 Sentry
|
||||
Sentry.captureMessage(
|
||||
message,
|
||||
level: isWarning ? SentryLevel.warning : SentryLevel.info,
|
||||
);
|
||||
|
||||
// 2.写入本地文件
|
||||
_writeToLocalFile(logEntry);
|
||||
|
||||
if (kDebugMode) {
|
||||
debugPrint(logEntry);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _writeToLocalFile(String entry) async {
|
||||
try {
|
||||
// 使用追加模式写入
|
||||
await _localLogFile?.writeAsString(entry, mode: FileMode.append);
|
||||
} catch (e) {
|
||||
// 本地写入失败不应崩溃
|
||||
}
|
||||
}
|
||||
|
||||
// 增加一个获取本地日志文件路径的方法,方便你以后做“导出日志”功能
|
||||
Future<String?> getLocalLogPath() async {
|
||||
return _localLogFile?.path;
|
||||
}
|
||||
|
||||
@override
|
||||
void addBreadcrumb(String message, {String? category}) {
|
||||
Sentry.addBreadcrumb(Breadcrumb(message: message, category: category));
|
||||
}
|
||||
|
||||
@override
|
||||
void setUser(String userId) {
|
||||
Sentry.configureScope((scope) => scope.setUser(SentryUser(id: userId)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user