- 사전적 의미
통나무, 향해 일지, 배의 속력이나 항주한 거리를 계측하는 장치의 총칭
- 실질적 의미
기록을 남기는 것
System.out.print
를 사용하는 건 성능 저하를 야기함(가장 경미) DEBUG < INFO < WARN < ERROR < FATAL (가장 심각)
log4j / logback / slf4j
log4j.xml
파일을 서버 구동과 동시에 로딩하게 되어 있음log4j <-> logback
서로 변환을 해줄 수 있는 slf4j 라이브러리가 존재pom.xml
에 자동으로 slf4h 라이브러리가 추가되어 있음자동으로 slf4h가 추가되어 있다니...!
진짜로 확인해 보자!
...
<!-- Log4j (Logging) -->
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
...
이처럼 pom.xml
에 log4j 관련 라이브러리가 추가되어 있는 것을 확인할 수 있다.
(Simple logging Facade for Java)
(log4j <-> logback)
(로그 관련 설정 파일)
전달된 로그를 어디에 출력할지를 결정함
(콘솔 출력, 파일 기록, DB 저장)
- ConsoleAppender : 로그를 콘솔에 출력하기 위한 Appender
- JDBCAppender : 로그를 RDB에 출력하기 위한 Appender
- FileAppender : 로그를 파일에 출력하기 위한 Appender
-> 단, 지정한 파일에 로그가 계속 남기때문에 크기가 지나치게 커질 수 있고 지속적인 로그 관리가 불가능해짐
- RollingFileAppender : FileAppender를 보완한 개념
-> 일정한 조건 후에 기존 파일을 백업 파일로 바꾸고 다시 처음부터 로깅을 시작함
(대표적 예시 : DailyRollingFileAppender)
출력할 메세지를 Appender에 전달함
(로그 주체)
로그 주체, 패키지 작성
로그가 상위로 전달할지 여부 (기본값 true)
ref 속성값으로 appender 태그 name 값을 지정
로그 레벨을 설정함
-> 설정된 값 이상의 priority일 경우, 로깅 출력
이를 직접 확인해 보기 위해 현재 내 프로젝트 내 log4j.xml
을 살펴보자.
log4j.xml
는 사진 속 위치에 있다.
log4j의 DTD 파일 경로가 변경되어 2번째 줄 코드를 변경해 보았다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM
"http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%p] %m%n" />
</layout>
</appender>
<!-- //날짜별 로그 파일 생성 하기 -->
<appender name="dailyRollingFile" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="/logs/runtime.log" />
<param name="Append" value="true" />
<param name="encoding" value="UTF-8" />
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%p] %m%n" />
</layout>
</appender>
<!-- log level
trace -> debug -> info -> warn -> error -> fatal
-->
<!-- Application Loggers -->
<logger name="edu.kh.project">
<level value="debug" />
<appender-ref ref="dailyRollingFile" />
</logger>
<!-- 3rdparty Loggers -->
<logger name="org.springframework.core">
<level value="info" />
</logger>
<logger name="org.springframework.beans">
<level value="info" />
</logger>
<logger name="org.springframework.context">
<level value="info" />
</logger>
<logger name="org.springframework.web">
<level value="info" />
</logger>
<!-- Root Logger -->
<root>
<priority value="debug" />
<appender-ref ref="console" />
</root>
</log4j:configuration>
로그를 어떤 형식으로 출력할지 결정
- PatternLayout (가장 디버깅에 적합)
- DateLayout
- HTMLLayout
- SimpleLayout
- XMLLayout
debug, info, warn, error, fatal 등의 priority 출력
로그 내용 출력
로깅 이벤트가 발생한 시간 출력
-> 포맷을 %d{HH:mm:ss}, %d{yyyy-MM-dd HH:mm:ss}
같은 형태로 사용하면 SimpleDateFormat에 따른 포맷팅이 진행됨
로그 이벤트가 발생된 스레드의 이름 출력
% 표시 출력
플랫폼 종속적인 개행 문자 출력
(rn 또는 n 출력)
카테고리 표시
(예시 : 카테고리가 a.b.c 처럼 되어있다면 %c{2}는 b.c가 출력됨)
클래스명 표시
(예시 : 클래스 구조가 org.apache.xyz.SomeClass처럼 되어 있다면
%C{2}는 xyz.SomeClass가 출력됨)
로깅이 발생한 프로그램 파일명 출력
로깅이 발생한 caller의 정보 출력
로깅이 발생한 caller의 라인 수 출력
로깅이 발생한 method 이름 출력
어플리케이션 시작 이후부터 로깅이 발생한 시점의 시간(milliseconds) 출력
로깅이 발생한 thread와 관련된 NDC(nested diagnostic context) 출력
이제 로그를 한번 출력해 보자.
login() 메소드가 실행될 때 로그를 출력하기 위해 기존에 만들어 놓은 MemberServiceImpl
클래스로 가서 코드를 일부 추가해 볼 것이다.
package edu.kh.project.member.model.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import edu.kh.project.member.model.dao.MemberDAO;
import edu.kh.project.member.model.dto.Member;
@Service
public class MemberServiceImpl implements MemberService {
// org.slf4j.Logger : 로그를 작성할 수 있는 객체
// org.slf4j.LoggerFactory
private Logger logger = LoggerFactory.getLogger(MemberServiceImpl.class);
@Autowired
private MemberDAO dao;
@Autowired // bean으로 등록된 객체 중 타입이 일치하는 객체를 DI (의존성 주입)
private BCryptPasswordEncoder bcrypt;
@Override
public Member login(Member inputMember) {
// 로그 출력
logger.info("MemberService.login() 실행"); // 정보 출력
logger.debug("memberEmail : " + inputMember.getMemberEmail());
logger.warn("이건 경고 용도");
logger.error("이건 오류 발생 시");
Member loginMember = dao.login(inputMember);
if(loginMember != null) { // 아이디가 일치하는 회원이 조회된 경우
// 입력한 pw, 암호화된 pw 같은지 확인
// 같을 경우
if(bcrypt.matches(inputMember.getMemberPw(),
loginMember.getMemberPw())) {
// 비밀번호를 유지하지 않기 위해서 로그인 정보에서 제거
loginMember.setMemberPw(null);
} else { // 다를 경우
loginMember = null; // 로그인 실패처럼 만듦
}
}
return loginMember;
}
...
이렇게 작성한 뒤 서버를 실행해 보았다.
이렇게 작성된 로그는 어디서 확인할 수 있을까?
해당 위치에 logs
폴더가 생겼다.
폴더 안으로 들어가 보니 runtime
이라는 파일이 생긴 것을 볼 수 있다.
이 파일을 열어 보면
이렇게 로그들이 기록되어 있는 것을 볼 수 있다. 😉