Spring Boot 3.0 환경에서 Whatap 연동

Kotlin + Spring Boot 3.0 + Java 17 LTS 환경에서 Whatap APM을 연동할 일이 생겼다. 이 글에서는 연동 방법과 몇가지 애먹은 부분을 기술한다.

에이전트 설치

wget https://service.whatap.io/agent/whatap.agent.java.tar.gz
tar -zxvf whatap.agent.java.tar.gz

Whatap 공식 문서 곳곳에서 $WHATAP_HOME 라고 되어 있는 것은 .jar 파일이 있는 경로를 말한다.
환경변수로 $WHATAP_HOME를 설정해도 안먹으니까 주의하자.

이후, [whatap의 프로젝트 페이지 – 관리 – 에이전트 설치]를 참고해서 whatap.conf 를 수정한다.

그리고 whatap.conf맨 아래에 weaving 항목을 추가한다. Whatap Agent 버전과 프레임워크(Tomcat, Spring Boot, Netty 등)에 따라 값이 달라지는것을 유의하여, 공식 문서를 참고해야 한다. Spring Boot 3.0의 경우에는 아래와 같이 추가한다.

weaving=spring-boot-3.0
Spring Boot 는 https://docs.whatap.io/java/add-jvm-opt/spring-boot를 참고하면 된다.
결과적으로 whatap.conf 내용이 위와 같이 된다.

JVM 매개변수 추가

이후 -javaagent 매개변수를 추가하여, 원래 프로그램을 실행하는 것 처럼 실행하면 된다. 핵심 부분은 -javaagent를 whatap agent로 설정하는 것이다. Java 버전이 17 이상일 경우 --add-opens=java.base/java.lang=ALL-UNNAMED 를 추가한다.

java -javaagent:/path/to/whatap/whatap.agent-X.Y.Z.jar -Dwhatap.oname=AgentName --add-opens=java.base/java.lang=ALL-UNNAMED -jar ~~~~

로그 확인

.jar 파일이 있는 경로에 plugin 이라는 디렉터리가 생긴다. 해당 디렉토리에서 로그를 확인 하면 된다.

플러그인

Java APM은 플러그인 기능을 지원한다. (https://docs.whatap.io/java/script-plugin)

플러그인의 전신은 https://github.com/scouter-project/scouter/blob/master/scouter.agent.java/plugin/readme_kr.md 이다. 개인적으로는 whatap의 문서보다 이쪽이 구조를 이해하기 더 편리했다.

플러그인을 이용하면 Login ID를 설정할 수 있다. Login ID는 트랜잭션 맵에서 사용자를 구별할 때 사용할 수 있다.

whatap-agent.jar가 있는 디렉토리 아래에 plugin이라는 디렉토리를 만들고, 그 안에 *.x 파일을 만들면 된다. 이 파일은 에이전트 시작시에 컴파일 된다. Syntax에 이상이 있으면 컴파일 단계에서 실패한다. logs 디렉토리의 로그 파일에 관련된 정보가 나오니까 참고하자. 당연하게도, 실행중에는 수정해봤자 영향이 없다.

Spring Boot 3.0 기준에서 HttpServiceEnd.x 또는 HttpServiceStart.x 에서 Session 관련 함수는 작동하지 않았다. 어떻게 해도 WrSession 객체가 null로 나왔다. 혹시 Spring에서 에이전트로 데이터를 전달하고 싶으면 getAttritute() 를 사용하자.

// Kotlin Interceptor
class LoginInterceptor : HandlerInterceptor {
    override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
        super.preHandle(request, response, handler)

        val session = request.getSession(false)
        if (session == null) {
            response.sendRedirect("/")
            return false
        }

        val user = session.getAttribute("member")
        if (user == null) {
            response.sendRedirect("/")
            return false
        }

        return true
    }
}
// HttpServiceEnd.x (플러그인)
Object userName = $req.getAttribute("userName");

if (userName != null) {
        $ctx.login(cString(userName));
}

참고로, whatap에 세션으로 데이터가 안받아진다고 문의 하니까 getParameter() 로 데이터를 땡겨와라고 답변 받았다. 물론 가능은 한데, 그렇게 해야하나 싶은 생각이 들었다. 매 페이지의 주소에 파라메터로 userName 같은걸 넣어야 하는데… 영 꺼림칙 했다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

댓글을 작성하기 위해 아래의 숫자를 입력해 주세요. *Captcha loading…