ソースを参照

fluentd 日志修改

袁威 2 週間 前
コミット
ba1c391e50
3 ファイル変更51 行追加73 行削除
  1. 19 12
      .env
  2. 11 6
      app/core/config.py
  3. 21 55
      app/core/logger.py

+ 19 - 12
.env

@@ -2,26 +2,33 @@
 TEST_DATA=测试成功123abc
 TEST_DATA=测试成功123abc
 
 
 # 服务端口
 # 服务端口
-SERVER_PORT = 7755
+SERVER_PORT=7755
+LOG_LEVEL=INFO
 
 
 # 数据库配置
 # 数据库配置
-DB_USER = root
-DB_PASSWORD = 123456
-DB_HOST = 127.0.0.1
-DB_NAME = card_score_gray_database
+DB_USER=root
+DB_PASSWORD=123456
+DB_HOST=192.168.77.249
+DB_PORT=3306
+DB_NAME=card_score_gray_database
 
 
 # MinIO 配置
 # MinIO 配置
-MINIO_ENDPOINT = 192.168.77.249:9000
-MINIO_ACCESS_KEY = pZEwCGnpNN05KPnmC2Yh
-MINIO_SECRET_KEY = KfJRuWiv9pVxhIMcFqbkv8hZT9SnNTZ6LPx592D4
-MINIO_SECURE = false
-MINIO_BUCKET = grading
-MINIO_BASE_PREFIX = score_server_data
+MINIO_ENDPOINT=192.168.77.249:9000
+MINIO_ACCESS_KEY=pZEwCGnpNN05KPnmC2Yh
+MINIO_SECRET_KEY=KfJRuWiv9pVxhIMcFqbkv8hZT9SnNTZ6LPx592D4
+MINIO_SECURE=false
+MINIO_BUCKET=grading
+MINIO_BASE_PREFIX=score_server_data
 
 
 # 分数计算接口url
 # 分数计算接口url
-SCORE_UPDATE_SERVER_URL = http://192.168.77.249:7754
+SCORE_UPDATE_SERVER_URL=http://192.168.77.249:7754
 
 
+# Fluentd 日志配置
 FLUENTD_ENABLED=true
 FLUENTD_ENABLED=true
+# 本机 Fluentd 用 127.0.0.1;服务器环境改成 fluentd 服务地址(例如 fluentd-aggr1)
 FLUENTD_HOST=127.0.0.1
 FLUENTD_HOST=127.0.0.1
 FLUENTD_PORT=24224
 FLUENTD_PORT=24224
 FLUENTD_TAG=card_score.server
 FLUENTD_TAG=card_score.server
+FLUENTD_TAG_PREFIX=python
+# 可选:不填则自动使用机器 HOSTNAME
+# FLUENTD_HOSTNAME=card-score-data-server-01

+ 11 - 6
app/core/config.py

@@ -1,8 +1,7 @@
 from pathlib import Path
 from pathlib import Path
-from typing import Dict, List
-from enum import Enum
+from typing import Dict
 from typing import ClassVar
 from typing import ClassVar
-import json
+import socket
 from pydantic_settings import BaseSettings, SettingsConfigDict
 from pydantic_settings import BaseSettings, SettingsConfigDict
 
 
 
 
@@ -18,6 +17,7 @@ class Settings(BaseSettings):
     SERVER_PORT:int = 7755
     SERVER_PORT:int = 7755
     APP_NAME: str = "card-score-data-server"
     APP_NAME: str = "card-score-data-server"
     APP_ENV: str = "dev"
     APP_ENV: str = "dev"
+    LOG_LEVEL: str = "INFO"
 
 
     # --- MinIO 配置 ---
     # --- MinIO 配置 ---
     MINIO_ENDPOINT: str = "192.168.77.249:9000"
     MINIO_ENDPOINT: str = "192.168.77.249:9000"
@@ -42,11 +42,18 @@ class Settings(BaseSettings):
 
 
     # --- Fluentd 日志配置 ---
     # --- Fluentd 日志配置 ---
     FLUENTD_ENABLED: bool = False
     FLUENTD_ENABLED: bool = False
-    FLUENTD_HOST: str = "127.0.0.1"
+    FLUENTD_HOST: str = "fluentd"
     FLUENTD_PORT: int = 24224
     FLUENTD_PORT: int = 24224
     FLUENTD_TAG: str = "card_score.server"
     FLUENTD_TAG: str = "card_score.server"
