[SPRING] log4j 란❓

수경·2025년 3월 25일

SpringFrameWork

목록 보기
16/24
post-thumbnail

🌿Log4j 란❓

로그(logging) 를 남기기 위한 Java 기반의 로깅 라이브러리를 말한다.
스프링(Spring)에서 시스템이 실행되는 동안 에러, 경고, 디버깅 정보 등을 기록하기 위해 사용한다.

  • 애플리케이션에서 웹 사이트에 접속한 사용자 정보나 각 클래스의 메서드
    호출 시간 등 여러가지 정보를 로그로 출력해서 관리 할 수 있다.

  • 메이븐에서는 프로젝트를 생성할 때 자동으로 log4j 라이브러리가 설치된다.

Log4j를 사용하는 이유

1. System.out.println() 대신 사용

  • 일반적으로 System.out.println()을 쓰면 콘솔에 출력되지만,
    이 방식은 성능 저하와 유지보수 문제가 있다.

  • Log4j를 사용하면 로그 레벨별 관리, 파일 저장, 콘솔 출력, DB 저장 등이 가능하다!

2. 로그 레벨(Level) 관리

  • Log4j는 로그의 심각도(레벨) 를 설정해서 원하는 수준의 로그만 남길 수 있다.

  • 로그 레벨 종류 (낮은 순 → 높은 순)

TRACE < DEBUG < INFO < WARN < ERROR < FATAL
  • TRACE → 아주 상세한 디버깅 정보

  • DEBUG → 개발할 때 필요한 디버깅 정보

  • INFO → 일반적인 시스템 동작 로그

  • WARN → 주의해야 할 문제

  • ERROR → 에러 발생

  • FATAL → 치명적인 오류

PatternLayout 클래스 출력 속성

Log4j 기본 설정

1.src/main/resources → log4j.xml

2. log4j.xml 수정하기

	<appender name="dailyFileAppender" class="org.apache.log4j.DailyRollingFileAppender">
		<param name="File" value="C:\\springframework\\workspace\\pro10\\log\\output.log" />
		<param name="Append" value="true" />
	<layout class="org.apache.log4j.PatternLayout" >
		<param name="DatePattern" value="'.'yyyy-MM-dd" />
		<param name="ConversionPattern" value="[%d{HH:mm:ss}][%-5p] (%F:%L) - %m%n"/>
												
	</layout>
	</appender>

AOP를 이용한 로그 출력

  1. 패키지 생성(Controller, DAO, Service)
  2. pom.xml 에 Spring aop 기능 추가
  3. common 패키지 생성(Advice) , 위에서 생성한 패키지와는 별도로 만들어야 한다.

1. 패키지 생성

<TestController.java>

package com.test.pro10.ex02;  // 패키지 선언 (현재 클래스가 속한 패키지 경로)

/* 서블릿 관련 라이브러리 임포트 */
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/* Spring 프레임워크 관련 라이브러리 임포트 */
import org.springframework.beans.factory.annotation.Autowired;   // Spring의 의존성 주입(DI) 어노테이션
import org.springframework.context.annotation.EnableAspectJAutoProxy;  // AOP(Aspect-Oriented Programming) 기능 활성화 어노테이션
import org.springframework.stereotype.Controller;  // Spring MVC에서 컨트롤러 역할을 하는 클래스임을 선언하는 어노테이션
import org.springframework.web.bind.annotation.RequestMapping;  // 특정 URL과 메서드를 매핑하는 어노테이션

/* @Controller: 이 클래스가 Spring MVC의 컨트롤러 역할을 하는 클래스임을 선언 */
@Controller
/* @EnableAspectJAutoProxy: AOP(관점 지향 프로그래밍) 기능을 활성화 */
@EnableAspectJAutoProxy
public class TestController {  // 컨트롤러 클래스 선언

    /* @Autowired: TestService 빈(Bean)을 자동으로 주입 */
    @Autowired
    TestService service;
    
