[Spring Boot][Total-Back-Office Project] Log Back์„ ์ด์šฉํ•œ Discord์— Exception ์ •๋ณด ๋ณด๋‚ด๊ธฐ ๋ฐ Data Base ์ €์žฅ feat.MyBatis & Test Code(JUnit 5) - โ‘  Log Back ์„ค์ •

2023. 7. 19. 00:07ใ†๊ฐœ๋… ์ •๋ฆฌ ์ž‘์—…์‹ค/Java

728x90
๋ฐ˜์‘ํ˜•

 

 

 

 

 

 

์Šคํ”„๋ง ๋ถ€ํŠธ 3 ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž ๋˜๊ธฐ : ์ž๋ฐ” ํŽธ

COUPANG

www.coupang.com

"์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค."

 

 




๐Ÿ—‚ ๋ชฉ์ฐจ

๐Ÿง‘‍๐Ÿ’ป ์ฝ”๋”ฉ

โœ…  [Spring Boot][Total-Back-Office Project] AOP, Annotation์„ ์ด์šฉํ•œ API ๋™์ž‘ ์‹œ๊ฐ„ ์ธก์ •
โœ… [Spring Boot][Total-Back-Office Project] AOP, Annotation์„ ์ด์šฉํ•œ API ์š”์ฒญ ์ด์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ feat.MyBatis & Test Code(JUnit 5) (https://junyharang.tistory.com/457
)

โœ… [Spring Boot][Total-Back-Office Project] Log Back์„ ์ด์šฉํ•œ Discord์— Exception ์ •๋ณด ๋ณด๋‚ด๊ธฐ ๋ฐ Data Base  ์ €์žฅ feat.MyBatis & Test Code(JUnit 5) - โ‘  Log Back ์„ค์ •
โœ… [Spring Boot][Total-Back-Office Project] Log Back์„ ์ด์šฉํ•œ Discord์— Exception ์ •๋ณด ๋ณด๋‚ด๊ธฐ ๋ฐ Data Base ์ €์žฅ feat.MyBatis & Test Code(JUnit 5) - โ‘ก ๋””์Šค์ฝ”๋“œ๋กœ ๋กœ๊ทธ ์ •๋ณด ๋ฐœ์†ก
โœ… [Spring Boot][Total-Back-Office Project] Log Back์„ ์ด์šฉํ•œ Discord์— Exception ์ •๋ณด ๋ณด๋‚ด๊ธฐ ๋ฐ Data Base ์ €์žฅ feat.MyBatis & Test Code(JUnit 5) - โ‘ข ๋กœ๊ทธ ๋ฐ ์š”์ฒญ ์ด์šฉ์ž, ์š”์ฒญ ์ •๋ณด ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์— ์ €์žฅ

 

๐Ÿšš ๋ฐฐํฌ

โš ๏ธ ์•„๋ž˜ ๋ชฉ์ฐจ ์ค‘ ๋ช‡๋ช‡๊ฐœ์˜ ๋งํฌ๊ฐ€ ๊ฑธ๋ฆฌ์ง€ ์•Š๋Š” ๋ฌธ์ œ๋กœ ๊ธ€ ๋งจ ํ•˜๋‹จ์— ๋‹ค์Œ ๊ธ€๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