+    FLUENTD_TAG_PREFIX: str = "python"
+    FLUENTD_HOSTNAME: str = ""
     FLUENTD_TIMEOUT_SEC: float = 3.0
     FLUENTD_TIMEOUT_SEC: float = 3.0
 
 
+    @property
+    def FLUENTD_EFFECTIVE_TAG(self) -> str:
+        host = self.FLUENTD_HOSTNAME or socket.gethostname()
+        return f"{self.FLUENTD_TAG_PREFIX}.{self.FLUENTD_TAG}.{host}"
+
     @property
     @property
     def SCORE_RECALCULATE_ENDPOINT(self) -> str:
     def SCORE_RECALCULATE_ENDPOINT(self) -> str:
         return f"{self.SCORE_UPDATE_SERVER_URL}/api/card_score/score_recalculate"
         return f"{self.SCORE_UPDATE_SERVER_URL}/api/card_score/score_recalculate"
@@ -103,5 +110,3 @@ class Settings(BaseSettings):
 
 
 
 
 settings = Settings()
 settings = Settings()
-print("测试读取env", settings.TEST_DATA)
-print("测试拼接env", settings.TEST_DATA_END)

+ 21 - 55
app/core/logger.py

@@ -1,7 +1,5 @@
 import logging
 import logging
 import sys
 import sys
-import json
-from datetime import datetime, timezone
 from typing import Optional
 from typing import Optional
 
 
 from app.core.config import settings
 from app.core.config import settings
@@ -11,30 +9,6 @@ try:
 except Exception:  # pragma: no cover - 运行时兜底
 except Exception:  # pragma: no cover - 运行时兜底
     fluent_handler = None
     fluent_handler = None
 
 
-class JsonLogFormatter(logging.Formatter):
-    """
-    将日志格式化为 JSON(每行一条),便于 Fluentd/ELK 检索。
-    """
-
-    def format(self, record: logging.LogRecord) -> str:
-        log_obj = {
-            "timestamp": datetime.now(timezone.utc).isoformat(timespec="milliseconds"),
-            "level": record.levelname,
-            "logger": record.name,
-            "message": record.getMessage(),
-            "module": record.module,
-            "funcName": record.funcName,
-            "lineNo": record.lineno,
-            "app": settings.APP_NAME,
-            "env": settings.APP_ENV
-        }
-
-        if record.exc_info:
-            log_obj["exception"] = self.formatException(record.exc_info)
-
-        return json.dumps(log_obj, ensure_ascii=False)
-
-
 def _build_fluent_handler() -> Optional[logging.Handler]:
 def _build_fluent_handler() -> Optional[logging.Handler]:
     """
     """
     创建 Fluentd Handler。
     创建 Fluentd Handler。
@@ -48,28 +22,24 @@ def _build_fluent_handler() -> Optional[logging.Handler]:
 
 
     try:
     try:
         fh = fluent_handler.FluentHandler(
         fh = fluent_handler.FluentHandler(
-            tag=settings.FLUENTD_TAG,
+            tag=settings.FLUENTD_EFFECTIVE_TAG,
             host=settings.FLUENTD_HOST,
             host=settings.FLUENTD_HOST,
             port=settings.FLUENTD_PORT,
             port=settings.FLUENTD_PORT,
             timeout=settings.FLUENTD_TIMEOUT_SEC
             timeout=settings.FLUENTD_TIMEOUT_SEC
         )
         )
-        # 给 Fluentd 输出结构化字段(dict),避免 record 退化为 string。
-        # 这里不能使用普通 logging.Formatter,否则会变成纯文本。
+        # 输出结构化字段,避免 record 退化为 string。
         if hasattr(fluent_handler, "FluentRecordFormatter"):
         if hasattr(fluent_handler, "FluentRecordFormatter"):
             fh.setFormatter(fluent_handler.FluentRecordFormatter({
             fh.setFormatter(fluent_handler.FluentRecordFormatter({
-                "timestamp": "%(asctime)s",
                 "level": "%(levelname)s",
                 "level": "%(levelname)s",
                 "logger": "%(name)s",
                 "logger": "%(name)s",
                 "message": "%(message)s",
                 "message": "%(message)s",
-                "module": "%(module)s",
-                "funcName": "%(funcName)s",
-                "lineNo": "%(lineno)d",
+                "time": "%(asctime)s",
                 "app": settings.APP_NAME,
                 "app": settings.APP_NAME,
-                "env": settings.APP_ENV
+                "env": settings.APP_ENV,
             }))
             }))
         return fh
         return fh
     except Exception as e:
     except Exception as e:
