如果在扩展运行时发生问题,你可能想要将这些信息通知给用户。如果问题非常严重以致于不应该进行任何进一步的处理,扩展应该抛出一个错误(即,抛出一个异常)。否则,我们建议扩展以一个合适的严重级别作为日志消息来报告问题。你可以使用Asciidoctor的日志记录器来记录消息。
当Asciidoctor处理一个文档时,它会创建一个针对该文档的https://ruby-doc.org/3.2.2/stdlibs/logger/Logger.html[Logger^]实例。你可以在你的扩展中访问这个记录器来记录消息。这个页面描述了如何做到这一点。
混入日志记录器
要访问Asciidoctor的Logger实例,你必须将`Asciidoctor::Logging`模块包含到你的扩展中。这样做将提供对静态的`logger`方法的访问权,从而从`LoggerManager`中检索实例。
Tip
|
记录器也可以通过文档对象上的 logger 方法来访问。如果你正在编写一个有权访问文档对象的扩展,这可能是一种更简单的方法。
|
如果你正在编写一个基于类的扩展,你可以使用`include`关键字来包含`Logging`模块。
class CustomBlock < Asciidoctor::Extensions::BlockProcessor include Asciidoctor::Logging # ... end Asciidoctor::Extensions.register do block CustomBlock, :custom end
如果您仅使用DSL来编写扩展,处理器类将被动态创建。因此,您需要通过引用该类上的`include`方法来混合`Logging`模块。
Asciidoctor::Extensions.register do block :custom do singleton_class.include Asciidoctor::Logging # ... end end
Tip
|
如上所述,您可以通过传递给扩展进程方法的文档对象上的`logger`方法访问记录器。例如: Asciidoctor::Extensions.register do block :custom do process do |doc, reader, attrs| puts doc.logger # ... end end end |
为了记录一条消息,请将消息字符串传递给由`logger`方法返回的logger实例上的一个严重性方法(例如,error
、warn
、`info`等)。以下是在process方法中记录警告消息的示例。
def process doc, reader, attrs logger.warn 'We are logging!' # ... end
这是Asciidoctor将打印到日志的内容:
asciidoctor: WARN: We are logging!
请参考文档 Logger 以了解可用的方法。
这是一个完整的例子,展示了这些添加内容在上下文中的应用位置:
Asciidoctor::Extensions.register do block :custom do singleton_class.include Asciidoctor::Logging on_context :paragraph process do |parent, reader, attrs| logger.warn 'We are logging!' create_paragraph parent, reader.lines, attrs end end end
请记住,只有当用户启用其严重级别时,消息才会显示。默认情况下,将显示错误和警告消息。
除非扩展程序正在抛出错误过程中,否则你应该避免使用`fatal`方法。
为消息添加上下文
如果你向log方法传递一个字符串,Asciidoctor将只打印严重性级别和消息内容。这意味着用户不会知道这个消息是指哪部分AsciiDoc源代码,也不会知道消息来自于一个扩展。因此,你可能会想提供更多的细节。让我们开始,通过在消息中包含扩展的名称。
添加扩展名
首先,在记录消息时,你应该在消息前加上扩展名的前缀。
logger.warn '(custom-block-extension) Something is out of sorts.'
那将按如下方式打印消息:
asciidoctor: WARN: (custom-block-extension) Something is out of sorts.
或者,你可以将扩展名移动到紧跟程序名之后(例如,asciidoctor
)。
logger.log ::Logger::WARN, 'hi', %(#{logger.progname} (custom-block-extension))
那将按如下方式打印消息:
asciidoctor (custom-block-extension): WARN: Something is out of sorts.
另一种获得相同输出的方法是使用接受消息为块的形式。
logger.warn(%(#{logger.progname} (custom-block-extension))) { 'Something is out of sorts.' }
区块形式在其他方面也很有用。如果消息的计算成本很高,那么区块形式将推迟消息的评估,直到(因此如果)它被记录下来。
现在读者知道这个消息来自一个扩展程序,但却不知道扩展程序正在处理的AsciiDoc源文件的位置。让我们来看看如何做到这一点。
添加源位置
除了`logger`方法外,Asciidoctor的`Logging`模块还添加了一个名为`message_with_context`的帮助器,该帮助器生成了一个消息对象,将来源信息与字符串消息绑定在一起。
对于块和块宏扩展,您可能想要引用找到块的位置,您可以使用 parent.document.reader.cursor_at_mark
方法调用来检索。对于树处理器扩展,您可以从块的 source_location
方法检索源位置。对于大多数其他扩展,您可能想要引用当前光标,可以从 parent.document.reader.cursor
或者针对只提供对文档对象访问的扩展的 (doc.reader
) 访问。
这是一个用包含源位置的对象替换消息的例子:
logger.warn %(#{logger.progname} (custom-block-extension)) do message_with_context 'Something is out of sorts.', source_location: parent.document.reader.cursor_at_mark end
这是 Asciidoctor 打印内容的一个例子:
asciidoctor (custom-block-extension): WARNING: test.adoc: line 4: Something is out of sorts.
在树处理器扩展中,如果启用了源映射,您可以从任何块中获取源位置。如果没有启用,代码将通过在不包含源位置的情况下记录消息来优雅地降级处理。
Asciidoctor::Extensions.register do tree_processor do |doc| singleton_class.include Asciidoctor::Logging doc.find_by context: :paragraph do |paragraph| logger.warn %(#{logger.progname} (custom-tree-processor)) do message_with_context 'Found paragraph.', source_location: paragraph.source_location end end nil end end
Asciidoctor中的源位置跟踪并不完美,因此您可能需要检索光标并稍微调整它,以使其与消息中您想要引用的行对齐。
参考{url-api-gems}/asciidoctor/{release-version}/Asciidoctor/Reader#cursor-instance_method[Reader#cursor^]以获取光标方法的列表。