티스토리 뷰
보통 로깅을 할 때, 개발을 하다 보면 운영차원에서 System.out.println() 대신 로깅 라이브러리를 사용하도록 권장한다.
왜 그런지 알아보자.
동기화로 인한 성능 저하
println() 함수 내부를 들여다 보면,
이 처럼 write() 함수가 synchronized 블록으로 구성되어 있음을 확인 할 수 있다.
이는 멀티쓰레드 환경에서 write()를 호출할 때, 동기화 되어 한 쓰레드씩만 처리가 가능하고 다른 쓰레드들은 화면에 찍는 과정을 기다리게 된다. (Blocking)
따라서 이 과정에서 많은 수의 요청을 동시 처리하고자 할 때, 성능 저하가 발생할 수 있다.
+ 연산의 비효율성
문자열에 변수를 포함하기 위해서 + 연산자를 활용하여 다음과 같이 사용한다.
mopil = 25를 출력하고 싶을때 다음과 같이 해여한다.
String 객체는 불변 객체로, 한번 그 값이 할당 되면 내용물을 변경할 수 없다.
따라서 + 연산자는 기존 mopil 이라는 문자열에 새로운 값을 추가하는게 아닌, 아예 새로운 문자열 객체를 생성해내는 방식으로 동작한다.
이러면 기존에 필요없어진 mopil 문자열 객체는 heap 메모리에 존재하다가 GC에 의해 수거될 것 이다.
당연히 이러한 연산이 매우 많아진다면 성능상으로 좋지 못 한다.
Slf4j 라이브러리를 활용하여 동일하게 출력되도록 설정한 화면이다.
라이브러리가 제공하는 {} 포맷을 사용하면, 위에서 언급한 추가적인 + 연산을 하지 않고 출력할 수 있어서 성능상으로 더 효율적이다.
여담으로 StringBuffer나 StringBuilder를 사용하면 위 같은 연산 이슈는 해소할 순 있지만, 코드가 상당히 길어진다.
로그에 대한 기본적인 정보가 남지 않는다.
어떤 레벨에서 발생했는지, 언제, 어디서 발생했는지를 추가적으로 명시해줘야 나중에 모니터링할 때 편리할 것이다.
System.out.println()은 그냥 내용물만 달랑 찍으므로 좋지 못하다.
맹목적으로 쓰지 말라는 것이 아니다!
쓰면 안좋은 이유를 알고 있고, 어떨때 조심해야 하는지 숙지하고 있다면 적절한 곳에서 이를 활용하는 것은 상관없다.
가령, 아주 간단한 디버깅을 위해 출력 결과를 바로 확인하고 싶을 때는 print() 함수가 더 편리할 것이다. (물론 나중에 제거하는 걸 잊으면 곤란하다.)
여담으로 코틀린의 print() 함수는 내부적으로 System.out.print()를 호출하게끔 구현되어 있다.