algo-backend-framework 0.0.4__tar.gz → 0.0.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/PKG-INFO +2 -3
  2. algo_backend_framework-0.0.6/algo_backend/config/__init__.py +3 -0
  3. algo_backend_framework-0.0.6/algo_backend/config/basic_config.py +32 -0
  4. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/exception/error_code_manage.py +10 -10
  5. algo_backend_framework-0.0.6/algo_backend/handler/__init__.py +4 -0
  6. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/handler/simple_handler.py +11 -4
  7. algo_backend_framework-0.0.6/algo_backend/handler/sse_handler.py +84 -0
  8. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/log/__init__.py +4 -1
  9. algo_backend_framework-0.0.6/algo_backend/log/common.py +28 -0
  10. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/metrics/prometheus_context.py +0 -13
  11. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/metrics/time_cost_metrics.py +52 -16
  12. algo_backend_framework-0.0.6/algo_backend/schema/__init__.py +4 -0
  13. algo_backend_framework-0.0.6/algo_backend/schema/sse.py +39 -0
  14. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/starter/__init__.py +2 -1
  15. algo_backend_framework-0.0.6/algo_backend/starter/app_mounter.py +31 -0
  16. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/starter/default_app_generator.py +20 -28
  17. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/starter/default_service_starter.py +9 -13
  18. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend_framework.egg-info/PKG-INFO +2 -3
  19. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend_framework.egg-info/SOURCES.txt +3 -7
  20. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend_framework.egg-info/requires.txt +1 -2
  21. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/pyproject.toml +27 -28
  22. algo_backend_framework-0.0.4/algo_backend/config/__init__.py +0 -8
  23. algo_backend_framework-0.0.4/algo_backend/config/basic_config.py +0 -13
  24. algo_backend_framework-0.0.4/algo_backend/config/loguru_config.py +0 -19
  25. algo_backend_framework-0.0.4/algo_backend/handler/__init__.py +0 -3
  26. algo_backend_framework-0.0.4/algo_backend/log/common.py +0 -16
  27. algo_backend_framework-0.0.4/algo_backend/log/loguru/__init__.py +0 -5
  28. algo_backend_framework-0.0.4/algo_backend/log/loguru/log_clean.py +0 -140
  29. algo_backend_framework-0.0.4/algo_backend/log/loguru/log_setup.py +0 -89
  30. algo_backend_framework-0.0.4/algo_backend/log/loguru/log_starter.py +0 -65
  31. algo_backend_framework-0.0.4/algo_backend/log/loguru/patch_logging.py +0 -83
  32. algo_backend_framework-0.0.4/algo_backend/log/nblog/__init__.py +0 -0
  33. algo_backend_framework-0.0.4/algo_backend/schema/__init__.py +0 -3
  34. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/README.md +0 -0
  35. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/__init__.py +0 -0
  36. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/exception/__init__.py +0 -0
  37. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/exception/exception.py +0 -0
  38. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/exception/status_code.py +0 -0
  39. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/handler/exception_to_vo.py +0 -0
  40. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/intercept/__init__.py +0 -0
  41. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/intercept/common.py +0 -0
  42. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/intercept/http.py +0 -0
  43. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/intercept/validate.py +0 -0
  44. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/metrics/__init__.py +0 -0
  45. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/metrics/collector/__init__.py +0 -0
  46. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/metrics/collector/common.py +0 -0
  47. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/metrics/collector/gc_metrics.py +0 -0
  48. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/metrics/collector/schedule_monitor.py +0 -0
  49. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/metrics/collector/system_metrics.py +0 -0
  50. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/metrics/http_metrics.py +0 -0
  51. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/middleware/__init__.py +0 -0
  52. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/middleware/cors.py +0 -0
  53. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/middleware/metrics.py +0 -0
  54. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/schema/vo.py +0 -0
  55. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/starter/event_list.py +0 -0
  56. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/utils/__init__.py +0 -0
  57. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/utils/meta_class.py +0 -0
  58. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend/utils/utils.py +0 -0
  59. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend_framework.egg-info/dependency_links.txt +0 -0
  60. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/algo_backend_framework.egg-info/top_level.txt +0 -0
  61. {algo_backend_framework-0.0.4 → algo_backend_framework-0.0.6}/setup.cfg +0 -0
