Master ELK Log Collection: Docker‑Compose, Logback & Logstash for SpringBoot
This guide walks you through building a production‑ready ELK log collection system using Docker‑Compose, configuring Logback to route debug, error, business, and record logs, setting up Logstash pipelines, and leveraging Kibana for powerful log visualization in SpringBoot applications.
ELK Environment Installation
ELK refers to Elasticsearch, Kibana, and Logstash. This guide provides the latest Docker‑Compose script and key installation points.
docker-compose script
version: '3'
services:
elasticsearch:
image: elasticsearch:6.4.0
container_name: elasticsearch
environment:
- "cluster.name=elasticsearch"
- "discovery.type=single-node"
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- TZ=Asia/Shanghai
volumes:
- /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins
- /mydata/elasticsearch/data:/usr/share/elasticsearch/data
ports:
- 9200:9200
- 9300:9300
kibana:
image: kibana:6.4.0
container_name: kibana
links:
- elasticsearch:es
depends_on:
- elasticsearch
environment:
- "elasticsearch.hosts=http://es:9200"
- TZ=Asia/Shanghai
ports:
- 5601:5601
logstash:
image: logstash:6.4.0
container_name: logstash
environment:
- TZ=Asia/Shanghai
volumes:
- /mydata/logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
depends_on:
- elasticsearch
links:
- elasticsearch:es
ports:
- 4560:4560
- 4561:4561
- 4562:4562
- 4563:4563Installation key points
Run all services with docker-compose up -d.
If Elasticsearch fails to start, grant permission to the data directory: chmod 777 /mydata/elasticsearch/data.
Install Logstash JSON lines plugin: logstash-plugin install logstash-codec-json_lines.
Scenario Log Collection
Four log scenarios are defined:
Debug logs : all logs at DEBUG level and above, collected in development/testing environments.
Error logs : only logs at ERROR level, collected in all environments.
Business logs : logs printed in the application’s specific package.
Record logs : interface access records, useful for performance analysis.
Logback Configuration Details
To implement the scenarios, customize logback-spring.xml. The full configuration is shown below.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration>
<configuration>
<!-- include default configuration -->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="springBoot"/>
<property name="LOG_FILE_PATH" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/logs}"/>
<springProperty name="LOG_STASH_HOST" scope="context" source="logstash.host" defaultValue="localhost"/>
<!-- DEBUG file appender -->
<appender name="FILE_DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE_PATH}/debug/${APP_NAME}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<maxFileSize>${LOG_FILE_MAX_SIZE:-10MB}</maxFileSize>
<maxHistory>${LOG_FILE_MAX_HISTORY:-30}</maxHistory>
</rollingPolicy>
</appender>
<!-- ERROR file appender -->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE_PATH}/error/${APP_NAME}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<maxFileSize>${LOG_FILE_MAX_SIZE:-10MB}</maxFileSize>
<maxHistory>${LOG_FILE_MAX_HISTORY:-30}</maxHistory>
</rollingPolicy>
</appender>
<!-- DEBUG to Logstash -->
<appender name="LOG_STASH_DEBUG" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<destination>${LOG_STASH_HOST}:4560</destination>
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp>
<timeZone>Asia/Shanghai</timeZone>
</timestamp>
<pattern>
{"project":"mall-tiny","level":"%level","service":"${APP_NAME:-}","pid":"${PID:-}","thread":"%thread","class":"%logger","message":"%message","stack_trace":"%exception{20}"}
</pattern>
</providers>
</encoder>
<connectionStrategy>
<roundRobin>
<connectionTTL>5 minutes</connectionTTL>
</roundRobin>
</connectionStrategy>
</appender>
<!-- ERROR to Logstash -->
<appender name="LOG_STASH_ERROR" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<destination>${LOG_STASH_HOST}:4561</destination>
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp>
<timeZone>Asia/Shanghai</timeZone>
</timestamp>
<pattern>
{"project":"mall-tiny","level":"%level","service":"${APP_NAME:-}","pid":"${PID:-}","thread":"%thread","class":"%logger","message":"%message","stack_trace":"%exception{20}"}
</pattern>
</providers>
</encoder>
<connectionStrategy>
<roundRobin>
<connectionTTL>5 minutes</connectionTTL>
</roundRobin>
</connectionStrategy>
</appender>
<!-- BUSINESS to Logstash -->
<appender name="LOG_STASH_BUSINESS" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>${LOG_STASH_HOST}:4562</destination>
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp>
<timeZone>Asia/Shanghai</timeZone>
</timestamp>
<pattern>
{"project":"mall-tiny","level":"%level","service":"${APP_NAME:-}","pid":"${PID:-}","thread":"%thread","class":"%logger","message":"%message","stack_trace":"%exception{20}"}
</pattern>
</providers>
</encoder>
<connectionStrategy>
<roundRobin>
<connectionTTL>5 minutes</connectionTTL>
</roundRobin>
</connectionStrategy>
</appender>
<!-- RECORD to Logstash -->
<appender name="LOG_STASH_RECORD" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>${LOG_STASH_HOST}:4563</destination>
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp>
<timeZone>Asia/Shanghai</timeZone>
</timestamp>
<pattern>
{"project":"mall-tiny","level":"%level","service":"${APP_NAME:-}","class":"%logger","message":"%message"}
</pattern>
</providers>
</encoder>
<connectionStrategy>
<roundRobin>
<connectionTTL>5 minutes</connectionTTL>
</roundRobin>
</connectionStrategy>
</appender>
<!-- framework log level control -->
<logger name="org.slf4j" level="INFO"/>
<logger name="springfox" level="INFO"/>
<logger name="io.swagger" level="INFO"/>
<logger name="org.springframework" level="INFO"/>
<logger name="org.hibernate.validator" level="INFO"/>
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="LOG_STASH_DEBUG"/>
<appender-ref ref="LOG_STASH_ERROR"/>
</root>
<logger name="com.macro.mall.tiny.component" level="DEBUG">
<appender-ref ref="LOG_STASH_RECORD"/>
</logger>
<logger name="com.macro.mall" level="DEBUG">
<appender-ref ref="LOG_STASH_BUSINESS"/>
</logger>
</configuration>Key point explanations
Using default log configuration
The default console appender is defined in console-appender.xml inside the Spring Boot JAR.
springProperty
Allows values from application.yml (e.g., Logstash host) to be injected into the XML.
filter
ThresholdFilterdiscards logs below a level; LevelFilter accepts only a specific level.
appender
Three main appenders: ConsoleAppender, RollingFileAppender, and LogstashTcpSocketAppender for sending logs to Logstash.
logger
Only loggers with attached appenders are active. The configuration maps package names to the appropriate Logstash appender.
Logstash Configuration Details
Input listens on ports 4560‑4563 for the four log types, a filter processes record logs, and output indexes into Elasticsearch with type‑based indices.
input {
tcp { mode => "server" host => "0.0.0.0" port => 4560 codec => json_lines type => "debug" }
tcp { mode => "server" host => "0.0.0.0" port => 4561 codec => json_lines type => "error" }
tcp { mode => "server" host => "0.0.0.0" port => 4562 codec => json_lines type => "business" }
tcp { mode => "server" host => "0.0.0.0" port => 4563 codec => json_lines type => "record" }
}
filter {
if [type] == "record" {
mutate { remove_field => ["port", "host", "@version"] }
json { source => "message" remove_field => ["message"] }
}
}
output {
elasticsearch {
hosts => ["es:9200"]
action => "index"
codec => json
index => "mall-tiny-%{type}-%{+YYYY.MM.dd}"
template_name => "mall-tiny"
}
}SpringBoot Configuration
Environment‑specific application-*.yml files can override Logstash host and root logging level.
# application-dev.yml
logstash:
host: localhost
logging:
level:
root: debug # application-test.yml
logstash:
host: 192.168.3.101
logging:
level:
root: debug # application-prod.yml
logstash:
host: logstash-prod
logging:
level:
root: infoKibana Advanced Usage
After the ELK stack is running, use Kibana to create index patterns, discover logs per scenario, and search by fields. Screenshots illustrate the steps.
Project Source Code
GitHub repository: https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-log
Recommended Reading
https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==∣=2247485500&idx=1&sn=a8c4d2bb1d1510c59a034dd323e7f79b&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==∣=2247485428&idx=1&sn=4bf92e5db53b607be6ab04186da7c87e&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==∣=2247485400&idx=1&sn=8f935de6f79c18a34642e4957639bc7e&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==∣=2247485371&idx=1&sn=cbbab6671f28e6069f84110baff40237&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==∣=2247485316&idx=1&sn=86b2b6ecc1ed84ab93d7c2a0e24a63e3&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==∣=2247485281&idx=1&sn=eed2f292b6b27c0b21c06b919bad7fab&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==∣=2247485261&idx=1&sn=fd48af88d747ffc96e0b8f2ee0e997ff&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==∣=2247485177&idx=1&sn=4e8b4669e7164e2826232f74ea11938e&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==∣=2247484570&idx=1&sn=921b4e63a1cd80d93d8ee72356d74f0e&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==∣=2247483939&idx=1&sn=bef5753e4885856e6ae7932fb0bdb622&scene=21#wechat_redirect
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
