Skip to content

Commit 0a02471

Browse files
committed
feat: integrate grafana loki
1 parent ce4234b commit 0a02471

6 files changed

+135
-75
lines changed

Diff for: FasterRunner/log.py

+43
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
88

99
import logging
10+
from datetime import datetime
11+
12+
from django.conf import settings
13+
14+
from FasterRunner.mycelery import app
1015

1116

1217
class DatabaseLogHandler(logging.Handler):
@@ -18,3 +23,41 @@ def emit(self, record: logging.LogRecord) -> None:
1823
level=record.levelname,
1924
message=self.format(record),
2025
)
26+
27+
28+
class LokiHandler(logging.Handler):
29+
def __init__(self):
30+
super().__init__()
31+
self.loki_url = settings.LOKI_URL or ''
32+
self.loki_username = settings.LOKI_USERNAME
33+
self.loki_password = settings.LOKI_PASSWORD
34+
35+
def emit(self, record):
36+
log_entry = self.format(record)
37+
self.send_to_loki(log_entry, record.levelname.lower(), record.request_id)
38+
39+
def send_to_loki(self, log_entry, level, trace_id: str):
40+
if not self.loki_url or not self.loki_username or not self.loki_username:
41+
return
42+
data = {
43+
"streams": [
44+
{
45+
"stream": {
46+
"level": level,
47+
"job": "fastrunner",
48+
"traceID": trace_id,
49+
},
50+
"values": [
51+
[str(int(datetime.now().timestamp() * 1e9)), log_entry]
52+
]
53+
}
54+
]
55+
}
56+
try:
57+
kwargs = {
58+
'loki_url': self.loki_url, 'data': data, 'loki_username': self.loki_username,
59+
'loki_password': self.loki_password
60+
}
61+
app.send_task(name="system.tasks.send_log_to_loki", args=[], kwargs=kwargs)
62+
except Exception as e:
63+
logging.error(str(e))

Diff for: FasterRunner/settings/base.py

