返回博客首页
← 所有文章

跟踪 NativeScript 应用程序

2015 年 8 月 17 日 — 作者:John Bristowe

跟踪是在运行时记录应用程序诊断信息的过程。对于开发人员来说,这是一种非常有用的调试形式,因为它可以揭示有关应用程序内部工作原理的大量信息。这对于应用程序的非可视化部分(如网络和文件 I/O)尤其适用。跟踪使开发人员能够在运行时观察应用程序以识别问题。

但首先,简单介绍一下 Console 模块

在深入研究跟踪之前,让我们简要检查一下 console 模块,因为它被 NativeScript 的跟踪基础架构广泛使用。

控制台(或终端)并不是什么新鲜事物。我们已经使用它几十年了。

尽管用户界面发生了变化,但控制台在帮助开发人员调试代码方面仍然发挥着至关重要的作用。

在 NativeScript 中,console 模块提供用于将诊断输出记录到终端窗口的功能。大多数情况下,开发人员会使用 console 模块通过 console.log() 记录消息。

console.log("Hello, NativeScript!");

以下是生成的输出

2015-08-17-nativescript-console-output

请注意,我不必引用 console 模块本身。这是因为它属于全局作用域,可以在 NativeScript 应用程序内的任何位置访问它。

还值得一提的是,console 模块具有一系列有用的函数,您可以在跟踪 NativeScript 应用程序时使用它们。

  • console.time()console.timeEnd() 提供持续时间,这对于跟踪对时间敏感的操作(即性能)很有用。
  • console.trace() 将当前堆栈跟踪打印到控制台;在跟踪时提供上下文很有用。
  • console.dump() 打印对象的内部状态(目前仅限 Android)。

当您开始使用 NativeScript 的跟踪基础架构时,我强烈建议您在应用程序中考虑使用这些函数。

跟踪入门

NativeScript 的 trace 模块可用于记录您自己的应用程序及其使用的模块的信息。使用 NativeScript,核心设备功能数据用户界面WHATWG polyfill 模块都包含一定程度的跟踪,可以观察到。

默认情况下,跟踪处于禁用状态;必须通过其 enable() 方法显式启用它。

var trace = require("trace");
trace.enable(); // 跟踪已启用 -- 派对开始!

值得注意的是,您也可以通过其 disable() 方法禁用跟踪。

trace.disable(); // 跟踪已禁用 -- 扫兴的人!

启用跟踪后,任何调用 trace.write() 的代码或模块都会输出跟踪消息。

trace.write("I (heart) NativeScript!", trace.categories.Debug);

在我的应用程序中包含这行代码(上面)会在控制台中生成以下输出。

2015-08-11-nativescript-console-tracing-debug

trace.write() 方法接受三个 (3) 个参数。

  • message对象):这可以是任何内容,用于提供诊断信息。
  • category字符串):用于筛选跟踪消息的类别逗号分隔列表(稍后详细介绍)。
  • type数字):一个可选参数,用于表示正在输出的跟踪消息的类型(loginfowarnerror)。

在提供的示例(上面)中,我为跟踪消息提供了一个字符串,但我可以为更多上下文提供更详细的对象。

通过调用 trace.write() 生成所有跟踪消息都通过 TraceWriter 对象的集合写入。这些对象的目的是将跟踪消息写入特定输出(即文件)。trace 模块维护一个 TraceWriter 对象的集合,它将跟踪消息定向到这些对象。默认情况下,在初始化跟踪时,将向此集合中添加 ConsoleWriter。此写入器将通过 console 模块发出所有跟踪消息。有一组函数可用于控制此 TraceWriter 对象的集合。

  • trace.addWriter()TraceWriter 对象添加到跟踪写入器集合中。
  • trace.removeWriter() 从跟踪写入器集合中删除 TraceWriter 对象。
  • trace.clearWriters() 从跟踪写入器集合中删除所有 TraceWriter 对象。

目前,NativeScript 只有一个 TraceWriter 对象;ConsoleWriter。但是,没有任何东西可以阻止您编写自己的 TraceWriter

trace 模块提供了一种通过 setCategories() 方法过滤其输出的功能。这将强制 TraceWriter 对象的集合仅输出与您提供的类别列表匹配的写入语句。该方法参数是一个类别逗号分隔字符串,用于确定何时以及是否通过 TraceWriter 对象生成输出。trace 模块(本身)定义了以下预定义类别列表。

  • Animation:动画配置和事件的跟踪消息。
  • VisualTreeEvents:对可视化树进行修改时发生的事件的跟踪消息(仅限 Android)。
  • Layout:布局配置和事件的跟踪消息(即计算布局测量)。
  • Style:样式配置和事件的跟踪消息(即计算和应用样式)。
  • ViewHierarchy:视图修改时发生的事件的跟踪消息。
  • NativeLifecycle:修改本机框架时发生的事件的跟踪消息(仅限 Android)。
  • Debug:用于调试目的的跟踪消息;由 web-viewimage-cachetab-view 模块使用。
  • Navigation:导航事件的跟踪消息。
  • Test:在测试运行期间执行的测试的跟踪消息。
  • Binding:绑定事件的跟踪消息。
  • Error:运行时错误事件的跟踪消息(例如缺少字体文件)。
  • All:每个类别的跟踪消息。

这些类别(上面)由各种模块使用,因此在配置期间最好也使用它们。

