문자열 연결 대신 {}를 사용하여 형식화하는 Logger slf4j의 장점


100

{}문자열 연결 대신 사용하면 어떤 이점이 있습니까?

slf4j의 예

logger.debug("Temperature set to {}. Old temperature was {}.", t, oldT);

대신에

logger.debug("Temperature set to"+ t + ". Old temperature was " + oldT);

구성 파일에 따라 런타임에서 매개 변수 평가 (및 문자열 연결)를 피할 수 있기 때문에 속도 최적화에 관한 것이라고 생각합니다. 그러나 두 개의 매개 변수 만 가능하며 때로는 문자열 연결 외에 다른 선택이 없습니다. 이 문제에 대한 견해가 필요합니다.

답변:


74

그것은 이다 문자열 연결 성능에 대해. 밀도가 높은 로깅 문이있는 경우 잠재적으로 중요합니다.

(SLF4J 1.7 이전) 그러나 두 개의 매개 변수 만 가능합니다.

대부분의 로깅 명령문에는 2 개 이하의 매개 변수가 있으므로 버전 1.6까지의 SLF4J API는 대부분의 사용 사례 만 처리합니다. API 디자이너는 API 버전 1.7부터 varargs 매개 변수가있는 오버로드 된 메서드를 제공했습니다.

2 개 이상이 필요하고 1.7 이전 SLF4J를 사용하는 경우에는 문자열 연결 또는 new Object[] { param1, param2, param3, ... }. 성능이 그다지 중요하지 않을만큼 충분히 적어야합니다.


2
사용하지 않는 문자열 연결 (예 : 디버깅 문)은 피해야합니다. (지나치게 장황하지만 효율적인) 로그 수준 검사 또는 (희미하지만 약간의 오버 헤드) 개체 배열 매개 변수를 사용하십시오. (후자를 선호합니다. 모든 것이 동일합니다.) concat 문자열이 중요하지 않거나 성능에 영향을 미치지 않는다고 말하기는 어렵습니다. 객체 배열 생성은 이론적으로 인라인되고 최적화 될 수 있으며 "진짜"차이를 만들지 않을 수 있습니다 (희망적 사고 대비). (조기 최적화가 아니라 처음에 제대로 / 더 나은 작업을 수행하는 문제입니다.)
michael

System.out.println ()이 slf4j의 로거와 유사하게 따르도록 오버로드 된 수정이 수행되지 않아 문자열 연결을 방지하는 이유는 무엇입니까?
a3.14_Infinity 2014

45

짧은 버전 : 예, 더 적은 코드로 더 빠릅니다!

문자열 연결은 필요한지 여부를 알지 못해도 많은 작업을 수행하며 (log4j에서 알려진 기존의 "디버깅이 활성화 됨"테스트) 가능한 경우 피해야합니다. {}는 toString () 호출 및 문자열 생성을 지연시킬 수 있기 때문입니다. 이벤트 캡처가 필요한지 여부가 결정된 후 로거 형식을 단일 문자열로 지정하면 코드가 제 생각에 더 깨끗해집니다.

여러 인수를 제공 할 수 있습니다. 이전 버전의 sljf4j를 사용하고에 인수가 두 개 이상 있는 경우 대신 구문을 {}사용하여 new Object[]{a,b,c,d}배열을 전달 해야합니다 . 예를 들어 http://slf4j.org/apidocs/org/slf4j/Logger.html#debug(java.lang.String, java.lang.Object [])를 참조하십시오 .

속도와 관련하여 : Ceki는 목록 중 하나에 벤치 마크를 게시했습니다.


6
참고 : 최신 javadoc은 최신 var-arg 구문 인 debug(String format, Object... arguments). 참조 slf4j.org/faq.html#logging_performance
마이클

연결 성능 ​​외에도 .toString () 평가에 대한 언급으로 인해 찬성되었습니다. 이것은 로거 내부에서 일어나는 일이며 로거는 해당 메서드를 호출해야하는지 여부를 결정할 수 있습니다. 로깅 수준 막대가 충족되지 않으면 그렇지 않습니다.
Chetan Narsude

6

Java 에서는 문자열이 변경 불가능 하므로 모든 연결 쌍에 대해 왼쪽 및 오른쪽 문자열을 새 문자열로 복사해야합니다. 따라서 자리 표시자를 선택하는 것이 좋습니다.


2
단일 쌍이있는 경우에는 맞지만 컴파일러가 연결을 문자열 작성기 호출로 변환하여 많은 할당을 수행하지 않는 훨씬 빠른 코드를 생성하므로 일반적으로 올바르지 않습니다.
cdeszaq

3

또 다른 대안은 String.format(). 우리는 그것을 사용하는 jcabi 로그 (SLF4J 주위에 정적 유틸리티 래퍼).

Logger.debug(this, "some variable = %s", value);

훨씬 더 유지 관리 및 확장 가능합니다. 게다가 번역하기도 쉽습니다.


3
나는 그것이 더 유지하기 쉽다고 생각하지 않습니다. value변경 유형이있는 경우 돌아가서 로깅 문도 변경해야합니다. IDE가 도움이되지 않는 것. 로거는 디버깅을 지원해야하며 방해가되지 않아야합니다. :-)
Chetan Narsude

3
@ChetanNarsude IntelliJ 2016은 형식 문자열이 형식 지정 인수에 맞지 않을 때 적어도 알려줍니다. 예 : String.format("%d", "Test")IntelliJ 경고를 생성합니다 Argument type 'String' does not match the type of the format specifier '%d'.. 그래도 위의 솔루션으로 작업 할 때이 지능적인 응답을 제공 할 수 있을지 모르겠습니다.
crush

이것의 속도는 무엇입니까?
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersen 내부는 꽤 원시적이지만 물론 정적 로거보다 느립니다
yegor256

slf4j 랩핑? 그것은 slf4j 사용 목적을 무너 뜨리지 않습니까? 또한 많은 사람들이 logger.info (String.format ( "hello % s", username))과 같이 로그 수준이 평가되기 전에 문자열 형식이 지정되도록 String.format을 오용하는 것을 보았습니다.
Juan Bustamante

2

저자의 관점에서 볼 때 주된 이유는 문자열 연결에 대한 오버 헤드를 줄이는 것이라고 생각합니다. 로거의 문서를 읽고 다음과 같은 단어를 찾을 수 있습니다.

/**
* <p>This form avoids superfluous string concatenation when the logger
* is disabled for the DEBUG level. However, this variant incurs the hidden
* (and relatively small) cost of creating an <code>Object[]</code> before 
  invoking the method,
* even if this logger is disabled for DEBUG. The variants taking
* {@link #debug(String, Object) one} and {@link #debug(String, Object, Object) two}
* arguments exist solely in order to avoid this hidden cost.</p>
*/
*
 * @param format    the format string
 * @param arguments a list of 3 or more arguments
 */
public void debug(String format, Object... arguments);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.