@@ -1,15 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: algo-backend-framework
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Summary: Ctcdn algorithm backend framework
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
7
7
  Requires-Dist: fastapi>=0.128.0
8
- Requires-Dist: loguru>=0.7.3
9
8
  Requires-Dist: prometheus-client>=0.24.1
10
9
  Requires-Dist: psutil>=7.2.1
11
10
  Requires-Dist: pydantic>=2.12.5
12
- Requires-Dist: python-dotenv>=1.2.1
11
+ Requires-Dist: pydantic-settings>=2.12.0
13
12
  Requires-Dist: uvicorn>=0.40.0
14
13
 
15
14
  # algo-backend-framework-python
@@ -0,0 +1,3 @@
1
+ from .basic_config import ErrorCodeConfig, ServiceConfig, CommonLogConfig
2
+
3
+ __all__ = ["ServiceConfig", "ErrorCodeConfig", "CommonLogConfig"]
@@ -0,0 +1,32 @@
1
+ import os
2
+
3
+ from pydantic_settings import BaseSettings
4
+
5
+
6
+ class BasicConfig(BaseSettings):
7
+ class Config:
8
+ env_file = ".env"
9
+ case_sensitive = False
10
+ extra = "allow"
11
+
12
+
13
+ class ErrorCodeConfig:
14
+ SERVICE_PREFIX: int = os.getenv("ERROR_CODE_SERVICE_PREFIX", "0")
15
+
16
+
17
+ class ServiceConfig(BasicConfig):
18
+ HTTP_PORT: int = 8100
19
+ TIMEOUT_KEEP_ALIVE: int = 1000
20
+ PROCESS_NUM: int = 1
21
+
22
+
23
+ class CommonLogConfig(BasicConfig):
24
+ """
25
+ LOGGER_PATH: 日志文件路径
26
+ LOG_RETENTION_DAY: 日志保留天数
27
+ SAVE_LOG: 是否保存日志
28
+ """
29
+
30
+ LOGGER_PATH: str = "/logger"
31
+ LOG_RETENTION_DAY: int = 60
32
+ SAVE_LOG: bool = True
@@ -8,21 +8,21 @@ from . import status_code
8
8
  from .status_code import BasicApiId, BasicApiInnerErrorCode, BasicStatusCode
9
9
 
10
10
 
11
+ def set_error_code_prefix_env(prefix: Optional[int] = None):
12
+ """
13
+ 服务启动时执行这个函数
14
+ 也可以启动服务时通过环境变量ERROR_CODE_SERVICE_PREFIX指定服务前缀
15
+ 如果输入的prefix code不符合规则,则忽略,保持原来的6位
16
+ """
17
+ if prefix and 1 <= prefix <= 99:
18
+ ErrorCodeConfig.SERVICE_PREFIX = prefix
19
+
20
+
11
21
  class ApiErrorCodeManage:
12
22
  """
13
23
  构建”5aaabb“错误码,aaa接口id,bb表示接口内部错误码
14
24
  """
15
25
 
16
- @classmethod
17
- def set_error_code_prefix_env(cls, prefix: Optional[int] = None):
18
- """
19
- 服务启动时执行这个函数
20
- 也可以启动服务时通过环境变量ERROR_CODE_SERVICE_PREFIX指定服务前缀
21
- 如果输入的prefix code不符合规则,则忽略,保持原来的6位
22
- """
23
- if prefix and 1 <= prefix <= 99:
24
- ErrorCodeConfig.SERVICE_PREFIX = prefix
25
-
26
26
  @classmethod
27
27
  def scan_module_and_summary(cls, *list_module) -> list:
28
28
  """扫描模块中的ApiId和错误码枚举类"""
