DEV Community

Cover image for 鸿蒙开发:console日志输出
程序员一鸣
程序员一鸣

Posted on

鸿蒙开发:console日志输出

前言

本文代码案例基于Api13。

可以说,任何一种语言,都少不了日志,正因为有了日志,让开发者开发功能,排查问题,才显得游刃有余,一段代码执行的是否正确,某个结果是否匹配一致,等等,简简单单,一个日志打印,便可轻松知晓。

有过前端开发经验的同学,对于console,想必是非常的熟悉,它的使用方式和前端可以说是一模一样的,毕竟ArkTs是基于TypeScript而来的。

简单举例

我们随便打印一个内容,比如hello world,直接使用console.log()即可。

console.log("hello world")
Enter fullscreen mode Exit fullscreen mode

以上的代码,我们还是放在点击事件中执行,这一段代码是鸿蒙应用的主页面,在上一章节中,我们有过概述,大家一定要注意,特别是刚入门的开发者,因为再接下来的所有代码执行,我们都是在这个点击事件中进行执行,并且进行逻辑的验证。

@Entry
@Component
struct Index {
  @State message: string = '测试代码';

  build() {
    RelativeContainer() {
      Text(this.message)
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
        .onClick(() => {
          //点击事件,用于测试代码
          console.log("hello world")
        })
    }
    .height('100%')
    .width('100%')
  }
}
Enter fullscreen mode Exit fullscreen mode

点击模拟器或者真机右边的第一个绿色按钮,进行运行。

Image description

页面很是简单,和之前的一样。

Image description

点击“测试代码”文字,在控制台中,我们可以发现内容已经输出:

Image description

console方法概述

console是一个全局对象,可以直接访问,虽然说可以直接访问,但并不意味着它可以在任何的地方都能调用,使用它必须得有承载的逻辑,比如在方法中,在一个点击事件中,如果你直接写到一个类中,或者UI页面中,这个是完全禁止的,这一点,初学者需要注意。

常用方法汇总

方法 描述
debug 以格式化输出方式打印调试信息。
log 以格式化输出方式打印日志信息。
info 以格式化输出方式打印日志信息。(console.log()的别名)
warn 以格式化输出方式打印警告信息。
error 以格式化输出方式打印错误信息。

方法参数:

参数名 类型 必填 说明
message string 表示要打印的文本信息。
arguments any[] 表示其余要打印的信息或message的替换值。

常用方法举例

使用方式,和前言中的案例一样,大家选择具体的场景调用即可,比如你想打印警告信息,你就可以使用warn方法,错误信息,就可以使用error方法,每个方法对应的级别是不一样的,而且在颜色上也有所区分。

我们还是在点击事件中进行代码编写:

  console.debug("===打印调试信息")
  console.log("===打印日志信息")
  console.info("===打印日志信息")
  console.warn("===打印警告信息")
  console.error("===打印错误信息")
Enter fullscreen mode Exit fullscreen mode

点击“测试代码”后,控制台输出如下,可以发现警告是黄色的,而错误信息则是红色的。

Image description

设置Tag标签

一个日志,如果没有指定的tag标签,在茫茫的控制台中,寻找起来是非常费劲的,所以,在日常的开发中,聪明的程序员都会设置一些指定的tag标签,便于在控制台中快速的寻找。

比如在上面的日志输出中,我加了三个等号“===”,其作用就是用于标记,可以让控制台中以此作为检索。

Image description

tag可以直接和内容进行拼接,在前中后都无所谓,一般习惯而言,会放在前边,tag一般作为唯一性,特殊性,这样方便我们针对日志进行检索:

 console.debug("===打印调试信息")
Enter fullscreen mode Exit fullscreen mode

除了上边的设置tag之外,也可以多个参数进行设置,毕竟console是支持可变参数设置的。

console.debug("Tag标识:", "打印调试信息")
Enter fullscreen mode Exit fullscreen mode

控制台输出如下:

Image description

日志等级概念

所谓的等级,只是覆盖度的问题,比如在上面的案例中,我们打印了所有类型的日志输出,代码如下:

