热门标签 | 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');}}

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

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


推荐阅读
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • Netty源代码分析服务器端启动ServerBootstrap初始化
    本文主要分析了Netty源代码中服务器端启动的过程,包括ServerBootstrap的初始化和相关参数的设置。通过分析NioEventLoopGroup、NioServerSocketChannel、ChannelOption.SO_BACKLOG等关键组件和选项的作用,深入理解Netty服务器端的启动过程。同时,还介绍了LoggingHandler的作用和使用方法,帮助读者更好地理解Netty源代码。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • 本文介绍了一个React Native新手在尝试将数据发布到服务器时遇到的问题,以及他的React Native代码和服务器端代码。他使用fetch方法将数据发送到服务器,但无法在服务器端读取/获取发布的数据。 ... [详细]
  • 开源Keras Faster RCNN模型介绍及代码结构解析
    本文介绍了开源Keras Faster RCNN模型的环境需求和代码结构,包括FasterRCNN源码解析、RPN与classifier定义、data_generators.py文件的功能以及损失计算。同时提供了该模型的开源地址和安装所需的库。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 1简介本文结合数字信号处理课程和Matlab程序设计课程的相关知识,给出了基于Matlab的音乐播放器的总体设计方案,介绍了播放器主要模块的功能,设计与实现方法.我们将该设 ... [详细]
  • 使用Flutternewintegration_test进行示例集成测试?回答首先在dev下的p ... [详细]
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社区 版权所有