์ค๋๋ ์๋ก์ด ๊ฑธ ๊ฑด๋๋ฆฌ๊ณ ์์ต๋๋ค.
๊ฐ์ธ์ ์ผ๋ก ์น๊ตฌ๋ค๊ณผ ์งํํ๊ณ ์๋ ํ๋ก์ ํธ์์
๋์ ์ฒ์ ELK ์คํ๊ณผ docker๋ฅผ ์จ๋ณด๊ฒ ์๊ฒผ๋ค์๐ณ๐ณ
์๋ ์ด๊ฒ์ ๊ฒ ๋ง์ด ๊ธ์ด๋ชจ์ผ๋ฉด์ ์งํํ๋ ์ค์ด๋ผ ์ค์ค๋ก ๊น๋จน์ง ์๊ธฐ ์ํด ์ ๋ฆฌํ๋ ์ฑ๊ฒฉ์ด ๊ฐํ์ง๋ง
๊ทธ๋๋ ํน์๋ ๋๊ตฌ์๊ฒ๋ ๋์์ด ๋ ์๋ ์์ผ๋๊น... ํ๋ ๋ง์์ผ๋ก ์ต๋ํ ์ด์๊ฒ ์ ๋ฆฌํด๋ณด๋ ค๊ณ ํฉ๋๋ค.
๋ผ์ด๋ธ๋ก ์ฐพ์๋ณด๋ฉด์ ์คํํด๋ณด๋ฉด์ ์ฐ๋๊ฑฐ๋ผ ์ ํํ์ง ์์ ๋ด์ฉ์ด ์์ ์ ์์ต๋๋ค๐ฅ
1. ํ์ํ ๋ด์ฉ
์ผ๋จ ํ๋ก์ ํธ์ ์ ์ฒด ํด๋ ๊ตฌ์กฐ๋ ์๋์ ๊ฐ์ต๋๋ค.
morgen-muffel
โโtest-server
โ โโapp.py
โ โโDockerfile
โโlog-server
โ โโelasticsearch
โ โโkibana
โ โโlogstash
โ โโdocker-compose.yml
โdocker-compose-test.yml
ํด๋๋ ํ์ผ ์์ ๊ตฌ๋ถํ๊ณ ์ถ์ง๋ง ๊ทธ๊ฑด ํฌ๊ธฐํ๋๋ก ํ๊ตฌ์๐
test-server์์ ๋ฐ์ํ๋ ๋ก๊ทธ๋ฅผ Filebeat๊ฐ ๋ฐ์์ Logstash๋ก ๋ณด๋ด๊ณ , ์ด๋ฅผ Elasticsearch์ ์ ์ฌํ๊ณ Kibana๋ก ๋ณด๋
์ง๊ทนํ ์์์ ์ด๊ณ ์ผ๋ฐ์ ์ธ ๊ตฌ์กฐ์ ๋๋ค.
๋ค๋ง ELK๋ docker๋ฅผ ์ฒ์ ์ฐ๋ค๋ณด๋ ์์์ผ ํ ๊ฒ ๋๋ฌด ๋ง์์ ์ฝ๊ฐ ๊ณ ํต์ค๋ฝ๋ค์!
์ง๊ธ docker-compose๊ฐ ๋ ์ข ๋ฅ๊ฐ ์๋๋ฐ
log-server ์๋ ์๋ docker-compose.yml ํ์ผ์ ELK stask์ ํ๋์ ์ปจํ ์ด๋์ ๋์์ฃผ๋ ์์ฃผ ์ฐฉํ ๋ ์์ด๊ตฌ์(๋น์ฐํ ์ ๊ฐ ๋ง๋ค์ง ์์์ต๋๋ค)
GitHub - deviantony/docker-elk: The Elastic stack (ELK) powered by Docker and Compose.
The Elastic stack (ELK) powered by Docker and Compose. - GitHub - deviantony/docker-elk: The Elastic stack (ELK) powered by Docker and Compose.
github.com
์ ๊ฐ ๋ง๋ค์ด์ผ ํ ๊ฒ์ morgen-muffel ํ์์ ์๋ docker-compose-test.yml ํ์ผ์ ๋๋ค.
์ด ์น๊ตฌ์ ์ญํ ์
test-server์ ์๋ Dockerfile์ ์คํํด app.py์ ์๋ ๋ด์ฉ์ผ๋ก flask๋ก ๋์ฐ๋ ๊ฒ๊ณผ ๋์์
flask๋ก ๋ง๋ค์ด์ง ์๋ฒ๊ฐ log ํด๋์ ๋จ๊ถ์ฃผ๋ ๋ด์ฉ์ ์ฝ์ด์ Logstash์ ์ ์ฅํ๋ Filebeat๋ฅผ ๋์ฐ๋ ๊ฒ์ ๋๋ค๐คจ
๊ทธ๋ ๋ค๋ฉด docker-compose-test๋ test-server ํด๋ ์์ ๋ง๋ค๋ฉด ๋ ํ ๋ฐ! ํ๊ณ ์๊ฐํ์ง๋ง
์น๊ตฌ๋ค๊ณผ ๋๋ ์ ๋ง๋ค๋ค๋ณด๋, ์ test-server์ ํด๋นํ๋ ๋ด์ฉ์ ๋ค๋ฅธ ์น๊ตฌ๊ฐ ๋ง๋ค ์์ ์ด์์
๋์ค์ ์๊ธฐํด๋ณด๊ณ ํด๋ ๊ตฌ์กฐ๋ฅผ ๋ฐ๊ฟ์๋ ์์ง๋ง
์ผ๋จ์ "ํน์ ๊ฒฝ๋ก์ ์๋ Dockerfile๊ณผ Filebeat๋ฅผ ํจ๊ป ๋์ฐ๊ธฐ"์ ์ง์คํด๋ณด๋ ค๊ณ ํฉ๋๋ค
์ ์์ ์๋ ์คํ๋ค ์ค์ ์ ์จ๋ณธ๊ฒ ํ๋๋ ์๋ค์๐๐๐๐
์จ๋ณธ๊ฒ ์๋ค๋ ์๊ธฐ๋ ์ ๋ด์ฉ์ ํ๋ํ๋ ๋ง๋๋ ๋ชจ๋ ๊ณผ์ ์ ๊ตฌ๊ธ์ด ํจ๊ปํ๋ค๋ ๊ฒ!๐
2. ํ ์คํธ์ฉ ์๋ฒ ๋์ฐ๊ธฐ
ํ ์คํธ์ฉ ์๋ฒ์ด๊ธฐ ๋๋ฌธ์ ๋ง์๊ฑธ ๋ฐ๋ผ์ง ์์ต๋๋ค.
์์ฃผ ๋จ์ํ ์ ์ํ๋ฉด ์ ์ํ ์๊ฐ๋ง log์ ๋จ๊ถ์ฃผ๋ ์ญํ ๋ง ํ ์์ ์ ๋๋ค.
์ด ํ์ผ์ ์ฝ์ด์ ES์ ์ ๋๋ก ๋ณด๋ด๋์ง๋ง ๋ณด๋ฉด ๋๊ธฐ ๋๋ฌธ์!
ํ์ง๋ง ๊ทธ ์๋ฒ๋ฅผ Docker๋ก ๋์์ผ ํ๊ธฐ ๋๋ฌธ์
๊ทธ ๊ฐ๋จํ ๊ฒ๋ ๊ตฌ๊ธ์ ๋์์ ์๋ฉ ๋ฐ๊ณ ์์ต๋๋ค.
๋ง์นจ docker compose ๋ฌธ์์์ flask๋ก ์์๋ฅผ ๋ค๊ณ ์์ด์ ์ด๊ฑธ ๋ฐ๋ผํ๊ธฐ๋ก ํ์ต๋๋ค.
Get started with Docker Compose
docs.docker.com
app.py์ ๋ด์ฉ์ flask๋ก ๋์ฐ๋ ์์์ธ๋ฐ ๊ฐ๋จํ๊ณ ์์ฃผ ์ข๊ตฐ์.
ํ์ง๋ง ๋ฐ๋ก ๋ฌธ์ ์ ๋ด์ฐฉํ์ต๋๋ค.
์ ์์๋ redis์ count๋ฅผ ์ ์ฅํ๋๋ฐ, ์ log ํด๋์ log๋ฅผ ๋จ๊ตฌ๊ณ ์ถ๋จ ๋ง์ด์ฃ ...
Python logging์ ํ์ฉํด Flask์์ loggingํ๋ ๋ฐฉ๋ฒ
Flask Logging ํ๋ ๋ฐฉ๋ฒ
jangseongwoo.github.io
์ํ๋ ๋ก๊ทธ๋ฅผ ๋ง๋๋ ๋ด์ฉ์ ์ด ๊นํ ํ์ด์ง๋ฅผ ์ฐธ๊ณ ํ์ต๋๋ค.
๋ ๋ด์ฉ์ ์กฐํฉํด ์์ฑํ ์ฝ๋๋ ์๋์ ๊ฐ๋ค์
import datetime
import logging
from flask import Flask, request
app = Flask(__name__)
logging.basicConfig(filename = "logs/test.log", level = logging.DEBUG)
def log(request, message):
log_date = get_log_date()
log_message = "{0}/{1}/{2}".format(log_date, str(request), message)
logging.info(log_message)
def get_log_date():
dt = datetime.datetime.now(timezone("Asia/Seoul"))
log_date = dt.strftime("%Y%m%d_%H:%M:%S")
return log_date
@app.route('/')
def hello():
log(request, "hello route")
return "hello"
if __name__ == '__main__':
app.run(debug=True)
๊ทธ๋ฆฌ๊ณ dependency ์ค์ ์ ์ํ requirements.txt์ ์ด ์ฑ์ Flask๋ก ์คํํด์ฃผ๋ Dockerfile์ ์์ฑํฉ๋๋ค.
์ด๊ฑด docker compose ๋ฌธ์์ ์๋ ๋ด์ฉ์ ๊ทธ๋๋ก ์ผ์ด์!
๊ทธ๋ฆฌ๊ณ ์ต์์ ํด๋์ docker-compose-test.yml ํ์ผ์ ์์ฑํด์ค๋๋ค.
๊ธฐ๋ณธ์ ์ธ ๋ด์ฉ์ ๋ฌธ์์ ์๋๊ฑธ ์ฐธ๊ณ ํ์ง๋ง, ํ์ผ ๊ฒฝ๋ก๋ ์ ์๊ฒ ๋ง๊ฒ ๋ฐ๊ฟ์ฃผ์์ต๋๋ค.
์ผ๋จ Filebeat ์์ด Flask๊ฐ ์ ๋จ๊ณ log๋ฅผ ์ ์ฐ๋์ง ๋ณด๋๋ก ํฉ์๋ค.
version: "3.9"
services:
web:
build: ./test-server
ports:
- "5000:5000"
์ด๋ ๊ฒ ์์ฑํ ๋ค docker-compose up์ ์คํํด์คํ ๋ฐ,
์ง๊ธ์ ํ์ผ ์ด๋ฆ์ด ๋ํดํธ ๊ฐ(docker-compose.yml)์ด ์๋๋ฏ๋ก
docker-compose -f docker-compose-test.yml up
์ ์คํํด์ฃผ๋ฉด ๋๋ค๊ณ ํฉ๋๋ค. ๊ตฌ๊ธ์ด ๊ทธ๋ฌ์ด์.
์คํํ๋ฉด... ์ ์ ๋๋ก ์๋ฒ๊ฐ ์๋จ๋ค์
๋ญ๊ฐ ์๋ฌ๊ฐ ๋์ ๊ณ ์น๊ธฐ ์ ์๋ ๋ด๋๋ฐ ๊ทธ๊ฑธ ์์ ํ๊ณ ๋๋๊น ์๋น๋๋ค.
์ด๊ฒ์ ๊ฒ ํ ์คํธํด๋ณด๋ฉด์ ์๊ฒ ๋ ๊ฒฐ๊ณผ๋ logging.basicConfig๋ฅผ ์ญ์ ํ๋ฉด ์ ๋๋ก ์๋ฒ๊ฐ ๋ฌ๋ค๋ ์ ์ ๋๋ค.
๊ทธ๋ฆฌ๊ณ hello ์์์ log ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ๊ธฐ๋ณธ ๋ก๊ทธ ์ธ์ ๋ค๋ฅธ ๋ก๊ทธ๊ฐ ๋จ๋๋ฐ, INFO:werkzeug๋ก ์์ํ๋ ๋ก๊ทธ๊ฐ ๋จ๋ค์.
์ ์ง ์ด ์น๊ตฌ๋ ์ฐ๊ด์ด ์์ ๊ฒ ๊ฐ์ ๊ตฌ๊ธ๋ง์ ํด๋ณด์์ต๋๋ค.
Logging — Flask Documentation (2.0.x)
Logging Flask uses standard Python logging. Messages about your Flask application are logged with app.logger, which takes the same name as app.name. This logger can also be used to log your own messages. @app.route('/login', methods=['POST']) def login():
flask.palletsprojects.com
๋งจ ๋ง์ง๋ง์
Werkzeug logs basic request/response information to the 'werkzeug' logger. If the root logger has no handlers configured, Werkzeug adds a StreamHandler to its logger.
๋ผ๊ณ ํ๋๊ฑธ ๋ณด๊ณ ์ด๊ฒ์ ๊ฒ ํ ์คํธ๋ฅผ ํด๋ณด์์ต๋๋ค.
werkzeug์ file handler๋ฅผ ๋ถ์ด๋ฉด ๋ญ๊ฐ ๋ ์๋ ์์ง ์์๊น.... ํ๋ ์๊ฐ์ด ๋ค์ด์ ์ด๋์ ๋ ๋๋ฆฌ๋ฅผ ์น๋ฉด์
.
.
.
.
๊ทธ๋ฆฌ๊ณ ์๋ง์ ์ฝ์ง๋์ ๊ฒฐ๊ตญ ํด๊ฒฐ์ฑ ์ ์์๋์ต๋๋ค.
์ผ๋จ ์์ฑ๋ ์ฝ๋๋ถํฐ ๊ณต๊ฐํ๊ฒ ์ต๋๋ค.
import datetime
import logging
from flask import Flask, request
from pytz import timezone
app = Flask(__name__)
def log(request, message):
log_date = get_log_date()
log_message =
"{{\n\tdate: {0}\n\trequest: {1}\n\tmessage: {2}\n}}"
.format(log_date, str(request), message)
logging.getLogger('my').info(log_message)
def get_log_date():
dt = datetime.datetime.now(timezone("Asia/Seoul"))
log_date = dt.strftime("%Y/%m/%d %H:%M:%S")
return log_date
@app.route('/')
@app.route('/<name>')
def hello(name=''):
log(request, "hello " + name)
return "hello " + name
if __name__ == "app":
fileHandler = logging.FileHandler('logs/test.log')
myLogger = logging.getLogger('my')
myLogger.setLevel(logging.INFO)
myLogger.addHandler(fileHandler)
๋จผ์ ๋ฌธ์ ๊ฐ ๋๋ ์๋ฒ๊ฐ ๋จ์ง ์๋ ๊ฒฝ์ฐ๋
app์ด ์ ๋๋ก loading๋๊ธฐ ์ ์ logging.~~~ ๋ฅผ ํธ์ถํด์ ์๊ธด ๋ฌธ์ ์๋ ๊ฒ ๊ฐ์ต๋๋ค.
๊ทธ๋์ ๊ทธ ๋ถ๋ถ์ ์ฎ๊ฒจ์ค์ผ ํ๊ณ ๊ตฌ๊ธ๋ง์ ํด app.py๋ฅผ flask run์ผ๋ก ์คํํ๋ฉด __name__์ด app์ด ๋๋ค๋ ๋ด์ฉ์ ์ฐพ์ ๋ง์ง๋ง ๋ธ๋ก์ ๊ณ ์ณ์ฃผ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ 'werkzeug' logger ๊ด๋ จํด์๋, ์ ์น๊ตฌ์ ์ง์ file handler๋ฅผ ๋ถ์ด๋ฉด ๋์ง ์์๊น ํ์ง๋ง
root logger๋ก ์ถ์ ๋๋ ์น๊ตฌ์๊ฒ๋ ๋์ผํ๊ฒ ์ ์ฉ๋์ด ์ํ์ง ์๋ ๋ก๊ทธ๊น์ง ์ฐํ๋ ์ํฉ์ด ๋๋๋ผ๊ตฌ์.
๊ทธ๋์ ์๋ก์ด my logger๋ฅผ ๋ง๋ค์ด์, ์ฌ๊ธฐ์๋ง file handler๋ฅผ ์ฐ๊ฒฐํ๊ณ log ๋ฉ์๋์์๋ ์ด ์น๊ตฌ๋ฅผ ์ฌ์ฉํด ๋ด์ฉ์ ์ถ๋ ฅํ์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ฒฐ๊ณผ๋ฌผ์ ๋ณด๋ฉด
Flask Server Log์ test.log ํ์ผ ๋ด์ฉ์ด ์์ฃผ ์ ๋ถ๋ฆฌ๋์ด ์ ํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค!
ํฌ๋งทํ ์ ๊ทธ๋ฅ ๋๋ฌด ์ ๋์ ์ถ๊ฐํด ๋ฒ๋ ธ๊ตฌ์
๋ฌผ๋ก ์ ์ํ๋ก Filebeat๋ก ๋๊ฒจ์ฃผ๋ฉด Logstash๊ฐ ์ ๋ฐ์์ง๋ ๋ชจ๋ฅด๊ฒ ์ง๋ง๐
๊ทธ๋ฆฌ๊ณ ๋๋ฌด ์ ๋ ๊น์ route๋ ์ถ๊ฐํ์ต๋๋ค.
<name>๊ณผ ๊ฐ์ parameter๋ฅผ ์ฐ๋ฉด ์ด๋ค ๊ฐ์ด ๋ค์ด์๋ ๋ณ์๋ก ๋ฐ์ ์ ์๋๊ฒ ๊ฐ๋๋ผ๊ตฌ์.
๋ก๊ทธ์์ ๋ณด์๋ค์ํผ URL์ localhost:5000/morgenmuffel ์ด๋ผ๊ณ ์ ์ผ๋ฉด ๋ก๊ทธ์๋ ์ด ๊ฐ์ด ์ด์๊ฒ ๋ค์ด๊ฐ๋๋ค.
์ฌ์ค ํ๋ค๊ฐ ์ค๊ฐ์ ๋ฉ๋ถ์ด ์์ ์น๊ตฌํํ ํ์์ฐํ๋๋ฐ
๊ทธ๋ฅ file writer๋ฅผ ์ฐ๋ฉด ์๋๋๊ณ ํ๋๊ฑธ ๋ณด๊ณ .....
์ญ์ ๋จธ๋ฆฌ๊ฐ ๋์๋ฉด ๋ชธ์ด ๊ณ ์ํ๋ค๋๊ฑธ ๋๊ผ์ต๋๋ค.
๊ทธ๋ฅ append ๋ชจ๋๋ก ํ์ผ์ ์ด์ด์ ์ธ๊ฑธ....
๊ทธ๋๋ ๊ฒฐ๊ตญ ํด๋์ผ๋ ๋ง์กฑํฉ๋๋ค..... ์ง๊ธ ์๊ฐ ์๋ฒฝ 6์....
์๋ Filebeat๊น์ง ํ ์คํธ ํด๋ณด๋ ค๊ณ ํ๋๋ฐ ๋์ ํ ๋ชปํ๊ฒ ๋ค์.
์ ๊ฐ ์๋ ํฌ๋กฌ ํญ ๋ง์ด ๋ฌ๊ฑธ ์ซ์ดํด์ ๋งจ๋ ๋๋ฉด์ ์์ ํ๋๋ฐ
์ค๋์ ๊ฑฐ์ ๋งํ๊ฐ๊ฐ ๋ ์๋ค์!
์ ์ค์ Filebeat ์ฐ๊ฒฐํ ๋ ๋ญ๊ฐ ํ์ํ ์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.... ํ๋ํ๋ ๋ณด๋ฉด์ ๋จ๊ฒจ๋์ผ๊ฒ ์ด์
์๋ง ๋ด์ผ, ์ ์ค๋์ด๊ตฐ์ ์ค๋ ์ค์ Filebeat ์ฐ๊ฒฐํ๋ฉด์ ๋ ํธ๋ ๊ธ์ ์ ์ด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค!
'๐พ.knwldg' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Java Project ๋ฏ์ด ๊ณ ์น๊ธฐ - #2 (0) | 2021.08.01 |
---|---|
docker-ELK, Filebeat, ๊ทธ๋ฆฌ๊ณ docker compose - #2 (0) | 2021.07.26 |
Java Project ๋ฏ์ด ๊ณ ์น๊ธฐ - #1 (0) | 2021.07.20 |
Java Project ๋ฏ์ด ๊ณ ์น๊ธฐ - #0 (0) | 2021.07.17 |
๋ฆฌ์ฌ์ฃผ ๊ณก์ / ๋ฆฌ์ฌ์ฃผ ๊ทธ๋ฆผ (0) | 2021.06.13 |