코드 저장소.

System.out.println()을 쓰면 안 되는 이유 본문

포폴/일정관리앱

System.out.println()을 쓰면 안 되는 이유

slown 2025. 3. 23. 12:11

목차

1.사건의 발단

2.println을 쓰면 안되는가?

3.그래서? 어떻게 해야되는가?

4.느낀점.

 

1.사건의 발단

첨부파일 모듈에서 첨부파일 업로드에 관한 로직을 작성을 했고 pr을 올렸는데 다음과 같은 리뷰가 들어왔습니다. 

 

업로드를 테스트를 하기 위해서 작성을 했던 System.out.println()이었는데 사용을 하면 안된다고 해서 왜 안돼는지에 관해서 알아보기로 했습니다.

2.println을 쓰면 안되는가?

사실 처음엔 크게 문제 될 거라 생각 안 했습니다. 그냥 테스트용으로 했거든요. 근데 찾아보니 이게 생각보다 심각했었습니다.  우선은 System.out.println()이 무엇인지를 알아보기로 했습니다.

 

System.out.println()

  • System.out.println은 Java개발할때 디버깅 용도로 콘솔에 출력하는 메소드 중 하나다.
  • System은 java.lang 패키지의 내장된 최종 클래스다.
  • out은 System 클래스의 정적 멤버 필드이며 PrintStream이다.
  • println은 PrintStream 클래스의 메서드이고, 표준 콘솔에 전달된 인자와 줄 바꿈을 출력한다.

왜 안돼는가??

  1. 성능 이슈
    - 이유는 크게 2가지로 블로킹 I/O와 멀티쓰레드에서 락이 발생하기 때문이다.
    - System.out.println이 끝날때까지 아무 일을 실행할 수 없고 대기해야 하기에 성능을 저하시킬 수 있다. 
  2. 로그 레벨 관리가 어려움
    - 로그 레벨을 지정할 수 없기 때문에 디버깅 용도로 사용되는 경우, 어떤 로그 레벨로 출력되는지 확인하기 어렵다.
    - 로그 레벨이 제대로 관리되지 않으면, 프로덕션 환경에서도 불필요한 디버깅 정보가 출력되어 시스템의 안정성과 보안에 문제가 생길 수 있다.

그리고 println의 내부코드를 보면 다음과 같습니다.

public void println(int x) {
        if (getClass() == PrintStream.class) {
            writeln(String.valueOf(x));
        } else {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    }

 

위의 코드를 보면은 다음과 같이 알 수 있습니다.

  • getClass() == PrintStream.class 조건을 통해 리플렉션 기반 분기
  • 그렇지 않으면 synchronized (this)로 동기화 처리
  • 내부적으로 print() 호출 후 \n을 출력 (newLine())

이를 봤을때 알 수 있는 것은 내부적으로 동기화 + 조건 분기 + 복수 메서드 호출이 섞인 복잡한 메서드인것입니다.

 

그리고 로깅과 비교를 해보면 다음과 같이 볼 수가 있습니다.

항목 println() logback같은 로깅
로그 레벨 제어 무조건 출력 DEBUG/INFO 등 조절 가능
출력 위치 제어 콘솔이 고정 파일,콘솔,서버 등 다양
포맷 커스터마이징 없음 시간,클래스명, 스레드 등 가능
운영 환경 적합성 로그 수집이 안된다. 로그 시스템과 연동
다중 스레드 안전성 로그가 꼬일 수 있다. 스레드 안전 지원

3.그래서 어떻게 해야되는가?

이렇게 System.out.println()이 안 좋다는것이 맞다. 하지만 내 프로젝트에는 이미 MDC를 사용해서 로깅을 하고 있었다......

그래서 위의 출력을 @Slfj를 사용해서 로깅을 남기면 되는 것이다.

log.debug("업로드된 파일 이름: {}", multipartFile.getOriginalFilename());

4.느낀점

이번 경험을 통해 단순히 println 하나 때문에 "로깅 시스템의 필요성과 가치"를 되짚게 돼었습니다. 사실 System.out.println()은 누구나 쉽게 쓰고 바로 결과를 볼 수 있어서 익숙합니다. 하지만 그 편안함에 너무 의존하다 보면,
운영 환경, 멀티스레드, 디버깅 효율, 추적 가능성 같은 중요한 요소들을 놓치게 되는것 같습니다. 

 

이 계기를 통해서

  • 간단한 디버깅도 반드시 log.debug() 이상을 쓰겠다
  • 로그 설정은 처음부터 꼼꼼히 구성하겠다