必须提到的是,您不必使用预定义的类别(上面列出);您可以定义自己的类别。为此,只需定义您的类别,并确保在建立跟踪消息过滤器和调用 trace.write() 时一致地应用它,如下所示。

trace.setCategories("Questions");
trace.write("NativeScript: Great technology or the greatest technology?", "Questions");

应用此代码段(上面)会导致以下内容输出到控制台。

2015-08-11-nativescript-console-tracing-custom-category

您还可以通过 trace.addCategories() 方法将类别附加到现有集合中。或者,使用 trace.categories.concat() 方法构建您感兴趣的类别集合。

// 将绑定类别添加到现有的跟踪消息列表中。
trace.addCategories(trace.categories.Binding);
 
// 筛选除动画和调试类别外的所有跟踪消息。
trace.setCategories(trace.categories.concat(trace.categories.Animation, trace.categories.Debug));

如果您想更好地了解 NativeScript 的工作原理,请启用跟踪并指定 trace.categories.All 类别。当您执行此操作时,您将看到许多跟踪消息输出到控制台。

2015-08-11-nativescript-console-tracing

就像观看和理解香肠是如何制成的——以一种好的方式。

sneakers-console-output

编写自定义 TraceWriter

之前,我说过您可以编写自定义 TraceWriter。您可能希望执行此操作以将跟踪消息路由到控制台以外的特定输出。或者,您可能希望修改输出本身。假设我想在所有跟踪消息的开头添加一个时间戳。执行此操作将提供我可以在跟踪消息之间使用的时差。(注意:您可能会使用 timer 模块执行此操作,但现在让我们先这样处理。)我将首先定义一个名为 TimestampConsoleWriter 的自定义 TraceWriter

var TimestampConsoleWriter = (function () {
  function TimestampConsoleWriter() { }
  TimestampConsoleWriter.prototype.write = function (message, category, type) {
    if (!console) return;
 
    var msgType = types.isUndefined(type) ? trace.messageType.log : type;
    var traceMessage = new Date().toISOString() + " " + category + ": " + message;
 
    switch (msgType) {
      case trace.messageType.log:
        console.log(traceMessage);
        break;
      case trace.messageType.info:
        console.info(traceMessage);
        break;
      case trace.messageType.warn:
        console.warn(traceMessage);
        break;
      case trace.messageType.error:
        console.error(traceMessage);
        break;
    }
  };
  return TimestampConsoleWriter;
})();

由于我使用了**console**模块,因此我将清除我的TraceWriter对象集合,以移除ConsoleWriter。否则,每次调用trace.write()时,控制台都会输出多个跟踪消息。然后,我将**TimestampConsoleWriter**添加到TraceWriter对象的集合中。

trace.clearWriters();
trace.addWriter(new TimestampConsoleWriter());

此更改的结果是在控制台中显示以下输出

2015-08-11-nativescript-console-tracing-custom-trace-writer

如您所见,**trace**模块功能强大,因为您可以覆盖其默认行为,并通过自定义类别和TraceWriter对象来整合更改。

跟踪事件和事件监听器

**trace**模块还支持一种机制,可以通过事件通知在运行时跟踪您的NativeScript应用程序。这是一种强大的跟踪形式,因为它允许您将跟踪事件广播到实现EventListener接口的订阅者集合。事件监听器可以利用TraceWriter对象生成跟踪消息,或者它们可以处理事件通知中传达的信息并完全执行不同的操作。

以下是事件监听器的样板代码

var Listener = (function () {
  function Listener(filter) {
    this.filter = filter;
  }
  Listener.prototype.on = function (object, name, data) {
    // 验证参数并为 trace.notifyEvent() 执行某些操作
  };
  return Listener;
})();

on()方法是事件监听器响应接收事件通知时执行工作的地方,该通知通过对trace.notifyEvent()的调用传播(稍后将详细介绍)。filter属性是可选的,但应该包含它,因为它为**trace**模块提供了对通知哪些事件监听器的控制。就像TraceWriter对象的输出一样,除非启用了跟踪,否则不会通过trace.notifyEvent()通知事件监听器。

定义事件监听器后,下一步是通过trace.addEventListener()将其添加到**trace**模块中的事件监听器集合中。

var listener = new Listener("NativeScript Rocks!!11!");
trace.addEventListener(listener);

在代码(上文)中,我创建了一个新的事件监听器,它将接收名称为“NativeScript Rocks!!11!”的事件通知。除了添加事件监听器之外,我还可以通过trace.removeEventLister()将其移除。

事件监听器响应通过对trace.notifyEvent()的调用触发的事件通知。

var data = { /* ... */ };
trace.notifyEvent(this, "NativeScript Rocks!!11!", data);

trace.notifyEvent()方法接受三个(3)个参数

  • **object**(object):引发事件的对象实例
  • **name**(string):引发的事件的名称
  • **data**(object):一个可选参数,传递与事件关联的数据

当调用trace.notifyEvent()时,所有订阅了匹配名称/过滤器的事件监听器都会收到通知,并可以执行诸如记录到控制台等操作。

总结

更好地理解您的NativeScript应用程序在幕后是如何工作的,是构建用户喜爱的健壮应用程序的关键。**跟踪**模块提供了一些强大的机制,您可以使用这些机制来调试问题或验证假设。如果其他方法都不起作用,只需启用它就能更好地了解NativeScript的关键概念(如绑定或样式)是如何工作的。