개발공부/JAVA
log4j / logback / log4j2 정리
꽁렐
2022. 11. 9. 14:47
⊙ 적용환경
- sprnigboot 2.3.1버전
- jdk 1.8
- tomcat 7
⊙ 로그(Log)란 ?
- 애플리케이션의 상태를 관찰할 수 있도록 애플리케이션이 제공하는 정보 (=기록)
- log4j, logback, log4j2 모두 Java 로깅 애플리케이션
- 시간 순으로는 log4j → logback → log4j2 으로 등장
- 다른 로깅 프레임 워크로 전환할 때 slf4j 필요
※ slf4j
- Java 로깅 프레임워크들의 추상체 역할, 이 자체를 사용하는 편은 적음
- 자바로 따지면 인터페이스와 비슷한 역할, 사용중인 로깅 프레임워크가 변경되더라도 소스코드 자체의 변경을 막을 수 있음
- 만약 log4j → logback으로 변경할 때 log4j를 import 하던 파일들을 다 logback으로 바꿔줘야함
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggerFactory;
💡 소스마다 박혀있는 apache.log4j를 다 바꿔줘야함
- 하지만 slf4j를 쓴다면 사용하지 않는 dependency만 제거하면됨
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
- 개발자는 어떤 상황이든 대처하고 확장될 수 있는 느슨하고 유연한 코드를 만들어야 하기때문에 어떤 라이브러리를 쓰든 동일하게 동작하는 코드를 작성해야하고 그렇기때문에 slf4j를 사용해야함
💡 pom.xml
...
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
...
● log4j
- Apache에서 만든 오픈소스 라이브러리로 프로그램을 작성하는 도중 로그를 남기기 위해 사용되는 자바 기반 로깅 유틸리티
- !! 2015년 개발팀의 log4j 개발 중단 발표가 있어서 더이상 사용X !!
**구조
- Logger : 로깅이 일어나느 부분을 그룹화, 필요한 그룹의 로그만 추출하거나 카테고리에 우서순위를 부여함으로써 여러가지 출력방법을 지원
- Appender : 로그의 출력 위치를 지정
1) ConsoleAppender : 콘솔에 로그 메세지를 출력
- 현재 LCA는 이걸로 설정되어있음
2) FileAppender: 파일에 로그 메시지를 출력
3) RollingFileAppender: 로그의 크기가 지정한 용량 이상이 되면 다른 이름의 파일을 출력
- txt파일로 설정하고 싶으면 이걸로 설정
4) DailyRollingFileAppender: 하루를 단위로 로그 메세지를 파일에 출력
5) SMTPAppender: 로그 메세지를 이메일로 전송
6) NTEventLogAppender: 윈도우의 이벤트 로그 시스템에 기록한다.
- Layout : 로그의 출력 포맷을 지정
- %d : 로그의 기록시간
- %p : 로깅의 레벨
- %F : 로깅이 발생한 프로그램의 파일명
- %M : 로깅이 발생한 메소드의 이름
- %I : 호출지의 정보
- %L : 로깅이 발생한 호출지의 라인 수
- %t : 로깅이 발생한 Thread 명
- %c : 로깅이 발생한 카테고리
- %C : 로깅이 발생한 클래스명
- %m : 로그 메세지
- %n : 개행문자 출력
- %% : % 출력
- %r : 시작 이후로부터 로깅이 발생한 시점까지의 시간(ms)
▶ 실행
💡 pom.xml
...
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
...
💡 logback.xml
<예시>
ex) [%d{HH:mm:ss}] [%-5p] [%t] %c[%M:%L] - %m%n
💡 CzDemoApplication.java
💡 콘솔 로그 출력
● logback
- Logs4j를 토대로 새롭게 만들어진 로깅 라이브러리로 스프링부트의 기본 로그 객체
- 스프링이나 일반적인 자바프로그램의 경우 resources 디렉토리안의 logback.xml 참고
(logback.groovy → logback-test.xml → logback.xml 순서대로 찾음)
- 스프링부트는 logback-spring.xml 파일을 참고
**구조 : Log4j와 유사한 구조
- Logger : 실제 로깅을 수행하는 구성요소로 Level속성을 통해서 출력할 로그의 레벨 조절 가능
<Log4j의 로깅 레벨(지정한 것 이상의 레벨메세지가 출력)>
1) ERROR : 일반 에러가 일어났을 때 사용
2) WARN : 에러는 아니지만 주의할 필요가 있을 때 사용
3) INFO : 일반 정보를 나타낼 때 사용
4) DEBUG : 일반 정보를 상세히 나타낼 때 사용
5) TRACE : 경로추적을 위해 사용
- Layout
- %logger{length} : Logger name을 축약할 수 있음 {length}는 최대 자리 수
- %thread : 현재 Thread 이름
- %-5level : 로그 레벨, -5는 출력의 고정폭 값
- %msg : 로그 메시지 ( =%message)
- %n : new line
- %highlight: 로그레벨에 따른 색을 줄 수 있는 듯 함
- 나머지는 log4j와 비슷
** 특징
- log4j보다 약 10배정도 빠름, 메모리 효율성 향상
- 설정 파일을 변경하였을 경우, 서버 재기동 없이 변경 내용이 자동으로 갱신
- RollingFileAppender로 자동으로 오래된 로그 삭제
▶ 실행
💡 pom.xml
...
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
...
- logback은 logback-core, logback-classic, logback-access 3개의 모듈이 존재
- logback-core : classic과 access의 공통, 핵심 코어 컴포넌트
- logback-classic : slf4j에서 사용가능하도록 만든 플러그인 컴포넌트
- logback-access : 사용하는 어플리케이션이 '웹 어플리케이션'일 때 유용, HTTP요청에 대한 강력한 디버깅 기능을 제공
- maven repository를 쓴다면 classic만 추가하여 관련 라이브러리 사용 가능
💡 logback.xml
<예시>
ex) [%d{HH:mm:ss}] [%-5level] [%thread] %logger[%method:%line] - %msg%n
💡 CzDemoApplication.java
💡 콘솔 로그 출력
- 코드에는 trace레벨이 선언되어있는데(25줄) 콘솔 결과에는 출력되지 않음
→ logback설정에 로그출력레벨을 debug로 지정
→ 지정안하면 기본설정의 로그출력레벨은 debug
● log4j2
- log4j와 logback과 비교했을 때 가장 최근에 등장
- 다양한 설정파일 확장자 지원(properties, xml, yaml, json 등)
- logback의 기능을 대부분 제공하지만 성능면에서는 전반적으로 앞서고 있음
→ 이전버전들의 동기화 이슈들을 해결
▶ 실행
💡 pom.xml
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 해당 설정 안하는 경우 스프링부트에서 기본설정되어있는 logback을 사용하게됨 -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
...
<!-- Logging -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
</dependencies>
💡 log4j2.xml
- resources에 log4j2.xml 파일 생성해야함
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{HH:mm:ss}] [%-5p] [%t] %c[%M:%L] - %m%n" />
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="console" />
</Root>
</Loggers>
</Configuration>
💡 application.properties
logging.config=classpath:log4j2.xml
💡 CzDemoApplication.java
💡 콘솔 로그 출력
- logback과 마찬가지로 debug레벨이라 trace는 출력되지않음
● 이슈사항 정리
1) SLF4j(Logback) MultipleBinding
- slf4j와 logback 두개를 모두 dependency에 추가하여 생긴 멀티바인딩 문제
- log4j2를 사용하고싶은데 logback이 default로 잡히면서 문제가 생김
- 1개만 dependency를 사용하던지 아니면 pom.xml에 필요없는건 exclusion으로 제외시켜줘야함
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/CZ-kmki-N1/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/CZ-kmki-N1/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.12.0/log4j-slf4j-impl-2.12.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See <http://www.slf4j.org/codes.html#multiple_bindings> for an explanation.
2) springboot에서 log4j2 적용
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
**<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>**
</dependency>
...
<!-- Logging -->
<dependency>
<groupId>org.springframework.boot</groupId>
**<artifactId>spring-boot-starter-log4j2</artifactId>**
</dependency>
...
- log4j 나 logback와 다르게 log4j2는 스프링부트 log4j2로 적용해야함
(log4j나 logback은 기존 spring프로젝트에 있던거 적용해도 문제가 안됐었음)
- spring-boot-starter-web안에 exclusion 선언해줘야함
-