+22-8
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,17 @@
229229
rotation="00:00",
230230
retention="14 days",
231231
)
232-
232+
handlers = ["default", "console", "error", "db", "loki"]
233233
LOGGING = {
234234
"version": 1,
235235
"disable_existing_loggers": True,
236236
"formatters": {
237237
"standard": {
238238
"format": "%(levelname)-2s [%(asctime)s] [%(request_id)s] %(name)s [%(filename)s->%(funcName)s:%(lineno)s]: %(message)s",
239239
},
240+
"loki": {
241+
"format": "%(levelname)-2s [%(request_id)s] %(name)s [%(filename)s->%(funcName)s:%(lineno)s]: %(message)s",
242+
},
240243
"color": {
241244
"()": "colorlog.ColoredFormatter",
242245
"format": "%(green)s%(asctime)s [%(request_id)s] %(name)s %(log_color)s%(levelname)s [pid:%(process)d] "
@@ -294,42 +297,49 @@
294297
"formatter": "standard",
295298
"class": "FasterRunner.log.DatabaseLogHandler", # 指向你的自定义处理器
296299
},
300+
301+
'loki': {
302+
'level': 'INFO',
303+
'class': 'FasterRunner.log.LokiHandler',
304+
"formatter": "loki",
305+
},
306+
297307
},
298308
"loggers": {
299309
"django": {
300-
"handlers": ["default", "console", "error", "db"],
310+
"handlers": handlers,
301311
"level": "INFO",
302312
"propagate": True,
303313
},
304314

305315
'django.db.backends': {
306316
'level': 'DEBUG',
307-
'handlers': ['console'],
317+
'handlers': ['console', 'loki'],
308318
"propagate": False,
309319
},
310320

311321
"fastrunner": {
312-
"handlers": ["default", "console", "error", "db"],
322+
"handlers": handlers,
313323
"level": "INFO",
314324
"propagate": True,
315325
},
316326
"httprunner": {
317-
"handlers": ["default", "console", "error", "db"],
327+
"handlers": handlers,
318328
"level": "INFO",
319329
"propagate": True,
320330
},
321331
"fastuser": {
322-
"handlers": ["default", "console", "error", "db"],
332+
"handlers": handlers,
323333
"level": "INFO",
324334
"propagate": True,
325335
},
326336
"mock": {
327-
"handlers": ["default", "console", "error", "db"],
337+
"handlers": handlers,
328338
"level": "INFO",
329339
"propagate": True,
330340
},
331341
"django_auth_ldap": {
332-
"handlers": ["default", "console", "error", "db"],
342+
"handlers": handlers,
333343
"level": "INFO",
334344
"propagate": True,
335345
},
@@ -385,3 +395,7 @@
385395

386396
# mock配置, 如果是性能测试环境,就设置为1,会关闭写日志, db
387397
IS_PERF = os.environ.get("IS_PERF", "0")
398+
399+
LOKI_URL = os.environ.get("LOKI_URL") or "https://logs-prod3.grafana.net/loki/api/v1/push"
400+
LOKI_USERNAME = os.environ.get('LOKI_USERNAME', '')
401+
LOKI_PASSWORD = os.environ.get('LOKI_PASSWORD', '')

Diff for: docker-compose-build-db-mq.yml

+23-22
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,45 @@ version: '3.8'
33
# 用来构建db和mq,因为这两个组件几乎不会有改动,所以单独抽离出来
44
# db会默认初始化一些演示的数据, sql文件在db/init.sql
55

6-
x-env: &env
7-
# db
8-
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
6+
x-env-db: &env_db
97
MYSQL_DATABASE: ${MYSQL_DATABASE}
108
MYSQL_USER: ${MYSQL_USER}
119
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
12-
MYSQL_PORT_OUT: ${MYSQL_PORT_OUT:-3306}
10+
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
11+
MYSQL_HOST: ${MYSQL_HOST:-db}
12+
MYSQL_PORT: ${MYSQL_PORT:-3306}
1313

14-
# mq
14+
x-env-mq: &env_mq
1515
RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER}
1616
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS}
1717
MQ_PORT: ${MQ_PORT}
1818
MQ_HOST: ${MQ_HOST:-mq}
1919
MQ_ADMIN_PORT: ${MQ_ADMIN_PORT}
20+
MQ_VHOST: ${MQ_VHOST:-/}
2021

2122
services:
22-
# db:
23-
# #image: mysql:8.0.21
24-
# image: mariadb:10.6.1
25-
# # privileged: true
26-
# environment:
27-
# # 设置默认数据库和root默认密码,如果宿主机中/var/lib/mysql已经存在,这两个设置都不会生效
28-
# <<: *env
29-
# volumes:
30-
## - "/var/lib/mysql:/var/lib/mysql" # 挂载宿主机的mysql数据到docker中
31-
# - ./db/my.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
32-
# - ./db:/docker-entrypoint-initdb.d/:ro
33-
# # 端口映射,格式 宿主机端口:容器端口
34-
# ports:
35-
# - "${MYSQL_PORT_OUT}:3306"
36-
# restart: always
37-
# command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
23+
db:
24+
#image: mysql:8.0.21
25+
image: mariadb:10.6.1
26+
# privileged: true
27+
environment:
28+
# 设置默认数据库和root默认密码,如果宿主机中/var/lib/mysql已经存在,这两个设置都不会生效
29+
<<: *env_db
30+
volumes:
31+
# - "/var/lib/mysql:/var/lib/mysql" # 挂载宿主机的mysql数据到docker中
32+
- ./db/my.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
33+
- ./db:/docker-entrypoint-initdb.d/:ro
34+
# 端口映射,格式 宿主机端口:容器端口
35+
ports:
36+
- "${MYSQL_PORT_OUT}:3306"
37+
restart: always
38+
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
3839