console.debug("===打印调试信息")
console.log("===打印日志信息")
console.info("===打印日志信息")
console.warn("===打印警告信息")
console.error("===打印错误信息")
Enter fullscreen mode Exit fullscreen mode

当我们在控制台选择日志等级的时候,如下所示:

Image description

它们的覆盖度是debug>info>warn>error,也就是选择debug,所有类型的日志都会输出,如果你选择了error,那么它只会输出error这一种类型。

Image description

其它方法概述

日常的开发中,常见的方法已经完全满足,毕竟只是一个日志打印,但是,在console中还有着其它的方法,同样有着实际的用处,我们简单做一个介绍。

assert断言

断言的作用用于调试和测试,用于验证表达式是否为真,如果不为真则抛出异常。

参数:

参数名 类型 必填 说明
value Object 语句结果值。若value为假(false)或者省略,则输出以"Assertion failed"开头。如果 value 为真值(true),则无打印。
arguments Object value为假(false)的后续错误消息打印。省略则不打印。

如果表达式为真,则后面不会输出日志,像下面的案例,在控制台中是没有任何日志输出的。

console.assert(true, "表达式结果值为true, 无打印")
Enter fullscreen mode Exit fullscreen mode

如果表达式为假,后面的日志则会输出,并且以"Assertion failed"开头。

console.assert(false, "表达式结果值为false, 进行控制台打印")
Enter fullscreen mode Exit fullscreen mode

Image description

断言一般用于验证前边的逻辑是否为真,比如判断一个求和函数是否为等于10。

console.assert(this.add(6, 5) == 10, "求和函数 add(6, 5) 不为10,我就打印日志")
Enter fullscreen mode Exit fullscreen mode

求和函数,关于函数,后面会重点讲述。

 add(a: number, b: number): number {
    return a + b
  }
Enter fullscreen mode Exit fullscreen mode

由于传递的是6和5,相加不为10,则表达式为假,就会在控制台中进行打印。

Image description

count计数

维护一个内部计数器,调用时,打印此标签名以及对应的计数次数。

参数:

参数名 类型 必填 说明
label string 计数器标签名。默认值为'default'。

由于默认值是default,所以,加与不加都是一样的。

console.count()
console.count('default')
console.count()
Enter fullscreen mode Exit fullscreen mode

我们看下控制台打印:

Image description

当然了,你可以定义任意的标签名,比如我定义了一个test标签名:

console.count("test")
console.count("test")
console.count("test")
Enter fullscreen mode Exit fullscreen mode

控制台打印:

Image description

countReset清除计数

此方法主要用于清除指定标签名的计数,比如,还是上面的案例,我们调用一下清除。

console.count("test")
console.count("test")
console.countReset("test")
console.count("test")
Enter fullscreen mode Exit fullscreen mode

控制台打印如下,可以清楚的看到,执行了清除了之后,计数已经发生了变化。

Image description

dir对象

此方法主要用于对象内容打印。

参数:

参数名 类型 必填 说明
dir Object 需要打印内容的对象。省略则无任何打印。

对象可以直接以大括号的形式:

console.dir({ "name": "AbnerMing" })
Enter fullscreen mode Exit fullscreen mode

控制台效果:

直接打印一个创建的对象:

console.dir(new Test())

class Test {
  name: string = "AbnerMing"
}
Enter fullscreen mode Exit fullscreen mode

控制台效果:

两者的区别,大家可能看到了,自己创建的对象,打印会显示对象的名字,如果直接大括号形式打印,则会显示Object。

除了使用dir进行对象打印之外,其实我们也可以通过JSON.stringify()方式进行对象打印,用常见的打印方式即可。

 console.log(JSON.stringify(Object({ "name": "AbnerMing" })))
Enter fullscreen mode Exit fullscreen mode

控制台效果:

group缩进

默认将后续行的缩进增加两个空格。如果提供需要打印的信息,则首先打印信息,没有额外的缩进。

参数:

