JAVA 애플리케이션 RUM-APM-LOG 연동 분석¶
사용 사례 소개¶
기업의 가장 중요한 수익원은 비즈니스이며, 현재 대부분의 기업 비즈니스는 해당 IT 시스템에 의해 운영됩니다. 따라서 기업의 비즈니스 안정성을 보장하는 것은 결국 내부 IT 시스템을 보장하는 것으로 귀결됩니다. 비즈니스 시스템에 이상이나 장애가 발생하면 일반적으로 비즈니스, 애플리케이션 개발, 운영 등 여러 부서의 담당자가 함께 협력하여 문제를 파악해야 하며, 플랫폼 간, 부서 간, 전문 영역 간 등 다양한 문제가 존재하여 시간과 노력이 많이 소요됩니다.
이 문제를 해결하기 위해 현재 업계에서는 비교적 성숙한 방식으로, 인프라 모니터링 외에도 애플리케이션 계층과 로그 계층에 대한 심층 모니터링을 수행하고, RUM+APM+LOG를 통해 전체 비즈니스 시스템의 가장 핵심적인 프런트엔드 및 백엔드 애플리케이션과 로그를 통합 관리합니다. 기능이 더 뛰어난 모니터링 솔루션은 이러한 세 가지 데이터를 주요 필드를 통해 연결하여 연동 분석을 가능하게 함으로써 관련 작업자의 효율성을 높이고 시스템의 안정적인 운영을 보장합니다.
- APM: 애플리케이션 성능 모니터링(APM)
- RUM: 실제 사용자 모니터링(RUM)
- LOG: 로그
현재 Guance 는 이러한 기능을 갖추고 있습니다. 본 문서에서는 RuoYi 사무 시스템을 데모로 사용하여 RUM+APM+LOG 모니터링을 연동하는 방법과 Guance를 활용한 연동 분석 방법을 설명합니다.
DataKit 설치¶
1 설치 명령어 복사¶
Guance에 로그인하고 「통합」 - 「DataKit」을 선택한 후, 자신의 환경에 맞는 설치 명령어를 복사합니다.
2 서버에 DataKit 설치¶
3 DataKit 상태 확인¶
systemctl status datakit 명령어 실행
4 데이터 확인¶
DataKit이 설치되면 기본적으로 다음 항목을 수집합니다. 「Guance」 - 「인프라」 - 「호스트」에서 관련 데이터를 확인할 수 있습니다.
| 수집기 이름 | 설명 |
|---|---|
| cpu | 호스트의 CPU 사용량 수집 |
| disk | 디스크 사용량 수집 |
| diskio | 호스트의 디스크 IO 수집 |
| mem | 호스트의 메모리 사용량 수집 |
| swap | Swap 메모리 사용량 수집 |
| system | 호스트 운영 체제 부하 수집 |
| net | 호스트 네트워크 트래픽 수집 |
| host_process | 호스트에서 상주하는 (10분 이상 유지) 프로세스 목록 수집 |
| hostobject | 호스트 기본 정보 수집 (예: 운영 체제 정보, 하드웨어 정보 등) |
| docker | 호스트의 컨테이너 객체 및 컨테이너 로그 수집 |
다양한 통합 inputs 이름을 선택하면 해당 모니터링 뷰를 확인할 수 있으며, 모니터링 뷰 아래에서 로그, 프로세스, 컨테이너 등의 추가 데이터를 확인할 수 있습니다.
RUM¶
자세한 단계는 문서 웹 애플리케이션 모니터링(RUM) 모범 사례를 참조하세요.
1 JS 코드 복사¶
Guance에 로그인하고 「사용자 분석」 - 「애플리케이션 생성」 - 「Web」- 로드 유형 선택 「동기 로드」
2 JS 임베드¶
프런트엔드 페이지 /usr/local/ruoyi/dist/index.html의 head 태그에 JS를 붙여넣습니다.
<script src="https://static.guance.com/browser-sdk/v2/dataflux-rum.js" type="text/javascript"></script>
<script>
window.DATAFLUX_RUM &&
window.DATAFLUX_RUM.init({
applicationId: 'appid_9c7fd257fd824300ba70f7e6d3f5083e',
datakitOrigin: 'http://112.124.52.73:9529',
env: 'dev',
version: '1.0',
trackInteractions: true,
traceType: 'ddtrace',
allowedTracingOrigins: ['http://112.124.52.73']
})
</script>
파라미터 설명
- datakitOrigin: 데이터 전송 주소입니다. 프로덕션 환경에서 도메인을 구성한 경우, 도메인 요청을 DataKit(9529 포트)이 설치된 임의의 서버로 전달할 수 있습니다. 프런트엔드 액세스량이 많을 경우, 도메인과 DataKit 서버 사이에 SLB를 추가하여 프런트엔드 JS가 데이터를 SLB로 전송하고, SLB가 요청을 여러 DataKit 서버로 분산할 수 있습니다. 여러 DataKit이 RUM 데이터를 처리하며, 프런트엔드 요청 재사용으로 인해 세션 데이터가 중단되지 않으며 RUM 데이터 표시에도 영향을 주지 않습니다.
- allowedTracingOrigins: 프런트엔드와 백엔드(APM과 RUM)를 연결합니다. 이 시나리오는 프런트엔드에 RUM을 배포하고 백엔드에 APM을 배포한 경우에만 적용됩니다. 프런트엔드 페이지와 상호 작용하는 백엔드 애플리케이션 서버의 도메인(프로덕션 환경) 또는 IP(테스트 환경)를 입력해야 합니다. 사용 사례: 프런트엔드 사용자 액세스가 느린 경우, 백엔드 코드 로직 이상으로 인해 발생할 수 있습니다. 프런트엔드 RUM의 느린 요청 데이터에서 백엔드 APM 데이터로 직접 이동하여 해당 백엔드 코드 호출 상황을 확인하고 느린 요인의 근본 원인을 판단할 수 있습니다. 구현 원리: 사용자가 프런트엔드 애플리케이션에 액세스하면 프런트엔드 애플리케이션이 리소스 및 요청을 호출하여 rum-js 성능 데이터 수집을 트리거합니다. rum-js는 trace-id를 생성하여 요청의 request_header에 기록합니다. 요청이 백엔드에 도달하면 백엔드의 ddtrace가 해당 trace_id를 읽고 자체 trace 데이터에 기록하여, 동일한 trace_id를 통해 APM과 RUM 데이터를 연동합니다.
- env: 필수, 애플리케이션이 속한 환경입니다. test, product 또는 다른 값이 될 수 있습니다.
- version: 필수, 애플리케이션의 버전 번호입니다.
- trackInteractions: 사용자 행동 통계입니다. 예: 버튼 클릭, 정보 제출 등.
3 배포¶
페이지를 저장, 확인 및 배포합니다.
브라우저로 대상 페이지에 접속한 후, F12 검사자 모드에서 페이지 네트워크 요청에 rum 관련 요청이 있는지, 상태 코드가 200인지 확인합니다.
Warning
F12 검사자 모드에서 데이터를 보낼 수 없고 포트 refused가 표시되면 telnet IP:9529로 포트가 열려 있는지 확인합니다.
열려 있지 않으면 /usr/local/datakit/conf.d/datakit.conf를 수정하여 첫 번째 줄의 http_listen을 0.0.0.0으로 변경합니다.
그래도 안 되면 보안 그룹에서 9529 포트가 열려 있는지 확인하세요.
4 RUM 데이터 확인¶
「사용자 분석」에서 RUM 관련 데이터를 확인할 수 있습니다.
APM¶
자세한 단계는 문서 분산 추적(APM) 모범 사례를 참조하세요.
Guance 는 ddtrace, SkyWalking, Zipkin, Jaeger 등 OpenTracing 프로토콜을 지원하는 다양한 APM 도구를 지원합니다. 여기서는 ddtrace를 사용한 APM 관측 가능성 구현 예시를 보여줍니다.
1 inputs 수정¶
DataKit에서 APM(ddtrace)의 inputs을 수정합니다.
기본적으로 JVM inputs을 수정할 필요 없이 conf 파일을 복사하여 생성하면 됩니다.
$ cd /usr/local/datakit/conf.d/ddtrace/
$ cp ddtrace.conf.sample ddtrace.conf
$ vim ddtrace.conf
# 기본적으로 수정 불필요
2 Java 애플리케이션 시작 스크립트 수정¶
APM 관측 가능성을 위해 Java 애플리케이션에 에이전트를 추가해야 합니다. 이 에이전트는 애플리케이션 시작 시 바이트코드 인젝션을 통해 애플리케이션 내부 메서드 호출, SQL 호출, 외부 시스템 호출 등 관련 성능 데이터를 수집하여 애플리케이션 시스템 코드 품질에 대한 관측 가능성을 제공합니다.
# 원래 애플리케이션 시작 스크립트
$ cd /usr/local/ruoyi/
$ nohup java -Dfile.encoding=utf-8 -jar ruoyi-gateway.jar > logs/gateway.log 2>&1 &
$ nohup java -Dfile.encoding=utf-8 -jar ruoyi-auth.jar > logs/auth.log 2>&1 &
$ nohup java -Dfile.encoding=utf-8 -jar ruoyi-modules-system.jar > logs/system.log 2>&1 &
——————————————————————————————————————————————————————————————————————————————————————————
# ddtrace-agent 추가 후 애플리케이션 시작 스크립트
$ cd /usr/local/ruoyi/
$ nohup java -Dfile.encoding=utf-8 -javaagent:dd-java-agent-0.80.0.jar -XX:FlightRecorderOptions=stackdepth=256 -Ddd.logs.injection=true -Ddd.service.name=ruoyi-gateway -Ddd.service.mapping=redis:redis_ruoyi -Ddd.agent.port=9529 -Ddd.jmxfetch.enabled=true -Ddd.jmxfetch.check-period=1000 -Ddd.jmxfetch.statsd.port=8125 -Ddd.version=1.0 -jar ruoyi-gateway.jar > logs/gateway.log 2>&1 &
$ nohup java -Dfile.encoding=utf-8 -javaagent:dd-java-agent-0.80.0.jar -XX:FlightRecorderOptions=stackdepth=256 -Ddd.logs.injection=true -Ddd.service.name=ruoyi-auth -Ddd.service.mapping=redis:redis_ruoyi -Ddd.env=staging -Ddd.agent.port=9529 -Ddd.jmxfetch.enabled=true -Ddd.jmxfetch.check-period=1000 -Ddd.jmxfetch.statsd.port=8125 -Ddd.version=1.0 -jar ruoyi-auth.jar > logs/auth.log 2>&1 &
$ nohup java -Dfile.encoding=utf-8 -javaagent:dd-java-agent-0.80.0.jar -XX:FlightRecorderOptions=stackdepth=256 -Ddd.logs.injection=true -Ddd.service.name=ruoyi-modules-system -Ddd.service.mapping=redis:redis_ruoyi,mysql:mysql_ruoyi -Ddd.env=dev -Ddd.agent.port=9529 -Ddd.jmxfetch.enabled=true -Ddd.jmxfetch.check-period=1000 -Ddd.jmxfetch.statsd.port=8125 -Ddd.version=1.0 -jar ruoyi-modules-system.jar > logs/system.log 2>&1 &
ddtrace 관련 환경 변수(시작 파라미터) 설명:
- Ddd.env: 사용자 정의 환경 유형, 선택 사항.
- Ddd.tags: 사용자 정의 애플리케이션 태그, 선택 사항.
- Ddd.service.name: 사용자 정의 애플리케이션 이름, 필수.
- Ddd.agent.port: 데이터 업로드 포트(기본 9529), 필수.
- Ddd.version: 애플리케이션 버전, 선택 사항.
- Ddd.trace.sample.rate: 샘플링 비율 설정(기본 전체 샘플링), 선택 사항. 샘플링하려면 0~1 사이의 값(예: 0.6은 60% 샘플링)을 설정합니다.
- Ddd.service.mapping: 현재 애플리케이션이 호출하는 redis, mysql 등에 별칭을 추가하여 다른 애플리케이션이 호출하는 redis, mysql과 구분하는 데 사용됩니다. 선택 사항. 사용 사례: 예를 들어 프로젝트 A와 프로젝트 B가 모두 mysql을 호출하고 각각 mysql-a, mysql-b를 호출하는 경우, mapping 구성 항목을 추가하지 않으면 df 플랫폼에 프로젝트 A와 프로젝트 B가 동일한 mysql 데이터베이스를 호출하는 것으로 표시됩니다. mapping 구성 항목을 mysql-a, mysql-b로 추가하면 df 플랫폼에 프로젝트 A는 mysql-a, 프로젝트 B는 mysql-b를 호출하는 것으로 표시됩니다.
- Ddd.agent.host: 데이터 전송 대상 IP, 기본값은 로컬 localhost, 선택 사항.
3 APM 데이터 확인¶
APM은 Guance의 기본 내장 모듈이므로 별도의 시나리오나 뷰를 생성하지 않고도 확인할 수 있습니다.
뷰 예시:
이 뷰를 통해 애플리케이션 호출 상황, 토폴로지 뷰, 이상 데이터 등 기타 APM 관련 데이터를 빠르게 확인할 수 있습니다.
호출 체인의 문제 추적:
인터페이스, 데이터베이스 등의 문제를 진단할 수 있습니다.
LOG¶
1 표준 로그 수집¶
예: Nginx, MySQL, Redis 등
DataKit에 내장된 다양한 inputs을 활성화하여 관련 로그 수집을 바로 시작할 수 있습니다. 예를 들어 Nginx, Redis, 컨테이너, ES 등이 있습니다.
예시: Nginx
$ cd /usr/local/datakit/conf.d/nginx/
$ cp nginx.conf.sample nginx.conf
$ vim nginx.conf
## log 경로를 올바른 nginx 경로로 수정
$ [inputs.nginx.log]
$ files = ["/usr/local/nginx/logs/access.log","/usr/local/nginx/logs/error.log"]
$ pipeline = "nginx.p"
## pipeline은 grok 구문으로, 텍스트 로그를 파싱하는 데 사용됩니다. DataKit에는 nginx, mysql 등 다양한 pipeline이 내장되어 있습니다. pipeline의 기본 디렉터리는 /usr/local/datakit/pipeline/ 입니다. pipeline 경로를 수정할 필요가 없으며, DataKit이 자동으로 읽습니다.
뷰 표시:
2 사용자 정의 로그 수집¶
예: 애플리케이션 로그, 비즈니스 로그 등
예시: 애플리케이션 로그 Pipeline(로그 grok 파싱) 공식 문서
$ cd /usr/local/datakit/conf.d/log/
$ cp logging.conf.sample system-logging.conf
$ vim system-logging.conf
## log 경로를 올바른 애플리케이션 로그 경로로 수정
## source와 service는 필수 필드이며, 애플리케이션 이름을 사용하여 서로 다른 로그 이름을 구분할 수 있습니다.
[[inputs.logging]]
## required
logfiles = [
"/usr/local/java/ruoyi/logs/ruoyi-system/info.log",
"/usr/local/java/ruoyi/logs/ruoyi-system/error.log",
]
## glob 필터
ignore = [""]
## 로깅 소스, 비어 있으면 'default' 사용
source = "system-log"
## 서비스 태그 추가, 비어 있으면 $source 사용.
service = "system-log"
## grok pipeline 스크립트 경로
pipeline = "log_demo_system.p"
## 선택적 상태:
## "emerg","alert","critical","error","warning","info","debug","OK"
ignore_status = []
## 선택적 인코딩:
## "utf-8", "utf-16le", "utf-16le", "gbk", "gb18030" or ""
character_encoding = ""
## 패턴은 정규식이어야 합니다. '''정규식''' 사용에 유의하세요.
## 정규식 링크: https://golang.org/pkg/regexp/syntax/#hdr-Syntax
multiline_match = '''^\d{4}-\d{2}-\d{2}'''
## 텍스트 문자열에서 ANSI 이스케이프 코드 제거
remove_ansi_escape_codes = false
## pipeline은 grok 구문으로, 텍스트 로그를 파싱하는 데 사용됩니다. 이 구성을 활성화하지 않으면 df 플랫폼에 로그 원본 텍스트가 표시됩니다. 활성화하면 해당 로그가 grok 파싱됩니다. 여기에 지정하는 .p 파일은 직접 작성해야 합니다.
$ /usr/local/datakit/pipeline/
$ vim ruoyi_system.p
grok(_, "%{TIMESTAMP_ISO8601:time} %{NOTSPACE:thread_name} %{LOGLEVEL:status}%{SPACE}%{NOTSPACE:class_name} - \\[%{NOTSPACE:method_name},%{N
UMBER:line}\\] - %{DATA:service1} %{DATA:trace_id} %{DATA:span_id} - %{GREEDYDATA:msg}")
default_time(time)
3 로그 데이터 확인¶
RUM과 APM 데이터 연동 데모¶
원리 설명: 사용자가 프런트엔드 애플리케이션(RUM 모니터링이 추가되고 allowedTracingOrigins 필드가 구성된)에 액세스하면 프런트엔드 애플리케이션이 리소스 및 요청을 호출하여 rum-js 성능 데이터 수집을 트리거합니다. rum-js는 trace-id를 생성하여 요청의 request_header에 기록합니다. 요청이 백엔드에 도달하면 백엔드의 ddtrace가 해당 trace_id를 읽고 자체 trace 데이터에 기록하여, 동일한 trace_id를 통해 APM과 RUM 데이터를 연동 분석할 수 있습니다.
사용 사례: 프런트엔드와 백엔드 연결. 프런트엔드 요청과 백엔드 메서드 실행 성능 데이터를 일대일로 바인딩하여 프런트엔드와 백엔드 관련 문제를 더 쉽게 찾을 수 있습니다. 예를 들어, 프런트엔드 사용자 로그인이 느린 경우, 백엔드 서비스가 데이터베이스에서 사용자 정보를 조회하는 데 시간이 오래 걸려 발생할 수 있습니다. 이 경우 프런트엔드-백엔드 연동 분석을 통해 빠르게 팀 간, 부서 간 문제를 파악할 수 있습니다. 예시는 다음과 같습니다.
구성 방법: 웹 애플리케이션 모니터링(RUM) 모범 사례
1 프런트엔드 RUM 데이터¶
2 백엔드 APM 데이터로 이동¶
APM과 LOG 데이터 연동 데모¶
1 APM 모니터링 활성화¶
Kubernetes 애플리케이션의 RUM-APM-LOG 연동 분석의 APM 부분을 참조하세요. 추가 작업은 필요하지 않습니다.
2 애플리케이션 로그 출력 형식 수정¶
이 단계는 개발자 개입이 필요합니다. 애플리케이션 로그 출력 형식 파일 logback/log4j를 수정합니다.
<!-- 로그 출력 형식 -->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] %X{dd.service} %X{dd.trace_id} %X{dd.span_id} - %msg%n" />
해당 xml 파일을 저장하고 애플리케이션을 다시 배포합니다.
3 로그 모니터링 활성화¶
예시:
$ cd /usr/local/datakit/conf.d/log/
$ cp log.conf.sample ruoyi-system.conf
$ vim ruoyi-system.conf
## 아래 그림과 같이 내용 수정
## logfiles는 애플리케이션 로그의 절대 경로
## service와 source는 필수 필드로, df 플랫폼에서 검색할 수 있도록 함
## Pipeline은 필요에 따라 설정할 수 있으며, 주로 로그 필드 파싱에 사용됨. 파싱된 로그 내용은 메트릭으로 변환하여 시각화할 수 있음. trace-id 관련 내용은 시각화할 필요가 없으므로 파싱하지 않아도 됨.
4 APM & LOG 연동 분석¶
- 정방향 연동 [APM → 로그]
APM 트레이스 데이터에서 아래 로그 모듈의 검색창에trace_id를 입력하면 해당 트레이스 호출 시 생성된 애플리케이션 로그를 확인할 수 있습니다.
- 역방향 연동 [로그 → APM]
이상 로그를 확인하고, 로그에서trace_id를 복사합니다. 추적 페이지 검색창에 해당trace_id를 입력하면 해당 ID와 관련된 모든 trace 및 span 데이터를 검색할 수 있으며, 클릭하여 확인할 수 있습니다.

























