Develop/Java

gradle5 API server. log

크레이지제이 2021. 11. 14. 17:04
반응형

gradle5 API server

로그를 기록하도록 해 보자. 개발시에는 콘솔로 디버그 로그도 확인할 필요가 있고, 나중에 로그 파일에 기록된 것을 확인해 볼 필요도 있다....

log4j2

  • 이전 글에서 사용했던 것을 보면 다음과 같은 것이 있는데, 이게 로그 라이브러리를 추가한 것이다. 없으면 추가
  • build.gradle에 dependencies 섹션에 추가

        implementation 'org.apache.logging.log4j:log4j-api:2.13.1'
    implementation 'org.apache.logging.log4j:log4j-core:2.13.1'

    annotationProcessor 'org.apache.logging.log4j:log4j-api:2.13.1'
    annotationProcessor 'org.apache.logging.log4j:log4j-core:2.13.1'
  • 버전에 따라 사용법이 달라 질 수 있다.
  • VC 에서 로그 설정 파일을 추가한다.
  • 전에 app/src/main/webapp/WEB-INF 까지 폴더를 만들었을 것이다. 여기에 파일 추가를 누르고, 파일명을 classes/log4j2.xml 을 생성한다. (classes 폴더가 생성되고 그 안에 파일이 추가된다.)
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>

 <!-- Appender, Layout 설정 -->
 <Appenders>
  <Console name="console" target="SYSTEM_OUT">
   <PatternLayout/>
  </Console>
  <File name="file" fileName="./logs/file/sample.log" append="false">
   <PatternLayout pattern="%d %5p [%c] %m%n"/>
  </File>
 </Appenders>

 <!-- Logger 설정 -->
 <Loggers>
  <Logger name="egovLogger" level="DEBUG" additivity="false">
   <AppenderRef ref="console"/>
   <AppenderRef ref="file"/>
  </Logger>
  <Root level="INFO">
   <AppenderRef ref="console"/>
   <AppenderRef ref="file"/>
  </Root>
 </Loggers>

</Configuration>
  • 가장 아래 Root level을 보면 된다. 로그 등급을 어떻게 설정하냐에 따라 로그 기록양이 달라진다.
  • 로그 등급은 DEBUG < INFO < WARN < ERROR < FATAL 이 있다.
  • 소스에서 로그 기록은 logger.debug("aaa"), logger.info("bbb") 이런 식으로 로그 메시지를 출력하는데, 함수 명에 따라 등급이 결정된다.
  • 로그 설정에서 DEBUG로 하면 debug 레벨 이상(즉, 모든 로그)이 모두 출력된다.
  • 로그 설정에서 INFO로 하면 info 레벨 이상(즉, debug()는 출력안됨)만 출력된다.
  • 로그 설정에서 OFF로 하면 기록안함.
  • Appender에 따라서 콘솔만 출력할지 파일로도 출력할지 등을 설정한다.
  • 로그 파일은 /app/logs/file/sample.log 에 생성되었다.

log 기록

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

@WebServlet("/add")
public class Add extends HttpServlet {
      private static final Logger logger = LogManager.getLogger();
...

        @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
                  throws IOException, ServletException {
            logger.debug("[debug] /add : doPost");
            logger.info("[info] /add : doPost");
            logger.warn("[warn] /add : doPost");
            logger.error("[error] /add : doPost");
            process(request, response);
    }

        public void process(HttpServletRequest request, HttpServletResponse response)
                        throws IOException, ServletException {
                        BufferedReader br = request.getReader();
            char[] cbuf = new char[request.getContentLength()];
            br.read(cbuf);
            String input = new String(cbuf);
            System.out.println("/add: INPUT=" + input);

            PrintWriter out = response.getWriter();
            response.setContentType("application/json");

            JSONObject jret = new JSONObject();
            JSONParser jp = new JSONParser();
            long a = 0, b = 0, c = 0;
            try {
                  JSONObject jobj = (JSONObject) jp.parse(input);
                  System.out.println("name=" + jobj.get("name"));
                  System.out.println("age=" + jobj.get("age"));
                  a = (Long) jobj.get("a");
                  b = (Long) jobj.get("b");
                  c = a + b;
                  jret.put("sum", c);
            } catch (ParseException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
            }

            logger.info("[info] /add : process " + String.format("%d+%d=%d", a, b, c));

            out.write(jret.toJSONString());
        }
  • app/logs/sample.log 파일이 자동으로 생성된다.
2021-11-13 20:33:06,630  INFO [com.my.test.controller.Add] [info] /add : doPost
2021-11-13 20:33:06,633  WARN [com.my.test.controller.Add] [warn] /add : doPost
2021-11-13 20:33:06,634 ERROR [com.my.test.controller.Add] [error] /add : doPost
2021-11-13 20:33:06,638  INFO [com.my.test.controller.Add] [info] /add : process 324+5343=5667
2021-11-13 20:33:09,881  INFO [com.my.test.controller.Add] [info] /add : doPost
2021-11-13 20:33:09,881  WARN [com.my.test.controller.Add] [warn] /add : doPost
2021-11-13 20:33:09,881 ERROR [com.my.test.controller.Add] [error] /add : doPost
2021-11-13 20:33:09,882  INFO [com.my.test.controller.Add] [info] /add : process 1+2=3
  • 서버 실행 콘솔에서도 출력이 된다.
20:33:01 INFO  Tomcat 9.0.48 started and listening on port 8080
20:33:01 INFO  addserver runs at:
20:33:01 INFO    http://localhost:8080/addserver
[info] /add : doPost
[warn] /add : doPost
[error] /add : doPost
/add: INPUT={"a":324,"b":5343}
name=null
age=null
[info] /add : process 324+5343=5667
[info] /add : doPost
[warn] /add : doPost
[error] /add : doPost
/add: INPUT={"a":1,"b":2}
name=null
age=null
[info] /add : process 1+2=3
<===========--> 87% EXECUTING [1h 12m 11s]
> :app:tomcatStart

Log Pattern