参数名 类型 必填 说明
arguments Object 要打印的信息。

举例打印:

console.log("我是打印的第一条信息")
console.group()
console.log("我是打印的第二条信息")
console.group()
console.log("我是打印的第三条信息")
Enter fullscreen mode Exit fullscreen mode

控制台效果,可以发现只要使用了group,后续的日志就会有缩进的效果。

Image description

groupCollapsed缩进

使用与功能同console.group()一致。

参数:

参数名 类型 必填 说明
arguments Object 要打印的信息。
console.log("我是打印的第一条信息")
console.groupCollapsed()
console.log("我是打印的第二条信息")
console.groupCollapsed()
console.log("我是打印的第三条信息")
Enter fullscreen mode Exit fullscreen mode

控制台效果:

Image description

groupEnd

将后续行的缩进减少两个空格。

console.log("我是打印的第一条信息")
console.groupCollapsed()
console.log("我是打印的第二条信息")
console.groupEnd()
console.log("我是打印的第三条信息")
Enter fullscreen mode Exit fullscreen mode

控制台打印效果:

Image description

table表格

以表格形式打印数据。

参数:

参数名 类型 必填 说明
tableData Object 要打印为表格形式的对象。省略则无任何打印。

打印举例:

console.table([1, 2, 3])
Enter fullscreen mode Exit fullscreen mode

控制台打印效果:

Image description

打印举例2:

 console.table({ a: [1, 2, 3], b: 4, c: { e: 5 } });
Enter fullscreen mode Exit fullscreen mode

控制台打印效果:

Image description

time

启动可用于计算操作持续时间的计时器。可使用console.timeEnd()关闭计时器并打印经过的时间(单位:ms)。

参数:

参数名 类型 必填 说明
label string 计时器标识。默认值为'default'。

示例:

console.time("AbnerMing")
Enter fullscreen mode Exit fullscreen mode

timeEnd

停止之前通过调用 console.time() 启动的计时器并将打印经过的时间(单位:ms)。

参数:

参数名 类型 必填 说明
label string 计时器标识。默认值为'default'

示例:

console.time("AbnerMing")
console.timeEnd("AbnerMing")
Enter fullscreen mode Exit fullscreen mode

控制台打印效果:

timeLog

对于先前通过调用 console.time() 启动的计时器,打印经过时间和其他data参数。

参数:

参数名 类型 必填 说明
label string 计时器标识。默认值为'default'
arguments Object 需要打印的其他日志。

示例:

console.time('AbnerMing')
console.timeLog('AbnerMing', 88)
console.timeEnd('AbnerMing')
Enter fullscreen mode Exit fullscreen mode

控制台打印效果:

Image description

trace

打印当前堆栈。

参数:

参数名 类型 必填 说明
arguments Object 需要打印的其他日志。省略则仅打印堆栈信息。

示例:

console.trace("显示堆栈信息")
Enter fullscreen mode Exit fullscreen mode

控制台打印效果:

Image description

日志工具类封装

平常的开发中,我们可以直接使用console进行打印,这是完全没问题的,但是在项目开发中,一般会兼顾着正式包和测试包,比如测试包下日志正常输出,当正式包时为了性能,就需要关闭日志打印,那么就需要针对日志做一个开关处理;除此之外,针对输出的日志进行格式化处理,美观处理等等,就不得不需要针对现有的日志工具进行再次的封装,已满足我们日后的开发。

工具类全部源码,大家可以复制直接使用:

/**
 * AUTHOR:AbnerMing
 * DATE:2025/1/17
 * INTRODUCE:日志打印工具类
 * */
export class Console {
  private logTag: string = "AbnerMing" //日志tag
  private logClose: boolean = false //日志是否关闭

  /*
* Author:AbnerMing
* Describe:私有化构造器
*/
  private constructor() {
  }

  /*
* Author:AbnerMing
* Describe:提供一个外部可访问的的静态方法
*/
  public static getInstance() {
    if (!Console.mConsole) {
      Console.mConsole = new Console()
    }
    return Console.mConsole
  }