โœ… [CI/CD] Jenkins์™€ Gitea ์—ฐ๋™
โœ… [CI/CD] Jenkins Trigger ์ •๋ณด Discord๋กœ ๋ณด๋‚ด๊ธฐ
โœ… [CI/CD] ์ •์  ์ฝ”๋“œ ๋ถ„์„ ํˆด SonarQube์™€ Jenkins ์—ฐ๋™
โœ… [CI/CD] SonarQube๋ฅผ ํ†ตํ•ด Code Convention ์ ์šฉ
โœ… [DevOps] JAVA Gradle JaCoCo (Code coverage) ์„ค์ •ํ•˜๊ธฐ 
โœ… [DevOps] JAVA Gradle JaCoCo (Code coverage) ์„ค์ •ํ•˜๊ธฐ (์ถ”๊ฐ€)(https://junyharang.tistory.com/392)

โœ… [CI/CD] Jenkins + Docker๋ฅผ ์ด์šฉํ•œ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ - โ‘  Application Linuxt(Ubuntu)์— SSH๋ฅผ ์ด์šฉํ•œ ํŒŒ์ผ ์ „์†ก
โœ… [CI/CD] Jenkins + Docker๋ฅผ ์ด์šฉํ•œ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ - โ‘ก Create Docker Image And BackUp
โœ… [CI/CD] Jenkins + Docker๋ฅผ ์ด์šฉํ•œ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ - โ‘ข Application Server Docker Job (โ‘  Application ๋„์ปค ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ)
โœ… [CI/CD] Jenkins + Docker๋ฅผ ์ด์šฉํ•œ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ - โ‘ข Application Server Docker Job (โ‘ก Application Docker Run)(https://junyharang.tistory.com/406)
โœ… [CI/CD] Jenkins + Docker๋ฅผ ์ด์šฉํ•œ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ - โ‘ข Application Server Docker Job (โ‘ข Application Docker Health Check)
โœ… [CI/CD] Jenkins + Docker๋ฅผ ์ด์šฉํ•œ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ - โ‘ฃ NGINX Server Docker Job (โ‘  NGINX ๊ฐ ์ข… ์„ค์ •) 
โœ… [CI/CD] Jenkins + Docker๋ฅผ ์ด์šฉํ•œ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ - โ‘ฃ NGINX Server Docker Job (โ‘ก NGINX Docker ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ) 
โœ… [CI/CD] Jenkins + Docker๋ฅผ ์ด์šฉํ•œ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ - โ‘ฃ NGINX Server Docker Job (โ‘ข NGINX Docker Run & Health Check)
โœ… [CI/CD] Jenkins + Docker๋ฅผ ์ด์šฉํ•œ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ - โ‘ฃ NGINX Server Docker Job (โ‘ข NGINX ์žฌ ์„ค์ •)

 

 

๐Ÿ’พ Git Hub Repository : https://github.com/junyharang-personal-project/junyss-total-back-office

 

GitHub - junyharang-personal-project/junyss-total-back-office: [Back-Office] ๋””์Šค์ฝ”๋“œ ๋ด‡๊ณผ Logback, AOP ๋“ฑ์„ ์ด์šฉํ•˜

[Back-Office] ๋””์Šค์ฝ”๋“œ ๋ด‡๊ณผ Logback, AOP ๋“ฑ์„ ์ด์šฉํ•˜์—ฌ ์ด์šฉ์ž ์ ‘์† ์ •๋ณด, Exception ์ •๋ณด ๋“ฑ์„ ๋””์Šค์ฝ”๋“œ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋น„์Šค - GitHub - junyharang-personal-project/junyss-total-back-office: [Back-Office] ๋””์Šค์ฝ”๋“œ

github.com

 

 

 

 

๐Ÿš€ Log Back์„ ์ด์šฉํ•œ Discord์— Exception ์ •๋ณด ๋ณด๋‚ด๊ธฐ ๋ฐ Data Base ์ €์žฅ

    ๐Ÿ”ฝ ๊ฐœ์š”

        ๐Ÿ“ฆ ์†Œ๊ฐœ

๊ฐœ๋ฐœ์ž๊ฐ€ API๋ฅผ ๋งŒ๋“ค๊ณ , ์‹ค์ œ ์„œ๋น„์Šค ํ•  ๋•Œ, ์ด์šฉ์ž ์š”์ฒญ์ด ์ž˜ ๋ชป ๋˜๊ฑฐ๋‚˜, ์•…์˜์ ์ธ ์š”์ฒญ ๋“ฑ์„ ์ฆ‰๊ฐ์ ์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ๋ฌด์—‡์ผ๊นŒ? ๋ฅผ ๊ณ ๋ฏผํ•ด ๋ณด์•˜์–ด์š”.

๋งŽ์€ ํšŒ์‚ฌ์—์„œ ์—ฌ๋Ÿฌ SNS๋ฅผ ์ด์šฉํ•ด์„œ ์‚ฌ๋‚ด ์ปค๋ฎค๋‹ˆํ‹ฐ ์šฉ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ๋Œ€ํ‘œ์ ์œผ๋กœ Slack, Discord, Telegram ๋“ฑ์ด ์žˆ์–ด์š”.

๊ทธ ์ค‘ ์ฃผ๋‹ˆ๋Š” ํ™”์ƒ ํšŒ์˜๋„ ๊ฐ€๋Šฅํ•˜๊ณ , ๋ณด๋‹ค ํŽธ๋ฆฌํ•˜๋‹ค๊ณ  ์ƒ๊ฐ๋˜๋Š” ๋””์Šค์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ SNS๋กœ ํ™œ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ, Log Back์„ ์ด์šฉํ•˜์—ฌ ๋””์Šค์ฝ”๋“œ์— Exception ์ •๋ณด๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ณ , ์ด๋ฅผ Data Base์— ์ €์žฅํ•œ ๋’ค ์ด๋ฅผ ๋””์Šค์ฝ”๋“œ ๋ด‡์„ ํ†ตํ•ด ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค๋ฉด ์ข‹๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์–ด์š”.

Java๋ฅผ ์ด์šฉํ•˜์—ฌ ๋””์Šค์ฝ”๋“œ ๋ด‡ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€ ์ด ๊ณณ์— ์ค€๋น„ํ•ด ๋‘์—ˆ์–ด์š”.

https://junyharang.tistory.com/381

๊ทธ๋Ÿผ Log Back์„ ํ†ตํ•ด ๋””์Šค์ฝ”๋“œ์— Exception ์ •๋ณด ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด ๋ณผ๊ฒŒ์š”.

์ฐธ๊ณ ๋กœ ์ฃผ๋‹ˆ๊ฐ€ ๊ฐœ๋ฐœํ•œ API ๊ตฌ๋™ ํ™˜๊ฒฝ์€ Local, Dev(๊ฐœ๋ฐœ ํ™˜๊ฒฝ), Prod(์šด์˜ ํ™˜๊ฒฝ)์œผ๋กœ ๋‚˜๋ˆ„์—ˆ๊ณ , Prod๋กœ ๊ตฌ์„ฑํ•œ ๋‚ด์šฉ์„ ํ† ๋Œ€๋กœ ์ •๋ฆฌํ•ด ๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

 

    ๐Ÿ”ฝ ์†Œ์Šค ์ฝ”๋“œ ๋ถ„์„ (๊ตฌํ˜„๋ถ€)

        ๐Ÿ“ฆ logback-prod.xml

์ตœ์ดˆ ์ฃผ๋‹ˆ๊ฐ€ ์ž‘์„ฑํ•œ logback ์„ค์ •์€ ์•„๋ž˜์™€ ๊ฐ™์•„์š”.

<?xml version="1.0" encoding="UTF-8" ?>
<!-- 60์ดˆ๋งˆ๋‹ค ์„ค์ • ํŒŒ์ผ์˜ ๋ณ€๊ฒฝ์„ ํ™•์ธ ํ•˜์—ฌ ๋ณ€๊ฒฝ์‹œ ๊ฐฑ์‹  -->
<configuration scan="true" scanPeriod="60 seconds">
    <!--springProfile ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด logback ์„ค์ •ํŒŒ์ผ์—์„œ ๋ณต์ˆ˜๊ฐœ์˜ ํ”„๋กœํŒŒ์ผ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.-->
    <springProfile name="local">
        <property resource="application-local-logback.yml"/>
        <property resource="application-local-environment.yml"/>
    </springProfile>
    <springProfile name="dev">
        <property resource="application-dev-logback.yml"/>
        <property resource="application-dev-environment.yml"/>
    </springProfile>
    <springProfile name="prod">
        <property resource="application-prod-logback.yml"/>
        <property resource="application-prod-environment.yml"/>
    </springProfile>
    <springProperty name="DISCORD_WEBHOOK_URI" source="logging.discord.webhook-uri"/>
    <property name="LOG_ROOT_PATH" value="log"/>
    <springProperty name="SERVER_NAME" source="server.name"/>
    <springProperty name="ENVIRONMENT" source="server.environment"/>
    <springProperty name="PORT" source="server.port"/>
    <property name="LOG_PATH_NAME" value="${LOG_ROOT_PATH}/${SERVER_NAME}/${ENVIRONMENT}-${PORT}/%d{yyyy-MM-dd}"/>
    <springProperty scope="context" name="LOG_LEVEL" source="logging.level.root"/>
    <property name="ERR_LOG_FILE_NAME" value="Error"/>
    <property name="LOG_FILE_NAME" value="Info"/>
    <property name="FILE_LOG_PATTERN" value="%-5level %d{yy-MM-dd HH:mm:ss} [%thread] [%logger{0}:%line] - %msg%n"/>

    <!--DiscordAppender ์ ์šฉ -->
    <appender name="DISCORD"
              class="com.giggalpeople.backoffice.chatops.logback.appender.discord.append.DiscordAppender">
        <discordWebhookURL>${DISCORD_WEBHOOK_URI}</discordWebhookURL>
    </appender>

    <!-- Console appender ์„ค์ • -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--     ๋‚ ์งœ       ์‹œ๊ฐ„   ๋กœ๊ทธ๋ ˆ๋ฒจ  ๋กœ๊ฑฐ์ด๋ฆ„  ํ”„๋กœ์„ธ์Šค ID  [๋กœ๊น… ๋ฐœ์ƒ ํŒŒ์ผ๋ช…]๋ฉ”์†Œ๋“œ ๋ช…,ํ˜ธ์ถœ์ง€ ์ •๋ณด,(๋ผ์ธ ์ˆ˜) ๋กœ๊ทธ๋ฉ”์„ธ์ง€ -->
            <pattern>[%d{yyyy-MM-dd}] [%d{HH:mm:ss.SSS}] [%p] ${PID:-} [%F] %M (%L\) : %m%n</pattern>
        </encoder>
    </appender>

    <!-- Log File ์ €์žฅ -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH_NAME}/${SERVER_NAME}.log</file>

        <!-- ์ถœ๋ ฅํŒจํ„ด ์„ค์ •-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>

        <!-- Rolling ์ •์ฑ… -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH_NAME}/${LOG_FILE_NAME}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- ํŒŒ์ผ๋‹น ์ตœ๊ณ  ์šฉ๋Ÿ‰ kb, mb, gb -->
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!-- ์ผ์ž๋ณ„ ๋กœ๊ทธํŒŒ์ผ ์ตœ๋Œ€ ๋ณด๊ด€์ฃผ๊ธฐ(~์ผ), ํ•ด๋‹น ์„ค์ •์ผ ์ด์ƒ๋œ ํŒŒ์ผ์€ ์ž๋™์œผ๋กœ ์ œ๊ฑฐ-->
            <maxHistory>180</maxHistory>
        </rollingPolicy>
    </appender>

    <!-- ์—๋Ÿฌ์˜ ๊ฒฝ์šฐ ํŒŒ์ผ์— ๋กœ๊ทธ ์ฒ˜๋ฆฌ -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <file>${LOG_PATH_NAME}/${ERR_LOG_FILE_NAME}-%d{yyyy-MM-dd}.%i.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
        <!-- Rolling ์ •์ฑ… -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- .gz,.zip ๋“ฑ์„ ๋„ฃ์œผ๋ฉด ์ž๋™ ์ผ์ž๋ณ„ ๋กœ๊ทธํŒŒ์ผ ์••์ถ• -->

            <fileNamePattern>${LOG_PATH_NAME}/${ERR_LOG_FILE_NAME}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- ํŒŒ์ผ๋‹น ์ตœ๊ณ  ์šฉ๋Ÿ‰ kb, mb, gb -->
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!-- ์ผ์ž๋ณ„ ๋กœ๊ทธํŒŒ์ผ ์ตœ๋Œ€ ๋ณด๊ด€์ฃผ๊ธฐ(~์ผ), ํ•ด๋‹น ์„ค์ •์ผ ์ด์ƒ๋œ ํŒŒ์ผ์€ ์ž๋™์œผ๋กœ ์ œ๊ฑฐ-->
            <maxHistory>180</maxHistory>
        </rollingPolicy>
    </appender>

    <appender name="ASYNC_DISCORD" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="DISCORD"/>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
        </filter>
    </appender>

    <!-- ๋ชจ๋“  ๋กœ๊ทธ ์ถœ๋ ฅ (๋””์ฝ”/ํŒŒ์ผ) -->
    <root level="${LOG_LEVEL}">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="ASYNC_DISCORD"/>
        <appender-ref ref="FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </root>

    <!-- ํŠน์ •ํŒจํ‚ค์ง€ ๋กœ๊น…๋ ˆ๋ฒจ ์„ค์ • -->
    <logger name="org.hibernate.SQL" level="DEBUG" additivity="false">
        <appender-ref ref="FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </logger>
