Android 系列 3.10使用本地运行时应用程序日志来分析字段错误或情境

263 篇文章 2 订阅
164 篇文章 0 订阅
3.10使用本地运行时应用程序日志来分析字段错误或情境


问题
用户报告了你的应用程序,你不认为应该发生的事情,但现在的发布模式应用程序是在市场上,你没有办法找出在用户的环境中发生了什么,错误报告最终在一个“不能再现”的场景。

LogCat输出是伟大的,尽管它是,但更长期的日志记录机制将在某些情况下更有用。为您的应用程序设计一个内置的机制,在这种情况下提供额外的洞察力。您知道应用程序的重要事件或状态更改和资源需求,并且如果您将它们记录在来自应用程序的运行时应用程序日志中,则日志将成为额外的急需的资源,这是所报告和调查的问题的核心。这种简单的预防措施和机制在减少由不可预见的情况引起的低用户评级方面发挥了很大的作用,并提高了整体用户体验的质量。
一个解决方案是使用Java标准java.util.logging包。该配方提供了一个示例RuntimeLog,它使用java.util.logging写入设备上的日志文件,并给予开发人员对记录的详细程度的广泛控制。
讨论
您已经设计,开发和测试了您的应用程序,并在Android Market上发布,所以现在您认为您可以度假。不是很快!除了最简单的情况,在应用程序测试期间,不能处理所有可能的情况,用户必须报告一些意想不到的应用程序行为。它不一定是一个bug;它可能只是一个在测试中没有遇到的运行时情况。通过在应用程序中设计运行时应用程序日志机制,提前为此做好准备。
从应用程序记录最重要的事件 - 例如,状态更改,资源超时(网络访问,线程等待)或最大重试次数。甚至可能值得在奇怪的情况下防御性地记录意外的代码路径执行,或者发送给用户的一些最重要的通知。
只创建日志语句,将提供洞察应用程序如何工作。否则,大量的日志本身可能会成为一个问题,而且在运行时在被签名的应用程序中忽略Log.d()调用,太多的日志语句可能会减慢应用程序的速度。
实施例3-8。 Sidebar:为什么不使用LogCat?
你可能想知道为什么我们不使用LogCat,或者BugSense和ACRA之类的工具来处理这个任务。这些解决方案在所有情况下不足以满足以下原因:
•标准LogCat机制在最终用户运行时场景中无用,因为用户不太可能具有将调试器附加到他的设备的能力。代码中的Log.d和Log.i语句过多可能会对应用程序性能造成负面影响。实际上,由于这个原因,你不应该将Log。*语句编译到已发布的应用程序中。
•当设备连接到Internet时,ACRA和BugSense等工具运行良好。这可能不总是真实的,并且某些类别的应用可能不需要互联网,除了ACRA。此外,ACRA堆栈跟踪仅提供抛出异常时的详细信息(在堆栈跟踪中),而此配方在应用程序运行时提供较长期的视图。
RuntimeLog类在示例3-9中显示。

实施例3-9。 RuntimeLog类

import java.util.logging.*;
/** Run-time file-based logging, using standard java.util.logging (JUL).
* It is REALLY too bad that JUL was added before Java enums!
*/
public class RuntimeLog {
// The JUL Log Levels are:
// SEVERE (highest value)
// WARNING
// INFO
// CONFIG
// FINE
// FINER
// FINEST (lowest value)
// Change this to MODE_DEBUG to use for in-house debugging
enum Mode {
MODE_DEBUG,
MODE_RELEASE
}
private static final Mode mode = Mode.MODE_RELEASE;
private static String logfileName = "/sdcard/YourAppName.log";
private static Logger logger;
// initialize the log on first use of the class and
// create a custom log formatter
static {
try {
FileHandler fh = new FileHandler(logfileName, true);
fh.setFormatter(new Formatter() {
public String format(LogRecord rec) {
java.util.Date date = new java.util.Date();
return new StringBuffer(1000)
.append((date.getYear())).append('/')
.append(date.getMonth()).append('/')
.append(date.getDate())
.append(' ')
.append(date.getHours())
.append(':')
.append(date.getMinutes()).append(':')
.append(date.getSeconds())
.append('\n')
.toString();
}
});
logger = Logger.getLogger(logfileName);
logger.addHandler(fh);
}
catch (IOException e) {
e.printStackTrace();
}
}
// the log method
public static void log(Level logLevel, String msg) {
//don't log DEBUG and VERBOSE statements in release mode
if (mode == Mode.MODE_RELEASE &&
logLevel.intValue() >= Level.FINE.intValue())
return;
final LogRecord record = new LogRecord(logLevel, msg);
record.setLoggerName(logfileName);
logger.log(record);
}
/**
* Reveal the logfile path, so part of your app can read the
* logfile and either email it to you, or
* upload it to your server via REST
* @return
*/
public static String getFileName() {
return logfileName;
}
}

此代码具有在生产模式下自动删除详细级别日志调用的优点。当然,有可能使用的变化:
•在开发应用程序时,您可以使用相同的机制来发现复杂的运行时问题。为此,将Mode变量设置为MODE_DEBUG。
•对于具有许多模块的复杂应用程序,将模块名称作为附加参数添加到日志调用中可能很有用。
•您还可以从LogRecord中提取ClassName和MethodName,并将它们添加到日志语句中;但是,不建议对运行时日志执行此操作。
例3-10显示了这个工具的基本使用和普通的Log.d调用一样简单。
实施例3-10。使用RuntimeLog类
RuntimeLog.log(Level.ERROR,“网络资源访问请求失败”);
RuntimeLog.log(Level.WARNING,“App changed state to STRANGE_STATE”);
... ...
文件名不应该硬编码,但应该获得如在???。甚至更好的是,创建一个目录,使用日志文件轮换(删除比某个时期更早的日志文件,认为不再有用)。以限制日志文件的磁盘存储。
要允许用户从他们的设备卡发送日志文件到您的支持团队,您肯定要编写代码来执行自动化,使用getLogfileName()方法访问该文件。或者,您可以使用与崩溃记录器相同的Java语言钩子,并在检测到应用程序崩溃时自动发送文件。
该机制不必处于“始终开启”状态。您可以根据用户可设置的配置选项进行日志记录,并仅在最终用户尝试重现问题情况时启用它。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值