본문 바로가기
Spring

[Spring] MVC2 (1) 로깅, ajax

by moca7 2024. 10. 18.

 

 

 

ㅁ 로그, ajax 관련 프로젝트

 

 

ㅁ Spring legacy project 생성

 

 

 

- 베이스 패키지는 com.br.ajax로 했다.

모든 클래스는 전부 저 베이스 패키지로 해야 한다.

빈 스캐닝할 때 베이스 패키지를 기준으로 하기 때문에 2번째 레벨 등에서 쪼개지면 안 된다.

 

- 빈등록이 제대로 되려면 베이스 패키지로 com.br.ajax를 가지고 있어야 한다.

 

 

 

 

ㅁ 프로젝트를 만들면 바로 pom.xml을 바꾼다.

 

 
<?xml version="1.0" encoding="UTF-8"?>
   
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.br</groupId>
    <artifactId>ajax</artifactId>
    <name>03_Spring_Logging_AJAX</name>
    <packaging>war</packaging>
    <version>1.0.0-BUILD-SNAPSHOT</version>
   
    <properties>
        <java-version>11</java-version>
        <org.springframework-version>5.3.27</org.springframework-version>
        <org.aspectj-version>1.9.19</org.aspectj-version>
        <org.slf4j-version>2.0.7</org.slf4j-version>
    </properties>
   
    <dependencies>
   
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework-version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                 </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>
               
        <!-- AspectJ -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${org.aspectj-version}</version>
        </dependency>  
       
        <!-- Logging -->
        <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>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.15</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.mail</groupId>
                    <artifactId>mail</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>javax.jms</groupId>
                    <artifactId>jms</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jdmk</groupId>
                    <artifactId>jmxtools</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jmx</groupId>
                    <artifactId>jmxri</artifactId>
                </exclusion>
            </exclusions>
            <scope>runtime</scope>
        </dependency>

        <!-- @Inject -->
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>
               
        <!-- Servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
   
        <!-- Test -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>        
       
       
        <!-- Lombok 라이브러리 추가 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
       
       
       
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java-version}</source>
                    <target>${java-version}</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
 
</project>
 

 

- 기존의 프로젝트에서 pom.xml 내의 내용을 복사해서 붙여넣기 한다.

- 그런데 <modelVersion> ~ </version> 부분은은 가져오면 안된다.

- <properties> 부터 </build>까지만 복사해서 붙여넣기 한다.

 

- <dependencies>가 필요한 라이브러리 목록이었다.

 

- 자바 버전은 바로 반영이 안돼서, 프로젝트 우클릭 - maven - update project를 해서 자바 버전이 11버전으로 잘 바뀌었는지 확인한다.

 

 

 

 

ㅁ 샘플 파일들 삭제

 

 
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
    <title>Home</title>
</head>
<body>
<h1>
    Hello world!  
</h1>

<P>  The time on the server is ${serverTime}. </P>
</body>
</html>
 

 

- src/main/webapp/WEB-INF/views/home.jsp

- 얘네가 만들어놓은 메인페이지

- 그리고 home.jsp로 포워딩하는 HomeController.java도 만들어져있다.

컨트롤러용 클래스여서 @Controller 어노테이션이 있다.

- /가 오면 home으로 이동되게끔 반환하고 있다.