    /* @RequestMapping: 해당 URL 요청이 들어오면 logTest2() 메서드 실행 */
    @RequestMapping("/test02/logTest2.do")
    public String logTest2(HttpServletRequest request, HttpServletResponse response) { 
        /* 서비스 클래스의 logTest2() 메서드 실행 */
        service.logTest2();
        
        /* 뷰(View) 페이지 경로 반환 ("/test01/result" 페이지로 이동) */
        return "/test01/result";
    }
}

<TestDAO.java>

package com.test.pro10.ex02;  // 패키지 선언 (현재 클래스가 속한 패키지 경로)

import org.springframework.stereotype.Repository;  // Spring의 DAO(데이터 액세스 객체) 역할을 위한 어노테이션

/* @Repository: 해당 클래스가 데이터베이스 접근을 담당하는 DAO 역할을 하는 클래스임을 선언 */
@Repository
public class TestDAO {  // DAO(Data Access Object) 클래스 선언

    /* logTest2(): 단순 로그 출력 메서드 */
    public void logTest2() {
        // TODO Auto-generated method stub (자동 생성된 주석, 나중에 구현할 코드가 있을 때 사용 가능)

        /* 콘솔에 "DAO 실행" 출력 */
        System.out.println("DAO 실행");
    }
}

<TestService.java>

package com.test.pro10.ex02;  // 패키지 선언 (현재 클래스가 속한 패키지 경로)

import org.springframework.beans.factory.annotation.Autowired;  // Spring의 의존성 주입(DI) 어노테이션
import org.springframework.stereotype.Service;  // 서비스 계층을 나타내는 Spring 어노테이션

/* @Service: 해당 클래스가 비즈니스 로직을 처리하는 서비스 클래스임을 선언 */
@Service
public class TestService {  // 서비스 클래스 선언

    /* @Autowired: TestDAO 객체를 자동으로 주입 (의존성 주입) */
    @Autowired
    TestDAO dao;

    /* logTest2(): DAO의 logTest2() 메서드를 호출하는 서비스 메서드 */
    public void logTest2() {
        // TODO Auto-generated method stub (자동 생성된 주석, 나중에 구현할 코드가 있을 때 사용 가능)

        /* DAO의 logTest2() 메서드 호출 */
        dao.logTest2();
    }
}

spring-Aop

<pom.xml>

<!-- Spring AOP -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-aop</artifactId>
		<version>${org.springframework-version}</version>
		<type>jar</type>
		<scope>compile</scope>
	</dependency>
		<dependency>
		<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>2.2</version>
		<type>jar</type>
		<scope>compile</scope>
	</dependency>
	<dependency>
		<groupId>org.aspectj</groupId>
		<artifactId>aspectjweaver</artifactId>
		<version>${org.aspectj-version}</version>
	</dependency>

Advice

<Advice.java>

package com.test.pro10.common;  // 패키지 선언 (현재 클래스가 속한 패키지 경로)

import java.util.Arrays;  // 배열을 문자열로 변환하기 위한 유틸리티

import org.aspectj.lang.JoinPoint;  // AOP에서 조인포인트 정보를 가져오는 인터페이스
import org.aspectj.lang.ProceedingJoinPoint;  // AOP에서 Around 어드바이스를 사용할 때 필요한 인터페이스
import org.aspectj.lang.annotation.After;  // 메서드 실행 후 동작할 어드바이스를 지정하는 어노테이션
import org.aspectj.lang.annotation.Around;  // 메서드 실행 전후로 동작할 어드바이스를 지정하는 어노테이션
import org.aspectj.lang.annotation.Aspect;  // 이 클래스가 AOP(관점 지향 프로그래밍) 기능을 하는 클래스임을 선언하는 어노테이션
import org.aspectj.lang.annotation.Before;  // 메서드 실행 전에 동작할 어드바이스를 지정하는 어노테이션
import org.slf4j.Logger;  // 로깅을 위한 SLF4J 인터페이스
import org.slf4j.LoggerFactory;  // Logger 객체를 생성하는 SLF4J 클래스
import org.springframework.stereotype.Component;  // Spring이 관리하는 Bean으로 등록하기 위한 어노테이션