</configuration>


์ตœ์ดˆ ์„ค์ •๋ถ€์— ๋Œ€ํ•ด ํ™•์ธํ•ด ๋ณผ๊ฒŒ์š”.

logback-prod.xml 1 ~ 16๋ฒˆ์งธ ์ค„


์ผ๋‹จ ์œ„ ๋‚ด์šฉ์€ ๊ฐ ๊ตฌ๋™ ํ™˜๊ฒฝ (Profile)์— ๋”ฐ๋ฅธ ์„ค์ • ํŒŒ์ผ๋“ค์— ๋‚ด์šฉ์„ ์ฐธ์กฐํ•˜๋„๋ก ์„ค์ • ๋œ ๋ถ€๋ถ„์ด์—์š”.
ํ•ด๋‹น ํŒŒ์ผ๋“ค์„ ํ†ตํ•ด Application์˜ Logging ๋ฐ ํ™˜๊ฒฝ ์„ค์ •์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์–ด์š”.

๊ฐ Tag์— ๋Œ€ํ•ด ์•Œ์•„ ๋ณผ๊ฒŒ์š”.

Tag ๋‚ด   ์šฉ
<configuration> ์„ค์ • ํŒŒ์ผ์˜ ๋ฃจํŠธ ์š”์†Œ๋กœ scan ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ • ํŒŒ์ผ์˜ ๋ณ€๊ฒฝ์„ ์ฃผ๊ธฐ์ ์œผ๋กœ ๊ฐ์ง€ํ•˜์—ฌ
๋ณ€๊ฒฝ ์‹œ ๊ฐฑ์‹ ํ•  ์ง€ ์—ฌ๋ถ€๋ฅผ ์ง€์ •ํ•ด์ค€๋‹ค.

scanPeriod ์†์„ฑ์€ ๋ณ€๊ฒฝ ๊ฐ์ง€ ์ฃผ๊ธฐ ์„ค์ •๋ถ€๋กœ ์œ„ ์ฝ”๋“œ์—์„œ๋Š” 60์ดˆ๋‹จ์œ„๋กœ ๋ณ€๊ฒฝ ๊ฐ์ง€ ์ง„ํ–‰.
<springProfile> ํ”„๋กœํŒŒ์ผ ์ง€์ • ์‹œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์œผ๋กœ name ์†์„ฑ์€ ํ”„๋กœํŒŒ์ผ์˜ ์ด๋ฆ„์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ๋กœ๊น… ๋ฐ ํ™˜๊ฒฝ ์„ค์ • ํŒŒ์ผ ์ฐธ์กฐ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ.
<property> ๊ฐ ํ”„๋กœํŒŒ์ผ์— ํ•ด๋‹นํ•˜๋Š” ๋กœ๊น…๊ณผ ํ™˜๊ฒฝ ์„ค์ • ํŒŒ์ผ์˜ ๊ฒฝ๋กœ์™€ ์ด๋ฆ„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์œผ๋กœ
resource ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ์ผ ๊ฒฝ๋กœ ๋ฐ ์ด๋ฆ„ ์ง€์ •.


์ฃผ๋‹ˆ๋Š” ์œ„ Tag๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ๊ฐ์˜ ๊ตฌ๋™ ํ™˜๊ฒฝ๋ณ„๋กœ ์ฐธ์กฐ๋˜์–ด์•ผ ํ•˜๋Š” ์„ค์ • ํŒŒ์ผ๋“ค์„ ๋‹ค๋ฅด๊ฒŒ ํ•˜๊ณ ,
ํ•ด๋‹น ๋‚ด์šฉ์„ ์ฐธ์กฐํ•˜๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋กœํŒŒ์ผ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋กœ๊น… ๋ฐ ํ™˜๊ฒฝ ์„ค์ •์„ ์ œ๊ณตํ•˜์—ฌ ๊ฐœ๋ฐœ, ํ…Œ์ŠคํŠธ ๋ฐ ์šด์˜ ํ™˜๊ฒฝ์— ๋งž๊ฒŒ ์ ํ•ฉํ•œ
์„ค์ •์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ต๋‹ˆ๋‹ค.

 

logback-prod.xml 17 ~ 29๋ฒˆ์งธ ์ค„


์œ„ ๋‚ด์šฉ์€ ๋กœ๊น… ๊ด€๋ จ ์„ค์ •์— ๋Œ€ํ•œ ๋‚ด์šฉ์ธ๋ฐ, ํ•ด๋‹น ์„ค์ •์€ <property>์™€ <springProperty> ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •์˜ํ•˜์˜€๊ณ , ๋‹ค์–‘ํ•œ ์†์„ฑ๋“ค์„ ์ด์šฉํ•˜์—ฌ ๋กœ๊ทธ ํŒŒ์ผ์˜ ๊ฒฝ๋กœ, ์ด๋ฆ„, ๋กœ๊น… ํŒจํ„ด ๋“ฑ์„ ์ง€์ •ํ•ด ์ฃผ์—ˆ์–ด์š”.

Tag ์†์„ฑ ์†์„ฑ ์ƒ์„ธ
<springProperty> name="DISCORD_WEBHOOK_URI" ๋””์Šค์ฝ”๋“œ Webhook URI๋ฅผ logging.discord.webhook-uri
์†Œ์Šค์—์„œ ๊ฐ€์ ธ์™€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์„ค์ •
  name="SERVER_NAME" ์„œ๋ฒ„ ์ด๋ฆ„ ์ฆ‰, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ๋™ ์„œ๋ฒ„ ์ด๋ฆ„์„ ์„ค์ • ํŒŒ์ผ์˜
server.name์—์„œ ๊ฐ€์ ธ์™€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์„ค์ •.
  name="ENVIRONMENT" ์„œ๋ฒ„ ๊ตฌ๋™ ํ™˜๊ฒฝ์„ ์„ค์ • ํŒŒ์ผ
server.environment ์†Œ์Šค์—์„œ ๊ฐ€์ ธ์™€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์„ค์ •.
  name="PORT" ์„œ๋ฒ„ ๊ตฌ๋™ Listening Port๋ฅผ ์„ค์ • ํŒŒ์ผ
server.port ์†Œ์Šค์—์„œ ๊ฐ€์ ธ์™€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์„ค์ •
  name="LOG_LEVEL" Log Level์„ ์„ค์ • ํŒŒ์ผ
logging.level.root ์†Œ์Šค์—์„œ ๊ฐ€์ ธ์™€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์„ค์ •.

์ด ๋•Œ, scope="context"๋กœ ์ง€์ •๋˜์–ด Spring Context ๋ฒ”์œ„ ๋‚ด ๋™์ž‘.
<property> name="LOG_ROOT_PATH" Log File์ด ์ €์žฅ๋  Log Root ๊ฒฝ๋กœ๋ฅผ /log๋กœ ์„ค์ •.
  name="LOG_PATH_NAME" Log File ๊ฒฝ๋กœ๋ฅผ 
${LOG_ROOT_PATH}/${SERVER_NAME}/${ENVIRONMENT}-${PORT}/%d{yyyy-MM-dd} ๋กœ ์„ค์ •.

