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>