《Android应用开发攻略》——3.9 使用本地运行时应用程序日志分析现场错误情况

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 本节书摘来自华章计算机《Android应用开发攻略》一书中的第3章,第3.9节,作者:(美)达尔文(Darwin, I. F.)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

3.9 使用本地运行时应用程序日志分析现场错误情况

Atul Nene
3.9.1 问题
当用户报告了你认为不应该发生的情况时,往往应用程序的发布版本已经投放市场,你无法了解用户的环境中到底发生了什么,而缺陷报告提供的是一个“无法复制”的情景。
3.9.2 解决方案
为你的应用程序设计一个内建的机制,在这种情况下能够提供更多的细节。你知道重要的事件或者状态变化以及应用程序的资源需求,如果在应用程序的运行时日志中记录这些情况,日志就可以成为调查所报告的错误核心情况的又一个必需的资源。这种简单的预防手段和机制有助于减少因为不可预见的情况造成用户的抱怨,并且改进整体用户体验。
解决方案之一是使用标准的java.util.logging包。本攻略提供了一个RuntimeLog示例,使用java.util.logging写入设备上的一个日志文件,并且让开发人员能够全面控制记录的详细程度。
3.9.3 讨论
你已经设计、开发并且测试了应用程序,并将其发布到Android Market,因此你认为可以给自己放个假了。别着急!除了最简单的应用程序以外,开发人员无法在开发应用程序期间顾及所有可能的情境,开发时间也没有如此宽松,用户一定会报告某些预料之外的应用行为。这些行为不一定是缺陷;可能只是在测试中没有碰到的运行时情境。在应用程序中设计一个运行时应用程序日志机制,就能应对意外情况。
将应用程序中最重要的事件记录到日志中,例如,状态变化、资源超时(网络访问,线程等待)或者最高重试次数。甚至,可以防御性地记录异常情况下的代码路径执行,或者发送给用户的最重要通知。
警告: 只创建能够洞察应用程序工作情况的语句。否则,日志的尺寸本身就成为问题,虽然开发完毕的应用程序在运行时会忽略Log.d()调用,但是太多的日志语句仍然会使应用程序的速度降低。
注意: 你可能疑惑为什么不使用LogCat或者BugSense/ACRA来应对这一任务。这些解决方案无法满足需求的原因如下:
因为用户不太可能为其设备附加一个调试程序。代码中过多的Log.d和Log.i语句对应用程序性能有负面的影响。实际上,你在发布的应用程序中不应该编译Log.*语句。
ACRA/BugSense在设备连接到互联网时工作得很好,但是情况并非总是如此,除了ACRA之外,应用程序的一些类完全不需要互联网。而且,ACRA栈跟踪只提供抛出异常时的详情,而本攻略提供了应用程序运行中较长期的视图。
例3-5展示了RuntimeLog类。
例3-5:RuntimeLog类

//使用这些内建的机制
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class RuntimeLog {
  public static final int MODE_DEBUG = 1;
  public static final int MODE_RELEASE = 2;
  public static final int ERROR = 3;
  public static final int WARNING = 4;
  public static final int INFO = 5;
  public static final    int DEBUG = 6;
  public static final int VERBOSE = 7;
  //将模式修改为MODE_DEBUG,用于内部调试
  static boolean Mode = MODE_RELEASE;
  static logfileName = "/sdcard/YourAppName.log"
  static Logger logger;
  static LogRecord record;
  //在第一次使用类的时候实例化日志并创建自定义的格式化器
  static {
    try {
      FileHandler fh = new FileHandler(logfileName, true);
      fh.setFormatter(new Formatter() {
        public String format(LogRecord rec) {
          StringBuffer buf = new StringBuffer(1000);
          buf.append(new java.util.Date().getDate());
          buf.append('/');
          buf.append(new java.util.Date().getMonth());
          buf.append('/');
          buf.append((new java.util.Date().getYear())%100);
          buf.append(' ');
          buf.append(new java.util.Date().getHours());
          buf.append(':');
          buf.append(new java.util.Date().getMinutes());
          buf.append(':');
          buf.append(new java.util.Date().getSeconds());
          buf.append('\n');
          return buf.toString();
        }
      });
      logger = Logger.getLogger(logfileName);
      logger.addHandler(fh);
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }
  // 日志方法
  public static void log(int logLevel,String msg) {
    //在发行模式下不记录DEBUG和VERBOSE语句
    if (Mode == MODE_RELEASE) && (logLevel >= DEBUG))
      return;
    record=new LogRecord(Level.ALL, msg);
    record.setLoggerName(logfileName);
    try {
      switch(logLevel) {
        case ERROR:
          record.setLevel(Level.SEVERE);
          logger.log(record);
          break;
        case WARNING:
          record.setLevel(Level.WARNING);
          logger.log(record);
          break;
        case INFO:
          record.setLevel(Level.INFO);
          logger.log(record);
          break;
        //在某些API版本上FINE和FINEST级别可能无法正常工作,用INFO代替
        case DEBUG:
          record.setLevel(Level.INFO);
          logger.log(record);
          break;
        case VERBOSE:
          record.setLevel(Level.INFO);
          logger.log(record);
          break;
        }
      }
      catch(Exception exception) {
        exception.printStackTrace();
      }
   }
}

