개발공부/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개의 모듈이 존재
  1. logback-core : classic과 access의 공통, 핵심 코어 컴포넌트
  2. logback-classic : slf4j에서 사용가능하도록 만든 플러그인 컴포넌트
  3. 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 선언해줘야함
        •