热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Flutter项目开发之项目日志和错误捕获

使用框架的功能开发错误的捕获,可以写项目日志,可以记录设备信息,代码如下:import 'dart:io';import &#3

使用框架的功能开发错误的捕获,可以写项目日志,可以记录设备信息,代码如下:


import 'dart:io';
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart';
import 'package:device_info/device_info.dart';/// ### 记录项目日志、捕获项目错误、缓存所有记录、写入文件、上传服务器
/// * 初始化:
/// ```dart
/// ErrorLog.log = new ErrorLog(
/// reportZone: () async {
/// runApp(new MyApp());
/// },
/// debugMode: true,
/// uploadFile: (file) async {},
/// minutesWait: 30,
/// [fileName: 'error_log.txt']
/// );
/// ```
///
/// ### 项目日志
/// 默认标记的项目日志可以使用相应的方法;自定义标记的项目日志可以使用基础方法。
/// * 使用方式:
/// ```dart
/// ErrorLog.log.debug('msg'*8);
/// ErrorLog.log.info('msg'*8);
/// ErrorLog.log.warn('msg'*8);
/// ErrorLog.log.error('msg'*8);
/// ErrorLog.log.fatal('msg'*8);
/// ErrorLog.log.collectLog('msg'*8, 'error'); // 都是调用这个基础方法
/// ```
/// * 输出格式:
/// #### [2019-04-18 11:50:29.844858][error] msgmsgmsgmsgmsgmsgmsgmsg
///
/// ### 错误报告
/// 错误报告的信息比较多,标记为`report`。
/// * 使用方式:
/// 自动捕获错误,不包含 `try/catch`,不包含 `print`。
/// * 输出格式:
/// #### [2019-04-18 14:05:03.578755][report]
/// #### 所有错误信息
///
/// ### 写入文件
/// 所有记录都缓存在一个数组里,如果`debugMode`为真,打印到控制台;
/// 否则根据数组索引异步写入文件`error_log.txt`,在初始化时可传参`fileName`。
/// * 使用方式:
/// ```dart
/// ErrorLog.log.printBuffer(); // 打印记录缓存
/// ErrorLog.log.clearFile(); // 清空记录文件
/// ErrorLog.log.printFile(); // 打印文件内容
/// ```
///
/// ### 上传服务器
/// 打开应用时上传一次,然后设置计时器,建议30分钟上传一次。调试模式下,没有写入文件,不会调用上传接口。
/// * 使用方式:
/// 初始化时传参`uploadFile`和`minutesWait`,获取记录的文件`ErrorLog.log.logFile`。
///
/// ### 设备信息
/// 使用 [device_info](https://pub.dartlang.org/packages/device_info),应用启动时会获取和记录。
/// * 使用方式:
/// ```dart
/// await ErrorLog.log.getDeviceInfo(); // 异步返回设备信息
/// ```
/// * 输出格式:
/// 字符串,Future
/// #### [2019-04-24 10:05:11.413469][info] 设备信息 [device_info](https://pub.dartlang.org/packages/device_info)
/// #### [androidInfo] androidId: 1a08f53b320ccfef, ...
///
class ErrorLog {/// 实例,静态属性static ErrorLog log;/// 捕获错误的区域Function _reportZone;/// 是否调试模式bool _debugMode;/// 缓存记录的数组List _logBuffer;/// 文件记录File _logFile;File get logFile => _logFile;/// 文件记录的起点int _startIndex;/// 文件记录的终点int _endIndex;/// 上传记录文件Function _uploadFile;/// 上传时间间隔int _minutesWait;/// 记录文件是否变化bool _fileChange;/// 记录文件的名称String fileName;ErrorLog({@required Function reportZone, @required bool debugMode,@required Function uploadFile,@required int minutesWait,this.fileName = 'error_log.txt'}) {_reportZone = reportZone;_debugMode = debugMode;_uploadFile = uploadFile;_minutesWait = minutesWait;init();}/// 初始化void init() async {_logBuffer = [];_startIndex = 0;_endIndex = 0;_fileChange = false;FlutterError.onError = (FlutterErrorDetails details) {reportError(details);};runZoned(_reportZone, onError: (Object obj, StackTrace stack) {var details = makeDetails(obj, stack);reportError(details);});_logFile = await _getLocalFile();info('应用启动成功。');getDeviceInfo();if( !_debugMode ) _uploadFile(_logFile);Timer.periodic(Duration(minutes: _minutesWait), (timer) async {if ( _fileChange && !_debugMode ) {await _uploadFile(_logFile);_fileChange = false;}});}/// * 获取设备信息/// * [device_info](https://pub.dartlang.org/packages/device_info)Future getDeviceInfo() async {DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();String details = '设备信息[device_info](https://pub.dartlang.org/packages/device_info)\n ';try {IosDeviceInfo iosInfo = await deviceInfo.iosInfo;details += '[iosInfo] identifierForVendor: ${iosInfo.identifierForVendor}, ';details += 'isPhysicalDevice: ${iosInfo.isPhysicalDevice}, ';details += 'localizedModel: ${iosInfo.localizedModel}, ';details += 'model: ${iosInfo.model}, ';details += 'name: ${iosInfo.name}, ';details += 'systemName: ${iosInfo.systemName}, ';details += 'systemVersion: ${iosInfo.systemVersion}. ';details += '\n [iosInfo.utsname] machine: ${iosInfo.utsname.machine}, ';details += 'nodename: ${iosInfo.utsname.nodename}, ';details += 'release: ${iosInfo.utsname.release}, ';details += 'sysname: ${iosInfo.utsname.sysname}, ';details += 'version: ${iosInfo.utsname.version}. ';} catch(e) {error('无法获取 ios 设备信息。');}try {AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;details += '[androidInfo] androidId: ${androidInfo.androidId}, ';details += 'board: ${androidInfo.board}, ';details += 'bootloader: ${androidInfo.bootloader}, ';details += 'brand: ${androidInfo.brand}, ';details += 'device: ${androidInfo.device}, ';details += 'display: ${androidInfo.display}, ';details += 'fingerprint: ${androidInfo.fingerprint}, ';details += 'hardware: ${androidInfo.hardware}, ';details += 'host: ${androidInfo.host}, ';details += 'id: ${androidInfo.id}, ';details += 'isPhysicalDevice: ${androidInfo.isPhysicalDevice}, ';details += 'manufacturer: ${androidInfo.manufacturer}, ';details += 'model: ${androidInfo.model}, ';details += 'product: ${androidInfo.product}, ';details += 'supported32BitAbis: ${androidInfo.supported32BitAbis}, ';details += 'supported64BitAbis: ${androidInfo.supported64BitAbis}, ';details += 'supportedAbis: ${androidInfo.supportedAbis}, ';details += 'tags: ${androidInfo.tags}, ';details += 'type: ${androidInfo.type}. ';details += '\n [androidInfo.version] baseOS: ${androidInfo.version.baseOS}, ';details += 'codename: ${androidInfo.version.codename}, ';details += 'incremental: ${androidInfo.version.incremental}, ';details += 'previewSdkInt: ${androidInfo.version.previewSdkInt}, ';details += 'release: ${androidInfo.version.release}, ';details += 'sdkInt: ${androidInfo.version.sdkInt}, ';details += 'securityPatch: ${androidInfo.version.securityPatch}. ';} catch(e) {error('无法获取 android 设备信息。');}info(details);return details;}/// 错误报告void reportError(FlutterErrorDetails details) {String errorMeta = '[' + (new DateTime.now().toString()) + '][report]';_logBuffer.add(errorMeta + '\n' + details.toString());if (_debugMode) {print(errorMeta);print(details.toString());} else {_writeFile();}}/// 项目日志collectLog(String line, String label) {String contents = '[' + (new DateTime.now().toString()) + '][' + label + '] ' + line;_logBuffer.add(contents + '\n');if (_debugMode) {print(contents);} else {_writeFile();}}/// 打印文件Future printFile() async {_readLocalFile().then((contents) {print(contents);});}/// 打印缓存Future printBuffer() async {print( _logBuffer.toString() );}/// 清空文件Future clearFile() async {await _logFile.writeAsString('', mode: FileMode.write);}/// 实时写入文件,防止意外Future _writeFile() async {int len = _logBuffer.length;if (len > _endIndex) {_startIndex = _endIndex;_endIndex = len;Iterable range = _logBuffer.getRange(_startIndex, _endIndex);await _writeLocalFile( range.join('\n') );_fileChange = true;} }/// 获取文件Future _getLocalFile() async {String dir = (await getApplicationDocumentsDirectory()).path;return new File('$dir/' + fileName);}/// 读取文件Future _readLocalFile() async {String contents = await _logFile.readAsString();return contents;}/// 写入文件Future _writeLocalFile(String contents) async {await _logFile.writeAsString(contents, mode: FileMode.append, flush: false);}/// 构建错误信息FlutterErrorDetails makeDetails(Object obj, StackTrace stack) {return FlutterErrorDetails(exception: obj, stack: stack);}/// 调试void debug(String msg) {collectLog(msg, 'debug');}/// 信息void info(String msg) {collectLog(msg, 'info');}/// 警告void warn(String msg) {collectLog(msg, 'warn');}/// 错误void error(String msg) {collectLog(msg, 'error');}/// 致命错误void fatal(String msg) {collectLog(msg, 'fatal');}}

参考的文档:
文件操作
异常捕获
日志处理
设备信息

关联的公众号:三学子,满足您不一样的阅读需求。


推荐阅读
author-avatar
mobiledu2502891987
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有