[22.09.14] Daily 회고록 (CloudWatch를 활용한 프로젝트 로그 저장, 영어 스피치)
일간 회고록(TIL)

[22.09.14] Daily 회고록 (CloudWatch를 활용한 프로젝트 로그 저장, 영어 스피치)

[일일회고]

하루하루는 생각보다 느리게 가는데, 일주일은 너무 빠르게 지나간다. 추석 때 본가를 다녀오느라 버스에서만 2일을 버린 것도 일조했다고 생각한다 . . 지난 글에 올렸던 영어 스피치 시간이 벌써 다가왔다. 이번주에는 외국인도 두 명 참석해서 8명이나 됐고, 외국인들 이름이 리아랑 아짇나..? 아무튼 발음하기 어려운 이름이였다. 이번주에는 뭔가 나름 전보단 잘 말한 것 같아 뿌듯했다. ㅎㅎㅎ.. 매 주 수요일에 진행되서 수요일의 일정을 물어보는데 늦게 일어나서 수업 하나 듣고 밥 먹고 참석하기 때문에 따로 말할게 없어서 잡담을 더 많이 하는 것 같다.

[프로젝트]

추석 일정을 보내고, 공채 하반기 자소서를 작성하느라 글을 많이 작성하지 못했다.. 다음주 토요일에 코딩테스트이기 때문에 프로젝트를 빠르게 완료하고 준비를 하려고 한다.

EC2에 올라간 프로젝트 로그를 확인하려면 SSH로 직접 접속해서 확인해야하는 번거로움이 있고, SSH 포트를 열어둬야하기 때문에 보안상으로도 좋지 않다. 그렇기 때문에 CloudWatch에 로그를 저장하는 작업을 준비했다.
구글링을 해봤을 때 많은 자료들 중에 EC2에 CloudWatch 관련된 설치나, ~/.aws에 credentials를 작성하는 등의 방법이 있었지만 이 방법이 좀 처럼 끌리지 않아서, 최대한 간소화된 작업을 통해 가능하도록 구성해보았다.

일단 IAM을 만들어 CloudWatchFullAccess를 가진 IAM User의 AccessKey/SecretKey를 저장하고 Role을 만들어 EC2에 적용했다.

Role - EC2에 적용(CloudWatch에 접근하기 위한 권한)
IAM User - Spring Project에서 사용 예정



build.gradle에 관련된 패키지를 추가해준다.


그리고 spring project에서 /resources/logback-spring.xml을 만들어 준다.

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <conversionRule conversionWord="wEx"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
    <property name="LOG_PATTERN"
              value="${LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){blue} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <!-- aws key from yml, 이게 없으면 ~/.aws/credentials를 참고하게 된다, 이 Crendentials에 CloudWatch관련된 Role을 가지고 있어야한다. -->
    <springProperty name="AWS_ACCESS_KEY" source="cloud.aws.credentials.access-key"/>
    <springProperty name="AWS_SECRET_KEY" source="cloud.aws.credentials.secret-key"/>

    <!-- 기존과 동일한 Console 출력을 위한 appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>${LOG_PATTERN}</Pattern>
        </layout>
    </appender>

    <!-- CloudWatch에 등록하기 모든 로그를 출력하기 위함 -->
    <appender name="aws_cloud_watch_log_info" class="ca.pjer.logback.AwsLogsAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <layout>
            <pattern>[%thread] [%date] [%level] [%file:%line] - %msg%n</pattern>
        </layout>
        <logGroupName>exquiz-me-log-info</logGroupName>
        <logStreamUuidPrefix>prod-</logStreamUuidPrefix>
        <logRegion>ap-northeast-2</logRegion>
        <maxBatchLogEvents>50</maxBatchLogEvents>
        <maxFlushTimeMillis>30000</maxFlushTimeMillis>
        <maxBlockTimeMillis>5000</maxBlockTimeMillis>
        <retentionTimeDays>0</retentionTimeDays>
        <accessKeyId>${AWS_ACCESS_KEY}</accessKeyId>
        <secretAccessKey>${AWS_SECRET_KEY}</secretAccessKey>
    </appender>

    <!-- CloudWatch에 등록하기 에러 로그를 출력하기 위함 -->
    <appender name="aws_cloud_watch_log_error" class="ca.pjer.logback.AwsLogsAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <layout>
            <pattern>[%thread] [%date] [%level] [%file:%line] - %msg%n</pattern>
        </layout>
        <logGroupName>exquiz-me-log-error</logGroupName> <!-- 로그그룹명 -->
        <logStreamUuidPrefix>prod-</logStreamUuidPrefix> <!-- 로그 Prefix -->
        <logRegion>ap-northeast-2</logRegion>
        <maxBatchLogEvents>50</maxBatchLogEvents>
        <maxFlushTimeMillis>30000</maxFlushTimeMillis>
        <maxBlockTimeMillis>5000</maxBlockTimeMillis>
        <retentionTimeDays>0</retentionTimeDays>
        <accessKeyId>${AWS_ACCESS_KEY}</accessKeyId>
        <secretAccessKey>${AWS_SECRET_KEY}</secretAccessKey>
    </appender>

    <springProfile name="dev">
        <root level="info">
            <appender-ref ref="CONSOLE"/>
        </root>
    </springProfile>

    <springProfile name="prod">
        <root level="info">
            <appender-ref ref="aws_cloud_watch_log_info"/>
            <appender-ref ref="aws_cloud_watch_log_error"/>
        </root>
    </springProfile>
</configuration>

필요한 log에 따라 구분하기 위해 info와 error를 구분했고, dev에서는 console에, prod에서는 cloudwatch에 저장되도록 하였다.

프로젝트 내부에서 AWS와 연결해주기 위해서 Configuration도 하나 만들어줬다. (@Value 내용은 secret한 yml에 넣어주었다.)

@Configuration
@Slf4j
@Getter
public class AwsConfig {
    @Value("${cloud.aws.credentials.access-key}")
    private String accessKey;

    @Value("${cloud.aws.credentials.secret-key}")
    private String secretKey;

    @Value("${cloud.aws.region.static}")
    private String region;

    @Value("${cloud.aws.sns.arns.create-article}")
    private String snsTopicArn;

    private AWSCredentials awsCredentials;

    @PostConstruct
    public void init(){
        awsCredentials = new BasicAWSCredentials(accessKey,secretKey);
    }

    @Bean
    public AWSCredentialsProvider awsCredentialsProvider(){
        return new AWSStaticCredentialsProvider(awsCredentials);
    }
}


이제 CloudWatch에서 확인해보자

CloudWatch &gt; Logs &gt; Log groups
info
error


CloudWatch에 로그가 성공적으로 저장되었으므로, 이를 이용해서 곧 적용될 로그 시스템을 적용해볼 예정이다. 다음주 쯤이면 적용가능할 듯 싶다. 이후 S3에 저장하는 것으로 이어갈 듯 싶다.