   <PatternLayout pattern="%d %5p [%c] %m%n"/>
위에서 출력 패턴을 설정한 것이 있다. 각각의 의미.
2021-11-13 20:33:06,638  INFO [com.my.test.controller.Add] [info] /add : process 324+5343=5667

%d : 날짜시간 (2021-11-13 20:33:06,638)
%5p : 5컬럼으로 로그레벨 출력 (INFO )
[%c] : 카테고리 ([com.my.test.controller.Add])
%m : 메시지 ([info] /add : process 324+5343=5667)
%n : 줄바꿈
-----------------
기타.
%t : 쓰레드
%% : %문자
%F : 로그 발생 소스 파일명.
%l : Caller 
%L : 라인번호
%M : Method

Appender

- File 속성에 append를 false로 주면, 실행시 로그 파일이 초기화된다.
<File name="file" fileName="./logs/file/sample.log" append="false">

RollingFileAppender

  • FileAppender를 그대로 두면 로그파일이 한 없이 커지는 문제가 생긴다.
  • Size Based Trigger
    • 로그 파일이 일정 크기가 되면, 기존 파일을 백업(넘버링하여 이름변경)하고 로그 파일을 초기화하여 처음부터 기록한다.
    • 파일 사이즈별 로그 기록
      • rollingSample.log, rollingSample.1.log, rollingSample.2.log, ... 순서대로 항상 최신 로그가 기록되게 유지됨. ; 최대 백업개수는 3개. (3.log까지)
      • 각 파일은 최대 100메가.
    • Appender에 아래를 추가한다.
<!-- attribute: name(Appender명), fileName(target파일명), filePattern(history파일명), append, immediateFlush, ignoreExceptions, bufferedIO -->
<!-- element: Layout(출력패턴설정), Filters, Policy(file rolling 조건 설정), Strategy(file name과 location 관련 설정) -->
 <RollingFile name="rollingFile" fileName="./logs/rolling/rollingSample.log" filePattern="./logs/rolling/rollingSample.%i.log">
  <PatternLayout pattern="%d %5p [%c] %m%n" />
  <Policies>
   <!-- size 단위: Byte(default), KB, MB, or GB -->
   <SizeBasedTriggeringPolicy size="100MB" />
  </Policies>
  <!-- 기존 maxIndex 속성이 Strategy 엘리먼트로 변경됨 -->
  <!-- index는 min(default 1)부터 max(default 7)까지 증가 -->
  <!-- fileIndex="min"이므로 target file의 size가 지정크기를 넘어가면, fileIndex가 1(min)인 history file에 백업 (fixed window strategy) -->
  <!-- 지정크기를 넘어가면, rollingSample.1.log을 rollingSample.2.log 파일에 복사하고, target 파일을 rollingSample.1.log에복사한 후 target 파일에 새로 로깅 -->
  <DefaultRolloverStrategy max="3" fileIndex="min" />
 </RollingFile>
  • Time Based : 날짜별로 로그 기록
    • 최신 로그는 fileName 명칭으로 기록되고, 날짜가 변경되면 filePattern으로 백업된다고 보면 된다.
    • filePattern이 시간단위 (yyyy-MM-dd-HH) 까지 있으면 시간단위 백업이 된다.
<RollingFile name="rollingFile" fileName="./logs/rolling/dailyRollingSample.log" filePattern="./logs/daily/dailyRollingSample.log.%d{yyyy-MM-dd}">
  <PatternLayout pattern="%d %5p [%c] %m%n" />
  <Policies>
   <TimeBasedTriggeringPolicy />
  </Policies>
 </RollingFile>
  • 월별 폴더로 정리
<RollingFile name="file" fileName="./logs/file/all.log" filePattern="./logs/file/$${date:yyyy}/$${date:MM}/all_%d{yyyyMMddHH}.log"> 
    <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> 
  <Policies> 
      <TimeBasedTriggeringPolicy />
  </Policies> 
</RollingFile>

기타 로그

<Loggers> 
    <Logger name="java.sql" level="off" additivity="false"> 
        <AppenderRef ref="console" /> 
    </Logger> 
    <Logger name="egovframework" level="ERROR" additivity="false"> 
        <AppenderRef ref="console" /> 
        <AppenderRef ref="file"/> 
    </Logger> 
    <Logger name="org.springframework" level="DEBUG" additivity="false"> 
        <AppenderRef ref="console" /> 
        <AppenderRef ref="file"/> 
    </Logger> 
    <Logger name="jdbc.sqltiming" level="off" additivity="false"> 
        <AppenderRef ref="console" /> 
    </Logger> 
    <Logger name="jdbc.resultsettable" level="off" additivity="false"> 
        <AppenderRef ref="console"/> 
    </Logger> 
    <Logger name="jdbc.sqlonly" level="info" additivity="false">
        <AppenderRef ref="console"/> 
    </Logger> 
    <Root level="ERROR"> 
        <AppenderRef ref="console" /> 
    </Root> 
</Loggers>