Vert.x 使用 Lambda 表达式参数化的日志语句

Vert.x log statement parameterized with a Lambda Expression

我想在基于 Vert.x 的项目中添加一些额外的调试信息,该项目恰好使用 io.vertx.core.logging.Logger 进行日志记录。

据我查看 the Javadoc 所见,class 没有提供签名与功能接口匹配的方法。

我要输出的日志消息可以基于大量的值。我想避免不必要地转换它。

这似乎给我留下了以下模式:

if (LOGGER.isDebugEnabled()) {
    LOGGER.debug(buildMyLargeCollectionsStringRepresentation());
}

另一方面,这让我的代码一次又一次地检查 isDebugEnabled()

为了简洁和潜在的优化,我宁愿把它留给框架。

有没有办法以类似于 java.util.Logger class 的方式使用供应商?

看起来不像。但是稍微小心点,你可以不用像 isDebugEnabled() 这样的保护函数。记录器通常在格式化字符串之前检查记录函数内部的日志级别。如果它确定日志记录级别匹配,它将进行字符串格式化,包括对传入的任何参数调用 toString() 以包含在格式化字符串中。如果您避免将复杂的表达式直接传递给记录器方法,而是将您的表达式封装在一个对象中,该对象的 toString() 函数计算您希望记录的表达式,那么您可能无需使用它们就可以实现保护表达式的好处。

我不确定 vertx 如何将其 api 绑定到 JUL 日志记录。可能第一个 Object 参数将作为 JUL 中的 Supplier 参数传递。如果没有,您可以尝试下面的技术,该技术适用于在其参数上调用 toString() 的任何通用字符串记录机制。

考虑以下内容,它使用了 slf4j 的参数表示法:

debug("Doing something with {}", some_expression_that_is_expensive);

在此示例中,无论是否启用调试日志记录,每次调用 debug 函数时都会调用 some_expression_that_is_expensive。如果你有一个 class 比如

class EncapsulatedExpression {
    @Override
    public String toString() {
        return some_expression_that_is_expensive;
    }
}

然后你可以打电话给

debug("Doing something with {}", new EncapsulatedExpression());

然后 some_expression_that_is_expensive 只有在日志级别为调试时才会被调用。

你说 Supplier 会以更通用的方式提供类似的惰性求值,这是正确的,因此要获得你想要的东西,你需要一个工具来创建可以封装 Supplier,其 toString() 将导致对供应商进行评估。也许这样的事情会奏效:

class ToStringSupplier<T> {
    private Supplier<T> supplier;

    public ToStringSupplier(Supplier<T> supplier){
        this.supplier = supplier;
    }

    public static <T> ToStringSupplier<T> lazily(Supplier<T> supplier){
        return new ToStringSupplier<>(supplier);
    }

    @Override
    public String toString(){
        return Objects.toString(supplier.get());  // supplier could safely return null
    }
}

你可以这样使用它:

debug("Doing something with {}", lazily(() -> some_expression_that_is_expensive));