${} ๋ถ€๋ถ„์€ ์•ž ์„œ ์ •์˜ํ•œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ๋กœ ์‹ค์ œ ์‚ฌ์šฉ๋˜๋Š” Log File ๊ฒฝ๋กœ๋Š” ๊ฐ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ฐ’์— ๋”ฐ๋ผ ๊ฒฐ์ •.
  name="ERR_LOG_FILE_NAME" Error Log File ์ด๋ฆ„์„ Error๋กœ ์„ค์ •.
  name="LOG_FILE_NAME" Information Level Log File ์ด๋ฆ„์„ Info๋กœ ์„ค์ •.
  name="FILE_LOG_PATTERN" File Log Pattern์„ 
%-5level %d{yy-MM-dd HH:mm:ss} [%thread] [%logger{0}:%line] - %msg%n๋กœ ์„ค์ •.

ํ•ด๋‹น Pattern์€ Log Level, Log ๋ฐœ์ƒ ๋‚ ์งœ ๋ฐ ์‹œ๊ฐ„, Thread Info, Logger Name, Line Number, Log Detail Message ๋“ฑ Log File ์ถœ๋ ฅ ํ˜•์‹ ์ง€์ •.
728x90

์œ„์™€ ๊ฐ™์ด ์„ค์ •๋œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜์™€ ํ”„๋กœํผํ‹ฐ๋“ค์€ ์Šคํ”„๋ง์—์„œ ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์„ ์ฃผ์ž… ๋ฐ›์•„ ๋กœ๊น… ์‹œ์Šคํ…œ์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ต๋‹ˆ๋‹ค.
๊ฐ ํ™˜๊ฒฝ์— ๋งž๋Š” ์„œ๋ฒ„ ์ด๋ฆ„, ํ™˜๊ฒฝ, ํฌํŠธ, ๋กœ๊น… ์ˆ˜์ค€ ๋“ฑ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋กœ๊ทธ ํŒŒ์ผ ๊ฒฝ๋กœ์™€ ์ด๋ฆ„์ด ์ƒ์„ฑ๋  ๊ฒƒ์ด๊ณ , ํŠน์ • ์„œ๋ฒ„์˜ ๋กœ๊ทธ๋Š” ํ•ด๋‹น ๊ฒฝ๋กœ์— ์ €์žฅ๋˜๊ฒŒ ๋  ๊ฑฐ์—์š”.

๋˜ํ•œ, ๋””์Šค์ฝ”๋“œ ์›นํ›… URI๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ๋ฅผ ํŠน์ • ์ฑ„๋„๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ์„ค์ •ํ•ด ์ค„๊ฑฐ์—์š”.


logback-prod.xml 37 ~ 43๋ฒˆ์งธ ์ค„


์ตœ์ดˆ 32 ~ 35๋ฒˆ์งธ ์ค„์˜ ๋‚ด์šฉ์€ <appender> ํƒœ๊ทธ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋กœ๊ทธ ์ถœ๋ ฅ ๋ฐฉ์‹์„ ์ •์˜ํ•ด์ค€ ๋ถ€๋ถ„์ด์—์š”. ๋กœ๊ทธ ์ถœ๋ ฅ ๋ฐฉ์‹์€ com.giggalpeople.backoffice.chatops.logback.appender.discord.append.DiscordAppender
Java Class๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋””์Šค์ฝ”๋“œ๋กœ ๋กœ๊ทธ๋ฅผ ์ „์†กํ•˜๋Š” ๋ฐฉ์‹์„ ์„ค์ •ํ•ด ์ค€ ๋ถ€๋ถ„์ด์—์š”.

Tag ๋ฐ ์†์„ฑ ์ƒ ์„ธ ๋‚ด ์šฉ
name=DISCORD" ํ•ด๋‹น appender Tag์˜ ์ด๋ฆ„์„ DISCORD๋กœ ์ง€์ •.
์œ„ ์ด๋ฆ„์€ Log ์„ค์ •์—์„œ ํ•ด๋‹น appender Tag๋ฅผ ์ฐธ์กฐํ•  ๋•Œ, ์‚ฌ์šฉ.
class="com.gi...." ํ•ด๋‹น appender Tag๊ฐ€ ์‚ฌ์šฉํ•  Java Class์ธ DiscordAppender ์ง€์ •.
ํ•ด๋‹น Class๋Š” ๋””์Šค์ฝ”๋“œ๋กœ Log ์ „์†ก ์‹œ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ ๋‹ด๋‹น.
<discordWebhookURL> DiscordAppender Class์—์„œ ์‚ฌ์šฉํ•  ๋””์Šค์ฝ”๋“œ ์›นํ›…์˜ URL ์„ค์ • ๋ถ€๋ถ„.
์ด URL์€ ์œ„์—์„œ ์ •์˜ํ•œ ${DISCORD_WEBHOOK_URI} ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์‚ฌ์šฉํ•˜์—ฌ ๋™์  ์ง€์ •.
์ฆ‰, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์‹ค์ œ ๋””์Šค์ฝ”๋“œ ์›นํ›… URL์ด
${DISCORD_WEBHOOK_URI} ์˜ ๊ฐ’์— ๋”ฐ๋ผ ๊ฒฐ์ •.

 


์œ„ ์„ค์ •์„ ํ†ตํ•ด DISCORD ๋ผ๋Š” ์ด๋ฆ„์˜ appender๋ฅผ ์ด์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋กœ๊ทธ๋ฅผ ๋””์Šค์ฝ”๋“œ ์ฑ„๋„๋กœ ์ „์†กํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”. ๋””์Šค์ฝ”๋“œ ์›นํ›… URL์€ ํ™˜๊ฒฝ ๋ณ„์ˆ˜์— ์˜ํ•ด ๋™์ ์œผ๋กœ ๊ฒฐ์ •๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ํ™˜๊ฒฝ์—์„œ๋Š” ํ•ด๋‹น ๋””์Šค์ฝ”๋“œ ์ฑ„๋„๋กœ ๋กœ๊ทธ ์ „์†กํ•˜๋„๋ก ์‰ฝ๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ฃผ์—ˆ๋‹ต๋‹ˆ๋‹ค.



์ด๋ฒˆ์—๋Š” 38 ~ 43๋ฒˆ์งธ ์ค„ ๋‚ด์šฉ์ด์—์š”.

์œ„ ๋‚ด์šฉ์€ ๋˜ ๋‹ค๋ฅธ ๋กœ๊ทธ ์ถœ๋ ฅ ๋ฐฉ์‹์ธ STDOUT (ํ‘œ์ค€ ์ถœ๋ ฅ) appender๋ฅผ ์ •์˜ํ•˜๊ณ  ์žˆ๋Š” ๋ถ€๋ถ„์ด์—์š”.
์ฆ‰, ๋กœ๊ทธ๋ฅผ ์ฝ˜์†”์— ์ถœ๋ ฅํ•˜๋Š” ๋ฐฉ์‹์„ ์„ค์ •ํ•ด ์ค€ ๋ถ€๋ถ„์ด์—์š”.

