Parcourir la source

新增fluentd的日志服务

袁威 il y a 2 semaines
Parent
commit
141f61656e
8 fichiers modifiés avec 134 ajouts et 4 suppressions
  1. 5 0
      .env
  2. 18 2
      app/api/formate_xy.py
  3. 11 0
      app/core/config.py
  4. 43 0
      app/core/logger.py
  5. 5 2
      app/main.py
  6. 17 0
      docker-compose.yml
  7. 34 0
      fluentd.conf
  8. 1 0
      requirements.txt

+ 5 - 0
.env

@@ -20,3 +20,8 @@ MINIO_BASE_PREFIX = score_server_data
 
 # 分数计算接口url
 SCORE_UPDATE_SERVER_URL = http://192.168.77.249:7754
+
+FLUENTD_ENABLED=true
+FLUENTD_HOST=127.0.0.1
+FLUENTD_PORT=24224
+FLUENTD_TAG=card_score.server

+ 18 - 2
app/api/formate_xy.py

@@ -414,10 +414,18 @@ async def update_image_modified_json(
                 )
             )
         except Exception as e:
+            logger.error(
+                "调用分数计算服务失败(update/json): image_id=%s card_id=%s score_type=%s endpoint=%s error=%s",
+                id, card_id_to_update, score_type, settings.SCORE_RECALCULATE_ENDPOINT, e,
+                exc_info=True
+            )
             raise HTTPException(status_code=500, detail=f"调用分数计算服务失败: {e}")
 
         if response.status_code != 200:
-            logger.error(f"分数计算接口返回错误: {response.status_code}, {response.text}")
+            logger.error(
+                "分数计算接口返回错误(update/json): image_id=%s card_id=%s score_type=%s endpoint=%s status=%s body=%s",
+                id, card_id_to_update, score_type, settings.SCORE_RECALCULATE_ENDPOINT, response.status_code, response.text
+            )
             raise HTTPException(status_code=response.status_code,
                                 detail=f"分数计算接口返回错误: {response.text}")
         logger.info("分数计算完成")
@@ -606,10 +614,18 @@ async def update_gray_image_json(
                 )
             )
         except Exception as e:
+            logger.error(
+                "调用分数计算服务失败(update/json_gray): gray_id=%s ring_id=%s card_id=%s score_type=%s endpoint=%s error=%s",
+                id, ring_image_id, card_id, score_type, settings.SCORE_RECALCULATE_ENDPOINT, e,
+                exc_info=True
+            )
             raise HTTPException(status_code=500, detail=f"调用分数计算服务失败: {e}")
 
         if response.status_code != 200:
-            logger.error(f"分数计算接口返回错误: {response.text}")
+            logger.error(
+                "分数计算接口返回错误(update/json_gray): gray_id=%s ring_id=%s card_id=%s score_type=%s endpoint=%s status=%s body=%s",
+                id, ring_image_id, card_id, score_type, settings.SCORE_RECALCULATE_ENDPOINT, response.status_code, response.text
+            )
             raise HTTPException(status_code=response.status_code,
                                 detail=f"分数计算接口返回错误: {response.text}")
 

+ 11 - 0
app/core/config.py

@@ -16,6 +16,8 @@ class Settings(BaseSettings):
         return f'{self.TEST_DATA}/end'
 
     SERVER_PORT:int = 7755
+    APP_NAME: str = "card-score-data-server"
+    APP_ENV: str = "dev"
 
     # --- MinIO 配置 ---
     MINIO_ENDPOINT: str = "192.168.77.249:9000"
@@ -38,6 +40,13 @@ class Settings(BaseSettings):
     # 分数计算接口url
     SCORE_UPDATE_SERVER_URL: str = "http://127.0.0.1:7754"
 
+    # --- Fluentd 日志配置 ---
+    FLUENTD_ENABLED: bool = False
+    FLUENTD_HOST: str = "127.0.0.1"
+    FLUENTD_PORT: int = 24224
+    FLUENTD_TAG: str = "card_score.server"
+    FLUENTD_TIMEOUT_SEC: float = 3.0
+
     @property
     def SCORE_RECALCULATE_ENDPOINT(self) -> str:
         return f"{self.SCORE_UPDATE_SERVER_URL}/api/card_score/score_recalculate"
@@ -59,6 +68,7 @@ class Settings(BaseSettings):
     DB_USER: str = 'root'
     DB_PASSWORD: str = '123456'
     DB_HOST: str = '127.0.0.1'
+    DB_PORT: int = 3306
 
     @property
     def DATABASE_CONFIG(self) -> Dict[str, str]:
@@ -66,6 +76,7 @@ class Settings(BaseSettings):
             'user': self.DB_USER,
             'password': self.DB_PASSWORD,
             'host': self.DB_HOST,
