Skip to content

高级功能

Rakuyo edited this page Jan 23, 2024 · 16 revisions

如果您还没有阅读过构成组件,那么我们建议您先阅读该章节,再阅读本章内容,这将有助于您理解本章内容。

目录

注意

  • 如果您打算通过内建的 Log 类型打印、操作日志,那么您无需任何其他额外的代码,即可使用本章节内提到的所有功能。或者稍加配置,即可达成您想要的效果。

  • 如果您参考了自定义日志章节,打算通过自定义类型打印、操作日志,那么您可以将下文中所有的 Log 类型替换为您的自定义类型。

  • 如果您使用自定义类型,那么我们还要提醒您,使用以下功能时,请确保 “打印与存储/读取”、“打印与过滤” 的是同一类型。即使用存储功能时,遵循 PrintableStorable 的是同一类型;使用打印功能时,遵循 PrintableFilterable 的是同一类型。

缓存

RaLog 通过 Storable 协议,实现了对日志的存储、读取与删除功能。

存储

存储方式

借助 StorageMode 类型,用户可以指定将日志存储在磁盘内存两者全部OptionSet)。

在默认条件下,RaLog 采用的是 两者全部 的存储策略。

您可以通过 Log.filePath 属性,更改日志的本地存储路径,或通过 Log.storageMode 属性,更改存储方式。

执行存储

您无需执行额外的存储方法,即可享受存储功能。相关内容,可参考具体实现

截止 1.2.2 版本,RaLog 尚不提供灵活的,针对单条日志的存储策略。如果您想单独决定某条日志的存储方式,您只能在该条日志输出前,更改 Log.storageMode 属性的值,且该操作将一直生效,知道您再次修改它。

读取

内存

您可通过 Log.logs 属性,读取自应用程序启动后,缓存到内存中的所有日志。

磁盘

Storable 默认提供的读取磁盘中存储的日志的方法如下所示:

默认实现为该方法添加了 logDate: Date = Date() 的默认参数。

/// 从磁盘中读取与 `logDate` 相对应的日期的日志数据。
///
/// - Note: 默认实现未判断 `storageMode` 属性。也就是说,当 `storageMode` 不包含 `.disk` 时,本方法仍将尝试从磁盘读取日志数据。
//
/// - Parameter logDate: 要读取的日志的日期。
static func readLogFromDisk<T: LogModelProtocol>(logDate: Date) -> [T]?

您可通过 Log.readLogFromDisk() 读取当天的日志数据,或通过 Log.readLogFromDisk(logDate: someDate) 来读取某天的日志数据。

基于该方法,我们还扩展了 Storable,提供了另外两个读取方法,用来读取某一范围内的日志数据:

/// 读取前 `days` 天的日志数据。
///
/// 当 `days` 为 1 时, 将读取前 1 天的数据,即**昨天**的日志数据。
/// 当 `days` 为 2 时, 将读取前 2 天的数据,即**前天**的日志数据。
/// 以此类推
///
/// - Parameter days: 天数。
/// - Returns: 所读取那天的日志数据。
static func readLogFromDisk<T>(days: Int) -> [T]? where T : RaLog.LogModelProtocol

/// 读取某些时间点,或时间段内的日志数据。
///
/// `days` 可以是时间段(`ClosedRange<Int>`)
/// 例如, 当传入 `0 ... 7` 时, 意味着读取7天之内的数据(包括当天,即一共8天的数据)。
///
/// `days` 也可以是时间点 (`[Int]`)
/// 例如, 当传入 `[1, 3, 5]` 时, 意味着读取前1天、前3天、前5天的日志数据,即共3天的日志数据。
///
/// - Note:
///     正数表示当前日期之前的时间。
///
/// - Attention:
///     该方法将对 `days` 变量调用 `reversed()` 方法。请注意参数集合中元素的顺序。
///
/// - Parameters:
///   - days: 时间点或时间段。
///   - strategy: 中断方法执行的策略,详见 `BreakStrategy`。 默认为 `.never`。
/// - Returns: 获得的日志。 当整体为“ nil”时,表示没有日志,而当内部数组为“ nil”时,表示当天没有日志。
static func readLogFromDisk<C, T>(days: C, strategy: BreakStrategy = .never) -> [[T]?]? where C : Collection, T : RaLog.LogModelProtocol, C.Element == Int

