视频教程请移步 Ubuntu 环境下通过 Docker 快速搭建 ELK 日志系统环境_哔哩哔哩_bilibili
-
安装 Docker
# 允许apt通过HTTPS使用存储库来安装软件
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
# 添加Docker官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 使用下面的命令去设置稳定版的存储库
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# 使用下面的命令去设置稳定版的存储库
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
# 验证Docker
docker -v
-
安装 docker-compose
# 运行下面的命令来下载 Docker Compose 当前稳定版本
sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 添加权限
sudo chmod +x /usr/local/bin/docker-compose
# 验证安装
docker-compose --version
-
Docker 拉镜像加速
Docker 下载镜像慢,可以增加 /etc/docker/daemon.json 文件如下,然后 systemctl restart docker 生效后,继续 docker-compose up -d 的操作
{
"registry-mirrors": [
"http://f1361db2.m.daocloud.io",
"https://registry.docker-cn.com",
"http://hub-mirror.c.163.com",
"https://kfwkfulq.mirror.aliyuncs.com"
]
}
-
ELK 搭建
mkdir -p ~/projects/elk/{elasticsearch/data,logstash}
# yaml 文件,放在 projects/elk 文件夹下
version: '3'
services:
elasticsearch:
image: elasticsearch:7.7.0 #镜像
container_name: elk_elasticsearch #定义容器名称
# restart: always #开机启动,失败也会一直重启
environment:
- "cluster.name=elasticsearch" #设置集群名称为elasticsearch
- "discovery.type=single-node" #以单一节点模式启动
- "ES_JAVA_OPTS=-Xms512m -Xmx1024m" #设置使用jvm内存大小
volumes:
- /home/xiaobaiyang/projects/elk/elasticsearch/plugins:/usr/share/elasticsearch/plugins #插件文件挂载
- /home/xiaobaiyang/projects/elk/elasticsearch/data:/usr/share/elasticsearch/data #数据文件挂载
ports:
- 9200:9200
kibana:
image: kibana:7.7.0
container_name: elk_kibana
# restart: always
depends_on:
- elasticsearch #kibana在elasticsearch启动之后再启动
environment:
- ELASTICSEARCH_URL=http://elasticsearch:9200 #设置访问elasticsearch的地址
ports:
- 5601:5601
logstash:
image: logstash:7.7.0
container_name: elk_logstash
# restart: always
volumes:
- /home/xiaobaiyang/projects/elk/logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf #挂载logstash的配置文件
depends_on:
- elasticsearch #kibana在elasticsearch启动之后再启动
links:
- elasticsearch:es #可以用es这个域名访问elasticsearch服务
ports:
- 4560:4560
# logstash.conf 文件,放在 projects/elk/logstash 文件夹下
input {
tcp {
mode => "server"
host => "0.0.0.0"
port => 4560
codec => json_lines
}
}
output {
elasticsearch {
hosts => "es:9200"
index => "logstash-%{+YYYY.MM.dd}"
}
}
-
Django 接入 ELK
-
安装依赖库
使用 python-logstash 这个第三方依赖库。
pip install python-logstash
-
修改 Django 项目的设置
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
# 日志格式
'standard': {
'format': '[%(asctime)s] [%(filename)s:%(lineno)d] [%(module)s:%(funcName)s] '
'[%(levelname)s]- %(message)s'},
'simple': { # 简单格式
'format': '%(levelname)s %(message)s'
},
},
# 过滤
'filters': {
},
# 定义具体处理日志的方式
'handlers': {
# 默认记录所有日志
'default': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(log_path, 'all-{}.log'.format(time.strftime('%Y-%m-%d'))),
'maxBytes': 1024 * 1024 * 5, # 文件大小
'backupCount': 5, # 备份数
'formatter': 'standard', # 输出格式
'encoding': 'utf-8', # 设置默认编码,否则打印出来汉字乱码
},
'logstash': {
'level': 'INFO',
'class': 'logstash.TCPLogstashHandler',
'host': 'localhost',
'port': 4560, # Default value: 5959
'version': 1, # Version of logstash event schema. Default value: 0 (for backward compatibility of the library)
'message_type': 'django', # 'type' field in logstash message. Default value: 'logstash'.
'fqdn': False, # Fully qualified domain name. Default value: false.
'tags': ['django.request'], # list of tags. Default: None.
},
# 输出错误日志
'error': {
'level': 'ERROR',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(log_path, 'error-{}.log'.format(time.strftime('%Y-%m-%d'))),
'maxBytes': 1024 * 1024 * 5, # 文件大小
'backupCount': 5, # 备份数
'formatter': 'standard', # 输出格式
'encoding': 'utf-8', # 设置默认编码
},
# 控制台输出
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'standard'
},
# 输出info日志
'info': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(log_path, 'info-{}.log'.format(time.strftime('%Y-%m-%d'))),
'maxBytes': 1024 * 1024 * 5,
'backupCount': 5,
'formatter': 'standard',
'encoding': 'utf-8', # 设置默认编码
},
},
# 配置用哪几种 handlers 来处理日志
'loggers': {
# root logger 默认调用
'': {
'handlers': ['logstash'],
'level': 'INFO',
'propagate': True
},
# 类型 为 django 处理所有类型的日志, 默认调用
'django': {
'handlers': ['default', 'console'],
'level': 'INFO',
'propagate': True
},
# log 调用时需要当作参数传入
'log': {
'handlers': ['error', 'info', 'console', 'default'],
'level': 'INFO',
'propagate': True
},
}
}
-
ELK 的基本使用
-
创建索引
进入 ELK 后,点击左下角设置按钮,再点击 Index Patterns,最后点击右上角的 Create index pattern 按钮,即可创建索引了。
-
搜索日志
创建好索引后,接着点击左上角 discover 按钮,再选择我们创建的索引 logstash,然后添加一些过滤条件,即可搜索对应日志。
http://192.168.10.102:5601/goto/c1a3cde2acf09533f717b9c34c8c4aef
-
Django 日志中添加 trace id
Django 日志中,添加 trace id,实现链路追踪,能方便我们快速排查问题,大大提升发现问题,解决问题的效率。参考 https://zzun.app/repo/JonasKs-django-guid-python-django-utilities 的操作,以下为添加trace id 所需的操作步骤。
-
安装依赖
pip install django-guid
-
设置 setting.py
DJANGO_GUID = {
'GUID_HEADER_NAME': 'Correlation-ID',
'VALIDATE_GUID': True,
'RETURN_HEADER': True,
'EXPOSE_HEADER': True,
'INTEGRATIONS': [],
'IGNORE_URLS': [],
'UUID_LENGTH': 32,
}
# installed_app 里需要添加 django_guid 应用
INSTALLED_APPS = [
...
'django_guid',
]
# 中间件里需要添加 guid 的中间件,最好放在最开头,这样尽可能多的日志里会加上 trace id
MIDDLEWARE = [
'django_guid.middleware.guid_middleware',
...
]
#
LOGGING = {
...
'formatters': {
# 日志格式
'standard': {
'format': '[%(correlation_id)s][%(asctime)s] [%(filename)s:%(lineno)d] [%(module)s:%(funcName)s] '
'[%(levelname)s]- %(message)s'},
'simple': { # 简单格式
'format': '%(levelname)s %(message)s'
},
},
# 过滤
'filters': {
'correlation_id': {
'()': 'django_guid.log_filters.CorrelationId'
}
},
'handlers': {
# 默认记录所有日志
'default': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(log_path, 'all-{}.log'.format(time.strftime('%Y-%m-%d'))),
'maxBytes': 1024 * 1024 * 5, # 文件大小
'backupCount': 5, # 备份数
'formatter': 'standard', # 输出格式
'encoding': 'utf-8', # 设置默认编码,否则打印出来汉字乱码
'filters': ['correlation_id'],
},
'logstash': {
'level': 'INFO',
'class': 'logstash.TCPLogstashHandler',
'host': 'localhost',
'port': 4560, # Default value: 5959
'version': 1, # Version of logstash event schema. Default value: 0 (for backward compatibility of the library)
'message_type': 'django', # 'type' field in logstash message. Default value: 'logstash'.
'fqdn': False, # Fully qualified domain name. Default value: false.
'tags': ['django.request'], # list of tags. Default: None.
},
}
}
-
打印日志
import logging
logger = logging.getLogger('log')
class UserViewSet(viewsets.ModelViewSet):
"""
允许用户查看或编辑的API路径。
"""
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
def list(self, request, *args, **kwargs):
logger.info('welcome to django list')
user.test_log()
return super().list(request, *args, **kwargs)
import logging
logger = logging.getLogger('django')
def test_log():
logger.warning('test log trace id print')
try:
x = 1 / 0
logger.info(f'{x=}')
except Exception as e:
logger.exception(f'except:{str(e)}')
-
请求接口并查看日志
请求 Django 的接口,并找到 response header 中的 Correlation-ID。
打开 Kibana,搜索 Correlation-ID。如果找不到,则可能需要在 Kibana 上更新我们的日志索引。
在 Kibana 上更新我们的日志索引步骤:左下角设置按钮->Index Pattern->refresh filed list.
-
Django 接入 ELK APM
两步走,先搭建 APM server,再根据情况,接入 APM agent。
http://192.168.10.102:5601/app/kibana#/home/tutorial/apm
-
搭建 APM server
# Download and unpack APM Server
curl -L -O https://artifacts.elastic.co/downloads/apm-server/apm-server-7.7.0-amd64.deb
sudo dpkg -i apm-server-7.7.0-amd64.deb
# Edit the configuration,default config file is /etc/apm-server/apm-server.yml
output.elasticsearch:
hosts: ["localhost:9200"]
# 账号密码不需要也可以
# username: <username>
# password: <password>
# 开启防火墙
sudo ufw allow 8200
# 后台运行 apm server,运行时可能会出现错误 Exiting: error loading config file: config file ("/etc/apm-server/apm-server.yml") can only be writable by the owner but the permissions are "-rwxrwxrwx" (to fix the permissions use: 'chmod go-w /etc/apm-server/apm-server.yml')
sudo apm-server &
# 检查 APM server 状态
-
Django 接入 APM agent
# Install the APM agent
pip install elastic-apm
# Configure the agent
# Add the agent to the installed apps
INSTALLED_APPS = (
'elasticapm.contrib.django',
# ...
)
ELASTIC_APM = {
# Set required service name. Allowed characters:
# a-z, A-Z, 0-9, -, _, and space
'SERVICE_NAME': '',
# Use if APM Server requires a token
'SECRET_TOKEN': '',
# Set custom APM Server URL (default: http://localhost:8200)
'SERVER_URL': '',
}
# To send performance metrics, add our tracing middleware:
MIDDLEWARE = (
'elasticapm.contrib.django.middleware.TracingMiddleware',
#...
)
#
-
参考资料
安装 Docker 和 Docker Compose (Ubuntu)
访问Vmware中的服务不爱debug的BugMaker的博客-CSDN博客访问vmware服务
Python 修改 pip 源为国内源 - 137point5 - 博客园
Elasticsearch:如何在 Django 中使用 Elasticsearch_Elastic 中国社区官方博客的博客-CSDN博客_django使用elasticsearch
Inject an ID into every log message from a Django request. ASGI compatible, integrates with Sentry,