ํƒœ๊ทธ ๋ฐ ์†์„ฑ ์š”์†Œ ์ƒ ์„ธ ๋‚ด ์šฉ
name="STDOUT"   ํ•ด๋‹น appender ์ด๋ฆ„์„ STDOUT์œผ๋กœ ์ง€์ •.
์ด ์ด๋ฆ„์€ ๋กœ๊ทธ ์„ค์ •์—์„œ ์ด appender ์ฐธ์กฐ ์‹œ ์‚ฌ์šฉ.
class="ch.qos.log..."   ํ•ด๋‹น appender๊ฐ€ ์‚ฌ์šฉํ•  ํด๋ž˜์Šค์ธ ConsoleAppender ์ง€์ •.
์ด ํด๋ž˜์Šค๋Š” ์ฝ˜์†”์— ๋กœ๊ทธ๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ๊ธฐ๋Šฅ ๋‹ด๋‹น.
<encoder class="">   Log ์ถœ๋ ฅ ํ˜•์‹ ์ง€์ • ์‹œ ์‚ฌ์šฉ๋˜๋Š” ์ธ์ฝ”๋” ์„ค์ •.
<pattern>   ๋กœ๊ทธ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ ํ˜•์‹ ์ง€์ • ํŒจํ„ด ์„ค์ •.
  %d{yyyy-MM-dd} ๋กœ๊ทธ ๋ฉ”์‹œ์ง€์˜ ๋‚ ์งœ๋ฅผ ์—ฐ๋„-์›”-์ผ ํ˜•์‹์œผ๋กœ ํ‘œ์‹œ.
  %d{HH:mm:ss.SSS} ๋กœ๊ทธ ๋ฉ”์‹œ์ง€ ์‹œ๊ฐ„์„ ์‹œ:๋ถ„:์ดˆ.๋ฐ€๋ฆฌ์ดˆ ํ˜•์‹์œผ๋กœ ํ‘œ์‹œ.
  %p ๋กœ๊ทธ ๋ ˆ๋ฒจ (๋กœ๊ทธ ๋ฉ”์‹œ์ง€ ์šฐ์„  ์ˆœ์œ„) ํ‘œ์‹œ.
  ${PID:-} ํ”„๋กœ์„ธ์Šค ID ํ‘œ์‹œ.
ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ${PID} ๊ฐ€ ์„ค์ • ๋˜์–ด ์žˆ์ง€ ์•Š์„ ๊ฒฝ์šฐ ๋นˆ ๋ฌธ์ž์—ด ์ถœ๋ ฅ.
  [$F] ๋กœ๊น… ๋ฐœ์ƒ ํŒŒ์ผ๋ช… ์ถœ๋ ฅ.
  %M ๋กœ๊น… ๋ฐœ์ƒ ๋ฉ”์†Œ๋“œ ์ด๋ฆ„ ์ถœ๋ ฅ.
  (%L) ๋กœ๊ทธ ๋ฉ”์‹œ์ง€ ๋ฐœ์ƒ ๋ผ์ธ ๋ฒˆํ˜ธ ์ถœ๋ ฅ.
  %m ๋กœ๊ทธ ๋ฉ”์‹œ์ง€ ์ž์ฒด ์ถœ๋ ฅ.
  %n ์ค„ ๋ฐ”๊ฟˆ ๋ฌธ์ž ํ‘œ์‹œ.

 

์œ„ ์„ค์ •์„ ํ†ตํ•ด STDOUT ์ด๋ผ๋Š” ์ด๋ฆ„์˜ appender๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๊ทธ๋ฅผ ์ฝ˜์†”์— ์ถœ๋ ฅํ•˜๋„๋ก ์„ค์ •ํ•ด ์ฃผ์—ˆ์–ด์š”.
๋กœ๊ทธ ํ˜•์‹์€ ํŒจํ„ด์„ ํ†ตํ•ด ์ง€์ •๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋กœ๊ทธ ๋ฉ”์‹œ์ง€์— ์›ํ•˜๋Š” ์ •๋ณด๋ฅผ ํ‘œ์‹œ๋˜๋„๋ก ์„ค์ •ํ•ด ์ค€ ๋ถ€๋ถ„์ด์—์š”.

 

logback-prod.xml 45 ~ 64๋ฒˆ์งธ ์ค„


์œ„ ๋‚ด์šฉ์€ ํŒŒ์ผ๋กœ ๋กœ๊ทธ๋ฅผ ๊ธฐ๋กํ•˜๋Š” FILE appender๋ฅผ ์ •์˜ํ•˜๊ณ  ์žˆ๋Š” ๋ถ€๋ถ„์ด์—์š”.

์ด appender๋Š” ๋กœ๊ทธ๋ฅผ ์‹œ๊ฐ„ ๋ฐ ํฌ๊ธฐ ๊ธฐ๋ฐ˜์œผ๋กœ ๋กค๋งํ•˜๋ฉด์„œ ์—ฌ๋Ÿฌ ํŒŒ์ผ์— ๊ธฐ๋กํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์„ค์ •ํ•ด ์ฃผ์—ˆ์–ด์š”.


ํƒœ๊ทธ ๋ฐ ์†์„ฑ ์ƒ ์„ธ ๋‚ด ์šฉ
name="FILE" ํ•ด๋‹น appender ์ด๋ฆ„์„ FILE์œผ๋กœ ์ง€์ •.
์ด ์ด๋ฆ„์€ ๋กœ๊ทธ ์„ค์ •์—์„œ ์ด appender ์ฐธ์กฐ ์‹œ ์‚ฌ์šฉ.
class="ch.qos.log..." ํ•ด๋‹น appender๊ฐ€ ์‚ฌ์šฉํ•  ํด๋ž˜์Šค์ธ RollingFileAppender ์ง€์ •.
์ด ํด๋ž˜์Šค๋Š” ๋กœ๊ทธ๋ฅผ ๋กค๋งํ•˜์—ฌ ์—ฌ๋Ÿฌ ํŒŒ์ผ์— ๊ธฐ๋ก ๊ธฐ๋Šฅ ๋‹ด๋‹น.
<file> Log File ๊ฒฝ๋กœ์™€ ์ด๋ฆ„ ์„ค์ •.
์•ž์„œ ์ •์˜ํ•œ ${LOG_PATH_NAME}, ${SERVER_NAME}
ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ด์šฉํ•˜์—ฌ ์‹ค์ œ ์‚ฌ์šฉ๋˜๋Š” Log File์˜ ๊ฒฝ๋กœ์™€ ์ด๋ฆ„ ๊ฒฐ์ •.
<encoder> ๋กœ๊ทธ ์ถœ๋ ฅ ํ˜•์‹ ์ง€์ • ์‹œ ์‚ฌ์šฉ๋˜๋Š” ์ธ์ฝ”๋” ์„ค์ •.
<pattern> ์•ž์„œ ์ •์˜ํ•œ ${FILE_LOG_PATTERN} ์„ ํ†ตํ•ด Log Message ์ถœ๋ ฅ ํ˜•์‹ ์ง€์ •.
<rollingPolicy> ๋กค๋ง ์ •์ฑ… ์„ค์ • ๋ถ€๋กœ ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ๋กค๋ง ์ •์ฑ… ์‚ฌ์šฉ.
<fileNamePattern> ๋กค๋ง๋œ Log File์˜ File ์ด๋ฆ„ Pattern ์ง€์ •.
${LOG_PATH_NAME}, ${LOG_FILE_NAME}
ํ™˜๊ฒฝ ๋ณ€์ˆ˜์™€ ์‹œ๊ฐ„ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ
์‹ค์ œ File ์ด๋ฆ„ ๊ฒฐ์ •.
<timeBaseFileNamingAndTriggeringPolicy> File ๋กค๋ง ์กฐ๊ฑด์„ ์‹œ๊ฐ„๊ณผ ํฌ๊ธฐ๋กœ ์ง€์ •ํ•˜๋Š” ์ •์ฑ… ์„ค์ •.
<maxFileSize> File ์ตœ๋Œ€ ์šฉ๋Ÿ‰ 100MB๋กœ ์„ค์ •. ์ด ํฌ๊ธฐ๋ฅผ ์ดˆ๊ณผํ•  ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด File๋กœ ๋กค๋ง.
<maxHistory> ์ผ์ž๋ณ„ Log File ์ตœ๋Œ€ ๋ณด๊ด€ ์ฃผ๊ธฐ ์„ค์ •.
ํ•ด๋‹น ์„ค์ •์ผ ์ด์ƒ์œผ๋กœ ๋œ File์€ ์ž๋™ ์ œ๊ฑฐ.
์œ„์—์„œ๋Š” 180์ผ๋กœ ์ง€์ •๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— 180์ผ ์ด์ƒ๋œ Log File์€ ์‚ญ์ œ.
๋ฐ˜์‘ํ˜•


์œ„ ์„ค์ •์„ ํ†ตํ•ด FILE ์ด๋ผ๋Š” ์ด๋ฆ„์˜ appender๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๊ทธ๋ฅผ ํŒŒ์ผ์— ๊ธฐ๋กํ•˜๊ณ , ๋กœ๊ทธ๋ฅผ ์ผ์ • ๊ธฐ๊ฐ„ ๋˜๋Š” ํฌ๊ธฐ์— ๋”ฐ๋ผ ๋กค๋งํ•˜๋ฉด์„œ ๋ณด์กดํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑํ•ด ์ฃผ์—ˆ์–ด์š”.

