요구사항
1. tomcat의 로그를 웹사이트의 화면에서 실시간으로 보게 해주세요.
2. 특정 라인으로 잘라서 전체 로그가 아닌 일부를 보여주세요.
보통 이런 요구사항은 개발자가 사이트를 관리하기 위해 사용한다.
사이트의 보안때문에 따로 원격 접속이 어려울경우(특정 아이피에서만 접근가능한 사이트 라든가) 그럴경우 매번 서버 로그를 확인하러 갈 수 없기 때문에
컴퓨터는 로그를 파일로 가지고있고 계속해서 update를 하고 있다.
따라서 파일이 업데이트 될때의 메소드가 있다는걸 알고 그 메소드가 호출될때 마다 화면의 값을 바꿔주면 되는거 아닐까 했는데-> 안됨
실패한 코드는 날려먹었기에 적지 않겠다ㅎㅎ;
Logcontroller.java
@RequestMapping(value = {"/ajax/liveLog"})
@ResponseBody
public ResponseMessage ajax_liveLog(@RequestParam HashMap<String, Object> paramMap,
Model model) throws InterruptedException, IOException {
ResponseMessage responseMessage = new ResponseMessage();
LocalDate now = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String insertDt = now.format(formatter);
String filePath = Globals.CATALINA_BASE + "/catalina." + insertDt + ".log";
try {
RandomAccessFile randomAccessFile = new RandomAccessFile(filePath, "r");
StringBuffer lastLine = new StringBuffer();
int lineCount = 100;
long fileLength = randomAccessFile.length();
for (long pointer = fileLength - 1; pointer >= 0; pointer--) {
randomAccessFile.seek(pointer);
char c = (char) randomAccessFile.read();
if (c == '\n') {
lineCount--;
if (lineCount == 0) {
break;
}
}
lastLine.insert(0, c);
}
String liveLog= StringUtil.convertCharset(String.valueOf(lastLine), null, "UTF-8");
responseMessage.setData(ImmutableMap.of("liveLog", liveLog));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return responseMessage;
}
코드에 주석을 다는게 지저분해 보여서 아래에 한줄씩 설명하겠다.
내 사이트를 기준으로 내가 원하는 로그파일이 /catalina.+ 날짜.log 로 저장되는 규칙이 있었고
LocalDate now = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String insertDt = now.format(formatter);
이렇게 현재 날짜를 구해서 로그파일 날짜형태로 넣어줬다
파일에 특정 라인에 접근 하기 위해선 RandomAccessFile을 사용해야한다 모드를 r로 해주어 읽게 했다
int lineCount = 100; -> 몇 줄을 읽을껀지 설정
내가 설정한 값에 따라 몇 줄을 읽을지 결정된다.
이것 또한 사용자 화면애서 입력값을 따로 받고 변수로 지정하면 그때그때 원하는 값으로 변경 가능할 것같다.
처음에 위에 코드를 쓰고 sysout 해봤더니 인코딩이 안되서
StringUtil.convertCharset(String.valueOf(lastLine), null, "UTF-8");
해주었다.
responseMessage로 리턴해서 전달했다. model에 넣지 않은 이유는 model은 화면으로 리턴해야하니까 그럼 화면이 재호출되야하고 그럼 호출하는 화면 전체가 깜빡거리게된다.
화면에 다른 것들도 리로딩 되고 그럼 프로그램적으로 좋지 않다. 선호하지 않는다.
@RequestMapping(value = {"/liveLog")
public String liveLog(@RequestParam HashMap<String, Object> paramMap,
Model model) throws InterruptedException, IOException {
return "/liveLog";
}
미리 화면으로만 리턴하는 컨트롤러를 작성해놓고 그 화면에서 데이터를 가져오는 컨트롤러를 호출하면 된다.
liveLog.jsp
<script>
setInterval(function () {
const $searchForm = $('#logSearchForm');
$.ajax({
type: 'get',
url: '/ajax/liveLog',
success: function (resp) {
const liveLog = resp.data.liveLog;
$("#liveLog").text(liveLog);
},
error: function (x, o, e) {
alert('error occurred during data processing\n' + x.status + '\n' + o + '\n' + e);
}
});
}, 2000);
</script>
이렇게 함수를 작성해주면 2초마다 아까 만든 컨트롤러를 호출해서 로그를 가져온다.
아까 data에 실시간 로그 값을 넣었기에 data.liveLog 이렇게 가져올 수 있다.
그럼 언뜻 실시간인것 처럼 연출이 가능하고 부하도 오지 않는다.
일단 이렇게 마무리 해놓고.. 더 좋은 방법이 있으면 .. 고치도록하겠다
날짜별로 로그를 가져오는 것은 그냥 날짜를 화면에서 입력받아서 변수로 넣기만 하면 되서 더 쉽다.