# 调试日志

> 日志是调试过程最重要的一环，`YukiHookAPI` 为开发者封装了一套稳定高效的调试日志功能。

::: tip

`KavaRef` 的日志可以由其自身单独管理，详细的配置方案你可以参考 [这里](https://highcapable.github.io/KavaRef/zh-cn/library/kavaref-core#%E6%97%A5%E5%BF%97%E7%AE%A1%E7%90%86)，这将跳转到 `KavaRef` 的文档。

`YukiHookAPI` 默认接管了 `KavaRef` 的日志功能，你也可以自己配置 `KavaRef` 的日志功能。

:::

## 普通日志

你可以调用 `YLog.debug`、`YLog.info`、`YLog.warn` 来向控制台打印普通日志。

使用方法如下所示。

> 示例如下

```kotlin
YLog.debug(msg = "This is a log")
```

此时，`YukiHookAPI` 会调用 `android.util.Log` 与 (Xposed) 宿主环境中的日志功能同时打印这条日志。

日志默认的 `TAG` 为你在 `YLog.Configs.tag` 中设置的值。

你也可以动态自定义这个值，但是不建议轻易修改 `TAG` 防止过滤不到日志。

> 示例如下

```kotlin
YLog.debug(tag = "YukiHookAPI", msg = "This is a log")
```

打印的结果为如下所示。

> 示例如下

```:no-line-numbers
[YukiHookAPI][D][宿主包名] This is a log
```

你还可以使用 `YLog.EnvType` 自定义日志打印的环境，可选择使用 `android.util.Log` 还是 (Xposed) 宿主环境中的日志功能来打印日志。

默认类型为 `YLog.EnvType.BOTH`，含义为同时使用这两个方法来打印日志。

比如我们仅使用 `android.util.Log` 来打印日志。

> 示例如下

```kotlin
YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.LOGD)
```

或仅使用 (Xposed) 宿主环境中的日志功能来打印日志，此方法仅可在 (Xposed) 宿主环境使用。

> 示例如下

```kotlin
YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.XPOSED_ENVIRONMENT)
```

若你想智能区分 (Xposed) 宿主环境与模块环境，可以写为如下形式。

> 示例如下

```kotlin
YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.SCOPE)
```

这样 API 就会在不同环境智能选择指定的方法类型去打印这条日志。

::: tip

更多功能请参考 [YLog.debug](../public/com/highcapable/yukihookapi/hook/log/YLog#debug-method)、[YLog.info](../public/com/highcapable/yukihookapi/hook/log/YLog#info-method) 及 [YLog.warn](../public/com/highcapable/yukihookapi/hook/log/YLog#warn-method) 方法。

:::

## 错误日志

你可以调用 `YLog.error` 来向控制台打印 `E` 级别的日志。

使用方法如下所示。

> 示例如下

```kotlin
YLog.error(msg = "This is an error")
```

错误日志的级别是最高的，无论你有没有过滤仅为 `E` 级别的日志。

对于错误级别的日志，你还可以在后面加上一个异常堆栈。

```kotlin
// 假设这就是被抛出的异常
val throwable = Throwable(...)
// 打印日志
YLog.error(msg = "This is an error", e = throwable)
```

打印的结果为如下所示。

> 示例如下

```:no-line-numbers
[YukiHookAPI][E][宿主包名] This is an error
```

同时，日志会帮你打印整个异常堆栈。

> 示例如下

```:no-line-numbers
java.lang.Throwable
    at com.demo.Test.<init>(...) 
    at com.demo.Test.doTask(...) 
    at com.demo.Test.stop(...) 
    at com.demo.Test.init(...) 
    at a.a.a(...) 
    ... 3 more
```

在错误日志中，你同样也可以使用 `YLog.EnvType` 来指定当前打印日志所用到的方法类型。

::: tip

更多功能请参考 [YLog.error](../public/com/highcapable/yukihookapi/hook/log/YLog#error-method) 方法。

:::

## 保存日志与自定义元素

你可以使用 `YLog.saveToFile` 方法直接保存当前已打印的全部日志到文件。

> 示例如下

```kotlin
// 请注意保存的文件路径必须拥有读写权限，否则会抛出异常
YLog.saveToFile("/sdcard/Documents/debug_log.log")
```

你还可以使用 `YLog.contents` 获取当前已打印的全部日志文件内容。

> 示例如下

```kotlin
// 获取当前已打印的全部日志文件内容
val fileContent = YLog.contents
```

如果你需要一个实时日志的数据结构数组，你可以直接获取 `YLog.inMemoryData` 的内容。

> 示例如下

```kotlin
// 获取当前已打印的实时日志数据结构数组
YLog.inMemoryData.forEach {
    it.timestamp // 获取时间戳
    it.time // 获取 UTC 时间
    it.priority // 获取优先级
    it.msg // 获取消息
    it.throwable // 获取异常
    // ...
}
```

如果你想对得到的自定义日志数据进行格式化或保存到文件，你只需要使用如下方法即可。

> 示例如下

```kotlin
// 假设这就是你得到的自定义日志数据
val data: List<YLogData>
// 格式化日志数据到字符串
val dataString = YLog.contents(data)
// 保存日志数据到文件
// 请注意保存的文件路径必须拥有读写权限，否则会抛出异常
YLog.saveToFile("/sdcard/Documents/debug_log.log", data)
```

::: danger

你需要启用 **YLog.Configs.isRecord** 才能获取到 **YLog.inMemoryData** 的内容。

获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。

你只能在对应的进程中获取对应的日志数据，如果你需要在任何地方实时得到这些日志数据，请参考 [Xposed 模块与宿主通讯桥](xposed-channel)、[注册模块 Activity](host-inject#注册模块-activity)。

如果你只想通过模块或宿主来实时得到日志数据，请参考可选方案 [YukiHookDataChannel.obtainLoggerInMemoryData](../public/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel#obtainloggerinmemorydata-method) 方法。

:::

你还可以使用 `YLog.Configs.elements` 自定义调试日志对外显示的元素。

此功能需要在 Hook 入口类的 `onInit` 中对 `YukiHookAPI.Configs` 进行配置。

> 示例如下

```kotlin
override fun onInit() = configs {
    debugLog {
        // ...
        elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
    }
    // ...
}
```

::: tip

更多功能请参考 [YLog.inMemoryData](../public/com/highcapable/yukihookapi/hook/log/YLog#inmemorydata-field)、[YLog.contents](../public/com/highcapable/yukihookapi/hook/log/YLog#contents-field)、[YLog.contents](../public/com/highcapable/yukihookapi/hook/log/YLog#contents-method)、[YLog.saveToFile](../public/com/highcapable/yukihookapi/hook/log/YLog#savetofile-method) 方法以及 [YLog.Configs](../public/com/highcapable/yukihookapi/hook/log/YLog#configs-object)。

:::