@@ -0,0 +1,4 @@
1
+ from .simple_handler import timing_and_exception_handler
2
+ from .sse_handler import sse_timing_and_exception_handler
3
+
4
+ __all__ = ["timing_and_exception_handler", "sse_timing_and_exception_handler"]
@@ -1,3 +1,4 @@
1
+ import inspect
1
2
  import logging
2
3
  import time
3
4
  import traceback
@@ -9,7 +10,8 @@ from algo_backend.exception import (
9
10
  DefaultApiErrorCode,
10
11
  )
11
12
  from algo_backend.metrics import PrometheusTimeCostMetricSetting
12
- from algo_backend.schema import AbstractRespVo
13
+ from algo_backend.schema import AbstractRespVo, BaseRespVo
14
+
13
15
  from .exception_to_vo import gen_vo_from_exception
14
16
 
15
17
  logger = logging.getLogger(__name__)
@@ -20,10 +22,14 @@ def timing_and_exception_handler(
20
22
  *,
21
23
  api_id: BasicApiId = DefaultApiErrorCode.DEFAULT_ERROR,
22
24
  api_name: str = "",
25
+ vo_class_type: type(AbstractRespVo) = BaseRespVo,
23
26
  ):
24
27
  """
25
28
  装饰器:用于统计函数执行时间并捕获异常
26
29
  函数中需要包含参数reqid或者request_id
30
+ : param api_id: 错误码
31
+ : param api_name: api名称
32
+ : param vo_class_type: 返回值类型,优先从被装饰的函数typehint中获取,如果获取类型非AbstractRespVo的实现类,则从装饰器vo_class_type中获取,默认BaseRespVo
27
33
  """
28
34
 
