[英]Convert logger.debug(“message: ” + text) to logger.debug(message: {}", text)
I am trying to find the best way to address the issue of redundant string concatenation caused by using code of the following form: 我正在尝试找到最好的方法来解决由于使用以下形式的代码而导致的冗余字符串串联的问题:
logger.debug("Entering loop, arg is: " + arg) // @1
In most cases the logger.level
is higher than debug
and the arg.toString()
and the string concatenation are a waste that user up cpu cycles and briefly use up memory. 在大多数情况下,
logger.level
高于debug
,而arg.toString()
和字符串连接是浪费用户的CPU周期并短暂地占用内存。
Before the introduction of varargs the recommended approach was to test the logger level first: 在引入varargs之前,推荐的方法是首先测试记录器级别:
if (logger.isDebugEnabled())
logger.debug("Entering loop, arg is: " + arg); // @2
But now the preferred form is 但是现在首选形式是
logger.debug("Entering loop, arg is: {}", arg); // @3
It is not very difficult to prefix each logger.debug
with if (logger.isDebugEnabled())
(and its equivalent for the other methods) in a script, but I am trying to find the best way to convert the first form to the third. 这不是很困难的前缀每个
logger.debug
与if (logger.isDebugEnabled())
及其等价物的其他方法)的脚本,但我想找到的第一种形式转换到第三的最佳方式。
Any suggestions? 有什么建议么? The challenge is to insert the correct number brace pairs
{}
in the format string. 面临的挑战是在格式字符串中插入正确的数字大括号对
{}
。 I wish logback would append the remaining arguments not covered by the placeholder at the end but I cannot find a reference that it does that. 我希望logback会在末尾附加占位符未涵盖的其余参数,但我找不到能做到这一点的引用。
As an alternative, I am thinking to write a class Concatenator
as pasted at end and convert the first form to 作为替代方案,我正在考虑编写最后粘贴的
class Concatenator
并将第一种形式转换为
logger.debug(new Concatenator("Entering loop, arg is: ", arg)); // @4
The Concatenator
class delays the call to arg.toString()
and string concatenation until the logger
calls toString()
, thereby avoiding both if the logger is at a higher filter level. Concatenator
类arg.toString()
和字符串串联的调用延迟,直到logger
调用toString()
为止,从而避免了两者(如果记录器处于更高的过滤器级别)。 It does add the overhead of creating an Object[]
and a Concatenator
but that should be cheaper than the alternative. 它确实增加了创建
Object[]
和Concatenator
的开销,但是比其他方法要便宜。
Questions: 问题:
@1->@4
-- replace +
with ,
and enclose in new Contatenator(...)
) is much easier. @1->@4
用+
替换+
,
并包含在new Contatenator(...)
)要容易得多。 Is there something I am missing? @4
is much better than @1
? @4
比@1
好吗? public class Concatenator {
final Object[] input;
String output;
public Concatenator(Object... input) {
this.input = input;
}
public String toString() {
if (output == null) {
StringBuffer b = new StringBuffer();
for (Object s : input) b.append(s.toString());
output = b.toString();
}
return output;
}
public static void main(String args[]) {
new Concatenator("a", "b", new X());
System.out.println(new Concatenator("c", "d", new X()));
}
}
class X {
public String toString() {
System.out.println("X.toString");
return super.toString();
}
}
Unfortunately your approach isn't going to change anything. 不幸的是,您的方法不会改变任何事情。 In fact, it introduces an additional object instantiation/allocation (your
Concatenator
). 实际上,它引入了附加的对象实例化/分配(您的
Concatenator
)。 You're also using StringBuffer
which introduces synchronization overhead you don't need. 您还使用
StringBuffer
引入了不需要的同步开销。
The problem is the method signature for SLF4J's Logger.debug()
calls. 问题是SLF4J的
Logger.debug()
调用的方法签名。 The first argument is always a String
. 第一个参数始终是
String
。 This means you're going to have to call: 这意味着您将必须致电:
logger.debug(new Concatenator("Entering loop, arg is: ", arg).toString());
which means ... you're doing exactly the same thing as Java is going to do, but with more overhead. 这意味着...您正在做与Java完全相同的事情,但是开销更多。
The Java compiler handles the String concatenation operator ( +
) by creating a StringBuilder
and doing exactly what you're doing in your Concatenator
class on toString()
. Java编译器通过创建
StringBuilder
并完全在toString()
Concatenator
类中进行操作来处理String串联运算符( +
toString()
。
logger.debug("Entering loop, arg is: " + arg);
becomes: 变为:
logger.debug(new StringBuilder()
.append("Entering loop, arg is: ")
.append(arg).toString());
(If you use javap
to look at the generated bytecode, you'll see that's the case.) (如果您使用
javap
查看生成的字节码,则会看到这种情况。)
So, your current approach is going to be more expensive than what you have now. 因此,您当前的方法将比现在昂贵。
Edit: So, the way you could make this work is by doing ... 编辑:所以,您可以使这项工作的方法是通过...
logger.debug("{}", new Concatenator("Entering loop, arg is: ", arg));
This way your Concatenator
is passed as an Object
and its toString()
not called unless the logger needs to. 这样,除非记录器需要,否则您的
Concatenator
作为Object
传递,并且不调用其toString()
。 Also, replace the StringBuffer
in your class with StringBuilder
. 另外,用
StringBuffer
替换类中的StringBuilder
。
And if I didn't answer your question directly ... is this better than the original? 而且,如果我没有直接回答您的问题……这比原来的要好吗? Probably ;
大概 ; The string concatenation isn't occurring unless it needs to.
除非需要,否则不会发生字符串串联。 You are, however, introducing an object instantiation/allocation.
但是,您将引入对象实例化/分配。 The only real way to see the differences would be to profile it / write a benchmark.
观察差异的唯一真实方法是剖析差异/编写基准。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.