| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- 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
- 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_EFFECTIVE_TAG,
- host=settings.FLUENTD_HOST,
- port=settings.FLUENTD_PORT,
- timeout=settings.FLUENTD_TIMEOUT_SEC
- )
- # 输出结构化字段,避免 record 退化为 string。
- if hasattr(fluent_handler, "FluentRecordFormatter"):
- fh.setFormatter(fluent_handler.FluentRecordFormatter({
- "level": "%(levelname)s",
- "logger": "%(name)s",
- "message": "%(message)s",
- "time": "%(asctime)s",
- "app": settings.APP_NAME,
- "env": settings.APP_ENV,
- }))
- return fh
- except Exception as e:
- logging.getLogger(__name__).exception("初始化 Fluentd Handler 失败: %s", str(e))
- return None
- def setup_logging():
- """
- 配置日志系统,使其同时输出到文件和控制台。
- 这个函数应该在应用程序启动时只调用一次。
- """
- root_logger = logging.getLogger()
- # 避免重复初始化
- if root_logger.handlers:
- return
- root_logger.setLevel(getattr(logging, settings.LOG_LEVEL.upper(), logging.INFO))
- stream_formatter = logging.Formatter("%(asctime)s %(levelname)s [%(name)s] %(message)s")
- file_formatter = logging.Formatter("%(asctime)s %(levelname)s [%(name)s] %(message)s")
- console_handler = logging.StreamHandler(sys.stdout)
- console_handler.setFormatter(stream_formatter)
- root_logger.addHandler(console_handler)
- file_handler = logging.FileHandler('app.log', mode='w', encoding='utf-8')
- file_handler.setFormatter(file_formatter)
- root_logger.addHandler(file_handler)
- if not settings.FLUENTD_ENABLED:
- root_logger.info("日志系统已成功配置,将输出到控制台和 app.log 文件。")
- return
- fluentd_handler = _build_fluent_handler()
- if fluentd_handler:
- root_logger.addHandler(fluentd_handler)
- root_logger.info(
- "Fluentd日志输出已启用: host=%s port=%s tag=%s",
- settings.FLUENTD_HOST, settings.FLUENTD_PORT, settings.FLUENTD_EFFECTIVE_TAG
- )
- root_logger.info("日志系统已成功配置,将输出到控制台和 app.log 文件。")
- def get_logger(name: str) -> logging.Logger:
- """
- 获取一个指定名称的日志记录器实例。
- 假设 setup_logging() 已经在此之前被调用。
- """
- return logging.getLogger(name)
|