내 인생에서 처음으로 오픈 소스가 될 Java API를 작성하는 위치에 있습니다. 많은 다른 프로젝트에 포함되기를 바랍니다.
로깅을 위해 (그리고 실제로 작업하는 사람들) 항상 JUL (java.util.logging)을 사용했으며 아무런 문제가 없었습니다. 그러나 이제 API 개발을 위해해야 할 일을 더 자세하게 이해해야합니다. 나는 이것에 대해 약간의 연구를 해 왔으며 내가 얻은 정보로 더 혼란스러워합니다. 따라서이 게시물.
내가 JUL에서 왔기 때문에 나는 그것에 편견이 있습니다. 나머지에 대한 나의 지식은 그렇게 크지 않습니다.
내가 한 연구에서 사람들이 JUL을 좋아하지 않는 이유를 생각해 냈습니다.
"Sun이 JUL을 출시하기 훨씬 전에 Java로 개발을 시작했으며 새로운 것을 배우기보다는 logging-framework-X를 계속 사용하는 것이 더 쉬웠습니다 . " 흠. 농담이 아니에요. 사람들이 실제로하는 말입니다. 이 논쟁으로 우리 모두는 COBOL을 할 수 있습니다. (그러나 나는 이것이 게으른 친구임을 분명히 말할 수있다)
"JUL의 로깅 수준 이름이 마음에 들지 않습니다 . " 진지하게, 이것은 새로운 의존성을 도입할만한 이유가 충분하지 않습니다.
"JUL의 표준 출력 형식이 마음에 들지 않습니다 . " 흠. 이것은 단지 구성입니다. 코드 단위로 아무것도 할 필요조차 없습니다. (사실 옛날에는 포맷터 클래스를 직접 만들어야했습니다.)
"저는 logging-framework-X를 사용하는 다른 라이브러리를 사용하기 때문에 그 라이브러리를 사용하는 것이 더 쉽다고 생각했습니다 . " 이것은 원형의 주장이지 않습니까? 왜 '모두'가 JUL이 아닌 logging-framework-X를 사용합니까?
"다른 사람이 logging-framework-X를 사용하고 있습니다" . 나에게 이것은 위의 특별한 경우입니다. 대다수가 항상 옳은 것은 아닙니다.
그래서 진짜 큰 질문은 왜 JUL이 아닌가? . 내가 놓친 것이 무엇입니까? 외관 로깅 (SLF4J, JCL)에 대한 단점은 역사적으로 여러 로깅 구현이 존재했으며 그 이유는 내가 볼 때 JUL 이전으로 거슬러 올라갑니다. 만약 JUL이 완벽했다면, 정면의 로깅은 존재하지 않습니까? 문제를 더 혼란스럽게 만드는 JUL은 어느 정도 파사드 자체이므로 처리기, 포맷터 및 심지어 LogManager를 바꿀 수 있습니다.
똑같은 일을하는 여러 가지 방법 (로깅)을 포용하는 대신, 왜 그들이 왜 필요한지 의심해서는 안 되는가? (그리고 그 이유가 여전히 존재하는지 확인하십시오)
좋아, 지금까지의 연구는 JUL과 관련 하여 실제로 문제 가 될 수있는 몇 가지 사실을 발견했다 .
성능 . 어떤 사람들은 SLF4J의 성능이 다른 것보다 우수하다고 말합니다. 이것은 나에게 조기 최적화의 경우 인 것 같습니다. 초당 수백 메가 바이트를 기록 해야하는 경우 어쨌든 올바른 경로에 있는지 잘 모르겠습니다. JUL도 발전했으며 Java 1.4에서 수행 한 테스트가 더 이상 사실이 아닐 수도 있습니다. 여기에서 읽을 수 있으며이 수정으로 Java 7로 변경되었습니다. 많은 사람들이 로깅 메소드에서 문자열 연결의 오버 헤드에 대해서도 이야기합니다. 그러나 템플리트 기반 로깅은이 비용을 피하며 JUL에도 존재합니다. 개인적으로는 템플릿 기반 로깅을 작성하지 않습니다. 너무 게으르다. 예를 들어 JUL로 이것을하면 :
log.finest("Lookup request from username=" + username + ", valueX=" + valueX + ", valueY=" + valueY));
내 IDE가 경고하고 다음과 같이 변경해야한다는 권한을 요청합니다.
log.log(Level.FINEST, "Lookup request from username={0}, valueX={1}, valueY={2}", new Object[]{username, valueX, valueY});
.. 물론 받아 들일 것입니다. 권한 부여! 도와 주셔서 감사합니다.
따라서 실제로 그러한 진술을 직접 작성하지는 않습니다. IDE에서 수행합니다.
성능 문제에 대한 결론에서 나는 JUL의 성능이 경쟁사에 비해 좋지 않다는 것을 암시하는 것을 찾지 못했습니다.
클래스 경로에서 구성 . 기본 JUL은 클래스 경로에서 구성 파일을로드 할 수 없습니다. 그렇게 하는 것은 몇 줄의 코드 입니다. 왜 이것이 귀찮은 지 알 수 있지만 해결책은 짧고 간단합니다.
출력 핸들러의 가용성 . JUL에는 콘솔, 파일 스트림, 소켓 및 메모리 등 5 가지 출력 핸들러가 기본 제공됩니다. 이것들은 확장되거나 새로운 것을 쓸 수 있습니다. 예를 들어, UNIX / Linux Syslog 및 Windows 이벤트 로그에 쓰는 중일 수 있습니다. 나는 개인적 으로이 요구 사항을 갖지 못했거나 사용 된 것을 보지 못했지만 그것이 왜 유용한 기능 일 수 있는지 분명히 알 수 있습니다. 로그 백에는 Syslog의 어 펜더가 포함되어 있습니다. 여전히 나는 그것을 주장 할 것이다
- 출력 대상에 대한 요구의 99.5 %는 기본적으로 JUL에 포함되어 있습니다.
- 특별한 요구 사항은 다른 것보다는 JUL 위의 사용자 지정 처리기에 의해 제공 될 수 있습니다. JUL 용 Syslog 출력 핸들러를 다른 로깅 프레임 워크보다 작성하는 데 시간이 더 걸린다는 제안은 없습니다.
내가 간과 한 것이 있다는 것이 정말 걱정입니다. JUL 이외의 로깅 파사드와 로깅 구현의 사용은 너무나 널리 퍼져 있으므로 이해하지 못하는 사람이 나라는 결론에 도달해야합니다. 처음이 아니에요, 두렵습니다. :-)
API로 무엇을해야합니까? 나는 그것이 성공하기를 원합니다. 물론 "흐름을 따라가"고 SLF4J (요즘 가장 인기있는 것)를 구현할 수는 있지만, 내 자신을 위해 오늘의 JUL에 무엇이 잘못되었는지 정확히 이해해야합니까? 내 라이브러리에 JUL을 선택하여 스스로 방해 할 수 있습니까?
테스트 성능
(2012 년 7 월 7 일에 nolan600에 의해 추가 된 섹션)
Ceki에서 SLF4J의 매개 변수화가 JUL보다 10 배 이상 빠르다는 내용이 아래에 나와 있습니다. 그래서 간단한 테스트를 시작했습니다. 언뜻보기에 주장은 정확합니다. 예비 결과는 다음과 같습니다 (그러나 계속 읽어보십시오!).
- 실행 시간 SLF4J, 백엔드 로그 백 : 1515
- 실행 시간 SLF4J, 백엔드 JUL : 12938
- 실행 시간 JUL : 16911
위의 숫자는 msec이므로 적을수록 좋습니다. 따라서 성능 차이의 10 배는 실제로는 실제로 거의 비슷합니다. 내 초기 반응 : 그것은 많이입니다!
테스트의 핵심은 다음과 같습니다. 알 수 있듯이 정수와 문자열은 루프로 해석되어 로그 문에 사용됩니다.
for (int i = 0; i < noOfExecutions; i++) {
for (char x=32; x<88; x++) {
String someString = Character.toString(x);
// here we log
}
}
(로그 진술에 기본 데이터 유형 (이 경우 int)과 더 복잡한 데이터 유형 (이 경우 String)이 필요했습니다. 확실하지 않지만 거기에 있습니다.)
SLF4J에 대한 로그 설명 :
logger.info("Logging {} and {} ", i, someString);
JUL에 대한 로그 설명 :
logger.log(Level.INFO, "Logging {0} and {1}", new Object[]{i, someString});
실제 측정을 수행하기 전에 동일한 테스트를 한 번 실행하여 JVM이 '워밍업'되었습니다. Java 1.7.03은 Windows 7에서 사용되었습니다. 최신 버전의 SLF4J (v1.6.6) 및 Logback (v1.0.6)이 사용되었습니다. Stdout 및 stderr이 널 장치로 경로 재 지정되었습니다.
그러나 JUL은 getSourceClassName()
기본적으로 소스 클래스 이름을 출력에 출력하지만 Logback은 출력하지 않기 때문에 JUL이 대부분의 시간을 소비하고 있음을 조심 하십시오. 우리는 사과와 오렌지를 비교하고 있습니다. 테스트를 다시 수행하고 로깅 구현을 비슷한 방식으로 구성하여 실제로 동일한 내용을 출력해야합니다. 그러나 SLF4J + Logback은 여전히 위에 나와 있지만 초기 숫자와는 거리가 멀다고 생각합니다. 계속 지켜봐 주시기 바랍니다.
Btw : 테스트는 실제로 SLF4J 또는 Logback으로 작업 한 것이 처음입니다. 즐거운 경험. JUL은 시작할 때 훨씬 덜 환영합니다.
테스트 성능 (2 부)
(2012 년 7 월 8 일에 nolan600에 의해 추가 된 섹션)
JUL에서 패턴을 구성하는 방법, 즉 소스 이름 포함 여부에 관계없이 성능에는 문제가되지 않습니다. 나는 매우 간단한 패턴으로 시도했다.
java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"
그리고 그것은 위의 타이밍을 전혀 바꾸지 않았습니다. 내 프로파일 러는 로거 getSourceClassName()
가 내 패턴의 일부가 아니더라도 호출에 많은 시간을 보냈다고 밝혔다 . 패턴은 중요하지 않습니다.
따라서 테스트 된 템플릿 기반 로그 문에 대해 JUL (느린)과 SLF4J + 로그 백 (빠른)의 실제 성능 차이에 대략 10의 요인이있는 것으로 보이는 성능 문제에 대해 결론을 내 렸습니다. Ceki가 말한 것처럼.
또한 SLF4J의 getLogger()
통화가 JUL의 통화보다 훨씬 비싸다는 또 다른 것을 볼 수 있습니다 . (내 프로파일 러가 정확하면 95ms 대 0.3ms). 이것은 말이됩니다. SLF4J는 기본 로깅 구현의 바인딩에 약간의 시간을 할애해야합니다. 이것은 나를 두려워하지 않습니다. 이러한 호출은 응용 프로그램 수명 동안 다소 드 물어야합니다. 견뢰도는 실제 로그 호출에 있어야합니다.
최종 결론
(2012 년 7 월 8 일에 nolan600에 의해 추가 된 섹션)
모든 답변에 감사드립니다. 처음에 생각했던 것과는 달리 API에 SLF4J를 사용하기로 결정했습니다. 이것은 많은 것들과 당신의 입력을 기반으로합니다 :
배포시 로그 구현을 유연하게 선택할 수 있습니다.
응용 프로그램 서버 내에서 실행될 때 JUL 구성의 유연성이 부족한 문제
SLF4J는 Logback과 결합하면 특히 위에서 설명한 것처럼 훨씬 빠릅니다. 이것이 거친 테스트 일지라도 JUL보다 SLF4J + Logback에서 훨씬 많은 노력이 최적화되었다고 생각할 이유가 있습니다.
선적 서류 비치. SLF4J에 대한 문서는 훨씬 포괄적이고 정확합니다.
패턴 유연성. 테스트를 수행하면서 JUL이 Logback의 기본 패턴을 모방하도록 설정했습니다. 이 패턴에는 스레드 이름이 포함됩니다. JUL 은이 작업을 즉시 수행 할 수 없습니다. 좋아, 나는 지금까지 그것을 놓치지 않았다. 그러나 나는 그것이 로그 프레임 워크에서 없어야한다고 생각하지 않는다. 기간!
오늘날 대부분의 (또는 많은) Java 프로젝트는 Maven을 사용하므로 종속성을 추가하는 것이 특히 그 종속성이 다소 안정적인 경우, 즉 API를 지속적으로 변경하지 않는 경우 큰 문제는 아닙니다. 이것은 SLF4J에 해당되는 것 같습니다. 또한 SLF4J 항아리와 친구는 크기가 작습니다.
그래서 이상한 일이 실제로 SLF4J와 조금 일한 후 JUL에 대해 화가 났었습니다. JUL과 함께 해야하는 것이 여전히 유감입니다. JUL은 완벽하지는 않지만 그 일을합니다. 충분하지 않습니다. Properties
예를 들어 똑같이 말할 수는 있지만 사람들이 자신의 구성 라이브러리에 플러그인 할 수 있다고 추상화하지는 않습니다. 나는 그 이유가 Properties
바로 막대 바로 위에 오는 반면 오늘 JUL의 반대는 사실 이라고 생각합니다 ... 그리고 과거에는 존재하지 않았기 때문에 0에 도달했습니다.
java.lang.System.Logger
인 인터페이스를 그 프레임 워크가 잡은 그 인터페이스의 구현을 제공 한, 당신이 원하는 실제 어떤 로깅 프레임 워크로 리디렉션 할 수 있습니다. 모듈화와 결합 java.util.logging
하여 다른 프레임 워크를 선호하는 경우 번들 JRE를 포함하지 않는 번들로 애플리케이션을 배포 할 수도 있습니다.