3940

4041
mq:
4142
image: rabbitmq:management-alpine
4243
environment:
43-
<<: *env
44+
<<: *env_mq
4445
restart: always
4546
ports:
4647
- "${MQ_ADMIN_PORT}:15672"

Diff for: docker-compose-for-fastup.yml

+18-18
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,40 @@ version: '3.8'
44
# 默认会拉取dockerhub最新的镜像,不会用到本地的代码构建
55
# 仅适用想快速体验测试平台和一直使用最新版的用户,不适合二开
66

7-
x-env: &env
8-
# db
7+
x-env-db: &env_db
98
MYSQL_DATABASE: ${MYSQL_DATABASE}
109
MYSQL_USER: ${MYSQL_USER}
1110
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
1211
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
1312
MYSQL_HOST: ${MYSQL_HOST:-db}
1413
MYSQL_PORT: ${MYSQL_PORT:-3306}
1514

16-
# mq
15+
x-env-mq: &env_mq
1716
RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER}
1817
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS}
1918
MQ_PORT: ${MQ_PORT}
2019
MQ_HOST: ${MQ_HOST:-mq}
2120
MQ_ADMIN_PORT: ${MQ_ADMIN_PORT}
2221
MQ_VHOST: ${MQ_VHOST:-/}
2322

24-
# celery-worker
23+
x-env-celery: &env_celery
2524
SERVER_IP: ${SERVER_IP}
2625
DJANGO_API_PORT: ${DJANGO_API_PORT}
2726

28-
# app
27+
x-env-app: &env_app
2928
EMAIL_HOST: ${EMAIL_HOST}
3029
EMAIL_PORT: ${EMAIL_PORT}
3130
EMAIL_HOST_USER: ${EMAIL_HOST_USER}
3231
EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD}
32+
LOKI_USERNAME: ${LOKI_USERNAME}
33+
LOKI_PASSWORD: ${LOKI_PASSWORD}
34+
LOKI_URL: ${LOKI_URL}
3335

3436
services:
3537
app:
3638
image: rikasai/fast-runner-backend:latest
3739
environment:
38-
<<: *env
40+
<<: [*env_db, *env_celery, *env_app, *env_mq]
3941
entrypoint: /app/start.sh
4042
command: "app"
4143
restart: always
@@ -46,23 +48,25 @@ services:
4648
celery-worker:
4749
image: rikasai/fast-runner-backend:latest
4850
environment:
49-
<<: *env
51+
<<: [*env_db, *env_celery, *env_app, *env_mq]
5052
entrypoint: /app/start.sh
5153
command: "celery-worker"
5254
restart: always
55+
depends_on:
56+
- db
57+
- mq
5358

5459
celery-beat:
5560
image: rikasai/fast-runner-backend:latest
5661
environment:
57-
<<: *env
62+
<<: [*env_db, *env_celery, *env_app, *env_mq]
5863
entrypoint: /app/start.sh
5964
command: "celery-beat"
6065
restart: always
6166
depends_on:
6267
- db
6368
- mq
6469

65-
# django-admin & app proxy
6670
nginx:
6771
build: ./nginx-remote
6872
ports:
@@ -71,7 +75,8 @@ services:
7175
- app
7276
restart: always
7377
environment:
74-
<<: *env
78+
<<: *env_app
79+
7580
web:
7681
image: rikasai/fast-runner-frontend:latest
7782
ports:
@@ -80,17 +85,12 @@ services:
8085
- app
8186