当然,有几个替代方案可供使用:
你可以使用相同的机制在开发应用程序时发现复杂的运行时问题。为此,将Mode变量设置为MODE_DEBUG。
对于具备许多模块的复杂应用,在日志调用中添加模块名为附加参数可能有用。
你还可以从LogRecord中提取ClassName和MethodName添加到日志语句中;但是不建议在运行时日志中这么做。
例3-6说明,这种机制的基本用法和常规的Log.d调用同样简单。
例3-6:使用RuntimeLog类

RuntimeLog.log (RuntimeLog.ERROR, "Network resource access request failed");
RuntimeLog.log (RuntimeLog.WARNING, "App changed state to STRANGE_STATE");
...

如果有必要,你可以要求用户从其SD卡中读取日志文件,并发送给你的支持团队。更好的办法是,编写代码,在按下某个按钮时完成这一任务!
下面是一些附加的注意事项:
这种机制不一定要处于“始终开启”的状态。你可以根据用户设置的配置选项记录日志,仅在最终用户试图重现某种情景的时候启用它。
如果日志始终开启,用当前日期(在应用程序启动时确定)命名日志文件,删除某个日期之前确实不再使用的旧日志,这能够有效地控制日志文件的大小。
3.9.4 参阅
ACRA网站;攻略3.7;攻略3.8

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
3月前
|
存储 Android开发
如何查看Flutter应用在Android设备上已被撤销的权限?
如何查看Flutter应用在Android设备上已被撤销的权限?
205 64
|
4月前
|
存储 缓存 监控
【YashanDB数据库】数据库运行正常,日志出现大量错误metadata changed
数据库运行正常,日志出现大量错误metadata changed
|
3月前
|
缓存 Android开发 开发者
Flutter环境配置完成后,如何在Android设备上运行Flutter应用程序?
Flutter环境配置完成后,如何在Android设备上运行Flutter应用程序?
578 62
|
3月前
|
开发工具 Android开发 开发者
在Android设备上运行Flutter应用程序时,如果遇到设备未授权的问题该如何解决?
在Android设备上运行Flutter应用程序时,如果遇到设备未授权的问题该如何解决?
222 61
|
23天前
|
JSON 移动开发 Java
ArkUI-X通过Stage模型开发Android端应用指南(二)
本文介绍了StageApplication的三种初始化方式及Ability与原生Activity之间的交互方法。包括通过继承StageApplication、使用StageApplicationDelegate,以及在Activity中初始化;还详细说明了如何通过Intent传递参数,支持手动构建JSON或使用WantParams工具类,并列举了支持的数据类型和注意事项。
|
23天前
|
开发工具 Android开发 开发者
ArkUI-X通过Stage模型开发Android端应用指南(一)
本文介绍了如何将ArkUI框架扩展至Android平台,开发者可基于OpenHarmony复用应用代码并部署到Android,降低跨端开发成本,并详解了关键类及配置方法。
|
28天前
|
监控 安全 Linux
AWK在网络安全中的高效应用:从日志分析到威胁狩猎
本文深入探讨AWK在网络安全中的高效应用,涵盖日志分析、威胁狩猎及应急响应等场景。通过实战技巧,助力安全工程师将日志分析效率提升3倍以上,构建轻量级监控方案。文章详解AWK核心语法与网络安全专用技巧,如时间范围分析、多条件过滤和数据脱敏,并提供性能优化与工具集成方案。掌握AWK,让安全工作事半功倍!
39 0
|
4月前
|
存储 监控 算法
基于 PHP 语言的滑动窗口频率统计算法在公司局域网监控电脑日志分析中的应用研究
在当代企业网络架构中,公司局域网监控电脑系统需实时处理海量终端设备产生的连接日志。每台设备平均每分钟生成 3 至 5 条网络请求记录,这对监控系统的数据处理能力提出了极高要求。传统关系型数据库在应对这种高频写入场景时,性能往往难以令人满意。故而,引入特定的内存数据结构与优化算法成为必然选择。
98 3
|
4月前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
5月前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
313 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex

热门文章

最新文章