From 1e5bf43aab2aa2c5324fde4ea43701ffda2d2b38 Mon Sep 17 00:00:00 2001 From: dbswjd7 Date: Mon, 2 Feb 2026 17:08:36 +0900 Subject: [PATCH] =?UTF-8?q?feat(#284):=20=EB=A1=9C=EA=B7=B8=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=B4=ED=94=84=EB=9D=BC=EC=9D=B8=20=EA=B5=AC=EC=B6=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yaml | 64 ++++++++++ observability/fluent-bit/fluent-bit.conf | 18 +++ observability/grafana/dashboards/loki.json | 89 ++++++++++++++ .../grafana/dashboards/spring-gateway.json | 116 ++++++++++++++++++ observability/grafana/grafana.ini | 6 + test.sh | 6 +- 6 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 observability/fluent-bit/fluent-bit.conf create mode 100644 observability/grafana/dashboards/loki.json create mode 100644 observability/grafana/dashboards/spring-gateway.json create mode 100644 observability/grafana/grafana.ini diff --git a/docker-compose.yaml b/docker-compose.yaml index 684ccc2d..10310e74 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -87,6 +87,7 @@ services: - ./config/common.yml:/config/common.yml:ro - ./config/spot-gateway.yml:/config/application.yml:ro depends_on: + - fluent-bit - redis - spot-user - spot-store @@ -94,6 +95,11 @@ services: - spot-payment networks: - spot-network + logging: + driver: fluentd + options: + fluentd-address: 127.0.0.1:24224 + tag: spot-gateway spot-order: build: @@ -112,11 +118,17 @@ services: - ./config/kafka-topics.yml:/config/kafka-topics.yml:ro - ./config/spot-order.yml:/config/application.yml:ro depends_on: + - fluent-bit - db - redis - kafka networks: - spot-network + logging: + driver: fluentd + options: + fluentd-address: 127.0.0.1:24224 + tag: spot-order spot-payment: build: @@ -135,11 +147,17 @@ services: - ./config/kafka-topics.yml:/config/kafka-topics.yml:ro - ./config/spot-payment.yml:/config/application.yml:ro depends_on: + - fluent-bit - db - redis - kafka networks: - spot-network + logging: + driver: fluentd + options: + fluentd-address: 127.0.0.1:24224 + tag: spot-payment spot-store: build: @@ -155,10 +173,16 @@ services: - ./config/common.yml:/config/common.yml:ro - ./config/spot-store.yml:/config/application.yml:ro depends_on: + - fluent-bit - db - redis networks: - spot-network + logging: + driver: fluentd + options: + fluentd-address: 127.0.0.1:24224 + tag: spot-store spot-user: build: @@ -175,10 +199,50 @@ services: - ./config/common.yml:/config/common.yml:ro - ./config/spot-user.yml:/config/application.yml:ro depends_on: + - fluent-bit - db - redis networks: - spot-network + logging: + driver: fluentd + options: + fluentd-address: 127.0.0.1:24224 + + grafana: + image: grafana/grafana:9.1.2 + container_name: grafana + depends_on: + - loki + ports: + - "3000:3000" + environment: + - GF_SECURITY_ADMIN_USER=user + - GF_SECURITY_ADMIN_PASSWORD=password + volumes: + - ./observability/grafana/datasources:/etc/grafana/provisioning/datasources + - ./observability/grafana/dashboards:/etc/grafana/provisioning/dashboards + - ./observability/grafana/grafana.ini:/etc/grafana/grafana.ini + + loki: + image: grafana/loki:2.6.1 + container_name: loki + depends_on: + - fluent-bit + ports: + - "3100:3100" + + fluent-bit: + image: fluent/fluent-bit:4.0.3 + container_name: fluent-bit + ports: + - "24224:24224" + environment: + - LOKI_URL=http://loki:3100/loki/api/v1/push + volumes: + - ./observability/fluent-bit/fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf + + networks: spot-network: diff --git a/observability/fluent-bit/fluent-bit.conf b/observability/fluent-bit/fluent-bit.conf new file mode 100644 index 00000000..97629bc3 --- /dev/null +++ b/observability/fluent-bit/fluent-bit.conf @@ -0,0 +1,18 @@ +[SERVICE] + Flush 1 + Daemon Off + Log_Level info + +[INPUT] + Name forward + Listen 0.0.0.0 + Port 24224 + +[OUTPUT] + Name loki + Match * + Host loki + Port 3100 + Labels job=fluent-bit + Line_Format json + diff --git a/observability/grafana/dashboards/loki.json b/observability/grafana/dashboards/loki.json new file mode 100644 index 00000000..c362752a --- /dev/null +++ b/observability/grafana/dashboards/loki.json @@ -0,0 +1,89 @@ +{ + "uid": "loki-poc", + "title": "Loki Logs - POC", + "timezone": "browser", + "schemaVersion": 38, + "version": 1, + "refresh": "10s", + "tags": ["loki", "logs", "poc"], + "time": { "from": "now-15m", "to": "now" }, + "templating": { + "list": [ + { + "name": "service", + "type": "query", + "datasource": { "type": "loki", "uid": "loki-thomas-vitale" }, + "refresh": 1, + "query": "label_values({job=\"fluent-bit\"}, container_name)", + "includeAll": true, + "allValue": ".*", + "multi": false, + "current": { "text": "All", "value": "$__all" } + }, + { + "name": "level", + "type": "custom", + "query": "ALL,ERROR,WARN,INFO,DEBUG", + "current": { "text": "ALL", "value": "ALL" } + } + ] + }, + "annotations": { "list": [] }, + "panels": [ + { + "type": "timeseries", + "title": "Error logs / min", + "id": 1, + "datasource": { "type": "loki", "uid": "__default__" }, + "gridPos": { "x": 0, "y": 0, "w": 12, "h": 8 }, + "targets": [ + { + "refId": "A", + "expr": "sum by (container_name) (rate({job=\"fluent-bit\", container_name=~\"$service\"} |~ \"(?i)error\" [1m]))", + "legendFormat": "{{container_name}}" + } + ], + "options": { + "legend": { "showLegend": true, "displayMode": "list", "placement": "bottom" }, + "tooltip": { "mode": "multi" } + } + }, + { + "type": "bargauge", + "title": "Top services by ERROR (last 15m)", + "id": 2, + "datasource": { "type": "loki", "uid": "__default__" }, + "gridPos": { "x": 12, "y": 0, "w": 12, "h": 8 }, + "targets": [ + { + "refId": "A", + "expr": "topk(10, sum by (container_name) (count_over_time({job=\"fluent-bit\", container_name=~\"$service\"} |~ \"(?i)error\" [15m])))", + "legendFormat": "{{container_name}}" + } + ], + "options": { + "displayMode": "basic", + "reduceOptions": { "calcs": ["lastNotNull"], "values": false } + } + }, + { + "type": "logs", + "title": "Recent logs", + "id": 3, + "datasource": { "type": "loki", "uid": "__default__" }, + "gridPos": { "x": 0, "y": 8, "w": 24, "h": 12 }, + "targets": [ + { + "refId": "A", + "expr": "{job=\"fluent-bit\", container_name=~\"$service\"}" + } + ], + "options": { + "showTime": true, + "wrapLogMessage": true, + "prettifyLogMessage": true, + "sortOrder": "Descending" + } + } + ] +} diff --git a/observability/grafana/dashboards/spring-gateway.json b/observability/grafana/dashboards/spring-gateway.json new file mode 100644 index 00000000..81ad2b36 --- /dev/null +++ b/observability/grafana/dashboards/spring-gateway.json @@ -0,0 +1,116 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { "type": "datasource", "uid": "grafana" }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { "limit": 100, "matchAny": false, "tags": [], "type": "dashboard" }, + "type": "dashboard" + } + ] + }, + "description": "Loki-only POC dashboard (logs only)", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 2, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": { "type": "loki", "uid": "loki-thomas-vitale" }, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, + "id": 50, + "panels": [], + "targets": [{ "datasource": { "type": "loki", "uid": "loki-thomas-vitale" }, "refId": "A" }], + "title": "Logs", + "type": "row" + }, + { + "datasource": { "type": "loki", "uid": "loki-thomas-vitale" }, + "gridPos": { "h": 12, "w": 24, "x": 0, "y": 1 }, + "id": 1001, + "options": { + "dedupStrategy": "none", + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": true, + "sortOrder": "Descending", + "wrapLogMessage": true + }, + "targets": [ + { + "datasource": { "type": "loki", "uid": "loki-thomas-vitale" }, + "editorMode": "code", + "expr": "{job=~\"$job\"}", + "queryType": "range", + "refId": "A" + } + ], + "title": "Log Stream", + "type": "logs" + }, + { + "collapsed": false, + "datasource": { "type": "loki", "uid": "loki-thomas-vitale" }, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 13 }, + "id": 51, + "panels": [], + "targets": [{ "datasource": { "type": "loki", "uid": "loki-thomas-vitale" }, "refId": "A" }], + "title": "Notes", + "type": "row" + }, + { + "datasource": { "type": "loki", "uid": "loki-thomas-vitale" }, + "gridPos": { "h": 4, "w": 24, "x": 0, "y": 14 }, + "id": 1002, + "options": { + "content": "POC: Fluent Bit → Loki → Grafana. 이 대시보드는 Loki 로그만 확인합니다.", + "mode": "markdown" + }, + "title": "POC Memo", + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 38, + "tags": [], + "templating": { + "list": [ + { + "current": { "selected": true, "text": "All", "value": ".*" }, + "datasource": { "type": "loki", "uid": "loki-thomas-vitale" }, + "definition": "label_values(job)", + "hide": 0, + "includeAll": true, + "label": "Job", + "multi": true, + "name": "job", + "options": [], + "query": { "query": "label_values(job)", "refId": "StandardVariableQuery" }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { "from": "now-15m", "to": "now" }, + "timepicker": { + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] + }, + "timezone": "", + "title": "Spring Cloud Gateway (Loki Logs Only)", + "uid": "spring-cloud-gateway-loki-logs-only", + "version": 1, + "weekStart": "" +} diff --git a/observability/grafana/grafana.ini b/observability/grafana/grafana.ini new file mode 100644 index 00000000..1bb91819 --- /dev/null +++ b/observability/grafana/grafana.ini @@ -0,0 +1,6 @@ +[analytics] +enabled = false +reporting_enabled = false + +[users] +default_theme = light \ No newline at end of file diff --git a/test.sh b/test.sh index 056af09b..dbab2513 100755 --- a/test.sh +++ b/test.sh @@ -10,6 +10,10 @@ docker volume ls -q | grep "kafka-data" | xargs -r docker volume rm # 컨테이너가 없을 경우 에러 메시지를 숨기기 위해 || true 사용 docker rm -f redis_cache local-postgres_db spot-gateway spot-user spot-store spot-order spot-payment 2>/dev/null || true +echo "=== Observability Stack 먼저 실행 (fluent-bit, loki, grafana) ===" +docker compose up -d fluent-bit loki grafana +sleep 3 + echo "=== 각 MSA 서비스 빌드 ===" for service in spot-gateway spot-user spot-store spot-order spot-payment; do echo ">> $service 빌드 시작" @@ -28,5 +32,5 @@ mkdir -p ./logs LOG_FILE="./logs/current_logs_$(date +'%Y%m%d_%H%M%S').txt" docker compose logs -f | \ - grep --line-buffered -v -E "redis_cache|local-postgres_db" | \ + grep --line-buffered -v -E "redis_cache|local-postgres_db|fluent-bit|loki|grafana" | \ tee -a "$LOG_FILE" \ No newline at end of file