/* @Component: Spring의 Bean으로 등록하여 사용할 수 있도록 함 */
/* @Aspect: 해당 클래스가 AOP를 위한 클래스임을 명시 */
@Component
@Aspect
public class LogAdvice {  // AOP를 사용한 로그 처리 클래스

    /* Logger 객체 생성 (이름: LogAdvice.class) */
    private static final Logger logger = LoggerFactory.getLogger("LogAdvice.class");

    /* 
       @Before: 대상 메서드 실행 전에 실행되는 어드바이스
       execution(* com.test.pro10.ex02.*.*(..)): 
       com.test.pro10.ex02 패키지 내의 모든 클래스에서 모든 메서드 실행 전에 적용
    */
    @Before("execution(* com.test.pro10.ex02.*.*(..))")
    public void startLog(JoinPoint jp) {
        logger.info("===========================");
        logger.info("1 : " + Arrays.deepToString(jp.getArgs()));  // 메서드의 전달된 인자 값 출력
        logger.info("2 : " + jp.getKind());  // 실행된 메서드의 종류 (예: 메서드 실행)
        logger.info("3 : " + jp.getSignature().getName());  // 실행된 메서드 이름 출력
        logger.info("4 : " + jp.getTarget().toString());  // 대상 객체 (실제 실행된 객체) 정보 출력
        logger.info("5 : " + jp.getThis().toString());  // 프록시 객체 정보 출력
        logger.info("");
    }

    /* 
       @After: 대상 메서드 실행 후 실행되는 어드바이스 
       execution(* com.test.pro10.ex02.*.*(..)): 
       com.test.pro10.ex02 패키지 내의 모든 클래스에서 모든 메서드 실행 후 적용
    */
    @After("execution(* com.test.pro10.ex02.*.*(..))")
    public void endLog(JoinPoint jp) {
        logger.info("===========================");
        logger.info("1 : " + Arrays.deepToString(jp.getArgs()));  // 메서드의 전달된 인자 값 출력
        logger.info("2 : " + jp.getKind());  // 실행된 메서드의 종류 (예: 메서드 실행)
        logger.info("3 : " + jp.getSignature().getName());  // 실행된 메서드 이름 출력
        logger.info("4 : " + jp.getTarget().toString());  // 대상 객체 (실제 실행된 객체) 정보 출력
        logger.info("5 : " + jp.getThis().toString());  // 프록시 객체 정보 출력
        logger.info("");
    }

    /* 
       @Around: 대상 메서드 실행 전후에 실행되는 어드바이스 
       execution(* com.test.pro10.ex02.*.*(..)): 
       com.test.pro10.ex02 패키지 내의 모든 클래스에서 모든 메서드 실행 전후로 적용
    */
    @Around("execution(* com.test.pro10.ex02.*.*(..))")
    public Object timeLog(ProceedingJoinPoint pjp) throws Throwable {
        /* 시작 시간 측정 */
        long startTime = System.currentTimeMillis();
        
        logger.info("===========================");
        logger.info("1 : " + Arrays.toString(pjp.getArgs()));  // 메서드의 전달된 인자 값 출력
        
        /* 대상 메서드 실행 */
        Object result = pjp.proceed();
        
        logger.info("2 : " + pjp.getSignature().getName());  // 실행된 메서드 이름 출력

        /* 종료 시간 측정 및 실행 시간 계산 */
        long endTime = System.currentTimeMillis();
        logger.info("동작시간 : " + (endTime - startTime) + "ms");  // 실행 시간 로그 출력
        
        logger.info("===========================");
        
        return result;  // 원래 메서드의 반환값 리턴
    }
}

실행 결과

profile
개발 공부중•••

0개의 댓글