- 이 페이지에서 쓰라고 날짜과녈ㄴ해서 담아놨다. home.jsp에서 el구문으로 꺼내서 출력

 

 

 
package com.br.ajax;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {
   
    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
   
    /**
     * Simply selects the home view to render by returning its name.
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Locale locale, Model model) {
        logger.info("Welcome home! The client locale is {}.", locale);
       
        Date date = new Date();
        DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
       
        String formattedDate = dateFormat.format(date);
       
        model.addAttribute("serverTime", formattedDate );
       
        return "home";
    }
   
}
 

 

- src/main/java/com/br/ajax/HomeController.java

 

 

 

 

 

ㅁ 패키지 생성

 

- com.br.ajax.controller

- com.br.ajax.dto

- com.br.ajax.service

 

- dao는 두지 않고 service에서 받았다고 가정한다.

 

 

 

 

 

ㅁ views 폴더에 main.jsp 생성

 

 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
 
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
   
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

    <h3>메인페이지 입니다</h3>

</body>
</html>
 

 

 

 

 

 

 

ㅁ MvcController 클래스 생성

 

 
package com.br.ajax.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MvcController {

    @RequestMapping(value= {"/", "/main.do"})
    public String mainPage() {
       
        System.out.println("MvcController의 mainPage 메소드 작동됨");
       
        return "main";
    }
   
}
 

 

 

- 컨트롤러 역할을 하는 클래스에 바로 @Controller를 붙인다.

 

- 디버깅(데이터가 잘 담겼는지 확인하는 등)할 때 이때까지 System.out.println문을 사용해 왔다.

이 메소드가 잘 실행되는지 확인용으로 디버깅용으로 출력문을 작성했었다.

- 기본적으로 이 출력문은 운영되는 서버의 콘솔에 출력된다.

개발이 다 끝나고 실제 배포되면 운영되는 서버의 콘솔창에 출력된다.

 

 

 

 

 

ㅁ 브라우저로 접속

 

 

 

- 서버 우클릭 - add and remove로 이전 프로젝트는 내리고 지금 프로젝트를 올린다.

- http://localhost:8888/ajax를 입력해서 메인페이지에 접속해본다.

 

 

 

 

 

- 콘솔에도 출력되어 있다.

- 과부하가 심해서 로그로 출력하는 방법이 좋다.

 

 

 

 

 

ㅁ 

- 출력문은 성능 저하를 야기시켜서 로그를 출력한다.

- 알게모르게 서버를 start하는 순간 읽어들이는게 굉장히 많다.

콘솔창에 사실 로그 출력이 되고 있었다. 검은 글씨가 전부 로그 출력이다.

 web.xml 거쳐서 ~를 읽어들인다.

서버 start 되는 순간 일어나는 일이 굉장히 많다.

- 서버를 start하는 순간 스프링 객체들도 생성되고 거기에 로그 출력문들이 있어서 검은 글씨의 로그가 출력되고 있었다.

엄청 많은데 그중에 INFO 레벨 이상의 로그만 출력되고 있는 것이다.

로그의 레벨도 엄청 많다.

- 알게모르게 스프링 프레임워크를 쓰는 순간 

- 요즘은 로깅 프레임워크로 log4j보다 로그백을 쓰는 추세로 바뀌었다.

 

 

 

 

- src/main/resources의 log4j.xml 덕분에 로그 출력이 되고 있었다.

- log4j.xml을 열어본다.

 

 

 

 

 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "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="%-5p: %c - %m%n" />
        </layout>
    </appender>
   
    <!-- Application Loggers -->
    <logger name="com.br.ajax">
        <level value="info" />
    </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="warn" />
        <appender-ref ref="console" />
    </root>
   
</log4j:configuration>
 

 

 

- ConsoleAppender로 콘솔에 출력하고 있다.

- %p가 의미하는게 로그 레벨이다. %-5p로 INFO가 출력된다.

- %c가 의미하는게 그 로그가 어느 클래스에 위치하고 있는지 org.springframework.web.context.ContextLoader가 출력된다.

- %m은 출력 메세지

- %n은 줄바꿈

 

- 그리고 아래에 info 레벨 이상의 로그만 출력되게 설정되어 있다.

 

- 로그백을 쓰면 패턴도 달라진다.

 

- 콘솔 말고 파일에도 출력할 수 있다.

 

 

 

 

 

ㅁ 

- 로그 관련한 파일(xml)이 src/main/resources에만 ~이름으로 있으면 된다.

- log4j.xml를 삭제해도 된다. 나중엔 삭제한다. 근데 지금은 사용하지 않도록 이름만 log4j_notuse.xml로 바꿔본다.

 

 
 
<?xml version="1.0" encoding="UTF-8"?>
   
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.br</groupId>
    <artifactId>ajax</artifactId>
    <name>03_Spring_Logging_AJAX</name>
    <packaging>war</packaging>
    <version>1.0.0-BUILD-SNAPSHOT</version>
   
    <properties>
        <java-version>11</java-version>
        <org.springframework-version>5.3.27</org.springframework-version>
        <org.aspectj-version>1.9.19</org.aspectj-version>
        <org.slf4j-version>2.0.7</org.slf4j-version>
    </properties>
   
    <dependencies>
   
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework-version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                 </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>
               
        <!-- AspectJ -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${org.aspectj-version}</version>
        </dependency>  
       
        <!-- Logging -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.14</version>
            <!-- <scope>test</scope> 이건 지워야 함 -->
        </dependency>

        <dependency> <!-- 기존 dependency 중 이것만 남기고 다 지운다.-->
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${org.slf4j-version}</version>
        </dependency>
       
       

        <!-- @Inject -->
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>
               
        <!-- Servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
   
        <!-- Test -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>        
       
       
        <!-- Lombok 라이브러리 추가 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
   
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java-version}</source>
                    <target>${java-version}</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
 

 

 

- pom.xml에서 기존의 log4j 관련 라이브러리도 삭제한다.

<!-- Logging --> 중에서 맨 처음 dependency빼고 다 삭제한다.

 

- mvnrepository에서 "logback"을 검색한다.

"logback classic module"을 클릭해서 usages가 높은 1.4.14 버전으로 한다.

 

 

 

 

 

ㅁ src/main/resources에 logback.xml 생성

 

 

- 이름을 이렇게 작성해야 자동으로 실행된다.

 

 

 

 

- 로그 관련 환경설정 파일 작성법이 어렵다.

- 수정할 일은 없다. 그래도 볼 줄은 알아야 한다.

 

 

 

 

 

- 제일 바깥은 <configuration> 태그로 감싸있어야 한다. <configuration> 태그를 작성한다.

 

 

 

 

 

 

ㅁ 로깅(로그 출력)을 하는 이유

- 시스템 작동상태를 기록하거나 시스템의 동작들을 분석하기 위해 기록해둘 필요가 있다.

- 사용자가 시스템을 이용하면서 발생되는 문제점(장애)들을 기록해놔야 후에 유지보수할 수 있다.

- ~ 제일 먼저 해야하는 것이 로그 파일을 ~

- 디버깅 용으로 데이터들을 출력할 때 print로 출력시 성능저하를 야기시킨다.

또 콘솔에만 출력된다. 파일에 출력하려면 Stream으로 파일에 출력하는 코드를 작성해야 한다.

 

 

ㅁ 로그 장점

- 프로그램의 문제 파악에 용이

- 빠르고 효율적인 디버깅이 가능

- 로그 이력을 저장매체(파일, RDB=관계형데이터베이스 등)에 외부로 남길 수 있다.

 

 

ㅁ 로그 단점

- 로그에 대한 디바이스(저장매체) 입출력으로 인해 런타임 오버헤드가 발생할 수 있다.

(이것만의 과부하가 발생한다)(확인했으면 지워주기도 해야함)

- 로깅을 위한 추가 코드로 인해서 전체 코드 사이즈가 증가될 수 있다.

- 무분별한 로그 출력은 혼란을 야기하거나 애플리케이션 성능에 영향을 미친다.

 

 

※ Logging Framework (log4j, logback, log4j2, slf4j, ...)

- 스프링은 기본적으로 log4j가 잡혀있다.

- 스프링부트는 기본적으로 logback가 잡혀있다.

- 요즘에는 logback을 많이 쓰는 추세다. 이게 내부적으로 log4j보다 10배정도 빠르다고 한다.

- slf4j가 다양한 logging framework 간에 중간 인터페이스 역할을 수행하면서 호환성을 보장하는 역할을 수행한다.

그래서 pom.xml에서도 slf4j 부분은 지우지 않았다.

 

 

 

※ <appender> 

- 전달된 로그를 어디(콘솔, 파일, db)에 어떤 형식으로 출력할지 결정하는 태그

- ConsoleAppender       : 로그를 콘솔에 출력하기 위한 appender

- JDBCAppender           : 로그를 RDB에 출력하기 위한 appender

- FileAppender               : 로그를 파일에 출력하기 위한 appender

- RollingFileAppender   : FileAppender를 보완한 개념

 

 

- logback 공식 사이트에서도 영어로 설명이 있다. 그런데 보기 어려워서 ~

- ~ 그래서 결국 RollingFileAppender를 쓴다.

일정 조건(일정 용량, 일정 날짜 등) 후에 기존 파일을 백업 파일로 바꾸고 다시 새로운 파일로 로깅을 시작한다.

 

 

 

※ <encoder> + <pattern>

- 로그를 어떤 패턴으로 출력할건지 형식을 지정한다.

 

- %logger : 로거 주체 (로그가 출력되는 클래스)

- %logger{0}으로 하면 클래스명이 출력된다. 

- %logger{1}하면 패키지 이름의 마지막 부분과 클래스명이 출력된다.

- 그냥 %logger를 두면 풀 클래스명이다. 풀 클래스명으로 두는게 좋다.

 

- %line : 로거 발생 줄 수

- %level : 로그 레벨

- %msg : 로그 메세지

- %date : yyyy-MM-dd HH:mm:ss:SSS 형식으로 로그 출력 날짜가 출력된다.

- %date{포맷} : 내가 지정한 날짜 및 시간에 대한 포맷을 반영한 로그출력 날짜가 출력된다.

 

 

 

 

ㅁ logback.xml

 

 
<?xml version="1.0" encoding="UTF-8"?>
<configuration>


    <appender class="ch.qos.logback.core.ConsoleAppender" name="consoleLog">
   
        <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
   
    </appender>


</configuration>


 

- <pattern>%msg%n</pattern>

유지보수를 위해 남기는것이기 때문에 이렇게 메세지만 딸랑 출력해서는 의미가 없다. 

 

- %와 레벨 사이에 "-5"를 두면 5칸의 공간을 확보하고 왼쪽부터 출력하겠다는 의미다.

 

- 패턴은 마음대로 하면 된다. 대괄호를 써본다.

밀리세컨드까지도 출력한다면 그냥 %date만 쓰면 된다.

 

- 회사가면 패턴을 내가 지정하진 않는다. 이미 정해져 있다.

 

- 이렇게 appender 태그만 둔다고 로그가 출력되진 않는다.

어떤 패키지의 ~ 

 

 

 

 

 

ㅁ <root>

- 현재 애플리케이션의 "모든 패키지 안" "특정 레벨 이상"의 로그를 "특정 appender"에 적용시켜서 출력하는 태그.

- root logger라고도 한다.

- 작성방법

 

<root level="로그레벨(해당 레벨 이상의 로그만이 출력됨)">
	<appender-ref ref="로그를 출력시킬 appender 이름" />
</root>

 

 

 

※ 로그 레벨 (아래로 갈수록 레벨이 높아짐)

- TRACE   : 디버깅보다 상세한 정보 표현용

- DEBUG  : 개발 단계에서 디버깅용

- INFO      : 정보성 메세지 기록용

- WARN    : 처리는 가능하나 향후 시스템 에러의 원인이 될 수 있는 경고성 메세지 기록용

- ERROR  : 요청 처리 중 문제가 발생 기록용

- FATAL     : 아주 심각한 시스템적인 문제 발생 기록용

 

- 결론부터 말하면 회사가서도 우리가 쓸 로그 레벨은 DEBUG와 INFO 뿐이다. 

- 사실 외부 매체에 디버깅용을 남길 필요는 없다. 외부에 기록할 것은 INFO 메세지로 남기면 된다.

- 이 모든것을 우리가 다 콘솔이나 파일에 출력하진 않고 어떤 레벨 이상만 남긴다.

 

 

 

 

 

 

 

ㅁ logback.xml

 

 
<?xml version="1.0" encoding="UTF-8"?>
<configuration>


    <appender class="ch.qos.logback.core.ConsoleAppender" name="consoleLog">
        <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- (1) root logger 만으로 모든 클래스 내의 로그가 출력되도록 -->
    <root level="DEBUG">
        <appender-ref ref="consoleLog" />
    </root>

</configuration>





 

 

 

 

ㅁ MvcController

 

 
package com.br.ajax.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MvcController {
   
   
    private Logger logger = LoggerFactory.getLogger(MvcController.class);
   

    @RequestMapping(value= {"/", "/main.do"})
    public String mainPage() {
       
        // 출력문은 성능저하를 야기시킴 => 로그 출력 권장
        // System.out.println("MvcController의 mainPage 메소드 작동됨");
       
       
        // 다음과 같은 레벨로 다음과 같은 메세지가 출력되도록 작성. 각각의 레벨별로 출력.
        logger.trace("trace msg");
        logger.debug("debug msg");
        logger.info("info msg");
        logger.warn("warn msg");
        logger.error("error msg");
        // slf4j는 fatal은 없다.
       
       
        return "main";
    }
   
}
 

 

 

- Logger 객체가 필요하다. 다른 곳에서도 필요할 수 있으니 전역 필드?로 둔다.

- debug 이상 레벨만 출력이 돼야 한다. trace는 나오면 안된다.

 

 

 

 

 

 

- 페이지 요청도 안했는데 서버 스타트하는 순간 로그가 엄청 나온다. 

- 서버를 켜놓은 상태로 작업하면 실시간으로 반영돼서 오류가 날 수 있다.

life cycle어쩌구 spring framework 어쩌구 오류가 날 수 있다. sts 껐다가 다시 실행하면 된다ㅣ.

- 서버 스타트하는 순간 스프링과 관련된 ~

- 기존에는 INFO라고 붙은 것만 실행됐었다. 

 

 

 

 

 

- HandlerMapping

 

 

 

 

 

 

- 메소드가 실행되게끔 메인페이지가 보여지게한다.

- 우리가 작성한 패턴대로 콘솔에 로그가 출력된다. 

- DEBUG 이상의 레벨만 출력되게 했기 때문에 trace는 보여지지 않는다.

 

- 그런데 debug 이상 출력되게 했더니 너무 무분별하게 많이 출력된다.

org.springframework는 INFO만, 

내가 만든 com.br.ajax는 DEBUG레벨 이상만 출력되게끔 따로따로 설정해본다.

 

 

 

 

 

 

ㅁ Logger 임포트

 

 

- Logger를 import할 때 logback의 Logger가 아닌 slf4j의 Logger여야 한다.

- slf4j도 2개가 있는데 internal이 아닌 "org.slf4j.Logger"여야 한다.

 

 

 

 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

 

- import를 하면 위와 같은 import문 2줄이 생긴다.

 

 

 

 

 

 

 

ㅁ <logger>

- 현재 애플리케이션의 "특정 패키지 안"의 "특정 레벨 이상"의 로그를 "특정 appender"에 적용시켜 출력

- 작성방법

 

<logger name="특정패키지" level="로그레벨" [additivity="true | false"]>
	[<appender-ref ref="로그를 출력시킬 appender 이름" />]
</logger>

 

- 다시 또 root logger가 있으면 또 출력이 된다. 

- 기본적으로 logger가 먼저 반영되고 root logger가 반영된다.

- root logger로 전달 여부. 기본값 true.

 

 

 

 

 

ㅁ logback.xml

 
<?xml version="1.0" encoding="UTF-8"?>
<configuration>


    <appender class="ch.qos.logback.core.ConsoleAppender" name="consoleLog">
        <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
    </appender>


    <!-- (1) root logger 만으로 모든 클래스 내의 로그가 출력되도록
    <root level="DEBUG">
        <appender-ref ref="consoleLog" />
    </root>
    -->


    <!-- (2) logger 태그로 특정 패키지를 따로 레벨 지정 -->
    <logger name="org.springframework" level="INFO">
        <appender-ref ref="consoleLog" />
    </logger>

    <logger name="com.br.ajax" level="DEBUG">
        <appender-ref ref="consoleLog" />
    </logger>


</configuration>
 

 

- name의 특정 패키지에 level별로 특정 레벨 이상만 consoleLog appender로 적용시켜서 출력한다.

 

 

 

 

- warn, error는 발생하지 않아서 안보이는 것이다.

 

 

 

 

- http://localhost:8888/ajax를 요청하면 콘솔에 이렇게 4줄만 찍힌다.

 

 

 

========================================================================

 

 

 

ㅁ logback.xml

 

 
<?xml version="1.0" encoding="UTF-8"?>
<configuration>


    <appender class="ch.qos.logback.core.ConsoleAppender" name="consoleLog">
        <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
    </appender>


    <appender class="ch.qos.logback.core.FileAppender" name="fileLog">
        <file>/logs/ajax.log</file>
        <append>true</append>
        <immediateFlush>true</immediateFlush>
 
        <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
    </appender>




    <!-- (1) root logger 만으로 모든 클래스 내의 로그가 출력되도록
    <root level="DEBUG">
        <appender-ref ref="consoleLog" />
    </root>
    -->


    <!-- (2) logger 태그로 특정 패키지를 따로 레벨 지정 -->
    <logger name="org.springframework" level="INFO">
        <appender-ref ref="consoleLog" />
    </logger>

    <logger name="com.br.ajax" level="DEBUG">
        <appender-ref ref="consoleLog" />
    </logger>


</configuration>


 

 

주로 파일에 많이 쓴다.

 

- FileAppender를 만든다. 로그가 파일에 기록되게끔 한다.

- appender는 위에 모아놓는게 좋다.

 

- <file>, <append>, <immediateFlush>를 작성해야 한다. 공식 문서에 다 나와있다.

- <file> 태그. c드라이브의 /logs라는 폴더에 ajax.log라는 파일로 기록되게끔 작성한다.

폴더가 없으면 만들어진다.

- <append>, <immediateFlush>는 true.

 

 

 

 

 

- FileAppender는 등록만하고 사용되게끔 하지 않았다.

쓰지도 않았는데 왜 등록했냐는 거다.

 

 

 

 

ㅁ logback.xml

 

 
<?xml version="1.0" encoding="UTF-8"?>
<configuration>


    <appender class="ch.qos.logback.core.ConsoleAppender" name="consoleLog">
        <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
    </appender>


    <appender class="ch.qos.logback.core.FileAppender" name="fileLog">
        <file>/logs/ajax.log</file>
        <append>true</append>
        <immediateFlush>true</immediateFlush>
 
        <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
    </appender>




    <!-- (1) root logger 만으로 모든 클래스 내의 로그가 출력되도록
    <root level="DEBUG">
        <appender-ref ref="consoleLog" />
    </root>
    -->


    <!-- (2) logger 태그로 특정 패키지를 따로 레벨 지정 -->
    <logger name="org.springframework" level="INFO">
        <appender-ref ref="consoleLog" />
        <appender-ref ref="fileLog" />
    </logger>

    <logger name="com.br.ajax" level="DEBUG">
        <appender-ref ref="consoleLog" />
        <appender-ref ref="fileLog" />
    </logger>


</configuration>


 

- 각각 <appender-ref ref="fileLog" />를 추가해서 콘솔에도 출력하고 파일에도 출력하게 한다.

 

 

 

 

 

- 서버 스타트 후 메인페이지 접속. 정상적으로 로그가 출력된다.

 

 

 

 

 

 

 

- 콘솔에 출력된 로그가 파일에도 쌓여있다. 

- 그런데 FileAppender는 파일 하나에만 쌓이기 때문에 좋지 않다.

 

 

 

=========================================================

 

 

ㅁ logback.xml

 

 
<?xml version="1.0" encoding="UTF-8"?>
<configuration>


    <appender class="ch.qos.logback.core.ConsoleAppender" name="consoleLog">
        <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
    </appender>


    <appender class="ch.qos.logback.core.FileAppender" name="fileLog">
        <file>/logs/ajax.log</file>
        <append>true</append>
        <immediateFlush>true</immediateFlush>
       
        <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
    </appender>

    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" name="rollingFileLog">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>/logs/ajax-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>10GB</totalSizeCap>
        </rollingPolicy>
       
                <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
    </appender>




    <!-- (1) root logger 만으로 모든 클래스 내의 로그가 출력되도록
    <root level="DEBUG">
        <appender-ref ref="consoleLog" />
    </root>
    -->


    <!-- (2) logger 태그로 특정 패키지를 따로 레벨 지정 -->
    <logger name="org.springframework" level="INFO">
        <appender-ref ref="consoleLog" />
        <appender-ref ref="fileLog" />
        <appender-ref ref="rollingFileLog" />
    </logger>

    <logger name="com.br.ajax" level="DEBUG">
        <appender-ref ref="consoleLog" />
        <appender-ref ref="fileLog" />
        <appender-ref ref="rollingFileLog" />
    </logger>
   

</configuration>


 

- 기존 파일은 백업파일이 되고 새로운 로그 파일이 생성된다.

- 보관 정책을 적어야 한다.

 

- <rollingPolicy> 태그는 로그 파일의 보관 정책을 설정하는 데 사용된다.

- <fileNamePattern> 태그. 똑같은 날짜에도 한 파일에 용량이 많이 쌓이면 여러 파일이 만들어질 수 있다. 

뒤에 넘버링되게 %i를 두면 0부터 1, 2, 3, ...이 붙는다.

- <maxHistory>로 파일의 보관일을 정할 수 있다. 30일로 정한다.

- <totalSizeCap>은 로그 파일 전체의 용량을 어느정도로 허용할건지.

10GB를 넘으면 오래된것부터 지워진다.

 

- 이걸 더 짧게 쓸 수 있다.

 

 

 

 

 
<?xml version="1.0" encoding="UTF-8"?>
<configuration>


    <appender class="ch.qos.logback.core.ConsoleAppender" name="consoleLog">
        <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
    </appender>


    <appender class="ch.qos.logback.core.FileAppender" name="fileLog">
        <file>/logs/ajax.log</file>
        <append>true</append>
        <immediateFlush>true</immediateFlush>
       
        <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
    </appender>

    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" name="rollingFileLog">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>/logs/ajax-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>10GB</totalSizeCap>
        </rollingPolicy>
       
        <encoder>
            <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
        </encoder>
    </appender>




    <!-- (1) root logger 만으로 모든 클래스 내의 로그가 출력되도록
    <root level="DEBUG">
        <appender-ref ref="consoleLog" />
    </root>
    -->



    <!-- (2) logger 태그로 특정 패키지를 따로 레벨 지정
    <logger name="org.springframework" level="INFO">
        <appender-ref ref="consoleLog" />
        <appender-ref ref="fileLog" />
        <appender-ref ref="rollingFileLog" />
    </logger>

    <logger name="com.br.ajax" level="DEBUG">
        <appender-ref ref="consoleLog" />
        <appender-ref ref="fileLog" />
        <appender-ref ref="rollingFileLog" />
    </logger>
    -->
     
     
     
    <!-- (3) root logger와 logger 함께 사용하기 -->
   
    <logger name="org.springframework" level="INFO" />
    <logger name="com.br.ajax" level="DEBUG" />
    <!-- appender를 안쓰고 root logger로 전달. additivity가 기본값 true로 되어 있다. -->
    <!-- 그 밖의 다른 패키지의 것들은 WARN레벨 이상으로 설정. -->
   
   
    <!-- 모든 패키지에 적용됨. 기본 로그 레벨은 WARN으로 설정 -->
    <root level="WARN">
        <appender-ref ref="consoleLog" />
        <appender-ref ref="fileLog" />
        <appender-ref ref="rollingFileLog" />
    </root>  
         
     

</configuration>
 

 

 

- logger 태그에 appender를 쓰지 않고 ~

- <rollingPolicy> 태그의 <fileNamePattern> 태그에 %i도 있어야 한다. 빠지면 콘솔 출력도 이상하게 나오고 파일도 안만들어 진다.

 

 

 

 

 

ㅁ print와 log의 차이

- print와 log는 모두 프로그램 실행 중 정보를 출력하거나 확인하는 데 사용되지만, 목적과 기능성에서 차이가 있습니다.

- print는 주로 콘솔에 단순히 메시지를 출력하는 용도로, 디버깅이나 테스트 시 임시로 사용됩니다.

반면, log는 시스템의 상태와 오류를 기록하여 나중에 분석할 수 있도록 하는데, 다양한 로그 레벨(INFO, DEBUG, ERROR 등)을 지원하며 파일이나 외부 저장소에 기록됩니다.

- 또한, log는 출력 외에 로그 회전(롤링), 포맷팅, 필터링 등의 기능도 제공하여 운영 환경에서 문제를 추적하고 해결하는 데 중요한 역할을 합니다.