前言
本文代码案例基于Api13。
可以说,任何一种语言,都少不了日志,正因为有了日志,让开发者开发功能,排查问题,才显得游刃有余,一段代码执行的是否正确,某个结果是否匹配一致,等等,简简单单,一个日志打印,便可轻松知晓。
有过前端开发经验的同学,对于console,想必是非常的熟悉,它的使用方式和前端可以说是一模一样的,毕竟ArkTs是基于TypeScript而来的。
简单举例
我们随便打印一个内容,比如hello world,直接使用console.log()即可。
console.log("hello world")
以上的代码,我们还是放在点击事件中执行,这一段代码是鸿蒙应用的主页面,在上一章节中,我们有过概述,大家一定要注意,特别是刚入门的开发者,因为再接下来的所有代码执行,我们都是在这个点击事件中进行执行,并且进行逻辑的验证。
@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%') } }
点击模拟器或者真机右边的第一个绿色按钮,进行运行。
页面很是简单,和之前的一样。
点击“测试代码”文字,在控制台中,我们可以发现内容已经输出:
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("===打印错误信息")
点击“测试代码”后,控制台输出如下,可以发现警告是黄色的,而错误信息则是红色的。
设置Tag标签
一个日志,如果没有指定的tag标签,在茫茫的控制台中,寻找起来是非常费劲的,所以,在日常的开发中,聪明的程序员都会设置一些指定的tag标签,便于在控制台中快速的寻找。
比如在上面的日志输出中,我加了三个等号“===”,其作用就是用于标记,可以让控制台中以此作为检索。
tag可以直接和内容进行拼接,在前中后都无所谓,一般习惯而言,会放在前边,tag一般作为唯一性,特殊性,这样方便我们针对日志进行检索:
console.debug("===打印调试信息")
除了上边的设置tag之外,也可以多个参数进行设置,毕竟console是支持可变参数设置的。
console.debug("Tag标识:", "打印调试信息")
控制台输出如下:
日志等级概念
所谓的等级,只是覆盖度的问题,比如在上面的案例中,我们打印了所有类型的日志输出,代码如下:
console.debug("===打印调试信息") console.log("===打印日志信息") console.info("===打印日志信息") console.warn("===打印警告信息") console.error("===打印错误信息")
当我们在控制台选择日志等级的时候,如下所示:
它们的覆盖度是debug>info>warn>error,也就是选择debug,所有类型的日志都会输出,如果你选择了error,那么它只会输出error这一种类型。
其它方法概述
日常的开发中,常见的方法已经完全满足,毕竟只是一个日志打印,但是,在console中还有着其它的方法,同样有着实际的用处,我们简单做一个介绍。
assert断言
断言的作用用于调试和测试,用于验证表达式是否为真,如果不为真则抛出异常。
参数:
参数名 |
类型 |
必填 |
说明 |
value |
Object |
否 |
语句结果值。若value为假(false)或者省略,则输出以"Assertion failed"开头。如果 value 为真值(true),则无打印。 |
arguments |
Object |
否 |
value为假(false)的后续错误消息打印。省略则不打印。 |
如果表达式为真,则后面不会输出日志,像下面的案例,在控制台中是没有任何日志输出的。
console.assert(true, "表达式结果值为true, 无打印")
如果表达式为假,后面的日志则会输出,并且以"Assertion failed"开头。
console.assert(false, "表达式结果值为false, 进行控制台打印")
断言一般用于验证前边的逻辑是否为真,比如判断一个求和函数是否为等于10。
console.assert(this.add(6, 5) == 10, "求和函数 add(6, 5) 不为10,我就打印日志")
求和函数,关于函数,后面会重点讲述。
add(a: number, b: number): number { return a + b }
由于传递的是6和5,相加不为10,则表达式为假,就会在控制台中进行打印。
count计数
维护一个内部计数器,调用时,打印此标签名以及对应的计数次数。
参数:
参数名 |
类型 |
必填 |
说明 |
label |
string |
否 |
计数器标签名。默认值为'default'。 |
由于默认值是default,所以,加与不加都是一样的。
console.count() console.count('default') console.count()
我们看下控制台打印:
当然了,你可以定义任意的标签名,比如我定义了一个test标签名:
console.count("test") console.count("test") console.count("test")
控制台打印:
countReset清除计数
此方法主要用于清除指定标签名的计数,比如,还是上面的案例,我们调用一下清除。
console.count("test") console.count("test") console.countReset("test") console.count("test")
控制台打印如下,可以清楚的看到,执行了清除了之后,计数已经发生了变化。
dir对象
此方法主要用于对象内容打印。
参数:
参数名 |
类型 |
必填 |
说明 |
dir |
Object |
否 |
需要打印内容的对象。省略则无任何打印。 |
对象可以直接以大括号的形式:
console.dir({ "name": "AbnerMing" })
控制台效果:
直接打印一个创建的对象:
console.dir(new Test()) class Test { name: string = "AbnerMing" }
控制台效果:
两者的区别,大家可能看到了,自己创建的对象,打印会显示对象的名字,如果直接大括号形式打印,则会显示Object。
除了使用dir进行对象打印之外,其实我们也可以通过JSON.stringify()方式进行对象打印,用常见的打印方式即可。
console.log(JSON.stringify(Object({ "name": "AbnerMing" })))
控制台效果:
group缩进
默认将后续行的缩进增加两个空格。如果提供需要打印的信息,则首先打印信息,没有额外的缩进。
参数:
参数名 |
类型 |
必填 |
说明 |
arguments |
Object |
否 |
要打印的信息。 |
举例打印:
console.log("我是打印的第一条信息") console.group() console.log("我是打印的第二条信息") console.group() console.log("我是打印的第三条信息")
控制台效果,可以发现只要使用了group,后续的日志就会有缩进的效果。
groupCollapsed缩进
使用与功能同console.group()一致。
参数:
参数名 |
类型 |
必填 |
说明 |
arguments |
Object |
否 |
要打印的信息。 |
console.log("我是打印的第一条信息") console.groupCollapsed() console.log("我是打印的第二条信息") console.groupCollapsed() console.log("我是打印的第三条信息")
控制台效果:
groupEnd
将后续行的缩进减少两个空格。
console.log("我是打印的第一条信息") console.groupCollapsed() console.log("我是打印的第二条信息") console.groupEnd() console.log("我是打印的第三条信息")
控制台打印效果:
table表格
以表格形式打印数据。
参数:
参数名 |
类型 |
必填 |
说明 |
tableData |
Object |
否 |
要打印为表格形式的对象。省略则无任何打印。 |
打印举例:
console.table([1, 2, 3])
控制台打印效果:
打印举例2:
console.table({ a: [1, 2, 3], b: 4, c: { e: 5 } });
控制台打印效果:
time
启动可用于计算操作持续时间的计时器。可使用console.timeEnd()关闭计时器并打印经过的时间(单位:ms)。
参数:
参数名 |
类型 |
必填 |
说明 |
label |
string |
否 |
计时器标识。默认值为'default'。 |
示例:
console.time("AbnerMing")
timeEnd
停止之前通过调用 console.time() 启动的计时器并将打印经过的时间(单位:ms)。
参数:
参数名 |
类型 |
必填 |
说明 |
label |
string |
否 |
计时器标识。默认值为'default' |
示例:
console.time("AbnerMing") console.timeEnd("AbnerMing")
控制台打印效果:
timeLog
对于先前通过调用 console.time() 启动的计时器,打印经过时间和其他data参数。
参数:
参数名 |
类型 |
必填 |
说明 |
label |
string |
否 |
计时器标识。默认值为'default' |
arguments |
Object |
否 |
需要打印的其他日志。 |
示例:
console.time('AbnerMing') console.timeLog('AbnerMing', 88) console.timeEnd('AbnerMing')
控制台打印效果:
trace
打印当前堆栈。
参数:
参数名 |
类型 |
必填 |
说明 |
arguments |
Object |
否 |
需要打印的其他日志。省略则仅打印堆栈信息。 |
示例:
console.trace("显示堆栈信息")
控制台打印效果:
日志工具类封装
平常的开发中,我们可以直接使用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 }
初始化,有两个参数看一个是日志打印开关,一个是日志的Tag,都可以进行全局设置,大家可以在AbilityStage里进行初始化。
Console.getInstance().init(false,"AbnerMing")
普通打印
Console.error("我是一个普通打印")
控制台效果,经过美化之后的日志输出,可以看到还是很直观的,还有打印的日志位置,可以点击直接的定位,可以说非常的方便。
对象打印:
Console.error(Object({ "name": "AbnerMing", "age": 18 }))
控制台效果,对象也进行了格式化处理。
小结
针对初学者而言,大家只需要掌握住日志打印即可,等到了鸿蒙应用开发的时候,还有一个鸿蒙原生的打印工具HiLog,到时,我们也会详细的去讲述,也会针对HiLog,封装一个通用的工具类。