๋กค๋ง๋œ ํŒŒ์ผ๋“ค์€ ์„ค์ •๋œ ๊ฒฝ๋กœ์™€ ์ด๋ฆ„ ํŒจํ„ด์— ๋”ฐ๋ผ ์ƒ์„ฑ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

logback-prod.xml 66 ~ 89๋ฒˆ์งธ ์ค„


์œ„ ๋‚ด์šฉ์€ ์—๋Ÿฌ ๋ ˆ๋ฒจ์˜ ๋กœ๊ทธ ํŒŒ์ผ๋กœ ๊ธฐ๋กํ•˜๋Š” ERROR_FILE appender๋ฅผ ์ •์˜ํ•ด ์ค€ ๋ถ€๋ถ„์ด์—์š”.
ํ•ด๋‹น appender๋Š” ๋กœ๊ทธ ๋ ˆ๋ฒจ์ด WARN ์ด์ƒ์ธ ๋กœ๊ทธ๋ฅผ ๊ธฐ๋กํ•˜๊ณ , ์ผ์ • ๊ธฐ๊ฐ„ ๋˜๋Š” ํฌ๊ธฐ์— ๋”ฐ๋ผ ๋กค๋งํ•˜๋ฉด์„œ ์—ฌ๋Ÿฌ ํŒŒ์ผ์— ๊ธฐ๋ก๋˜๋„๋ก ์„ค์ •ํ•ด ์ฃผ์—ˆ์–ด์š”.

ํƒœ๊ทธ ๋ฐ ์†์„ฑ ์ƒ ์„ธ ๋‚ด ์šฉ
name="ERROR_FILE" ํ•ด๋‹น appender ์ด๋ฆ„์„ ERROR_FILE์œผ๋กœ ์ง€์ •.
์ด ์ด๋ฆ„์€ ๋กœ๊ทธ ์„ค์ •์—์„œ ์ด appender ์ฐธ์กฐ ์‹œ ์‚ฌ์šฉ.
class="ch.qos.log..." ํ•ด๋‹น appender๊ฐ€ ์‚ฌ์šฉํ•  ํด๋ž˜์Šค์ธ RollingFileAppender ์ง€์ •.
์ด ํด๋ž˜์Šค๋Š” ๋กœ๊ทธ๋ฅผ ๋กค๋งํ•˜์—ฌ ์—ฌ๋Ÿฌ ํŒŒ์ผ์— ๊ธฐ๋ก ๊ธฐ๋Šฅ ๋‹ด๋‹น.
<filter> ๋กœ๊ทธ ํ•„ํ„ฐ๋ฅผ ์„ค์ •.
ํ•ด๋‹น ํ•„ํ„ฐ๋Š” WARN ๋ ˆ๋ฒจ ์ด์ƒ ๋กœ๊ทธ๋งŒ ๊ธฐ๋กํ•˜๋„๋ก ์„ค์ •.

โˆ™ <level>WARN</level>: WARN ๋ ˆ๋ฒจ ์ด์ƒ์˜ ๋กœ๊ทธ๋งŒ ๊ธฐ๋กํ•˜๋„๋ก ํ•„ํ„ฐ ์„ค์ •.

โˆ™ <onMatch>ACCEPT</onMatch>:
ํ•„ํ„ฐ์™€ ์ผ์น˜ํ•˜๋Š” ๋กœ๊ทธ ๋ ˆ๋ฒจ์— ๋Œ€ํ•ด ๊ธฐ๋ก ํ—ˆ์šฉ.

โˆ™ <onMismatch>DENY</onMismatch>:
ํ•„ํ„ฐ์™€ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๋กœ๊ทธ ๋ ˆ๋ฒจ์— ๋Œ€ํ•ด ๊ธฐ๋ก ๊ฑฐ๋ถ€.
<file> Log File ๊ฒฝ๋กœ์™€ ์ด๋ฆ„ ์„ค์ •.
์•ž์„œ ์ •์˜ํ•œ ${LOG_PATH_NAME}, ${ERR_LOG_FILE_NAME}
ํ™˜๊ฒฝ ๋ณ€์ˆ˜์™€ ์‹œ๊ฐ„ ํŒจํ„ด ์ด์šฉํ•˜์—ฌ ์‹ค์ œ ์‚ฌ์šฉ๋˜๋Š” Log File์˜ ๊ฒฝ๋กœ์™€ ์ด๋ฆ„ ๊ฒฐ์ •.
<encoder> ๋กœ๊ทธ ์ถœ๋ ฅ ํ˜•์‹ ์ง€์ • ์‹œ ์‚ฌ์šฉ๋˜๋Š” ์ธ์ฝ”๋” ์„ค์ •.
<pattern> ์•ž์„œ ์ •์˜ํ•œ ${LOG_PATTERN} ์„ ํ†ตํ•ด Log Message ์ถœ๋ ฅ ํ˜•์‹ ์ง€์ •.
<rollingPolicy> ๋กค๋ง ์ •์ฑ… ์„ค์ • ๋ถ€๋กœ ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ๋กค๋ง ์ •์ฑ… ์‚ฌ์šฉ.
<fileNamePattern> ๋กค๋ง๋œ Log File์˜ File ์ด๋ฆ„ Pattern ์ง€์ •.
${LOG_PATH_NAME}, ${ERR_LOG_FILE_NAME}
ํ™˜๊ฒฝ ๋ณ€์ˆ˜์™€ ์‹œ๊ฐ„ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ์‹ค์ œ File ์ด๋ฆ„ ๊ฒฐ์ •.
<timeBaseFileNamingAndTriggeringPolicy> File ๋กค๋ง ์กฐ๊ฑด์„ ์‹œ๊ฐ„๊ณผ ํฌ๊ธฐ๋กœ ์ง€์ •ํ•˜๋Š” ์ •์ฑ… ์„ค์ •.
<maxFileSize> File ์ตœ๋Œ€ ์šฉ๋Ÿ‰ 100MB๋กœ ์„ค์ •. ์ด ํฌ๊ธฐ๋ฅผ ์ดˆ๊ณผํ•  ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด File๋กœ ๋กค๋ง.
<maxHistory> ์ผ์ž๋ณ„ Log File ์ตœ๋Œ€ ๋ณด๊ด€ ์ฃผ๊ธฐ ์„ค์ •.
ํ•ด๋‹น ์„ค์ •์ผ ์ด์ƒ์œผ๋กœ ๋œ File์€ ์ž๋™ ์ œ๊ฑฐ.
์œ„์—์„œ๋Š” 180์ผ๋กœ ์ง€์ •๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— 180์ผ ์ด์ƒ๋œ Log File์€ ์‚ญ์ œ.

 

์œ„ ์„ค์ •์„ ํ†ตํ•ด ERROR_FILE์ด๋ผ๋Š” ์ด๋ฆ„์˜ appender๋ฅผ ์ด์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์—๋Ÿฌ ๋ ˆ๋ฒจ ๋กœ๊ทธ ํŒŒ์ผ์— ๊ธฐ๋กํ•˜๊ณ , ๋กœ๊ทธ๋ฅผ ์ผ์ • ๊ธฐ๊ฐ„ ๋˜๋Š” ํฌ๊ธฐ์— ๋”ฐ๋ผ ๋กค๋งํ•˜๋ฉด์„œ ๋ณด์กด ๋˜๋„๋ก ํ•ด ์ฃผ์—ˆ์–ด์š”.