29
35
  def decorator(
@@ -59,9 +65,10 @@ def timing_and_exception_handler(
59
65
  f"Traceback:\n{traceback.format_exc()}"
60
66
  )
61
67
 
62
- vo_cls: type(AbstractRespVo) = get_type_hints(func).get(
63
- "return"
64
- ) # 这里可能会失败,因为无法强制用户的类型
68
+ vo_cls = get_type_hints(func).get("return")
69
+ if inspect.isclass(vo_cls) and issubclass(vo_cls, AbstractRespVo):
70
+ vo_cls = vo_class_type
71
+
65
72
  return gen_vo_from_exception(
66
73
  vo_cls, e, api_name=_name, request_id=request_id, api_id=api_id
67
74
  )
@@ -0,0 +1,84 @@
1
+ import logging
2
+ import time
3
+ import traceback
4
+ from functools import wraps
5
+ from typing import AsyncIterable, Callable, TypeVar
6
+
7
+ from pydantic import BaseModel
8
+
9
+ from algo_backend.exception import (
10
+ BasicApiId,
11
+ BasicException,
12
+ DefaultApiErrorCode,
13
+ transfer_exception,
14
+ )
15
+ from algo_backend.metrics import PrometheusTimeCostMetricSetting
16
+ from algo_backend.schema import SseVoGenerator
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ D = TypeVar("D", bound=BaseModel)
22
+
23
+
24
+ def sse_timing_and_exception_handler(
25
+ transfer_obj_cls=type(SseVoGenerator),
26
+ *,
27
+ api_id: BasicApiId = DefaultApiErrorCode.DEFAULT_ERROR,
28
+ api_name: str = "",
29
+ ):
30
+ def decorator(
31
+ func: Callable[..., AsyncIterable[D]],
32
+ ) -> Callable[..., AsyncIterable[D]]:
33
+ @wraps(func)
34
+ async def wrapper(*args, **kwargs):
35
+ request_id = kwargs.get("request_id", None) or kwargs.get("reqid", None)
36
+ _name = func.__name__ or api_name
37
+
38
+ transfer_obj: SseVoGenerator = transfer_obj_cls(request_id=request_id)
39
+ # 提供额外参数,方便丰富上下文
40
+ transfer_obj.extract_info(*args, **kwargs)
41
+
42
+ start_time = time.perf_counter()
43
+ # 执行原函数
44
+ logger.info(f"ReqId: {request_id} | Function: {_name} | Start")
45
+
46
+ try:
47
+ start_event = transfer_obj.start()
48
+ if start_event:
49
+ yield start_event
50
+
51
+ async for item in func(*args, **kwargs):
52
+ yield transfer_obj.generate(item)
53
+
54
+ elapsed_time = time.perf_counter() - start_time
55
+
56
+ logger.info(
57
+ f"ReqId: {request_id} | Function: {_name} | COST:{elapsed_time:.4f}s"
58
+ )
59
+ PrometheusTimeCostMetricSetting.api_metrics_instance().add(
60
+ _name, elapsed_time
61
+ )
62
+
63
+ end_event = transfer_obj.done()
64
+ if end_event:
65
+ yield end_event
66
+
67
+ except Exception as e:
68
+ # 计算耗时
69
+ elapsed_time = time.perf_counter() - start_time
70
+ PrometheusTimeCostMetricSetting.api_metrics_instance().add_error(_name)
71
+ # 记录异常信息和完整堆栈
72
+ logger.error(
73
+ f"ReqId: {request_id} | Function: {_name} | COST:{elapsed_time:.4f}s | Exception: {str(e)}\n"
74
+ f"Traceback:\n{traceback.format_exc()}"
75
+ )
76
+
77
+ basic_exception: BasicException = transfer_exception(
78
+ e, api_name=_name, api_id=api_id, request_id=request_id
79
+ )
80
+ yield transfer_obj.error(basic_exception)
81
+
82
+ return wrapper
83
+
84
+ return decorator
@@ -1 +1,4 @@
1
- from .common import BasicLogStarter
1
+ from .common import BasicLogStarter
2
+
3
+
4
+ __all__ = ["BasicLogStarter"]
@@ -0,0 +1,28 @@
1
+ class BasicLogStarter:
2
+ """
3
+ 日志启动器,初始化日志格式和落盘等
4
+ """
5
+
6
+ def __init__(self, service_name: str):
7
+ """
8
+ :param service_name: 服务名
9
+ """
10
+ self.service_name = service_name
11
+
12
+ def setup_log(self):
13
+ """
14
+ 执行一些日志设置
15
+ """
16
+ ...
17
+
18
+ def app_generator_hook(self, app_generate):
19
+ """
20
+ 钩子函数,传入对象类型DefaultAlgoAppGenerator
21
+ """
22
+ ...
23
+
24
+ def service_generator_hook(self, service_generate):
25
+ """
26
+ 钩子函数:传入对象类型DefaultAlgoServiceStarter
27
+ """
28
+ ...
@@ -2,8 +2,6 @@ import logging
2
2
  import os
3
3
  import shutil
4
4
 
5
- from fastapi import FastAPI
6
-
7
5
  logger = logging.getLogger(__name__)
8
6
 
9
7
 
@@ -42,14 +40,3 @@ class PrometheusContext:
42
40
 
43
41
  os.makedirs(prom_dir, exist_ok=True)
44
42
  logger.info(f"Created new Prometheus multiprocessing directory: {prom_dir}")
45
-
46
- @classmethod
47
- def mount_prometheus_endpoint(cls, app: FastAPI):
48
- """
49
- Mount the Prometheus metrics endpoint on the given application.
50
- """
51
- from prometheus_client import CollectorRegistry, make_asgi_app, multiprocess
52
-
53
- registry = CollectorRegistry()
54
- multiprocess.MultiProcessCollector(registry=registry)
55
- app.mount("/metrics", make_asgi_app(registry=registry))
@@ -2,7 +2,8 @@ import logging
2
2
  import os
3
3
  import time
4
4
  from functools import wraps
5
- from typing import Awaitable, Callable, List, Optional
5
+ from typing import List, Optional
6
+ import inspect
6
7
 
7
8
  from prometheus_client import Counter, Histogram
8
9
 
@@ -120,27 +121,62 @@ class PrometheusTimeCostMetricSetting:
120
121
  def client_metrics_instance(cls) -> BasicTimeCostMetrics:
121
122
  return cls.get_metrics("client")
122
123
 
124
+ @classmethod
125
+ def _create_async_gen_wrapper(cls, func, metrics_cls_name: str, key: str):
126
+ """
127
+ 创建异步生成器包装器
128
+ """
129
+
130
+ @wraps(func)
131
+ async def async_gen_wrapper(*args, **kwargs):
132
+ metrics = cls.get_metrics(metrics_cls_name)
133
+ start = time.perf_counter()
134
+ try:
135
+ async for item in func(*args, **kwargs):
136
+ yield item
137
+ cost = time.perf_counter() - start
138
+ metrics.add(key, cost)
139
+ except Exception as e:
140
+ metrics.add_error(key)
141
+ raise e
142
+
143
+ return async_gen_wrapper
144
+
145
+ @classmethod
146
+ def _create_async_func_wrapper(cls, func, metrics_cls_name: str, key: str):
147
+ """
148
+ 创建普通异步函数包装器
149
+ """
150
+
151
+ @wraps(func)
152
+ async def async_func_wrapper(*args, **kwargs):
153
+ metrics = cls.get_metrics(metrics_cls_name)
154
+ start = time.perf_counter()
155
+ try:
156
+ result = await func(*args, **kwargs)
157
+ metrics.add(key, time.perf_counter() - start)
158
+ return result
159
+ except Exception as e:
160
+ metrics.add_error(key)
161
+ raise e
162
+
163
+ return async_func_wrapper
164
+
123
165
  @classmethod
124
166
  def metrics_handler(cls, key: str, metrics_cls_name: str):
125
167
  """
126
168
  装饰器只会初始化一次,因此要使用动态方式获取指标类,否则初始化装饰器时,指标类还没有被初始化
127
169
  """
128
170
 
129
- def decorator(func: Callable[..., Awaitable]) -> Callable[..., Awaitable]:
130
- @wraps(func)
131
- async def wrapper(*args, **kwargs):
132
- metrics = cls.get_metrics(metrics_cls_name)
133
- try:
134
- start = time.perf_counter()
135
- result = await func(*args, **kwargs)
136
- cost = time.perf_counter() - start
137
- metrics.add(key, cost)
138
- return result
139
- except Exception as e:
140
- metrics.add_error(key)
141
- raise e
142
-
143
- return wrapper
171
+ def decorator(func):
172
+ if inspect.isasyncgenfunction(func):
173
+ return cls._create_async_gen_wrapper(func, metrics_cls_name, key)
174
+ elif inspect.iscoroutinefunction(func):
175
+ return cls._create_async_func_wrapper(func, metrics_cls_name, key)
176
+ else:
177
+ raise ValueError(
178
+ f"{func.__name__} is not a async function or async generator"
179
+ )
144
180
 
145
181
  return decorator
146
182
 
@@ -0,0 +1,4 @@
1
+ from .vo import AbstractRespVo, BaseRespVo
2
+ from .sse import SseVoGenerator
3
+
4
+ __all__ = ["BaseRespVo", "AbstractRespVo", "SseVoGenerator"]
@@ -0,0 +1,39 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import TypeVar, Optional
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from algo_backend.exception import BasicException
7
+
8
+
9
+ T = TypeVar("T", bound=BaseModel)
10
+
11
+
12
+ class SseVoGenerator(ABC):
13
+ def __init__(self, request_id: str = None):
14
+ self.request_id = request_id
15
+
16
+ @abstractmethod
17
+ def extract_info(self, *args, **kwargs):
18
+ """额外获取信息"""
19
+ ...
20
+
21
+ @abstractmethod
22
+ def start(self) -> Optional[T]:
23
+ """
24
+ 返回None时,sse_timing_and_exception_handler会忽略这一步
25
+ """
26
+ ...
27
+
28
+ @abstractmethod
29
+ def generate(self, content: BaseModel) -> T: ...
30
+
31
+ @abstractmethod
32
+ def done(self) -> T:
33
+ """
34
+ 返回None时,sse_timing_and_exception_handler会忽略这一步
35
+ """
36
+ ...
37
+
38
+ @abstractmethod
39
+ def error(self, exception: BasicException) -> T: ...
@@ -1,4 +1,5 @@
1
1
  from .default_app_generator import DefaultAlgoAppGenerator
2
2
  from .default_service_starter import DefaultAlgoServiceStarter
3
+ from .app_mounter import AbstractAppMounter
3
4
 
4
- __all__ = ["DefaultAlgoAppGenerator", "DefaultAlgoServiceStarter"]
5
+ __all__ = ["DefaultAlgoAppGenerator", "DefaultAlgoServiceStarter", "AbstractAppMounter"]
@@ -0,0 +1,31 @@
1
+ from abc import abstractmethod, ABC
2
+
3
+ from fastapi import FastAPI
4
+
5
+
6
+ class AbstractAppMounter(ABC):
7
+ """
8
+ App接口挂载点
9
+ """
10
+
11
+ def __init__(self, service_name: str):
12
+ self.service_name = service_name
13
+
14
+ @abstractmethod
15
+ def mount_app(self, app: FastAPI): ...
16
+
17
+
18
+ class PrometheusAppMounter(AbstractAppMounter):
19
+ """
20
+ Prometheus metrics endpoint 挂载点
21
+ """
22
+
23
+ def mount_app(self, app: FastAPI):
24
+ """
25
+ Mount the Prometheus metrics endpoint on the given application.
26
+ """
27
+ from prometheus_client import CollectorRegistry, make_asgi_app, multiprocess
28
+
29
+ registry = CollectorRegistry()
30
+ multiprocess.MultiProcessCollector(registry=registry)
31
+ app.mount("/metrics", make_asgi_app(registry=registry))
@@ -6,20 +6,18 @@ from fastapi import FastAPI
6
6
  from fastapi.exceptions import RequestValidationError, StarletteHTTPException
7
7
  from starlette.middleware import Middleware
8
8
 
9
- from algo_backend.exception import ApiErrorCodeManage
9
+ from algo_backend.exception.error_code_manage import set_error_code_prefix_env
10
10
  from algo_backend.intercept import (
11
11
  BasicExceptionInterceptor,
12
12
  HTTPExceptionInterceptor,
13
13
  ValidateExceptionInterceptor,
14
14
  )
15
15
  from algo_backend.log import BasicLogStarter
16
- from algo_backend.metrics import (
17
- PrometheusContext,
18
- PrometheusTimeCostMetricSetting,
19
- )
16
+ from algo_backend.metrics import PrometheusTimeCostMetricSetting
20
17
  from algo_backend.metrics.collector import MetricsScheduleMonitor
21
18
  from algo_backend.middleware import default_cors_middleware
22
19
 
20
+ from .app_mounter import AbstractAppMounter, PrometheusAppMounter
23
21
  from .event_list import EventList
24
22
 
25
23
  logger = logging.getLogger(__name__)
@@ -37,7 +35,7 @@ class DefaultAlgoAppGenerator:
37
35
  app_error_code_prefix: Optional[int] = None,
38
36
  custom_start_event: List[Callable[[], Coroutine[Any, Any, None]]] = None,
39
37
  custom_end_event: List[Callable[[], Coroutine[Any, Any, None]]] = None,
40
- log_starter: Optional[BasicLogStarter] = None,
38
+ log_starter: Optional[type(BasicLogStarter)] = BasicLogStarter,
41
39
  intercept_dict: Optional[Dict[Exception, BasicExceptionInterceptor]] = None,
42
40
  middlewares: List[Middleware] = (default_cors_middleware,),
43
41
  api_time_cost_buckets: Optional[List[int]] = None,
@@ -55,7 +53,7 @@ class DefaultAlgoAppGenerator:
55
53
  :param client_time_cost_buckets: 客户端耗时统计的桶,None表示使用默认的,空列表表示不启用这个指标
56
54
  """
57
55
  # 注册8位错误码前缀
58
- ApiErrorCodeManage.set_error_code_prefix_env(app_error_code_prefix)
56
+ set_error_code_prefix_env(app_error_code_prefix)
59
57
  self.service_name = service_name
60
58
 
61
59
  self.__app: Optional[FastAPI] = FastAPI()
@@ -63,7 +61,7 @@ class DefaultAlgoAppGenerator:
63
61
  self.start_event_list = EventList()
64
62
  self.end_event_list = EventList()
65
63
 
66
- self.log_starter = log_starter or BasicLogStarter(service_name=service_name)
64
+ self.log_starter: BasicLogStarter = log_starter(service_name=service_name)
67
65
 
68
66
  self.intercept_dict = {
69
67
  RequestValidationError: ValidateExceptionInterceptor(),
@@ -73,6 +71,10 @@ class DefaultAlgoAppGenerator:
73
71
 
74
72
  self.middleware_list = list(middlewares)
75
73
 
74
+ self.app_mounter_list: List[type(AbstractAppMounter)] = [
75
+ PrometheusAppMounter,
76
+ ]
77
+
76
78
  self.time_cost_metrics_initializer = (
77
79
  lambda: PrometheusTimeCostMetricSetting.initialize(
78
80
  api_metrics_buckets=api_time_cost_buckets,
@@ -117,26 +119,20 @@ class DefaultAlgoAppGenerator:
117
119
  self.middleware_list.append(middleware)
118
120
  return self
119
121
 
120
- def set_log_stater(self, log_starter: BasicLogStarter) -> "DefaultAlgoAppGenerator":
121
- self.log_starter = log_starter
122
- return self
123
-
124
- def use_log_loguru(self):
125
- """
126
- 使用loguru日志框架
127
- """
128
- from algo_backend.log.loguru import LoguruStarter
122
+ def append_mounter(self, mounter_cls: type(AbstractAppMounter)):
123
+ self.app_mounter_list.append(mounter_cls)
129
124
 
130
- return self.set_log_stater(LoguruStarter(service_name=self.service_name))
125
+ def add_mounter(self) -> "DefaultAlgoAppGenerator":
126
+ for mounter_cls in self.app_mounter_list:
127
+ mounter_cls(self.service_name).mount_app(self.__app)
128
+ return self
131
129
 
132
- def use_log_nblog(self):
130
+ def generate(self):
133
131
  """
134
- 使用nblog日志框架,待实现
132
+ 主方法
133
+ :return:
135
134
  """
136
- ...
137
-
138
- def generate(self):
139
- self.init_app().add_prometheus_endpoint().add_interceptor()
135
+ self.init_app().add_interceptor().add_mounter()
140
136
  return self.app
141
137
 
142
138
  @property
@@ -149,10 +145,6 @@ class DefaultAlgoAppGenerator:
149
145
  )
150
146
  return self
151
147
 
152
- def add_prometheus_endpoint(self):
153
- PrometheusContext.mount_prometheus_endpoint(self.__app)
154
- return self
155
-
156
148
  def add_interceptor(self):
157
149
  for exc, interceptor in self.intercept_dict.items():
158
150
  self.__app.add_exception_handler(exc, interceptor.intercept)
@@ -4,6 +4,7 @@ import uvicorn
4
4
 
5
5
  from algo_backend.config import ServiceConfig
6
6
  from algo_backend.metrics import PrometheusContext
7
+ from algo_backend.log import BasicLogStarter
7
8
 
8
9
 
9
10
  class DefaultAlgoServiceStarter:
@@ -32,16 +33,9 @@ class DefaultAlgoServiceStarter:
32
33
  self.__main_pid_event.insert(index, func)
33
34
  return self
34
35
 
35
- def use_loguru(self):
36
- """
37
- 使用loguru日志设置,对主进程的日志生效
38
- 注册loguru的定时清理器
39
- """
40
- from algo_backend.log.loguru import LoguruStarter
41
-
42
- loguru_stater = LoguruStarter(service_name=self.service_name)
43
- self.insert_event(loguru_stater.setup_log)
44
- self.append_event(loguru_stater.run_log_cleaner)
36
+ def use_log_stater(self, log_starter_class: type(BasicLogStarter)):
37
+ log_starter: BasicLogStarter = log_starter_class(service_name=self.service_name)
38
+ log_starter.service_generator_hook(self)
45
39
  return self
46
40
 
47
41
  def main_pid_setup(self) -> "DefaultAlgoServiceStarter":
@@ -59,12 +53,14 @@ class DefaultAlgoServiceStarter:
59
53
  host: str = "0.0.0.0",
60
54
  **kwargs,
61
55
  ):
56
+ service_config = ServiceConfig()
62
57
  # 启动服务
63
58
  uvicorn.run(
64
59
  app_str,
65
60
  host=host,
66
- port=ServiceConfig.HTTP_PORT,
67
- timeout_keep_alive=ServiceConfig.TIMEOUT_KEEP_ALIVE,
68
- workers=ServiceConfig.PROCESS_NUM,
61
+ port=service_config.HTTP_PORT,
62
+ timeout_keep_alive=service_config.TIMEOUT_KEEP_ALIVE,
63
+ workers=service_config.PROCESS_NUM,
64
+ log_config=None,
69
65
  **kwargs,
70
66
  )
@@ -1,15 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: algo-backend-framework
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Summary: Ctcdn algorithm backend framework
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
7
7
  Requires-Dist: fastapi>=0.128.0
8
- Requires-Dist: loguru>=0.7.3
9
8
  Requires-Dist: prometheus-client>=0.24.1
10
9
  Requires-Dist: psutil>=7.2.1
11
10
  Requires-Dist: pydantic>=2.12.5
12
- Requires-Dist: python-dotenv>=1.2.1
11
+ Requires-Dist: pydantic-settings>=2.12.0
13
12
  Requires-Dist: uvicorn>=0.40.0
14
13
 
15
14
  # algo-backend-framework-python
@@ -3,7 +3,6 @@ pyproject.toml
3
3
  algo_backend/__init__.py
4
4
  algo_backend/config/__init__.py
5
5
  algo_backend/config/basic_config.py
6
- algo_backend/config/loguru_config.py
7
6
  algo_backend/exception/__init__.py
8
7
  algo_backend/exception/error_code_manage.py
9
8
  algo_backend/exception/exception.py
@@ -11,18 +10,13 @@ algo_backend/exception/status_code.py
11
10
  algo_backend/handler/__init__.py
12
11
  algo_backend/handler/exception_to_vo.py
13
12
  algo_backend/handler/simple_handler.py
13
+ algo_backend/handler/sse_handler.py
14
14
  algo_backend/intercept/__init__.py
15
15
  algo_backend/intercept/common.py
16
16
  algo_backend/intercept/http.py
17
17
  algo_backend/intercept/validate.py
18
18
  algo_backend/log/__init__.py
19
19
  algo_backend/log/common.py
20
- algo_backend/log/loguru/__init__.py
21
- algo_backend/log/loguru/log_clean.py
22
- algo_backend/log/loguru/log_setup.py
23
- algo_backend/log/loguru/log_starter.py
24
- algo_backend/log/loguru/patch_logging.py
25
- algo_backend/log/nblog/__init__.py
26
20
  algo_backend/metrics/__init__.py
27
21
  algo_backend/metrics/http_metrics.py
28
22
  algo_backend/metrics/prometheus_context.py
@@ -36,8 +30,10 @@ algo_backend/middleware/__init__.py
36
30
  algo_backend/middleware/cors.py
37
31
  algo_backend/middleware/metrics.py
38
32
  algo_backend/schema/__init__.py
33
+ algo_backend/schema/sse.py
39
34
  algo_backend/schema/vo.py
40
35
  algo_backend/starter/__init__.py
36
+ algo_backend/starter/app_mounter.py
41
37
  algo_backend/starter/default_app_generator.py
42
38
  algo_backend/starter/default_service_starter.py
43
39
  algo_backend/starter/event_list.py