์คํ๋ง ๋ถํธ ์ก์ธ์ค ๋ก๊ทธ๋ฅผ ์๋ผ์คํฑ์์น์ ๊ธฐ๋กํ๊ธฐ
์๋ ํ์ธ์ Mambo ์ ๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์๋ฒ๋ก ์์ฒญ๋๋ ์ ๋ณด๋ฅผ ๊ธฐ๋กํ๋ ์ก์ธ์ค ๋ก๊ทธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด์๊ณผ ์ฅ์ ๋์์ ์์ด์ ์๋นํ ์ค์ํ ์ ๋ณด์ ๋๋ค. ์๋ง์กด ์น ์๋น์ค์์๋ Amazon S3 ์๋ฒ ์ก์ธ์ค ๋ก๊น ํ์ฑํ์ฒ๋ผ ์ก์ธ์ค ๋ก๊ทธ๋ฅผ ๊ธฐ๋กํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ฃ . ์คํ๋ง ๋ถํธ๋ ํฐ์บฃ(Tomcat) ์ด๋ ์ธ๋ํ ์ฐ(Undertow) ์ ๊ฐ์ WAS์ ๋ํ์ฌ ์ก์ธ์ค ๋ก๊ทธ๋ฅผ ํ์ผ๋ก ์ ์ฅํ ์ ์๋ ๊ธฐ๋ฅ์ ๊ธฐ๋ณธ์ ์ผ๋ก ํฌํจํ๊ณ ์์ต๋๋ค.
๋ง์ฝ, ์ธ๋ํ ์ฐ๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ก์ธ์ค ๋ก๊ทธ๋ฅผ ํ์ฑํํ๊ณ ํจํด์ ์ง์ ํ ์ ์์ต๋๋ค.
server.undertow.accesslog.enabled=true
server.undertow.accesslog.pattern=common
์คํ๋ง ๋ถํธ ๋ก๊น
์คํ๋ง ๋ถํธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก Slf4j ๊ธฐ๋ฐ์ ๋ก๊ทธ๋ฐฑ(Logback)์ ๋ก๊น ํ๋ ์์ํฌ๋ก ์ฌ์ฉํฉ๋๋ค. ๊ทธ๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ก๊ทธ๋ฅผ ์๋ผ์คํฑ์์น์ ๊ธฐ๋กํ๊ธฐ ์ํด์๋ Logstash Logback Encoder์ ๊ฐ์ด ๋ก๊ทธ๋ฐฑ์ผ๋ก ๊ธฐ๋ก๋๋ ๋ก๊ทธ๋ฅผ ์๋ผ์คํฑ์์น๋ก ์ ๋ฌํ ์ ์๊ฒ ๊ตฌํํด์ผํฉ๋๋ค.
Logback Elasticsearch Appender
Logback Elasticsearch Appender๋ ELK ์คํ์ด ์๋๋๋ผ๋ ๋ก๊ทธ๋ฐฑ์ผ๋ก ๊ธฐ๋ก๋๋ ๋ก๊ทธ๋ฅผ ์๋ผ์คํฑ์์น๋ก ์ ๋ฌํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ์ค๋์ ์ด๊ฒ์ ํ์ฉํ์ฌ ์คํ๋ง ๋ถํธ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฐ์ํ๋ ์ก์ธ์ค ๋ก๊ทธ๋ฅผ ์๋ผ์คํฑ์์น์ ๊ธฐ๋กํด๋ณด๊ณ ์ ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ ์ฒ๋ผ Logback Access์ ๋ํ Appender๋ฅผ ํฌํจํ๊ณ ์์ผ๋ฏ๋ก ์ก์ธ์ค ๋ก๊ทธ๋ฅผ ์ฝ๊ฒ ์๋ผ์คํฑ์์น๋ก ์ ๋ฌํ ์ ์๊ฒ ๋ฉ๋๋ค.
Logback Access Spring Boot Starter
logback-access-spring-boot-starter๋ ๋ก๊ทธ๋ฐฑ ์์ธ์ค ์ค์ ์ ๋ํ ์คํ๋ง ๋ถํธ ์คํํฐ์ ๋๋ค. ์ธ๋ํ ์ฐ๊น์ง ์ง์ํ๋ฏ๋ก ์ธ๋ํ ์ฐ์ ๋ํด ๋ก๊ทธ๋ฐฑ ์์ธ์ค ์ค์ ์ ์ํ ์ปค์คํฐ๋ง์ด์ ๋ฅผ ์ง์ ๊ตฌํํ์ง ์์๋ ๋ฉ๋๋ค.
๋ฐ๋ผํ๊ธฐ
์คํ๋ง ๋ถํธ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค๊ณ ์ ๋ ์ธ๋ํ ์ฐ๋ฅผ ์ ํธํ๋ฏ๋ก ํฐ์บฃ ๋ชจ๋์ ์ ์ธํ๊ณ ์ธ๋ํ ์ฐ ์คํํฐ๋ฅผ ์ถ๊ฐํ์ต๋๋ค.
configurations.all {
exclude module: 'spring-boot-starter-tomcat'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-undertow'
implementation 'com.internetitem:logback-elasticsearch-appender:1.6'
implementation 'dev.akkinoc.spring.boot:logback-access-spring-boot-starter:3.2.1'
}
๋ก๊ทธ๋ฐฑ ์์ธ์ค ์คํํฐ๋ ์ธ๋ํ ์ฐ ๋ฟ๋ง ์๋๋ผ ํฐ์บฃ๋ ์ง์ํ๋ฏ๋ก ์ค์ ์ ๋ํ ์ฐจ์ด๋ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ค์๊ณผ ๊ฐ์ด ๋ก๊ทธ๋ฐฑ ์์ธ์ค๋ฅผ ์ํ ์ค์ ํ์ผ์ ํด๋์คํจ์ค์ ์ถ๊ฐํฉ๋๋ค. ์ค์ ํ์ผ์ ๋ถ๋ฌ์ค๋ ์ฐ์ ์์์ ๋ฐ๋ผ ์ค์ ํ์ผ๋ช ์ logback-access-spring.xml ์ด๋ผ๊ณ ์์ฑํ๊ฒ ์ต๋๋ค.
logback-access-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<springProperty scope="context" name="elasticsearch_uris" source="spring.elasticsearch.uris" defaultValue="http://localhost:9200"/>
<appender name="ELASTIC" class="com.internetitem.logback.elasticsearch.ElasticsearchAccessAppender">
<url>${elasticsearch_uris}/_bulk</url>
<index>application-accesslog-%date{yyyy-MM-dd}</index>
<headers>
<header>
<name>Content-Type</name>
<value>application/json</value>
</header>
</headers>
</appender>
<appender-ref ref="ELASTIC"/>
</configuration>
์คํ๋ง ๋ถํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ๊ณ ๋ธ๋ผ์ฐ์ ๋๋ ํด๋ผ์ด์ธํธ ๋๊ตฌ๋ฅผ ํตํด ์ก์ธ์ค ๊ธฐ๋ก์ ๋จ๊ฒจ๋ณด๊ณ ์๋ผ์คํฑ์์น์ ์ ์ ์ฅ๋๋์ง ํ์ธํด๋ด ๋๋ค.
์ธ๋ฑ์ค๋ ์์ฑ๋์์ง๋ง ์ก์ธ์ค ๋ก๊ทธ์ ๋ํ ์ ๋ณด๊ฐ ์์ต๋๋ค. ์ก์ธ์ค ๋ก๊ทธ ์ ๋ณด๋ฅผ ๊ธฐ๋กํ๊ธฐ ์ํด์๋ Logback Access conversion words๋ฅผ ์ฐธ๊ณ ํด์ ํ๋กํผํฐ๋ฅผ ์ค์ ํด์ผํฉ๋๋ค. ์์ ์์ฑํ ๋ก๊ทธ๋ฐฑ ์์ธ์ค ์ค์ ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ด ํ๋กํผํฐ ํญ๋ชฉ์ ์ถ๊ฐ๋ก ์ ์ํ๊ฒ ์ต๋๋ค.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<springProperty scope="context" name="elasticsearch_uris" source="spring.elasticsearch.uris" defaultValue="http://localhost:9200"/>
<appender name="ELASTIC" class="com.internetitem.logback.elasticsearch.ElasticsearchAccessAppender">
<url>${elasticsearch_uris}/_bulk</url>
<index>application-accesslog-%date{yyyy-MM-dd}</index>
<properties>
<property>
<name>contentLength</name>
<value>%b</value>
</property>
<property>
<name>remoteHost</name>
<value>%h</value>
</property>
<property>
<name>protocol</name>
<value>%H</value>
</property>
<property>
<name>referer</name>
<value>%i{Referer}</value>
</property>
<property>
<name>userAgent</name>
<value>%i{User-Agent}</value>
</property>
<property>
<name>requestMethod</name>
<value>%m</value>
</property>
<property>
<name>statusCode</name>
<value>%s</value>
</property>
<property>
<name>elapsedTime</name>
<value>%D</value>
</property>
<property>
<name>date</name>
<value>%t{yyyy-MM-dd'T'HH:mm:ss}</value>
</property>
<property>
<name>user</name>
<value>%u</value>
</property>
<property>
<name>queryString</name>
<value>%q</value>
</property>
<property>
<name>requestURI</name>
<value>%U</value>
</property>
</properties>
<headers>
<header>
<name>Content-Type</name>
<value>application/json</value>
</header>
</headers>
</appender>
<appender-ref ref="ELASTIC"/>
</configuration>
๋ฏธ๋ฆฌ ์ ์๋ ํจํด์ธ combined๋ฅผ ์ฐธ๊ณ ํ์ฌ ๋ฆฌํผ๋ฌ์ ์ ์ ์์ด์ ํธ ํค๋๋ฅผ ํฌํจํ๋๋ก ํ๋กํผํฐ๋ฅผ ์ค์ ํ์ต๋๋ค.
์ ์ฒ๋ผ ํ๋กํผํฐ๋ฅผ ์ค์ ํ์์ผ๋ฏ๋ก ์์ฒญ๋ ์ก์ธ์ค์ ๋ํ ๋ก๊ทธ๋ฅผ ํตํด ์ ์ ์์ด์ ํธ๊ฐ ํฌ์คํธ๋งจ์ด๋ฉฐ ์์ฒญ๋ ๊ฒฝ๋ก๋ ์ก์ถ์์ดํฐ์ธ ๊ฒ์ ํ์ธํ ์ ์๊ฒ ๋์์ต๋๋ค. ๋ฐ๋ผํ์๋ ์ฌ๋ฌ๋ถ์ ๋ค์ํ ํญ๋ชฉ์ ๋ํด์๋ ๊ธฐ๋กํด๋ณด์๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
์ก์ธ์ค ๋ก๊ทธ ์ธ๋ฑ์ค ํ ํ๋ฆฟ
์์ฑ๋ ์ก์ธ์ค ๋ก๊ทธ์ ๋ํ ์ธ๋ฑ์ค ๋งคํ ์ ๋ณด๋ฅผ ์กฐํํ๋ฉด ๋์ ๋งคํ์ ์ํด์ ์๋ผ์คํฑ์์น๊ฐ ํ๋ ์ ํ์ ์์๋๋ก ์ง์ ํ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ๋์ ๋งคํ์ ์ ์ฅ๋๋ ๋ํ๋จผํธ์ ํ๋ ์ ๋ณด๋ฅผ ์๊ธฐ ์ด๋ ค์ธ ๋๋ ํธ๋ฆฌํ ๊ธฐ๋ฅ์ด์ง๋ง ์ง๊ธ์ฒ๋ผ ์ก์ธ์ค ๋ก๊ทธ์ ์ ์ฅ๋๋ ํ๋๊ฐ ๊ณ ์ ๋์ด์๊ณ ํ๋ ์ ํ์ ํ์ ํ ์ ์๋ค๋ฉด ์ ์ ๋งคํ์ ์ ์ํด๋๋ ๊ฒ์ด ์ข์ต๋๋ค.
์ก์ธ์ค ๋ก๊ทธ์ ๊ธฐ๋ก๋๋ ์ ๋ณด๊ฐ ๋ช ํํ๋ฏ๋ก ๋์ ๋งคํ์ ์ํํ์ง ์๊ณ ๋ฏธ๋ฆฌ ์ ์๋ ๋งคํ์ ์ฌ์ฉํ๋๋ก ์ธ๋ฑ์ค ํ ํ๋ฆฟ์ ์ ์ํด๋๊ฒ ์ต๋๋ค.
{
"index_patterns": [
"applicaiton-accesslog-*"
],
"template": {
"settings": {
"analysis": {
"analyzer": {
"path_analyzer": {
"tokenizer": "path_hierarchy"
}
}
}
},
"mappings": {
"properties": {
"@timestamp": {
"type": "date"
},
"contentLength": {
"type": "long"
},
"date": {
"type": "date",
"format": "date_hour_minute_second || epoch_millis"
},
"elapsedTime": {
"type": "integer"
},
"protocol": {
"type": "keyword"
},
"referer": {
"type": "keyword"
},
"remoteHost": {
"type": "ip"
},
"requestMethod": {
"type": "keyword"
},
"requestURI": {
"type": "text",
"analyzer": "path_analyzer"
},
"statusCode": {
"type": "short"
},
"user": {
"type": "keyword"
},
"userAgent": {
"type": "keyword"
}
}
}
}
}
ํ์ฌ ์กฐ์ง์์๋ ์๋ผ์คํฑ์์น์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ก๊ทธ ๋ฐ ์ก์ธ์ค ๋ก๊ทธ๋ฅผ ๊ธฐ๋กํ์ง๋ ์๊ณ ์์ต๋๋ค๋ง, ์๋ผ์คํฑ์์น๋ฅผ ํ์ตํ๊ธฐ ์ํ ์ํ ๋ฐ์ดํฐ๊ฐ ์์ด์ ๊ฐ๋จํ๊ฒ๋๋ง ์ก์ธ์ค ๋ก๊ทธ๋ฅผ ๊ธฐ๋กํด๋ณด๋ฉด ์ด๋ ํ ๊น ์๊ฐํด์ ์๋ํด๋ณด์์ต๋๋ค. ํ์ฌ ๋๋์ ๋๋ค ์ก์ธ์ค ๋ก๊ทธ๋ฅผ ๋ง๋ค๊ธฐ ์ํด์ ์ปฌ๋ผํ ์๊ณ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ธ KDB๋ฅผ ํ์ฉํด๋ณด๊ณ ๋ ์์ต๋๋ค๋ง ์ฝ์ง๋ ์๋ค์. ์ด ๋ถ๋ถ์ ๋ํด์๋ ๋ง์ด ์๋ํด๋ณด๊ณ ์ ๋ฆฌํ์ฌ ๊ณต์ ํด๋ณด๊ฒ ์ต๋๋ค.
๊ฐ์ฌํฉ๋๋ค.