  private static mConsole: Console

  /**
   * 初始化
   * @param logTag { string } 日志tag
   * @param logClose { boolean } 是否关闭打印日志
   */
  init(logClose?: boolean, logTag?: string) {
    if (logTag != undefined) {
      this.logTag = logTag
    }
    if (logClose != undefined) {
      this.logClose = logClose
    }
  }

  static log(message: string, tag?: string) {
    Console.getInstance().print(message, tag, LogType.LOG)
  }

  static info(message: string, tag?: string) {
    Console.getInstance().print(message, tag, LogType.INFO)
  }

  static debug(message: string, tag?: string) {
    Console.getInstance().print(message, tag, LogType.DEBUG)
  }

  static warn(message: string, tag?: string) {
    Console.getInstance().print(message, tag, LogType.WARN)
  }

  static error(message: string, tag?: string) {
    Console.getInstance().print(message, tag, LogType.ERROR)
  }

  /**
   * 日志打印
   * @param tag { string } 日志tag
   * @param message { Object } 日志内容
   */
  private print(message: Object, tag?: string, logType?: LogType) {
    if (this.logClose) {
      return
    }
    let lTag = this.logTag
    if (tag != undefined) {
      lTag = tag
    }
    switch (logType) {
      case LogType.DEBUG:
        console.debug(this.getMessage(lTag, message))
        break
      case LogType.LOG:
      case LogType.INFO:
        console.log(this.getMessage(lTag, message))
        break
      case LogType.WARN:
        console.warn(this.getMessage(lTag, message))
        break
      case LogType.ERROR:
        console.error(this.getMessage(lTag, message))
        break
    }
  }

  /**
   * 获取输出位置
   * */
  getMessage(tag: string, message: Object): string {
    let log = "┌───────" + tag + "────────────────────────────────────────────────────────────────────────────────"
    log = log.substring(0, log.length - tag.length) + "\n"

    try {

      const stackTrace = new Error().stack
      const traceArray = stackTrace!.split('\n')
      const trace = traceArray[traceArray.length-2]

      log = log + "|" + trace + "\n"

      let type = typeof message
      if (type == "object") {
        //是对象
        message = this.getObjectToJson(message)
      } else if (type == "string") {
        //判断是否包含大括号
        const content = message + ""
        if (content.startsWith("{") && content.endsWith("}")) {
          //对象
          const obj: string = JSON.parse(String(message))
          message = this.getObjectToJson(obj)
        } else {
          message = content
        }
      }
      log = log + "\n|    " + message
    } catch (e) {

    }
    log = log + "\n└───────────────────────────────────────────────────────────────────────────────────────"
    return log
  }

  /**
   * 对象转json
   * @param message
   * @returns
   */
  private getObjectToJson(message: Object): String {
    const json = JSON.stringify(message, null, 2)
    const endMessage = json.replace(/\n/g, "\n|    ")
    return endMessage
  }
}

enum LogType {
  DEBUG, LOG, INFO, WARN, ERROR
}
Enter fullscreen mode Exit fullscreen mode

初始化,有两个参数看一个是日志打印开关,一个是日志的Tag,都可以进行全局设置,大家可以在AbilityStage里进行初始化。

Console.getInstance().init(false,"AbnerMing")
Enter fullscreen mode Exit fullscreen mode

普通打印

Console.error("我是一个普通打印")
Enter fullscreen mode Exit fullscreen mode

控制台效果,经过美化之后的日志输出,可以看到还是很直观的,还有打印的日志位置,可以点击直接的定位,可以说非常的方便。

Image description

对象打印:

 Console.error(Object({ "name": "AbnerMing", "age": 18 }))
Enter fullscreen mode Exit fullscreen mode

控制台效果,对象也进行了格式化处理。

Image description

小结

针对初学者而言,大家只需要掌握住日志打印即可,等到了鸿蒙应用开发的时候,还有一个鸿蒙原生的打印工具HiLog,到时,我们也会详细的去讲述,也会针对HiLog,封装一个通用的工具类。

Top comments (0)