๋กค๋ง๋œ ๋กœ๊ทธ ํŒŒ์ผ๋“ฑ์€ ์„ค์ •๋œ ๊ฒฝ๋กœ์™€ ์ด๋ฆ„ ํŒจํ„ด์— ๋”ฐ๋ผ ์ƒ์„ฑ๋˜๊ณ , ๋กœ๊ทธ ๋ ˆ๋ฒจ ํ•„ํ„ฐ๋ฅผ ํ†ตํ•ด WARN ์ด์ƒ์˜ ๋กœ๊ทธ๋งŒ ๊ธฐ๋ก๋˜๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ ๋ ˆ๋ฒจ ๋กœ๊ทธ๋งŒ ํ•ด๋‹น appender์— ๊ธฐ๋ก๋˜๊ฒŒ ํ•ด ์ค€ ๋ถ€๋ถ„์ด์—์š”.

 

logback-prod.xml 91 ~ 96๋ฒˆ์งธ ์ค„


์œ„ ๋‚ด์šฉ์€ ๋น„๋™๊ธฐ ๋ฐฉ์‹์œผ๋กœ ๋””์Šค์ฝ”๋“œ๋กœ ๋กœ๊ทธ๋ฅผ ์ „์†กํ•˜๋Š” ASYNC_DISCORD appender๋ฅผ ์ •์˜ํ•ด์ค€ ๋ถ€๋ถ„์ด์—์š”.
ํ•ด๋‹น appender๋Š” ๊ธฐ์กด DISCORD appender๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋กœ๊ทธ ๋ ˆ๋ฒจ์„ WARN ์ด์ƒ์œผ๋กœ ์ œํ•œํ•˜๋Š” ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜์—ฌ WARN ์ด์ƒ์˜ ๋กœ๊ทธ๋งŒ ๋””์Šค์ฝ”๋“œ๋กœ ์ „์†ก๋  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ค€ ์„ค์ •์ด์—์š”.

ํƒœ๊ทธ ๋ฐ ์†์„ฑ ์ƒ ์„ธ ๋‚ด ์šฉ
name="ASYNC_DISCORD" ํ•ด๋‹น appender ์ด๋ฆ„์„ ASYNC_DISCORD๋กœ ์ง€์ •.
์ด ์ด๋ฆ„์€ ๋กœ๊ทธ ์„ค์ •์—์„œ ์ด appender ์ฐธ์กฐ ์‹œ ์‚ฌ์šฉ.
class="ch.qos.log..." ํ•ด๋‹น appender๊ฐ€ ์‚ฌ์šฉํ•  ํด๋ž˜์Šค์ธ AsyncAppender ์ง€์ •.
์ด ํด๋ž˜์Šค๋Š” ๋กœ๊ทธ๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ „์†กํ•˜๋Š” ๊ธฐ๋Šฅ ๋‹ด๋‹น.
<filter> ๋กœ๊ทธ ํ•„ํ„ฐ๋ฅผ ์„ค์ •.
ํ•ด๋‹น ํ•„ํ„ฐ๋Š” WARN ๋ ˆ๋ฒจ ์ด์ƒ ๋กœ๊ทธ๋งŒ ์ „์†กํ•˜๋„๋ก ์„ค์ •.

โˆ™ <level>WARN</level>: WARN ๋ ˆ๋ฒจ ์ด์ƒ์˜ ๋กœ๊ทธ๋งŒ ๊ธฐ๋กํ•˜๋„๋ก ํ•„ํ„ฐ ์„ค์ •.

 

์œ„ ์„ค์ •์„ ํ†ตํ•ด ASYNC_DISCORD๋ผ๋Š” ์ด๋ฆ„์˜ appender๋ฅผ ์ด์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ WARN ์ด์ƒ์˜ ๋กœ๊ทธ๋ฅผ ๋น„๋™๊ธฐ ๋ฐฉ์‹์œผ๋กœ ๋””์Šค์ฝ”๋“œ๋กœ ์ „์†กํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•ด ์ฃผ์—ˆ์–ด์š”.

๋น„๋™๊ธฐ ๋ฐฉ์‹์œผ๋กœ ๋กœ๊ทธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋กœ๊ทธ ๊ธฐ๋ก๊ณผ ์ „์†ก์ด ๋ณ„๊ฐœ์˜ Thread์—์„œ ์ฒ˜๋ฆฌ ๋˜์–ด ๋กœ๊ทธ ์ž‘์—…์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฃผ Thread๋ฅผ ์ฐจ๋‹จํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •ํ•ด ์ฃผ์—ˆ์–ด์š”.

์ด๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ ์ž‘์—…์˜ ์„ฑ๋Šฅ๊ณผ ์‘๋‹ต์„ฑ์„ ํ–ฅ์ƒ ์‹œํ‚ฌ ์ˆ˜ ์žˆ์„๊ฑฐ์—์š”.

 

logback-prod.xml 98 ~ 111๋ฒˆ์งธ ์ค„


์œ„ ๋‚ด์šฉ์€ ๋กœ๊ทธ์˜ ๋ฃจํŠธ ์„ค์ •๊ณผ ํŠน์ • ํŒจํ‚ค์ง€(org.hibernate.SQL) ๋กœ๊น… ๋ ˆ๋ฒจ ์„ค์ •์„ ์ •์˜ํ•ด์ค€ ๋ถ€๋ถ„์ด์—์š”.

root์™€ logger ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ๊ฐ ์ „์ฒด ๋กœ๊ทธ ๋ฐ ํŠน์ • ํŒจํ‚ค์ง€ ๋กœ๊ทธ์— ๋Œ€ํ•ด ์„ค์ •์„ ๊ตฌ์„ฑํ•ด ์ฃผ์—ˆ๋‹ต๋‹ˆ๋‹ค.

ํƒœ๊ทธ ๋ฐ ์†์„ฑ ์ƒ ์„ธ ๋‚ด ์šฉ
<root level="${LOG_LEVEL}"> ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด root Log ์„ค์ • ์ •์˜.

โˆ™ level"=${LOG_LEVEL}: ${LOG_LEVEL} ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ฐ’์— ๋”ฐ๋ผ root Log Level ์„ค์ • ${LOG_LEVEL} ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋Š” ์•ž์„œ ์ •์˜ํ•œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ค‘ LOG_LEVEL์— ํ•ด๋‹น.

โˆ™ <appender-ref ref="STDOUT"/>:
root Logger STDOUT appender ์ถ”๊ฐ€. ์ด๋กœ ์ธํ•ด root Log๋Š” Console์— ์ถœ๋ ฅ.

โˆ™ <appender-ref ref="ASYNC_DISCORD"/>:
root Logger์— ASYNC_DISCORD appender ์ถ”๊ฐ€.
์ด๋กœ ์ธํ•ด root Log๋Š” ๋น„๋™๊ธฐ ๋ฐฉ์‹์œผ๋กœ ๋””์Šค์ฝ”๋“œ์— ์ „์†ก.

โˆ™<appender-ref ref="FILE"/>: root Logger์— FILE appender ์ถ”๊ฐ€.
์ด๋กœ ์ธํ•ด root Log๋Š” File์— ๊ธฐ๋ก.

โˆ™ <appender-ref ref="ERROR_FILE"/>: root Logger์—
ERROR_FILE appender ์ถ”๊ฐ€.
์ด๋กœ ์ธํ•ด root Log ์ค‘ WARN ์ด์ƒ์˜ Log๋Š” ๋”ฐ๋กœ File์— ์ €์žฅ.
<logger name="org.hibernate.SQL"
level="DEBUG" additivity="false">
ํŠน์ • ํŒจํ‚ค์ง€์ธ org.hibernate.SQL์— ๋Œ€ํ•œ Log ์„ค์ •.

โˆ™ name="org.hibernate.SQL": ํ•ด๋‹น Logger ์ด๋ฆ„์„ org.hibernate.SQL๋กœ ์„ค์ •.

โˆ™ level="DEBUG": org.hibernate.SQL Package์— ๋Œ€ํ•œ Log Level์„
DEBUG๋กœ ์„ค์ •.

โˆ™ additivity="false": ์ถ”๊ฐ€์ ์ธ Logger์—๊ฒŒ Event ์ „ํŒŒ๋˜์ง€ ์•Š๋„๋ก ์„ค์ •.
์ด Logger์—์„œ ๊ธฐ๋ก๋œ Log Event๋Š” ๋ถ€๋กœ Logger๋กœ ์ „ํŒŒ๋˜์ง€ ์•Š์Œ.

 