-        logging.getLogger(__name__).error(f"初始化 Fluentd Handler 失败: {e}")
+        logging.getLogger(__name__).exception("初始化 Fluentd Handler 失败: %s", str(e))
         return None
         return None
 
 
 
 
@@ -78,42 +48,38 @@ def setup_logging():
     配置日志系统,使其同时输出到文件和控制台。
     配置日志系统,使其同时输出到文件和控制台。
     这个函数应该在应用程序启动时只调用一次。
     这个函数应该在应用程序启动时只调用一次。
     """
     """
-    # 获取根日志记录器
     root_logger = logging.getLogger()
     root_logger = logging.getLogger()
-    root_logger.setLevel(logging.INFO)  # 设置根日志记录器的级别
 
 
-    # 如果已经有处理器,先清空,防止重复添加
-    if root_logger.hasHandlers():
-        root_logger.handlers.clear()
+    # 避免重复初始化
+    if root_logger.handlers:
+        return
+
+    root_logger.setLevel(getattr(logging, settings.LOG_LEVEL.upper(), logging.INFO))
 
 
-    # 创建 JSON 格式化器(用于控制台与本地文件)
-    formatter = JsonLogFormatter()
+    stream_formatter = logging.Formatter("%(asctime)s %(levelname)s [%(name)s] %(message)s")
+    file_formatter = logging.Formatter("%(asctime)s %(levelname)s [%(name)s] %(message)s")
 
 
-    # 1. 创建控制台处理器 (StreamHandler)
-    #    - 将日志输出到标准输出(您的终端)
     console_handler = logging.StreamHandler(sys.stdout)
     console_handler = logging.StreamHandler(sys.stdout)
-    console_handler.setFormatter(formatter)
+    console_handler.setFormatter(stream_formatter)
     root_logger.addHandler(console_handler)
     root_logger.addHandler(console_handler)
 
 
-    # 2. 创建文件处理器 (FileHandler)
-    #    - 将日志写入文件 app.log
-    #    - mode='w' 表示每次启动都覆盖旧日志
-    #    - encoding='utf-8' 确保正确处理中文字符
     file_handler = logging.FileHandler('app.log', mode='w', encoding='utf-8')
     file_handler = logging.FileHandler('app.log', mode='w', encoding='utf-8')
-    file_handler.setFormatter(formatter)
+    file_handler.setFormatter(file_formatter)
     root_logger.addHandler(file_handler)
     root_logger.addHandler(file_handler)
 
 
-    # 3. 可选:创建 Fluentd 处理器 (fluent-logger)
+    if not settings.FLUENTD_ENABLED:
+        root_logger.info("日志系统已成功配置,将输出到控制台和 app.log 文件。")
+        return
+
     fluentd_handler = _build_fluent_handler()
     fluentd_handler = _build_fluent_handler()
     if fluentd_handler:
     if fluentd_handler:
         root_logger.addHandler(fluentd_handler)
         root_logger.addHandler(fluentd_handler)
-        logging.info(
+        root_logger.info(
             "Fluentd日志输出已启用: host=%s port=%s tag=%s",
             "Fluentd日志输出已启用: host=%s port=%s tag=%s",
-            settings.FLUENTD_HOST, settings.FLUENTD_PORT, settings.FLUENTD_TAG
+            settings.FLUENTD_HOST, settings.FLUENTD_PORT, settings.FLUENTD_EFFECTIVE_TAG
         )
         )
 
 
-    # 配置完成后,可以记录一条消息来确认
-    logging.info("日志系统已成功配置,将同时输出到控制台和 app.log 文件。")
+    root_logger.info("日志系统已成功配置,将输出到控制台和 app.log 文件。")
 
 
 
 
 def get_logger(name: str) -> logging.Logger:
 def get_logger(name: str) -> logging.Logger: