[ELK Stack] Filebeat 소개 및 사용
1. Beats 소개
엄밀히 말하면 ELK Stack에서는 Beats라는 단일 목적의 데이터 수집기 무료 오픈 소스 플랫폼을 제공합니다. 하기와 같이 filebeat 외에 metricbeat, heartbeat 등 여러가지 beat가 있습니다.
https://www.elastic.co/kr/beats/
Beats: Elasticsearch를 위한 데이터 수집기 | Elastic
로그, 네트워크, 인프라 데이터 등을 위한 수집기를 구축하기 위한 오픈 소스 플랫폼으로 Elasticsearch, Logstash, Kibana와 통합됩니다.
www.elastic.co
Beats는 Go 언어로 작성된 경량 프로그램으로 logstash, elasticsearch와 연계해 다양한 시스템 이벤트를 수집할 수 있게 도와 줍니다.
Libbeat라는 프레임워크를 제공해 사용자들이 직접 필요한 beat를 구현할 수 있습니다.
1.1 logstash vs beats
똑같이 log를 수집할수 있기 때문에 왜 2개를 지원하는지 의문이 들수 있습니다. 하기와 같이 다른점이 있습니다.
- logstash를 사용해보면 알수 있겠지만 다양한 기능(log정제)을 제공하기 때문에 무거움. 반면 beats는 특수 목적만 수행하도록 가볍게 구성되어 앱의 성능에 영향을 미치지 않고 동작할 수 있음.
- beats도 간단한 이벤트 가공을 제공하기 때문에 정제를 많이 할 필요없는 log이면 logstash보다 beat를 사용하는것이 성능상 유리함.
- beats는 logstash의 대체재라기보다 공생 관계로 이해하면 좋음. 실제로 많은 서비스들이 beats로 log를 수집해서 logstash로 전송하고 logstash에서 또 한번의 정제를 거친 후 elasticsearch에 보내도록 구현되어 있음.
2. Filebeat
filebeat 구조는 다음과 같습니다. https://www.elastic.co/guide/en/beats/filebeat/current/how-filebeat-works.html
- Input:
- 설정 파일에서 harvester에 대한 입력 소스를 정함.
- filebeat는 하나 혹은 여러개의 입력을 가질 수 있음.
- 파일당 한개 harvester가 실행 됨.
- harvester가 종료 후 파일사이즈가 변경되면 신규 데이터가 추가된거스로 판단하고 새로운 harvester를 실행 함.
- Harvester:
- 입력에 명시된 파일을 수집하는 주체
- 파일을 한 줄씩 읽고 내보내는 역할
- 파일을 열고 닫는 역할
- harvester가 실행되는 동안에는 파일 디스크립터(File descriptor)가 열려 있음
- Spooler: harvester가 수집한 data를 elasticsearch / logstash 같은 곳에 전달함
- Registry file:
- 각 log 파일의 상태를 기록 함. log 파일에서 마지막으로 읽은 offset, output에 성공적으로 보낸 offset 등.
- 처음으로 log file를 읽을 때 해당 file에 unique identifier를 부여함. 때문에 파일명이 변경되어도 계속 tracking 할수 있음.
- filebeat가 restart할 때 registry file를 이용하여 close하기 전 상태로 복구 함.
- filebeat는 at-least-one delivery를 보장 함.
3. Filebeat 실행
filebeat.yml 파일을 통해 filebeat을 설정 함.
filebeat.inputs:
- type: log
enabled: true
paths:
- /Users/user/Source/Elastic_Stack_Study/log/*.log
output.elasticsearch:
hosts: ['localhost:9200']
#output.console:
# pretty: true
# kibana index pattern mapping등을 해줌. 실행할 때 setup option을 주면 됨.
setup.kibana:
host: ['localhost:5601']
3.1 Filebeat input type 관련
- log: 파일시스템의 지정한 경로에서 로그 파일을 읽기 위한 입력
- container: 도커 같은 컨테이너의 로그를 수집하기 위한 입력
- s3: log type과 유사하나, 아마존 웹 서비스의 S3버킷에 위차한 파일을 읽기 위한 입력
- kafka: 카프카의 토픽을 읽기 위한 입력
3.2 Filebeat output type관련
- elasticsearch: 수집한 log를 elasticsearch로 indexing함.
- logstash: 수집한 log를 logstash로 보냄.
- kafka: 수집한 log를 kafka로 보냄.
- console: 수집한 log를 console로 출력
4. Filebeat 설정
https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-log.html
Log input | Filebeat Reference [8.4] | Elastic
During testing, you might notice that the registry contains state entries that should be removed based on the clean_inactive setting. This happens because Filebeat doesn’t remove the entries until it opens the registry again to read a different file. If
www.elastic.co
4.1 ignore_older
- 새로운 파일 탐색 시 오래된 파일은 읽어 들이지 않고 무시하기 위한 설정
- input type이 log일 때만 사용 가능 함.
- 10h, 10m 등 형태로 값을 줄 수 있음
- 기본 값은 0
filebeat.inputs:
- type: log
enabled: true
paths:
- /Users/user/Source/Elastic_Stack_Study/log/*.log
ignore_older: 24h
4.2 include_lines, exclude_lines, exclude_files
- include_lines: 선언된 정규식에 맞는 line만 읽음.
- exclude_lines: 선언된 정규식에 맞는 line을 무시함
- exclude_files: 선언된 정규식에 맞는 file를 무시함.
filebeat.inputs:
- type: log
enabled: true
paths:
- /Users/user/Source/Elastic_Stack_Study/log/*.log
exclude_lines: ['^\[DEBUG']
include_lines: ['^\[WARN', '^\[ERROR']
4.3 멀티라인 로그 처리: multiline
- filebeat는 싱글라인 단위로 이벤트를 처리함.
- multiline.pattern: 정규식을 이용해 패턴을 지정함. 패턴과 일치하는 라인이 나타나면 멀티라인으로 인식함.
- multiline.negate: false이면 패턴과 일치한 라인을, true이면 패턴과 일치하지 않는 라인을 멀티라인으로 인식함.
- multiline.match: 멀티라인으로 인식한 라인을 패턴과 일차하지 않는 앞쪽(after) 라인에 붙일 지, 뒷쪽(before) 라인에 붙일지 결정함.
pattern 예제:
data:
`Error: Stack Trace Error
at firstFunction (/tmp/soQIcxVbky.js:2:9)
at secondFunction (/tmp/soQIcxVbky.js:6:3)
at thirdFunction (/tmp/soQIcxVbky.js:10:3)
at Object.<anonymous> (/tmp/soQIcxVbky.js:13:1)
at Module._compile (internal/modules/cjs/loader.js:778:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)`
설정:
filebeat.inputs:
- type: log
enabled: true
paths:
- /Users/user/Source/Elastic_Stack_Study/log/*.log
multiline.pattern: '^[[:space:]]'
multiline.negate: false
multiline.match: after
negate, match 예제:
data:
`
aoo
koo
boo
boo
zoo
boo
`
설정:
filebeat.inputs:
- type: log
enabled: true
paths:
- /Users/user/Source/Elastic_Stack_Study/log/*.log
multiline.pattern: '^b'
multiline.negate: false or true
multiline.match: after or before
결과:
negate->false, match->after: ['aoo', 'koo\nboo\nboo', 'zoo\nboo']
negate->false, match->before: ['aoo', 'koo', 'boo\nboo\nzoo', 'boo']
negate->true, match->after: ['aoo\nkoo', 'boo', 'boo\nzoo', 'boo']
negate->true, match->before: ['aoo\nkoo\nboo', 'boo', 'zoo\nboo']
5. 모듈
- 모듈은 많이 사용되고 잘 알려진 시스템 데이터를 수집하기 위한 일반적인 설정을 사전 정의해 둔 것.
- nginx, apache 서버 로그들은 사용자가 설정 변경이 없으면 설치 경로, 위치, 로그 형태 등이 동일함으로 모듈형태로 사전설정을 제공하는 것.
- filebeat지원하는 모듈들: https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html
모듈 설정방법은 다음과 같습니다.
- filebeat.yml 설정
filebeat.inputs:
- type: log
enabled: true
paths:
- /Users/user/Source/Elastic_Stack_Study/log/*.log
output.elasticsearch:
hosts: ['localhost:9200']
filebeat.config.modules:
path: ${path.config}/modules.d/*.yml
setup.kibana:
host: 'localhost:5601'
- 모듈 활성화
./filebeat modules enable logstash kibana elasticsearch
Enabled logstash
Enabled kibana
Enabled elasticsearch
- 활성화된 모듈 확인하는 명령
./filebeat modules list
Enabled:
elasticsearch
kibana
logstash
Disabled:
activemq
apache
auditd
aws
awsfargate
...
- 모듈 설정 파일 수정
- logstash나 elasticsearch등을 default 설정값들을 그대로 사용하면 추가로 수정할 필요가 없음.
- 모듈 설정 파일 위치: modules.d 폴더, 들어가 보면 위에서 enable한 모듈은 .yml로 disable된 모듈들은 .yml.disabled 로 되어있음.
- elasticsearch log파일 위치를 하기와 같이 지정 함.
- module: elasticsearch
# Server log
server:
enabled: true
var.paths: ["/Users/user/Source/Elastic_Stack_Study/elasticsearch-7.14.0/logs/elasticsearch.log*"]
# Set custom paths for the log files. If left empty,
# Filebeat will choose the paths depending on your OS.
#var.paths:
gc:
enabled: true
var.paths: ["/Users/user/Source/Elastic_Stack_Study/elasticsearch-7.14.0/logs/gc.log*"]
# Set custom paths for the log files. If left empty,
# Filebeat will choose the paths depending on your OS.
#var.paths:
6. filebeat - logstash - elasticsearch 연동설정 예제
logstash 설정
input {
beats {
port => 5044
}
}
output {
elasticsearch {
hosts => ["http://localhost:9200"]
index => "custom-filebeat-%{[@metadata][version]}-%{+YYYY.MM.dd}"
}
}
filebeat 설정
filebeat.inputs:
- type: log
enabled: true
paths:
- /Users/user/Source/Elastic_Stack_Study/log/*.log
output.logstash:
hosts: ['localhost:5044']
주의할점은 logstash 설정의 input.beats.port 값으로 filebeat 설정의 output.logstash.hosts 를 설정해야 합니다.
7. 예제에서 사용한 log 생성 코드
const fs = require('fs')
const {EOL} = require('os');
function generateOneline() {
const msg = `[DEBUG][${new Date().toISOString()}] Debug message
[WARN][${new Date().toISOString()}] Warning message
[ERROR][${new Date().toISOString()}] Error message${EOL}`
fs.appendFile('filbeat_test.log', msg, function (err) {
if (err) return console.log(err);
console.log('successfully appended "' + msg + '"');
});
}
function generateJSError() {
const msg = `Error: Stack Trace Error
at firstFunction (/tmp/soQIcxVbky.js:2:9)
at secondFunction (/tmp/soQIcxVbky.js:6:3)
at thirdFunction (/tmp/soQIcxVbky.js:10:3)
at Object.<anonymous> (/tmp/soQIcxVbky.js:13:1)
at Module._compile (internal/modules/cjs/loader.js:778:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)${EOL}`
fs.appendFile('filbeat_test.log', msg, function (err) {
if (err) return console.log(err);
console.log('successfully appended "' + msg + '"');
});
}
function generateMultilineExp() {
const msg = `aoo
koo
boo
boo
zoo
boo${EOL}`
fs.appendFile('filbeat_test.log', msg, function (err) {
if (err) return console.log(err);
console.log('successfully appended "' + msg + '"');
});
}
function main() {
const option = process.argv[2]
console.log(option)
if (option === 'multi_exp') {
generateMultilineExp()
} else if (option === 'multi') {
generateJSError()
}
else {
generateOneline()
}
}
main()