8287
db:
83-
#image: mysql:8.0.21
8488
image: mariadb:10.6.1
85-
# privileged: true
8689
environment:
87-
# 设置默认数据库和root默认密码,如果宿主机中/var/lib/mysql已经存在,这两个设置都不会生效
88-
<<: *env
90+
<<: *env_db
8991
volumes:
90-
# - "/var/lib/mysql:/var/lib/mysql" # 挂载宿主机的mysql数据到docker中
9192
- ./db/my.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
9293
- ./db:/docker-entrypoint-initdb.d/:ro
93-
# 端口映射,格式 宿主机端口:容器端口
9494
ports:
9595
- "${MYSQL_PORT_OUT}:3306"
9696
restart: always
@@ -99,8 +99,8 @@ services:
9999
mq:
100100
image: rabbitmq:management-alpine
101101
environment:
102-
<<: *env
103-
restart: always
102+
<<: *env_mq
104103
ports:
105104
- "${MQ_ADMIN_PORT}:15672"
106105
- "${MQ_PORT}:5672"
106+
restart: always

Diff for: docker-compose-without-db-mq.yml

+12-15
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,28 @@ version: '3.8'
55
# 可以搭配docker-compose-build-db—mq使用
66
# 或者已有mq和db也是OK的
77

8-
x-env: &env
9-
# db
10-
MYSQL_DATABASE: ${MYSQL_DATABASE}
11-
MYSQL_USER: ${MYSQL_USER}
12-
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
13-
MYSQL_HOST: ${MYSQL_HOST:-db}
14-
MYSQL_PORT: ${MYSQL_PORT:-3306}
15-
# mq
8+
9+
10+
x-env-mq: &env_mq
1611
RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER}
1712
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS}
1813
MQ_PORT: ${MQ_PORT}
1914
MQ_HOST: ${MQ_HOST:-mq}
2015
MQ_ADMIN_PORT: ${MQ_ADMIN_PORT}
2116
MQ_VHOST: ${MQ_VHOST:-/}
2217

23-
# celery-worker
18+
x-env-celery: &env_celery
2419
SERVER_IP: ${SERVER_IP}
2520
DJANGO_API_PORT: ${DJANGO_API_PORT}
2621

27-
# app
22+
x-env-app: &env_app
2823
EMAIL_HOST: ${EMAIL_HOST}
2924
EMAIL_PORT: ${EMAIL_PORT}
3025
EMAIL_HOST_USER: ${EMAIL_HOST_USER}
3126
EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD}
27+
LOKI_USERNAME: ${LOKI_USERNAME}
28+
LOKI_PASSWORD: ${LOKI_PASSWORD}
29+
LOKI_URL: ${LOKI_URL}
3230

3331
services:
3432
app:
@@ -40,7 +38,7 @@ services:
4038
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.tuna.tsinghua.edu.cn/simple}
4139
DEBIAN_REPO: ${DEBIAN_REPO:-mirrors.aliyun.com}
4240
environment:
43-
<<: *env
41+
<<: [*env_celery, *env_app, *env_mq]
4442
entrypoint: /app/start.sh
4543
command: "app"
4644
restart: always
@@ -53,7 +51,7 @@ services:
5351
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.tuna.tsinghua.edu.cn/simple}
5452
DEBIAN_REPO: ${DEBIAN_REPO:-mirrors.aliyun.com}
5553
environment:
56-
<<: *env
54+
<<: [*env_celery, *env_app, *env_mq]
5755
entrypoint: /app/start.sh
5856
command: "celery-worker"
5957
restart: always
@@ -66,8 +64,7 @@ services:
6664
PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.tuna.tsinghua.edu.cn/simple}
6765
DEBIAN_REPO: ${DEBIAN_REPO:-mirrors.aliyun.com}
6866
environment:
69-
<<: *env
70-
entrypoint: /app/start.sh
67+
<<: [*env_celery, *env_app, *env_mq]
7168
command: "celery-beat"
7269
restart: always
7370

@@ -80,7 +77,7 @@ services:
8077
- app
8178
restart: always
8279
environment:
83-
<<: *env
80+
<<: [*env_celery, *env_app, *env_mq]
8481
web:
8582
build:
8683
context: ./web

0 commit comments

Comments
 (0)