이번에 일하는 회사에서 신입분이 들어오셔서 디버깅과 로거의 개념을 알려드리기위해 나도 정리를 해보았다.
디버깅을 하는 이유
"디버그(debug)는컴퓨터 프로그램 상의 오류(버그)를 찾아내어 바로잡는 과정을 뜻한다.디버깅(debugging)이라고도 한다. "
1. 버그 식별
디버깅 도구는 애플리케이션의 실행 중에 발생하는 버그를 식별하는 데 사용됩니다. 프로그램이 의도한 대로 동작하지 않을 때, 디버깅 도구를 사용하여 코드의 어떤 부분에서 문제가 발생하는지 찾을 수 있습니다.
2. 프로그램의 상태 분석
디버깅 도구는 애플리케이션의 상태를 실시간으로 모니터링하고 분석할 수 있습니다. 변수의 값을 확인하거나 스택 추적을 통해 프로그램의 흐름을 이해할 수 있습니다. 이를 통해 애플리케이션의 오류 원인을 파악할 수 있습니다.
3. 코드 실행 추적
디버깅 도구는 코드 실행을 추적하고, 중단점을 설정하여 특정 시점에서 코드의 실행을 멈출 수 있습니다. 이를 통해 원하는 지점에서 코드를 분석하고 문제를 진단할 수 있습니다.
4. 변수 값 검사
디버깅 도구를 사용하면 변수의 현재 값을 검사할 수 있습니다. 따라서 잘못된 변수 값이나 예기치 않은 결과를 확인하고 이를 수정할 수 있습니다.
5. 성능 개선
디버깅 도구는 애플리케이션의 성능 문제를 분석하고 개선하는 데 사용됩니다. 실행 시간, 메모리 사용량, 네트워크 요청 등과 관련된 데이터를 수집하여 성능 병목 현상을 찾고 최적화할 수 있습니다.
디버깅 방법
sysout 과 logger 차이
휘발된다
System.out.println() 은 로그가 표준 출력으로 출력된다. 즉, 파일로 저장되지 않고 휘발된다는 의미이다. 로그는 에러가 발생한 상황을 기록하고, 추후 확인하여 문제를 진단하고, 재현하고, 고치기 위해 사용된다. 하지만 표준 출력으로 한번 출력되고 어디에도 저장되지 않으면 로그의 제 역할을 할 수 없다.
로그된 데이터는 실제로 기록되어야 한다. 하지만 System.out.println() 만으로는 불가능하다.
에러 발생 시 추적할 수 있는 최소한의 정보가 남지 않는다
System.out.println() 은 인자로 전달한 문자열만을 출력한다. 문제가 발생한 날짜, 시각 그리고 문제의 수준, 로그가 발생한 위치 등 최소한의 정보가 기록되지 않는다는 것 이다. 이런 제한적인 정보만으로는 문제를 해결하기 어려울 것 이다. 물론 이런 정보도 함께 인자로 전달한다면 충분히 에러와 장애를 추적할 수 있는 정보를 남길수야 있지만… 매번 그런 정보를 일일히 남기기엔 번거로울 것 이다.
로그 출력 레벨을 사용할 수 없다
로컬에서 개발할 때에는 디버깅을 위한 아주 상세한 정보가 출력되어 확인할 수 있어야한다. 하지만, 프로덕션에서 동작하는 코드는 에러/장애가 발생할 때 문제를 진단할 수 있는 정보만을 남겨야한다. 개발시에만 사용되는 정보와 문제 상황에 대한 정보가 함께 로깅된다면 문제 해결을 위한 정작 중요한 정보를 얻기 힘들 뿐더러, 민감한 정보를 로그로 남길수도 있기 때문이다. 또한 의미없는 로그가 쌓여 서버 용량을 차지할 수도 있다.
따라서 로깅 라이브러리는 환경에 맞게(로컬 개발 환경, 개발 서버, 프로덕션 서버 등) 로그가 출력될 수 있도록 로그 출력 레벨이라는 기능을 제공한다. 많이 사용되는 Logback이라는 라이브러리에서는 TRACE, DEBUG, INFO, WARN, ERROR, FATAL 와 같은 레벨을 제공한다. 하지만 System.out.println() 은 이런 기능을 제공하지 않는다. 어떤 환경에서든 동일한 로그가 출력된다. 프로덕션에서 이런 로그를 제거하려면 코드를 일일히 제거하거나 주석처리하거나 별도의 조건문을 설정하는 등 번거로운 일들을 해야한다.
성능저하의 원인이 될 수 있다
System.out.println() 의 구현을 한번 살펴보자.
/**
* Terminates the current line by writing the line separator string. The
* line separator string is defined by the system property
* {@code line.separator}, and is not necessarily a single newline
* character ({@code '\n'}).
*/
public void println() {
newLine();
}
println() 은 newLine() 을 호출한다. newLine() 의 구현도 살펴보자.
private void newLine() {
try {
synchronized (this) {
ensureOpen();
textOut.newLine();
// ...
synchronized 키워드가 붙어있다. 이때 newLine() 메소드는 임계영역(critical section)이 된다. 멀티 쓰레드 환경에서 A 쓰레드가 newLine() 메소드를 실행하면, 메소드는 잠기게 된다. 다른 쓰레드는 A 쓰레드가 모두 사용하고 잠금을 풀어준 뒤에서야 newLine() 메소드를 실행할 수 있다. 오버헤드가 발생하게 되는 것 이다.
스프링을 실행하는 톰캣은 멀티 쓰레드로 동작한다. 요청이 오면 쓰레드 풀에서 쓰레드를 하나 가져와 요청을 처리한다. 그런데, System.out.println() 을 여러 쓰레드가 사용하면 그만큼 위에서 이야기한 오버헤드가 발생하고 처리가 느려질 것 이다. 따라서 실제 프로덕트의 코드에서는 System.out.println() 을 절대 사용해서는 안된다.
한 번 요청 시 5000명의 사용자를 요청하고, 처리 과정에서 응답시간이 20초 걸리는 사이트가 있는데, 원인을 알아보니 5000명의 정보를 다 System.out.println()으로 처리하고있던 것이다. 이는 System.out.println()을 줄임으로써 응답시간이 6초까지 줄었다. - 이상민, 자바 성능 튜닝이야기, 인사이트, 2013
Logger라이브러리 : slf4j, log4j2, logback 등
라이브러리 |
설명 |
SLF4J (Simple Logging Facade for Java) | 로깅 인터페이스(추상화 계층) 역할을 수행, 구현체(Logback, Log4j2 등)와 결합 |
Log4j2 | Apache에서 제공하는 강력한 로깅 프레임워크, 성능 최적화 및 JSON 설정 지원 |
Logback | SLF4J의 기본 구현체, Spring Boot 기본 로거, Log4j보다 가벼움 |
Log4j2 (Apache Log4j 2)
Log4j2는 Apache에서 제공하는 강력한 로깅 프레임워크입니다.
기존 Log4j의 성능 문제를 해결하고 JSON/YAML 설정을 지원합니다.
Log4j2 설정 및 사용법
(1) 의존성 추가 (Maven)
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
(2) Logger 사용
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class MyService {
private static final Logger logger = LogManager.getLogger(MyService.class);
public void doSomething() {
logger.info("정보 로그 출력");
logger.debug("디버그 로그 출력");
logger.error("에러 로그 출력");
}
}
(3) 장점
- 비동기 로깅 지원 (성능 최적화)
- JSON, YAML 기반의 유연한 설정 파일 지원
- 필터링 기능이 강력하여 다양한 레벨의 로깅 설정 가능
(4) 단점
- 설정이 다소 복잡할 수 있음
- 일부 환경에서는 Logback보다 무거울 수 있음
Logback
Logback은 SLF4J의 기본 로깅 구현체이며, Spring Boot에서 기본적으로 사용됩니다.
Logback 설정 및 사용법
(1) 의존성 추가 (Maven)
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.14</version>
</dependency>
(2) Logger 사용 (SLF4J와 동일)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyService {
private static final Logger logger = LoggerFactory.getLogger(MyService.class);
public void doSomething() {
logger.info("정보 로그 출력");
logger.debug("디버그 로그 출력");
logger.error("에러 로그 출력");
}
}
(3) 장점
- Spring Boot 기본 로깅 라이브러리
- 기존 Log4j보다 가볍고 빠름
- XML 기반 설정 파일 사용 가능
(4) 단점
- Log4j2에 비해 성능 최적화 기능이 부족함
- JSON/YAML 설정 지원이 제한적임
SLF4J, Log4j2, Logback 비교
기능 | SLF4J | Log4j2 | Logback |
역할 | 로깅 인터페이스 | 로깅 프레임워크 | 로깅 프레임워크 |
기본 설정 | 구현체 필요 | XML, JSON, YAML 설정 가능 | XML 설정 가능 |
성능 | 구현체에 따라 다름 | 비동기 로깅 지원 (빠름) | 기본적인 성능 최적화 |
Spring Boot 기본 지원 | ❌ (인터페이스만 제공) | ❌ | ✅ (Spring Boot 기본 로거) |
JSON/YAML 설정 | ❌ | ✅ | ❌ (XML만 지원) |
비동기 로깅 | 구현체에 따름 | ✅ (AsyncAppender 지원) | ✅ (AsyncAppender 지원) |
어떤 Logger를 선택해야 할까?
✅ Spring Boot 프로젝트 → Logback (기본 설정)
✅ 고성능 & 대규모 시스템 → Log4j2 (비동기 로깅 지원)
✅ 유연한 설정 & 인터페이스 분리 → SLF4J + Logback 또는 Log4j2
결론
- SLF4J는 로깅 인터페이스 역할을 하며, Logback, Log4j2 등과 함께 사용해야 한다.
- Log4j2는 고성능 로깅 프레임워크로, JSON/YAML 설정 지원 및 비동기 로깅 기능이 강력하다.
- Logback은 Spring Boot의 기본 로거로, 가볍고 빠르며 기본적인 로깅 기능을 제공한다.
Logger레벨
log4j2 는 다음과 같은 로그 레벨을 가진다.
TRACE > DEBUG > INFO > WARN > ERROR > FATAL
- INFO로 셋팅하면, INFO, WARN, ERROR, FATAL은 기록된다.
FATAL : 아주 심각한 에러가 발생한 상태를 나타낸다.
ERROR : 어떠한 요청을 처리하는 중 문제가 발생한 상태를 나타낸다. 프로그램 동작에 큰 문제가 발생했다는 것으로 즉시 문제를 조사해야 하는 것 (DB를 사용할 수 없는 상태, 중요 에러가 나오는 상황)
WARN : 프로그램의 실행에는 문제가 없지만, 향후 시스템 에러의 원인이 될 수 있는 경고성 메시지를 나타낸다. WARN에서도 2가지의 부분에선 종료가 일어남
- 명확한 문제 : 현재 데이터를 사용 불가, 캐시값 사용 등
- 잠재적 문제 : 개발 모드로 프로그램 시작, 관리자 콘솔 비밀번호가 보호되지 않고 접속 등
INFO : 어떠한 상태 변경과 같은 정보성 메시지를 나타낸다.
DEBUG : 개발시 디버그 용도로 사용하는 메시지를 나타낸다.
TRACE : 디버그 레벨이 너무 광범위한 것을 해결하기 위해서 좀 더 상세한 이벤트를 나타낸다.
연관된 글 :
참고:
디버깅 (개념 / 과정 / Intellij 디버깅 방법 / Eclipse 디버깅 방법)
로깅을 System.out.println() 로 하면 안되는 이유
JAVA logging framework (기본) - slf4j, log4j와 logback
[Web] Logging Level(로그 레벨) 이란?
'개발 > 개발지식' 카테고리의 다른 글
도메인 네임(Domain Name) (0) | 2024.06.06 |
---|---|
트랜잭션 (0) | 2024.06.06 |
[네트워크] 로드 밸런싱(Load balancing) (0) | 2023.05.11 |
암호화 알고리즘 (0) | 2023.04.25 |
블록 다이어 그램 (0) | 2023.04.23 |