删除

Storable 默认提供的删除磁盘中存储的日志的方法如下所示:

默认实现为该方法添加了 logDate: Date = Date() 的默认参数。

/// 从磁盘删除取与 `logDate` 相对应的日期的日志数据。
///
/// - Note: 默认实现未判断 `storageMode` 属性。也就是说,当 `storageMode` 不包含 `.disk` 时,本方法仍将尝试从磁盘读取日志数据。
//
/// - Parameter logDate: 要读取的日志的日期。
/// - Return: 如果删除成功,将返回 `.success(())`,否则将返回错误消息。
static func removeLogFromDisk(logDate: Date) -> Result<Void, Error>

您可通过 Log.removeLogFromDisk() 删除当天全部的日志数据,或通过 Log.removeLogFromDisk(logDate: someDate) 来删除某天全部的日志数据。

过滤

日志的过滤功能不会影响存储功能,即被过滤的日志依然可以被正确存储。

RaLog 通过 Filterable 协议,实现了对日志的过滤功能,被过滤的日志将不会在控制台进行输出。

过滤方式

过滤方式有以下两种:

  • 日志分类过滤
  • 文件名过滤

按日志分类过滤

RaLog 支持按日志分类对输出的日志进行过滤。

  • 您可以通过 Set<Log.Flag> 类型的 Log.filteredFlags 属性,静态的设置初始所要过滤的日志分类。
  • 或者通过 Log.addFilter(flag: ...)Log.addFilter(flag: ...) 动态的增加/删除所要过滤的日志分类。

按文件名过滤

RaLog 支持按文件名对输出的日志进行过滤。

  • 您可以通过 Set<String> 类型的 Log.filteredFiles 属性,静态的设置初始所要过滤的文件。
  • 或者通过 Log.fileterCurrentFileLogs(...) 方法,过滤当前文件(默认实现),或某一特定文件的日志输出。

截止 1.2.2 版本,RaLog 暂时没有提供额外的取消文件过滤的方法。如有需要,您可直接操作 Log.filteredFiles 属性。

执行过滤

您无需执行额外的过滤方法,即可享受过滤功能。相关内容,可参考具体实现

柯里化

在设计上,Printable 协议中负责输出的 print(...) 方法接收一个遵循 LogModelProtocol 协议的泛型模型。然而在使用上,这是非常不方便的。

所以在内建工具文件中,我们对 print(...) 方法进行了封装:

public extension Printable {
    
    @inline(__always) @discardableResult
    static func p(
        _ kLog: Any?, module: String? = nil, file: String = #file, function: String = #function, line: Int = #line
    ) -> (Log.Flag) -> Log {
        
        return { print(Log(kLog, file: file, function: function, line: line, flag: $0, module: module)) }
    }
}

执行该方法后,并不会立刻打印日志,而是会返回一个 (Log.Flag) -> Log 类型的闭包。调用该闭包并传入日志分类,才会执行打印操作。

像是上文中提到的 Log.debug(...) 方法,即是对该方法的进一步封装。

如此设计 p(...) 方法的好处在于,您可以通过该方法更加灵活的输出日志:

  • 假如您在基类中调用 Log.appear(...),但又想在某个特殊的控制器中修改该方法的输出内容,并且依然想使用 .jump 分类,那么最简单的方法就是执行 Log.p(...)(.jump)
  • 如果您想封装自定义的日志分类,可使用 p(...) 方法,并参考内建工具中提供的方法,封装自己的日志打印方法。