Lined Notebook

[스프링 MVC - 백엔드 웹 개발 기술] 12. 프로젝트 생성과 로깅 간단히 알아보기

by ymkim

01. 프로젝트 생성

  • 스프링부트 스타터 사이트 이동 후 신규 프로젝트 생성
  • https://start.spring.io
  • 프로젝트 선택
    • Project: Gradle Project
    • Language: Java
    • Spring Boot: 2.7.x
  • Project Metadata
    • Group: hello
    • Artifact: springmvc
    • Name: springmvc
    • Package name: hello.springmvc
    • Packaging: Jar(주의)
    • Java: 11
  • Dependencies: Spring Web, Thymleaf, Lombok

01-1. 주의 사항

  • Packaging는 War가 아닌 Jar를 선택하자
  • JSP를 사용하지 않기 때문에 Jar 사용하는 것이 좋음
  • Jar 사용 시 항상 내장 서버(톰캣)을 사용하고, webapp 경로도 사용하지 않음
  • War를 사용하면 내장 서버도 가능하지만, 주로 외부 서버 배포하는 목적으로 사용

01-2. build.gradle

plugins {
	id 'java'
	id 'org.springframework.boot' version '2.7.16'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'hello'
version = '0.0.1-SNAPSHOT'

java {
	sourceCompatibility = '11'
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' // 타임리프
	implementation 'org.springframework.boot:spring-boot-starter-web' // spring web
	compileOnly 'org.projectlombok:lombok' // 롬복
	annotationProcessor 'org.projectlombok:lombok' // 롬복
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
	useJUnitPlatform()
}
  • build.gradle 설정도 완료 되었으니 구동 여부 확인 진행
  • localhost:8080 테스트 진행

01-3. Welcome 페이지 만들기

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul>
    <li>로그 출력
        <ul>
            <li><a href="/log-test">로그 테스트</a></li>
        </ul>
    </li>
    <!-- -->
    <li>요청 매핑
        <ul>
            <li><a href="/hello-basic">hello-basic</a></li>
            <li><a href="/mapping-get-v1">HTTP 메서드 매핑</a></li>
            <li><a href="/mapping-get-v2">HTTP 메서드 매핑 축약</a></li>
            <li><a href="/mapping/userA">경로 변수</a></li>
            <li><a href="/mapping/users/userA/orders/100">경로 변수 다중</a></li>
            <li><a href="/mapping-param?mode=debug">특정 파라미터 조건 매핑</a></li>
            <li><a href="/mapping-header">특정 헤더 조건 매핑(POST MAN 필요)</a></
            li>
            <li><a href="/mapping-consume">미디어 타입 조건 매핑 Content-Type(POST
                MAN 필요)</a></li>
            <li><a href="/mapping-produce">미디어 타입 조건 매핑 Accept(POST MAN
                필요)</a></li>
        </ul>
    </li>
    <li>요청 매핑 - API 예시
        <ul>
            <li>POST MAN 필요</li>
        </ul>
    </li>
    <li>HTTP 요청 기본
        <ul>
            <li><a href="/headers">기본, 헤더 조회</a></li>
        </ul>
    </li>
    <li>HTTP 요청 파라미터
        <ul>
            <li><a href="/request-param-v1?username=hello&age=20">요청 파라미터
                v1</a></li>
            <li><a href="/request-param-v2?username=hello&age=20">요청 파라미터
                v2</a></li>
            <li><a href="/request-param-v3?username=hello&age=20">요청 파라미터
                v3</a></li>
            <li><a href="/request-param-v4?username=hello&age=20">요청 파라미터
                v4</a></li>
            <li><a href="/request-param-required?username=hello&age=20">요청
                파라미터 필수</a></li>
            <li><a href="/request-param-default?username=hello&age=20">요청
                파라미터 기본 값</a></li>
            <li><a href="/request-param-map?username=hello&age=20">요청 파라미터
                MAP</a></li>
            <li><a href="/model-attribute-v1?username=hello&age=20">요청 파라미터
                @ModelAttribute v1</a></li>
            <li><a href="/model-attribute-v2?username=hello&age=20">요청 파라미터
                @ModelAttribute v2</a></li>
        </ul>
    </li>
    <li>HTTP 요청 메시지
        <ul>
            <li>POST MAN</li>
        </ul>
    </li>
    <li>HTTP 응답 - 정적 리소스, 뷰 템플릿
        <ul>
            <li><a href="/basic/hello-form.html">정적 리소스</a></li>
            <li><a href="/response-view-v1">뷰 템플릿 v1</a></li>
            <li><a href="/response-view-v2">뷰 템플릿 v2</a></li>
        </ul>
    </li>
    <li>HTTP 응답 - HTTP API, 메시지 바디에 직접 입력
        <ul>
            <li><a href="/response-body-string-v1">HTTP API String v1</a></li>
            <li><a href="/response-body-string-v2">HTTP API String v2</a></li>
            <li><a href="/response-body-string-v3">HTTP API String v3</a></li>
            <li><a href="/response-body-json-v1">HTTP API Json v1</a></li>
            <li><a href="/response-body-json-v2">HTTP API Json v2</a></li>
        </ul>
    </li>
</ul>
</body>
</html>

02. 로깅 간단히 알아보기

앞으로 로그를 사용한다, 이번 시간에는 로그에 대해 간략히 알아본다

02-1. 로깅 라이브러리

  • 운영 시스템에서는 System.out.println() 사용하지 않고, 별도의 로깅 라이브러리(Log4j, Logback) 사용
  • 기본적으로 Spring Boot 사용 시 아래 LIB 포함
    • spring-boot-starter-logging

스프링 부트는 기본적으로 아래 로깅 LIB를 사용한다

로그 라이브러리는 Logback, Log4J, Log4J2 등 수 많은 라이브러리가 존재하는데, 그것을 통합해서 인터페이스로 제공하는 것을 SLF4J 라이브러리라 한다.

Logback은 SLF4J를 구현한 구현 클래스이다.

02-2. 로그 선언

  • private Logger log = LoggerFactory.getLogger(getClass());
  • private static final Logger log = LoggerFactory.getLogger(Xxx.class);
  • @Slf4j: 롬복 사용

02-3. 로그 호출

package hello.springmvc.basic;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class LogTestController {

//    private final Logger log = LoggerFactory.getLogger(getClass());

    @GetMapping(value = "/log-test")
    public String logTest() {
        String name = "spring";

        System.out.println("name = " + name);

        log.trace("trace log = {}", name);
        log.debug("debug log = {}", name);
        log.info("info log = {}", name);
        log.warn("warn log = {}", name);
        log.error("error log = {}", name);

        return "ok";
    }

}
  • log.info(”hello”);
  • System.out.println(”hello”)
  • 시스템 로그 사용보다 로그 사용을 하면 다음과 같은 장점이 있다. 실무에서는 반드시 로그 사용

02-4. 로그 호출 결과

2023-10-10 22:50:18.297  INFO 20816 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-10-10 22:50:18.298  INFO 20816 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
name = spring
2023-10-10 22:50:18.318  INFO 20816 --- [nio-8080-exec-1] hello.springmvc.basic.LogTestController  : info log = spring
2023-10-10 22:50:18.319  WARN 20816 --- [nio-8080-exec-1] hello.springmvc.basic.LogTestController  : warn log = spring
2023-10-10 22:50:18.319 ERROR 20816 --- [nio-8080-exec-1] hello.springmvc.basic.LogTestController  : error log = spring
  • System.out.println 사용 시 아무 내용 없이 name = spring 만 출력
  • Logger 사용 시 시간 | Log Level | thread | 컨트롤러 이름 | 메시지 순으로 출력

02-5. application.properties

#hello.springmvc 패키지와 그 하위 로그 레벨 설정
logging.level.hello.springmvc=debug
  • 위와 같이 특정 패키지의 로그 레벨(Log Level) 지정 가능
  • TRACE < DEBUG < INFO < WARN < ERROR < FATAL

02-6. @RestController

  • @Controller는 반환 값이 String → 뷰(view)로 인식 → 뷰를 랜더링
  • @RestController는 반환 값 → 뷰 x → HTTP 메시지 바디에 바로 입력 → @ResponseBody와 연관있음

02-7. 로그의 올바른 사용법

String name = "Spring";

log.trace("trace my log =" + name); // 연산이 일어나는 경우 (cpu, memory)

// log.trace("trace my log=Spring); // 내부적으로는 이렇게 된다
  • 위와 같이 ‘**+**’ 를 사용하면 내부적으로 연산이 발생한다
    • 사용도 안하는데 CPU, Mem 를 사용하는 경우 발생
    • 불필요한 리소스 사용으로, 이러한 사소한 부분이 서비스 장애로 연결될 수 있음
log.trace("trace log = {}", name);
  • 위와 같이 ‘,’ 기호와 {} 기호를 통해 내부 연산을 안할 수 있음
  • 파라미터만 넘겨주는 차이가 존재

02-8. 로그 사용 시 장점

  • 쓰레드 정보, 클래스명과 같은 부가정보 확인 가능
  • 개발환경(DEV, PROD)에 따라 로그 레벨 조절 가능
  • 콘솔 출력뿐 아니라, 파일, 네트워크(S3..) 등 별도 위치에 로그 남기는 것 가능
    • 파일로 남길 때는 logrotate도 가능
  • 성능 System.out.println보다 좋음 (내부 버퍼링, 멀티 쓰레드 등등)

02-9. 로깅 참고 자료

블로그의 정보

기록하고, 복기하고

ymkim

활동하기