鸿蒙开源第三方组件—日志工具组件Timber_ohos

系统
Timber_ohos是一个带有小型可扩展API的日志工具组件,它可以给开发者提供统一的API接口,来记录不同类型的日志,帮助开发者管理不同类型的log。

[[409611]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

前言

基于安卓平台的日志工具组件Timber ( https://github.com/JakeWharton/timber), 实现鸿蒙的功能化迁移和重构。代码已经开源到(https://gitee.com/isrc_ohos/timber_ohos),欢迎各位开发者提出宝贵意见。

背景

Timber_ohos是一个带有小型可扩展API的日志工具组件,它可以给开发者提供统一的API接口,来记录不同类型的日志,帮助开发者管理不同类型的log。同时,Timber_ohos是项目开发时的log开关,通过此开关控制log的打印与关闭,从而形成不同的软件版本。该组件功能丰富且使用简单高效,可以被广泛应用于软件项目开发中。

组件效果展示

1、测试界面。

如图1所示,这是一个为了测试Timber_ohos功能而简单构建的UI页面。点击“测试”按钮即可输出相应的log。

鸿蒙开源第三方组件——日志工具组件Timber_ohos-鸿蒙HarmonyOS技术社区

图1 测试界面UI图

2、Log打印

Timber类的静态方法调用如图2中的(a)图所示。运行项目后查看HiLog显示,可以看到实时打印出来的日志,如图2中的(b)图所示。

鸿蒙开源第三方组件——日志工具组件Timber_ohos-鸿蒙HarmonyOS技术社区
鸿蒙开源第三方组件——日志工具组件Timber_ohos-鸿蒙HarmonyOS技术社区

图2 HiLog日志打印

Sample解析

1、Tree的使用

Timber_ohos将不同的日志操作以树(Tree)的概念进行表示,种植一种树就拥有一种日志记录功能,种植多种树就拥有多种日志记录的功能,树的种类有很多,常见的树有:DebugTree、RealeseTree、FileTree、CrashReportingTree等,这些树都是继承自Tree类。

  • DebugTree:对所有的日志进行记录。
  • RealeseTree:只对 warn,error,wtf 信息进行记录。
  • FileTree:在运行时将日志记录到文件中。
  • CrashReportingTree:对应用崩溃时的信息进行记录。

Timber_ohos中默认已经种植了DebugTree,由于Timber_ohos本身是一个可扩展的框架,因此开发者想得到其他类型的Log日志时,就需要自己实现一个日志记录类 ,然后种植到Timber_ohos中即可。

2、Sample的实现

Sample部分需要添加日志记录种类,并负责整体显示布局的搭建。首先为Timber_ohos组件添加想要的任何Tree子类实例(这里使用的是DebugTree),然后设置简单的按钮监听器,当按动按钮时在鸿蒙常规HiLog中出现调试日志。下面将详细介绍组件的使用方法。

步骤1. 种树(添加Tree子类实例)。

步骤2. 创建整体的显示布局。

步骤3. 导入相关类并设置按钮监听。

步骤4. 使用Tree实例。

(1)种树(添加Tree子类实例)

本步骤是在ExampleApp类的onInitialize()方法中实现的。首先需要创建Tree子类实例,然后调用Timber的plant()方法,同时将实例作为plant()方法的参数,这个过程叫做“种树”。

  1. Timber.plant(new Timber.DebugTree(0x001f00)); 

复制(2)创建整体的显示布局 在XML文件中创建一个DirectionalLayout作为整体显示布局,宽度和高度都跟随父控件变化而调整。创建两个组件,分别是Text组件和Button组件,用于控制组件效果显示。整体显示布局如图1所示。

  1. <DirectionalLayout 
  2.     xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  3.     ohos:height="match_parent" 
  4.     ohos:width="match_parent" 
  5.     ohos:orientation="vertical" 
  6.     ohos:padding="32vp" 
  7.     ohos:background_element="#ffffff" 
  8.     ohos:alignment="horizontal_center"
  9.     <Text   //“测试”提示 
  10.         ohos:height="match_content" 
  11.         ohos:width="match_content" 
  12.         ohos:layout_alignment="horizontal_center" 
  13.         ohos:text="Timber测试" 
  14.         ohos:text_size="35fp"/> 
  15.     <Button  //控制按钮 
  16.         ohos:id="$+id:btn1" 
  17.         ohos:height="match_content" 
  18.         ohos:width="match_content" 
  19.         ohos:top_margin="35vp" 
  20.         ohos:text_size="25fp" 
  21.         ohos:background_element="#FF51A8DD" 
  22.         ohos:padding="10vp" 
  23.         ohos:text="测试"/> 
  24. </DirectionalLayout> 

 (3)导入显示布局并设置按钮监听

在MainAbilitySlice中,整体显示布局也需要通过super.setUIContent()方法进行设置,才能生效并成功显示。然后给按钮设置点击事件,当用户需要使用Tree子类实例时,可通过手指进行点击。

  1. super.setUIContent(ResourceTable.Layout_ability_main);//设置整体显示布局 
  2. findComponentById(ResourceTable.Id_btn1).setClickedListener(new Component.ClickedListener() { 
  3.     ...//按钮的点击事件 

 (4)使用Tree实例

当用户需要打印调试日志的时候,调用Timber的静态方法,就会在鸿蒙常规HiLog上出现调试日志。调试日志如组件效果展示部分的图2所示。

  1. Timber.e  ("Timber.e 测试成功!!!"); 
  2. Timber.d  ("Timber.d 测试成功!!!"); 
  3. Timber.i  ("Timber.i 测试成功!!!"); 
  4. Timber.w   ("Timber.w 测试成功!!!"); 
  5. Timber.wtf   ("Timber.wtf测试成功!!!"); 

Library解析

Library主要为Timber_ohos组件提供日志输出的统一接口。以Sample中种植的调试树(DebugTree)为例,当使用Timber的静态方法Timber.e时,从MainAbilitySlice到Timber.e打印log的地方可以分为5个步骤,整体调用的流程如图3所示。

鸿蒙开源第三方组件——日志工具组件Timber_ohos-鸿蒙HarmonyOS技术社区

图3 调用顺序图

下面我们着重介绍树(Tree类)在Library中的实现,核心算法prepareLog()内部的逻辑结构这两个方面的内容。

1.树(Tree)的实现

Tree类是一种概念形式的日志操作,具体可分为(DebugTree、ReleaseTree、FileTree等)。而在Library内部,Tree类也实现了一系列方法,以便于对森林中的各类树进行增加、删除、修改等操作。

(1)在Timber_ohos组件中维护一个森林对象(FOREST)。

森林对象由不同类型的日志树组合而成,并提供对外的接口进行日志的打印。每种类型的树都可以通过种植操作来把自己添加到森林对象中,或者通过移除操作从森林对象中删除,从而实现该类型日志记录的开启和关闭。

  1. private static final List<Tree> FOREST = new ArrayList<>();  

(2)种树。

调用plant()方法,把Tree实例添加进FOREST里面 可以种植一棵树,也可以种植多棵树。这里以种一棵树为例。可以看到,树的种植是在plant()静态方法的synchronized 同步代码块中进行的。具体流程是先将树对象添加到 FOREST 列表中,然后将日志树保存到 forestAsArray 数组中(将树种植到森林中)。

需要注意的是,如果树为空,则抛出空指针异常的错误;如果开发者手动种植灵魂之树(TREE_OF_SOULS),Timber_ohos将会抛出非法数据异常。

  1. public static void plant(@NotNull Tree tree) { 
  2.   if (tree == null) { 
  3.     throw new NullPointerException("tree == null"); 
  4.   } 
  5.   if (tree == TREE_OF_SOULS) { 
  6.     throw new IllegalArgumentException("Cannot plant Timber into itself."); 
  7.   } 
  8.   synchronized (FOREST) { 
  9.     FOREST.add(tree); 
  10.     forestAsArray = FOREST.toArray(new Tree[FOREST.size()]); 
  11.   } 

 (3)移除Tree实例

同样的,树的移除也是在静态方法uproot()中的synchronized 同步代码块中进行的。如果没有该树可以移除,则Timber_ohos组件将抛出一个非法数据异常;反之,Timber_ohos组件将根据移除该树后的 FOREST列表生成 新的forestAsArray 数组。

  1. public static void uproot(@NotNull Tree tree) { 
  2.   synchronized (FOREST) { 
  3.     if (!FOREST.remove(tree)) { 
  4.       throw new IllegalArgumentException("Cannot uproot tree which is not planted: " + tree); 
  5.     } 
  6.     forestAsArray = FOREST.toArray(new Tree[FOREST.size()]); 
  7.   } 

 (4)清除森林里面全部的Tree实例

移除森林里所有的Tree实例,首先使用FOREST的clear()方法清除所有的Tree实例,将会自动生成一个对应的新的Tree数组,而forestAsArray就是这个数组的引用。因此forestAsArray 数组被设置为空数组。

  1. public static void uprootAll() { 
  2.   synchronized (FOREST) { 
  3.     FOREST.clear(); 
  4.     forestAsArray = TREE_ARRAY_EMPTY; 
  5.   } 

 (5) 灵魂之树(TREE_OF_SOULS)

估计很多同学好奇上述TREE_OF_SOULS。代码实现中,在这里运用的是经典设计模式中的代理模式,TREE_OF_SOULS 本质上是一个代理对象,森林中所有其他普通的树对象都是被代理对象,代理对象通过 for 循环来依次调用被代理对象的同名方法,从而实现不同类型的日志记录,如下所示。

  1. private static final Tree TREE_OF_SOULS = new Tree() { 
  2.   @Override public void v(String message, Object... args) { 
  3.     Tree[] forest = forestAsArray; 
  4.     for (Tree tree : forest) { 
  5.       tree.v(message, args); 
  6.     } 
  7.   } 

2.核心算法( prepareLog)

Timber_ohos组件的日志记录功能的核心算法在抽象类 Tree 的私有化 prepareLog()方法中,该方法接收四个参数,如图4所示:

鸿蒙开源第三方组件——日志工具组件Timber_ohos-鸿蒙HarmonyOS技术社区

图4 参数表

prepareLog()中首先判断了打log的条件,然后将要打印的message信息进行了处理,最后调用了抽象方法log进行日志输出。总体而言 prepareLog()算法流程如下:

(1)获取当前线程的 tag。

(2)当正常信息message不为null且信息长度为0时,这时正常信息message为null。

(3)当正常信息message和异常信息t都是 null 时,说明没有信息可以记录,方法直接返回。

(4)异常信息t通过getStackTraceString方法转换为字符串。

(5)正常信息message和可选格式化参数 args 通过formatMessage方法拼装成一个字符串。

(6)调用抽象方法 log 进行日志记录,这个方法由Tree的子类来实现。

  1. private void prepareLog(int priority, Throwable t, String message, Object... args) { 
  2.       //获取当前线程的 tag 
  3.       String tag = getTag(); 
  4.       //当正常信息message不为null且信息长度为0时,这时正常信息message为null 
  5.       if (message != null && message.length() == 0) { 
  6.         message = null
  7.       } 
  8.       //当正常信息 message 和异常信息 t 都是 null 时,说明没有信息可以记录,方法直接返回 
  9.       if (message == null) { 
  10.         if (t == null) { 
  11.           return; // Swallow message if it's null and there'no throwable. 
  12.         } 
  13.         //异常信息 t 通过 getStackTraceString 方法转换为字符串 
  14.         message = getStackTraceString(t); 
  15.       } else { 
  16.         if (args != null && args.length > 0) { 
  17.     //正常信息 message 和可选格式化参数 args 通过 formatMessage 方法拼装成一个字符串 
  18.           message = formatMessage(message, args); 
  19.         } 
  20.         if (t != null) { 
  21.           message += "\n" + getStackTraceString(t); 
  22.         } 
  23.       } 
  24.       //调用抽象方法 log 进行日志记录,这个方法由 Tree 的子类来实现 
  25.       log(priority, tag, message, t); 
  26.     } 

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2021-04-20 15:06:42

鸿蒙HarmonyOS应用

2021-08-30 17:55:58

鸿蒙HarmonyOS应用

2021-04-08 14:57:52

鸿蒙HarmonyOS应用

2021-04-15 17:47:38

鸿蒙HarmonyOS应用

2021-07-20 15:20:40

鸿蒙HarmonyOS应用

2021-11-17 15:37:43

鸿蒙HarmonyOS应用

2021-11-02 14:54:21

鸿蒙HarmonyOS应用

2021-06-29 09:28:16

鸿蒙HarmonyOS应用

2021-08-10 15:23:08

鸿蒙HarmonyOS应用

2021-10-19 10:04:51

鸿蒙HarmonyOS应用

2021-03-24 09:30:49

鸿蒙HarmonyOS应用

2021-03-10 15:03:40

鸿蒙HarmonyOS应用

2021-04-29 14:32:24

鸿蒙HarmonyOS应用

2021-07-28 09:40:04

鸿蒙HarmonyOS应用

2021-06-17 14:56:00

鸿蒙HarmonyOS应用

2021-03-03 09:42:26

鸿蒙HarmonyOS图片裁剪

2021-08-26 16:07:46

鸿蒙HarmonyOS应用

2021-03-01 14:00:11

鸿蒙HarmonyOS应用

2021-08-03 10:07:41

鸿蒙HarmonyOS应用

2021-08-05 15:06:30

鸿蒙HarmonyOS应用
点赞
收藏

51CTO技术栈公众号