์œ„ ์„ค์ •์„ ํ†ตํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด ๋กœ๊ทธ ๋ ˆ๋ฒจ๊ณผ ๊ฐ ๋กœ๊ฑฐ(๋ฃจํŠธ ๋กœ๊ฑฐ ๋ฐ org.hibernate.SQL ๋กœ๊ฑฐ)์— ๋Œ€ํ•ด ๋กœ๊ทธ ๋ ˆ๋ฒจ๊ณผ ์ถœ๋ ฅ ๋ฐฉ์‹ ์ •์˜ํ•ด ์ฃผ์—ˆ์–ด์š”.

๋กœ๊ทธ ๋ ˆ๋ฒจ, ์ถœ๋ ฅ ๋ฐฉ์‹ ๋ฐ ๋น„๋™๊ธฐ ์„ค์ •์„ ์กฐํ•ฉํ•˜์—ฌ ๋กœ๊น… ์‹œ์Šคํ…œ์„ ์œ ์—ฐํ•˜๊ณ , ํšจ๊ณผ์ ์œผ๋กœ ๊ตฌ์„ฑํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

 

 

        ๐Ÿ“ฆ application-logback.yml

์ด๋ฒˆ์—๋Š” ํ™˜๊ฒฝ ์„ค์ • ๋ถ€๋ถ„์„ ์‚ดํŽด ๋ณผ๊ฒŒ์š”.

logging:
  config: classpath:logback-${spring.profiles.active}.xml
  discord:
    webhook-uri: {๋””์Šค์ฝ”๋“œ ์›นํ›… URI}

  level:
    root: WARN

    org:
      hibernate:
        type:
          descriptor:
            sql:
              BasicBinder: TRACE
        SQL: INFO
  logback:
    rollingpolicy:
      max-history: 180
      max-file-size: 100MB

log:
  file:
    path: /var/log/Giggal-Total-Back-Office/*/Error_0.log


์œ„์˜ ๋‚ด์šฉ์„ ํ†ตํ•ด Log Back ํ™˜๊ฒฝ ์„ค์ •์„ ํ•ด ์ฃผ์—ˆ์–ด์š”.

์ตœ์ดˆ Log Back ์„ค์ •์€ ์•„๋ž˜์™€ ๊ฐ™์•„์š”.

 

์†์„ฑ ์ƒ ์„ธ ๋‚ด ์šฉ
logging.config Logback ์„ค์ • ํŒŒ์ผ ์œ„์น˜๋ฅผ classpath:logback-${spring.profiles.active}.xml๋กœ ์ง€์ •.
${spring.profiles.active}๋Š” ์Šคํ”„๋ง ํ”„๋กœํ•„์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ํ•ด๋‹น ๊ฐ’์— ๋”ฐ๋ผ ์‹ค์ œ logback ์„ค์ • ํŒŒ์ผ ๊ฒฐ์ •.
logging.discord ๋””์Šค์ฝ”๋“œ ์›นํ›…(Webhook) URI๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ถ€๋ถ„.
์ด๋Š” ๋กœ๊น… ์ด๋ฒคํŠธ๋ฅผ ๋””์Šค์ฝ”๋“œ๋กœ ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ ์„ค์ •.
logging.level log level ์„ค์ •๋ถ€.

โˆ™ root: Root Logger Level์„ WARN์œผ๋กœ ์„ค์ •. Root Logger๋Š” ๋‹ค๋ฅธ Logger์˜ ์ƒ์œ„
   Logger๋กœ์จ, ๋ชจ๋“  Log Event๋ฅผ ๋ฐ›๋Š”๋‹ค. ์ด ์„ค์ •์„ ํ†ตํ•ด WARN Level ์ด์ƒ์˜ Log๋งŒ
   ๊ธฐ๋กํ•˜๋„๋ก ์„ค์ •.


โˆ™org.hibernate: org.hibernate Package์— ๋Œ€ํ•œ Log Level ์„ค์ •.
  - type.descriptor.sqlBasicBinder:
     org.hibernate.type.descriptor.sql.BasicBinder

     ํด๋ž˜์Šค์— ๋Œ€ํ•œ Log Level์„ TRACE๋กœ ์„ค์ •. TRACE Level์€ ๊ฐ€์žฅ ์ƒ์„ธํ•œ Log Level๋กœ
     SQL Parameter Binding๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  Log ๊ธฐ๋ก์„ ์œ„ํ•ด ์„ค์ •.

 - SQL: org.hibernate.SQL: ํด๋ž˜์Šค์— ๋Œ€ํ•œ Log Level์„ INFO๋กœ ์„ค์ •. INFO Level์€ SQL
    ๋ฌธ์žฅ๋“ค์„ ๊ธฐ๋กํ•˜๊ธฐ ์œ„ํ•˜์—ฌ ์„ค์ •.
logging.logback Logback ์„ค์ • ์ถ”๊ฐ€ ์†์„ฑ ์ง€์ •.

โˆ™rollingpolicy Log File Rolling ์ •์ฑ… ์„ค์ •.
 - rollingpolicy: Log File Rolling ์ •์ฑ… ์„ค์ •๋ถ€.
 - max-history: Log File ์ตœ๋Œ€ ๋ณด๊ด€ ๊ธฐ๊ฐ„ 180์ผ๋กœ ์„ค์ •.
 - max-file-size: ํ•˜๋‚˜์˜ Log File ์ตœ๋Œ€ ํฌ๊ธฐ๋ฅผ 100MB๋กœ ์„ค์ •.

 

๊ทธ๋Ÿฐ ๋’ค ๋กœ๊ทธ ํŒŒ์ผ ์„ค์ •์€ ๋กœ๊ทธ ํŒŒ์ผ์ด ์ €์žฅ๋  ๊ฒฝ๋กœ /var/log/....Error_0.log๋กœ ์„ค์ •ํ•ด ์ฃผ์—ˆ์–ด์š”.
์ด๋Š” Docker Container๋กœ ๋ฐฐํฌํ•  ์˜ˆ์ •์ด๊ณ , ํ•ด๋‹น Container ์•ˆ์— ์œ„ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋กœ๊ทธ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•จ์ด์—์š”.

* ์™€์ผ๋“œ์นด๋“œ๋กœ, ์–ด๋–ค ๊ฐ’์ด ๋“ค์–ด์˜ค๋”๋ผ๋„ ํ•ด๋‹น ์œ„์น˜์˜ ๋กœ๊ทธ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค๊ณ  ํ•ด ์ฃผ์—ˆ์–ด์š”.

์ฃผ๋‹ˆ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ Logback์„ ์ทจ์™€ ๊ฐ™์ด ์„ค์ •ํ•ด ์ฃผ์—ˆ๊ณ , ๊ณ ๋ฅด ๋ ˆ๋ฒจ ๋ฐ ํŒŒ์ผ ๋กค๋ง ์ •์ฑ… ๋“ฑ์„ ์„ค์ •ํ•˜์—ฌ ๋กœ๊น…์„ ์กฐ์ •ํ•˜๊ณ , ๋””์Šค์ฝ”๋“œ ์›นํ›…์„ ์ด์šฉํ•˜์—ฌ ๋กœ๊ทธ ์ด๋ฒคํŠธ๋ฅผ ๋””์Šค์ฝ”๋“œ๋กœ ์ „์†กํ•  ์ˆ˜ ์žˆ๋„๋ก ์ค€๋น„ํ•ด ์ฃผ์—ˆ์–ด์š”.

๋‹ค์Œ ๊ธ€์—์„œ๋Š” ๋ณธ๊ฒฉ์ ์œผ๋กœ ๋””์Šค์ฝ”๋“œ๋กœ ๋กœ๊ทธ ์ •๋ณด๋ฅผ ๋ณด๋‚ด๊ณ , ์ด๋ฅผ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์— ์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋ถ„์„ํ•ด ๋ณผ๊ฒŒ์š”!

 

 

 

728x90
๋ฐ˜์‘ํ˜•