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));
我想在基于 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));