ecsimsw
CloudWatch agent로 로그 파일 수집 본문
CloudWatch agent 로그 파일 지정과 이벤트 수집
Spring application에서 발생하는 로그 파일을 확인하기 위해 매번 인스턴스에 직접 들어가서 파일을 확인하는 작업은 번거롭고, 위험하다. 가급적이면 개발자 개인이 배포 서버 인스턴스를 직접 건드는 작업을 피하고 싶었고, application에서 생성되는 로그 파일을 CloudWatch에 출력하고자 했다.
애플리케이션에서 생성된 파일을 CloudWatch에 출력하는 방법, 그리고 파일로 생성하지 않고 서버의 정보를 CloudWatch에 직접 뿌리는 방법을 공부해왔다. 전자의 경우에는 에러 파일을 그래도 출력하기 위함이었고, 후자의 경우에는 서버의 동작 여부를 확인하기 위함이었다.
해당 프로젝트내에선 사실상 에러 로깅 외의 로그가 없었고, 에러 파일만 CloudWatch로 관리하는 경우 에러가 나지 않는 이상 서버가 정상 작동됨을 확인할 방법이 었었다. 그래서 서버 동작 확인을 위한 단순 로그를 찍고자 했고, 이를 또 파일로 관리하자니 굳이 불필요한 로그를 파일로 저장하고 읽는 부분이 비효율적이라고 생각했다. 가벼운 정보를 파일이 아닌 Console 로그를 찍 듯, cloudWatch에서 볼 수 있었으면 좋겠다는 생각이었다.
Cloudwatch agent를 이용하면 쉽게 파일 로그를 CloudWatch에 출력할 수 있다. 파일이 아닌 Stream을 사용한 CloudWatch 직접 출력은 외부 라이브러리를 사용하였고, 각각의 방법을 소개하고자 한다.
CloudWatch agent 설치
CloudWatch agent는 두 방법에 공통적이다. agent를 사용하면 꼭 로깅이 아니더라도, Cpu사용률, 디스크 사용률 등의 기본 인스턴스 정보 출력 외에 metrics를 출력할 수 있으니 함께 알아봤으면 한다.
로그 파일 출력하기
cloudwatch 설정 파일에 로그 파일 위치 지정
sudo vi /opt/aws/amazon-cloudwatch-agent/bin/config.json
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": [로그파일위치],
"log_group_name": [로그그룹명],
"log_stream_name": [로그스트림명]
}
]
}
}
}
(로그 그룹명, 로그 스트림명은 자유롭게 하시되 기억해주세요. 3번에서 사용됩니다.)
설정 파일 적용
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json -s
설정 파일에 작성한대로 cloudwatch 로그 그룹, 스트림 생성
로그 이벤트 확인
metrics 수집과 로그 파일 이벤트 수집을 적용한 CW agent 설정 파일 예시
{
"agent": {
"metrics_collection_interval": 60,
"run_as_user": "root"
},
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/home/ubuntu/api-server/logs/err_log.log",
"log_group_name": "GPU-IS-MINE-prod-error-logs",
"log_stream_name": "error"
},
{
"file_path": "/home/ubuntu/api-server/logs/log.log",
"log_group_name": "GPU-IS-MINE-prod-http-logs",
"log_stream_name": "http"
}
]
}
}
},
"metrics": {
"metrics_collected": {
"disk": {
"measurement": [
"used_percent",
"used",
"total"
],
"metrics_collection_interval": 60,
"resources": [
"*"
]
},
"mem": {
"measurement": [
"mem_used_percent",
"mem_total",
"mem_used"
],
"metrics_collection_interval": 60
}
}
}
}
Stream으로 직접 출력
파일 저장없이 로그를 직접 출력하기 위해 아래 외부 라이브러리를 사용했다. 사용 방법이 너무 간단하고, 문서화가 잘되어있어 다른 설명은 불필요할 것 같다.
pierredavidbelanger/logback-awslogs-appender 사용 예시
build.gradle
dependencies {
implementation("ca.pjer:logback-awslogs-appender:1.4.0")
}
logback.xml
<configuration packagingData="true">
<!-- Register the shutdown hook to allow logback to cleanly stop appenders -->
<!-- this is strongly recommend when using AwsLogsAppender in async mode, -->
<!-- to allow the queue to flush on exit -->
<shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/>
<!-- Timestamp used into the Log Stream Name -->
<timestamp key="timestamp" datePattern="yyyyMMddHHmmssSSS"/>
<!-- The actual AwsLogsAppender (asynchronous mode because of maxFlushTimeMillis > 0) -->
<appender name="ASYNC_AWS_LOGS" class="ca.pjer.logback.AwsLogsAppender">
<!-- Send only WARN and above -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<!-- Nice layout pattern -->
<layout>
<pattern>%d{yyyyMMdd'T'HHmmss} %thread %level %logger{15} %msg%n</pattern>
</layout>
<!-- Hardcoded Log Group Name -->
<logGroupName>XXXXXXX</logGroupName>
<!-- Log Stream Name UUID Prefix -->
<logStreamUuidPrefix></logStreamUuidPrefix>
<!-- Hardcoded AWS region -->
<!-- So even when running inside an AWS instance in us-west-1, logs will go to us-west-2 -->
<logRegion>XXXXXXX</logRegion>
<!-- Maximum number of events in each batch (50 is the default) -->
<!-- will flush when the event queue has 50 elements, even if still in quiet time (see maxFlushTimeMillis) -->
<maxBatchLogEvents>50</maxBatchLogEvents>
<!-- Maximum quiet time in millisecond (0 is the default) -->
<!-- will flush when met, even if the batch size is not met (see maxBatchLogEvents) -->
<maxFlushTimeMillis>30000</maxFlushTimeMillis>
<!-- Maximum block time in millisecond (5000 is the default) -->
<!-- when > 0: this is the maximum time the logging thread will wait for the logger, -->
<!-- when == 0: the logging thread will never wait for the logger, discarding events while the queue is full -->
<maxBlockTimeMillis>5000</maxBlockTimeMillis>
<!-- Retention value for log groups, 0 for infinite see -->
<!-- https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutRetentionPolicy.html for other -->
<!-- possible values -->
<retentionTimeDays>0</retentionTimeDays>
</appender>
<!-- <!– A console output –>-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyyMMdd'T'HHmmss} %thread %level %logger{15} %msg%n</pattern>
</encoder>
</appender>
<!-- Root with a threshold to INFO and above -->
<root level="INFO">
<!-- Append to the console -->
<appender-ref ref="STDOUT"/>
<!-- Append also to the (async) AwsLogsAppender -->
<appender-ref ref="ASYNC_AWS_LOGS"/>
</root>
</configuration>
결과
프로젝트의 운영 방법 소개 영상
https://www.youtube.com/watch?v=FgZ9tAd-DGg
'Architecture > Infrastructure' 카테고리의 다른 글
리버스 프록시 부하분산 개념과 시연 (2) | 2022.06.17 |
---|---|
로드 밸런싱을 활용한 무중단 배포 (4) | 2021.08.10 |
Cloudwatch Agent로 인스턴스 메트릭 수집 (0) | 2021.08.08 |
부하 분산에 세션을 유지하는 방법 (0) | 2021.06.07 |
WAS 전면에 Web Server를 두는 이유 (0) | 2021.06.06 |