+            'port': self.DB_PORT,
         }
 
     # 连接到指定数据库的配置

+ 43 - 0
app/core/logger.py

@@ -1,10 +1,44 @@
 import logging
 import sys
+from typing import Optional
+
+from app.core.config import settings
+
+try:
+    from fluent import handler as fluent_handler
+except Exception:  # pragma: no cover - 运行时兜底
+    fluent_handler = None
 
 # 定义一个全局的日志格式
 LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
 
 
+def _build_fluent_handler() -> Optional[logging.Handler]:
+    """
+    创建 Fluentd Handler。
+    若 fluent-logger 未安装或初始化失败,返回 None。
+    """
+    if not settings.FLUENTD_ENABLED:
+        return None
+    if fluent_handler is None:
+        logging.getLogger(__name__).warning("fluent-logger 未安装,已跳过 Fluentd 日志输出。")
+        return None
+
+    try:
+        fh = fluent_handler.FluentHandler(
+            tag=settings.FLUENTD_TAG,
+            host=settings.FLUENTD_HOST,
+            port=settings.FLUENTD_PORT,
+            timeout=settings.FLUENTD_TIMEOUT_SEC
+        )
+        # 注意:FluentHandler 不应设置普通字符串 formatter,
+        # 否则发送到 Fluentd 的 record 会退化为 string,导致 record_transformer 报错。
+        return fh
+    except Exception as e:
+        logging.getLogger(__name__).error(f"初始化 Fluentd Handler 失败: {e}")
+        return None
+
+
 def setup_logging():
     """
     配置日志系统,使其同时输出到文件和控制台。
@@ -35,6 +69,15 @@ def setup_logging():
     file_handler.setFormatter(formatter)
     root_logger.addHandler(file_handler)
 
+    # 3. 可选:创建 Fluentd 处理器 (fluent-logger)
+    fluentd_handler = _build_fluent_handler()
+    if fluentd_handler:
+        root_logger.addHandler(fluentd_handler)
+        logging.info(
+            "Fluentd日志输出已启用: host=%s port=%s tag=%s",
+            settings.FLUENTD_HOST, settings.FLUENTD_PORT, settings.FLUENTD_TAG
+        )
+
     # 配置完成后,可以记录一条消息来确认
     logging.info("日志系统已成功配置,将同时输出到控制台和 app.log 文件。")
 

+ 5 - 2
app/main.py

@@ -22,12 +22,15 @@ logger = get_logger(__name__)
 
 @asynccontextmanager
 async def lifespan(main_app: FastAPI):
-    print("--- 应用启动 ---")
+    logger.info(
+        "应用启动: app=%s env=%s fluentd_enabled=%s",
+        settings.APP_NAME, settings.APP_ENV, settings.FLUENTD_ENABLED
+    )
 
     init_database()
     load_database_pool()
     yield
-    print("--- 应用关闭 ---")
+    logger.info("应用关闭: app=%s env=%s", settings.APP_NAME, settings.APP_ENV)
     close_database_pool()
 
 

+ 17 - 0
docker-compose.yml

@@ -0,0 +1,17 @@
+services:
+  fluentd:
+    image: fluent/fluentd:v1.16-1
+    container_name: fluentd-consumer
+    restart: always
+    ports:
+      - "24224:24224"
+    volumes:
+      - ./fluentd.conf:/fluentd/etc/fluent.conf
+    mem_limit: 256m
+    mem_reservation: 16M
+    cpus: 0.5
+    logging:
+      driver: "json-file"
+      options:
+        max-file: "1"
+        max-size: "4m"

+ 34 - 0
fluentd.conf

@@ -0,0 +1,34 @@
+<source>
+  @type forward
+  port 24224
+  bind 0.0.0.0
+</source>
+
+<filter logback.**>
+  @type record_transformer
+  remove_keys ["caller", "throwable"]
+  <record>
+    fluentd "#{Socket.gethostname}"
+    tag ${tag}
+    application ${tag_parts[1]}
+    hostname ${tag_suffix[2]}
+  </record>
+</filter>
+
+<filter card_score.**>
+  @type record_transformer
+  remove_keys ["caller", "throwable"]
+  <record>
+    fluentd "#{Socket.gethostname}"
+    tag ${tag}
+    application card-score-data-server
+    hostname "#{Socket.gethostname}"
+  </record>
+</filter>
+
+<match **>
+  @type copy
+  <store>
+    @type stdout
+  </store>
+</match>

+ 1 - 0
requirements.txt

@@ -11,3 +11,4 @@ pydantic
 pydantic_settings
 requests
 uvicorn
+fluent-logger