728x90
운영자로 일 했을때 가장 무서웠던 단어가 '로그' 였다.
일하다가 오류가 발생해서 개발실에 문의를 하면 항상 로그 확인해서 누가 문제를 발생했는지 다 알 수 있었기 때문이다.
어떻게 그렇게 빨리 ' 확인하지 ? 온통 영어인데 정말 대단하다' 라고 생각했는데
오늘 직접 공부해보니 '오 ? 생각보다 별거 아니네!' 라고 생각해서 되게 재미있었던 시간이다 !
📂 Logging
📝 로그 ( Log )
- 사전적 의미 : 통나무, 향해 일지, 배의 속력이나 항주한 거리를 계측하는 장치의 총칭.
- 실질적 의미 : 기록을 남기는 것.
💬 로그 사용 이유
- 애플리케이션 운영 시 로그의 효율적인 관리가 가능하다.(콘솔 또는 특정파일)
- 콘솔 로그를 위해 System.out.print를 사용하는 건 성능저하를 야기함
🌝 로그 장점
- 프로그램의 문제 파악에 용이
- 빠르고 효율적인 디버깅 가능
- 수행내역 파악이 쉬움
- 로그 이력을 파일, DB 등으로 남길 수 있음
🌚 로그 단점
- 로그에 대한 디바이스(파일) 입출력으로 인해 런타임 오버헤드 발생
- 로깅을 위한 추가 코드로 인해 전체 코드 사이즈 증가
- 심하게 생성되는 로그는 혼란을 야기하거나 어플리케이션 성능에 영향을 미침
- 개발 중간에 로깅 코드를 추가하기 어려움
📂 Logging framework ( log4j / logback / slf4j )
- 스프링 프로젝트에는 기본적으로 log4j 라이브러리가 추가되어 있고,
log4j와 관련된 설정을 담는 log4j.xml 파일을 서버 구동과 동시에 로딩하게 되어 있음 - 하지만 log4j를 이용하여 많은 양의 로그를 출력하는 경우 성능 저하가 심해
최근에는 logback 이라는 라이브러리를 사용함 (10배 빠름) - 스프링 프로젝트에서 기존 사용하던 log4j를 새로운 logback로 변경을 해야 하는데,
이를 일일이 변경하기에는 비효율적이므로 log4j <-> logback 서로 변환을 해줄 수 있는 slf4j 라이브러리가 존재
-> STS 사용 시 pom.xml에 자동으로 slf4h 라이브러리가 추가되어 있음
📗 pom.xml ( 자동으로 log4j 추가되어 있다!)
<!-- 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>
이제 본격적로 로그 사용을 위해 설정을 해보자.
💬 설정방법
📚 Spring
📗 log4j.xml
<?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="dabug" />
<appender-ref ref="console" />
</root>
</log4j:configuration>
이렇게 설정하고 로그를 출력하기 위해서 처음 화면을 켜서
실행되는 LOGIN()메소드를 작성한 MemberServiceImpl 에 추가하였다.
📗 MemberServiceImpl.java
❗ 추가한 내용
//org.slf4j.Logger : 로그를 작성할 수 있는 객체
private Logger logger = LoggerFactory.getLogger(MemberServiceImpl.class);
// 현재 클래스명.class
// 로그 출력
logger.info("MemberService.login()실행"); // 정보 출력
logger.debug("memberEmail : "+inputMember.getMemberEmail());
logger.warn("이건 경고 용도");
logger.error("이건 오류 발생");
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 // service Layer
// 비즈니스 로직 (데이터 가공, dao 호출, 트랜잭션 제어) 처리하는 클래스라 명시
// + Bean 등록하는 어노테이션
public class MemberServiceImpl implements MemberService {
//org.slf4j.Logger : 로그를 작성할 수 있는 객체
private Logger logger = LoggerFactory.getLogger(MemberServiceImpl.class);
// 현재 클래스명.class
// private MemberDAO dao = new MemberDAO();
// 원래 이렇게 작성했는데 이미 DAO에 Bean 등록되어 있어 이렇게 작성할 필요 없음
// @Autowired : 작성된 필드와 Bean으로 등록된 객체 중 타입이 일치하는 Bean을
// 해당 필드에 자동으로 주입(Injection)하는 어노테이션
// == DI (Dependency Injection, 의존성 주입)
// -> 객체를 직접 만들지 않고, Spring이 만든걸 주입함
@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("이건 오류 발생");
// 암호화 추가 예정
System.out.println("암호화 확인 : " + bcrypt.encode(inputMember.getMemberPw()));
// bcrypt 암호화는 salt 가 추가되기 때문에
// 계속 비밀번호가 바뀌게 되어 DB에서 비교 불가능!!
// -> 별도로 제공해주는 matches(평문, 암호문)을 이용해 비교
// dao 매소드 호출
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;
}
// @Transactional(rollbackFor= {Exception.class})
// 예외가 발생하면 rollback
// 예외가 발생하지 않으면 Service 종료 시 commit
// 회원 가입 서비스
@Transactional(rollbackFor= {Exception.class})
@Override
public int signUp(Member inputMember) {
//비밀번호 BCrypt를 이용하여 암호화 후 다시 inputMember세팅
String encPw = bcrypt.encode(inputMember.getMemberPw());
inputMember.setMemberPw(encPw);
//DAO 호출
int result = dao.signUp(inputMember);
return result;
}
}
이렇게 세팅하고 서버를 켜보면 콘솔창과
log4j.xml에 작성한 <param name="File" value="/logs/runtime.log" /> 위치에 폴더가 생긴 것을 확인할 수 있다!
728x90