fiuai-sdk-python 0.6.8__py3-none-any.whl → 0.7.0__py3-none-any.whl
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.
- fiuai_sdk_python/auth/__init__.py +9 -3
- fiuai_sdk_python/auth/context_mgr.py +57 -3
- fiuai_sdk_python/auth/helper.py +63 -113
- fiuai_sdk_python/pkg/vector/vector.py +1 -1
- fiuai_sdk_python/utils/logger.py +45 -26
- {fiuai_sdk_python-0.6.8.dist-info → fiuai_sdk_python-0.7.0.dist-info}/METADATA +1 -1
- {fiuai_sdk_python-0.6.8.dist-info → fiuai_sdk_python-0.7.0.dist-info}/RECORD +9 -9
- {fiuai_sdk_python-0.6.8.dist-info → fiuai_sdk_python-0.7.0.dist-info}/WHEEL +0 -0
- {fiuai_sdk_python-0.6.8.dist-info → fiuai_sdk_python-0.7.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from .header import parse_auth_headers, extract_auth_from_request
|
|
2
2
|
from .type import AuthData, AuthHeader
|
|
3
3
|
from .helper import (
|
|
4
|
-
get_auth_data
|
|
4
|
+
get_auth_data,
|
|
5
5
|
get_current_user_id,
|
|
6
6
|
get_current_tenant_id,
|
|
7
7
|
get_current_company,
|
|
@@ -14,19 +14,23 @@ from .context_mgr import (
|
|
|
14
14
|
init_context,
|
|
15
15
|
WorldData,
|
|
16
16
|
get_auth_data_from_context,
|
|
17
|
-
get_auth_data,
|
|
18
17
|
set_auth_data,
|
|
19
18
|
update_auth_data,
|
|
20
19
|
get_world_data,
|
|
20
|
+
set_user_profile_info,
|
|
21
|
+
get_user_profile_info,
|
|
21
22
|
)
|
|
22
23
|
|
|
24
|
+
# 兼容旧用法:从 request 取 auth 时可用 get_auth_data(request) 或 get_auth_data_from_request(request)
|
|
25
|
+
get_auth_data_from_request = get_auth_data
|
|
26
|
+
|
|
23
27
|
__all__ = [
|
|
24
28
|
"parse_auth_headers",
|
|
25
29
|
"extract_auth_from_request",
|
|
26
30
|
"AuthData",
|
|
27
31
|
"AuthHeader",
|
|
28
|
-
"get_auth_data_from_request",
|
|
29
32
|
"get_auth_data",
|
|
33
|
+
"get_auth_data_from_request",
|
|
30
34
|
"get_auth_data_from_context",
|
|
31
35
|
"get_current_user_id",
|
|
32
36
|
"get_current_tenant_id",
|
|
@@ -40,4 +44,6 @@ __all__ = [
|
|
|
40
44
|
"set_auth_data",
|
|
41
45
|
"update_auth_data",
|
|
42
46
|
"get_world_data",
|
|
47
|
+
"set_user_profile_info",
|
|
48
|
+
"get_user_profile_info",
|
|
43
49
|
]
|
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
"""
|
|
9
9
|
上下文管理:ContextManager、init_context、WorldData,
|
|
10
10
|
以及从当前上下文获取/设置认证数据的 get_auth_data_from_context、set_auth_data、update_auth_data、get_world_data。
|
|
11
|
+
可选:user_profile_info 的 set_user_profile_info / get_user_profile_info(请求级存储,不影响未使用的调用方)。
|
|
11
12
|
"""
|
|
12
13
|
|
|
14
|
+
import contextvars
|
|
13
15
|
import uuid
|
|
14
16
|
import logging
|
|
15
17
|
from typing import Dict, Any, Optional
|
|
@@ -24,6 +26,11 @@ logger = logging.getLogger(__name__)
|
|
|
24
26
|
|
|
25
27
|
_current_context_manager: Optional["ContextManager"] = None
|
|
26
28
|
|
|
29
|
+
# 可选:请求级 UserProfileInfo,仅当调用方 set 时存在,不 set 则 get 为 None
|
|
30
|
+
_user_profile_info: contextvars.ContextVar[Optional[Any]] = contextvars.ContextVar(
|
|
31
|
+
"user_profile_info", default=None
|
|
32
|
+
)
|
|
33
|
+
|
|
27
34
|
|
|
28
35
|
class WorldData(BaseModel):
|
|
29
36
|
"""World 上下文数据模型"""
|
|
@@ -49,6 +56,7 @@ class ContextManager:
|
|
|
49
56
|
world_data: Optional[WorldData] = None,
|
|
50
57
|
event_id: Optional[str] = None,
|
|
51
58
|
task_id: Optional[str] = None,
|
|
59
|
+
user_profile_info: Optional[Any] = None,
|
|
52
60
|
):
|
|
53
61
|
if auth_data and headers:
|
|
54
62
|
raise ValueError("不能同时提供 auth_data 和 headers,请只提供其中一个")
|
|
@@ -60,6 +68,9 @@ class ContextManager:
|
|
|
60
68
|
else:
|
|
61
69
|
self.world_data = WorldData()
|
|
62
70
|
|
|
71
|
+
self._user_profile_info = user_profile_info
|
|
72
|
+
self._user_profile_info_token: Optional[contextvars.Token] = None
|
|
73
|
+
|
|
63
74
|
if auth_data:
|
|
64
75
|
self._context = self._create_context_from_auth_data(auth_data)
|
|
65
76
|
elif headers:
|
|
@@ -87,10 +98,15 @@ class ContextManager:
|
|
|
87
98
|
global _current_context_manager
|
|
88
99
|
_current_context_manager = self
|
|
89
100
|
self._context.__enter__()
|
|
101
|
+
if self._user_profile_info is not None:
|
|
102
|
+
self._user_profile_info_token = _user_profile_info.set(self._user_profile_info)
|
|
90
103
|
logger.debug("Context initialized")
|
|
91
104
|
return self
|
|
92
105
|
|
|
93
106
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
107
|
+
if self._user_profile_info_token is not None:
|
|
108
|
+
_user_profile_info.reset(self._user_profile_info_token)
|
|
109
|
+
self._user_profile_info_token = None
|
|
94
110
|
self._context.__exit__(exc_type, exc_val, exc_tb)
|
|
95
111
|
global _current_context_manager
|
|
96
112
|
_current_context_manager = None
|
|
@@ -124,17 +140,32 @@ def init_context(
|
|
|
124
140
|
world_data: Optional[WorldData] = None,
|
|
125
141
|
event_id: Optional[str] = None,
|
|
126
142
|
task_id: Optional[str] = None,
|
|
143
|
+
user_profile_info: Optional[Any] = None,
|
|
127
144
|
**kwargs: Any,
|
|
128
145
|
) -> ContextManager:
|
|
129
146
|
"""
|
|
130
147
|
初始化上下文,用于后台任务。返回的 ContextManager 必须在 `with` 语句中使用。
|
|
131
148
|
|
|
132
149
|
支持三种方式:1) auth_data 对象 2) headers 字典 3) user_id, auth_tenant_id, current_company。
|
|
150
|
+
trace_id 可从 auth_data.trace_id 或 kwargs["trace_id"](仅方式 3)传入。
|
|
151
|
+
可选 user_profile_info:在 with 块内 get_user_profile_info() 可读。
|
|
133
152
|
"""
|
|
134
153
|
if auth_data:
|
|
135
|
-
return ContextManager(
|
|
154
|
+
return ContextManager(
|
|
155
|
+
auth_data=auth_data,
|
|
156
|
+
world_data=world_data,
|
|
157
|
+
event_id=event_id,
|
|
158
|
+
task_id=task_id,
|
|
159
|
+
user_profile_info=user_profile_info,
|
|
160
|
+
)
|
|
136
161
|
if headers:
|
|
137
|
-
return ContextManager(
|
|
162
|
+
return ContextManager(
|
|
163
|
+
headers=headers,
|
|
164
|
+
world_data=world_data,
|
|
165
|
+
event_id=event_id,
|
|
166
|
+
task_id=task_id,
|
|
167
|
+
user_profile_info=user_profile_info,
|
|
168
|
+
)
|
|
138
169
|
if user_id and auth_tenant_id and current_company:
|
|
139
170
|
auth_data = AuthData(
|
|
140
171
|
user_id=user_id,
|
|
@@ -146,7 +177,13 @@ def init_context(
|
|
|
146
177
|
client=kwargs.get("client", "unknown"),
|
|
147
178
|
channel=kwargs.get("channel", "default"),
|
|
148
179
|
)
|
|
149
|
-
return ContextManager(
|
|
180
|
+
return ContextManager(
|
|
181
|
+
auth_data=auth_data,
|
|
182
|
+
world_data=world_data,
|
|
183
|
+
event_id=event_id,
|
|
184
|
+
task_id=task_id,
|
|
185
|
+
user_profile_info=user_profile_info,
|
|
186
|
+
)
|
|
150
187
|
raise ValueError(
|
|
151
188
|
"必须提供以下之一:"
|
|
152
189
|
"1. auth_data 对象 "
|
|
@@ -235,3 +272,20 @@ def get_world_data() -> Optional[WorldData]:
|
|
|
235
272
|
except Exception as e:
|
|
236
273
|
logger.warning("Failed to get world data: %s", e)
|
|
237
274
|
return None
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def set_user_profile_info(profile: Optional[Any]) -> None:
|
|
278
|
+
"""
|
|
279
|
+
设置当前请求/上下文内的可选 UserProfileInfo。
|
|
280
|
+
仅当需要 profile 时调用;不调用则 get_user_profile_info() 为 None,不影响其他使用者。
|
|
281
|
+
在 HTTP 请求内由业务在 set_user_context 等入口调用;在 with init_context(...) 内也可通过 init_context(..., user_profile_info=...) 传入。
|
|
282
|
+
"""
|
|
283
|
+
_user_profile_info.set(profile)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def get_user_profile_info() -> Optional[Any]:
|
|
287
|
+
"""
|
|
288
|
+
获取当前请求/上下文内的可选 UserProfileInfo。
|
|
289
|
+
未设置时返回 None;类型由调用方约定(如 profile.UserProfileInfo 或 dict)。
|
|
290
|
+
"""
|
|
291
|
+
return _user_profile_info.get()
|
fiuai_sdk_python/auth/helper.py
CHANGED
|
@@ -8,172 +8,122 @@
|
|
|
8
8
|
from fastapi import Request, HTTPException
|
|
9
9
|
from typing import Optional, Union, Dict, Literal
|
|
10
10
|
from .type import AuthData
|
|
11
|
+
from .context_mgr import get_auth_data as get_auth_data_from_context
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
def get_auth_data(
|
|
14
|
-
request: Union[Request, Dict[str, str]],
|
|
15
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
16
|
-
) -> AuthData:
|
|
17
|
-
"""
|
|
18
|
-
从请求中获取认证数据
|
|
19
|
-
|
|
20
|
-
Args:
|
|
21
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
22
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
23
|
-
|
|
24
|
-
Returns:
|
|
25
|
-
AuthData: 认证数据
|
|
26
|
-
|
|
27
|
-
Raises:
|
|
28
|
-
HTTPException: 当认证数据不存在时抛出 401 错误(仅限 FastAPI)
|
|
29
|
-
ValueError: 当使用 dict 引擎且认证数据不存在时
|
|
15
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
16
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
17
|
+
) -> Optional[AuthData]:
|
|
30
18
|
"""
|
|
19
|
+
从请求或当前上下文中获取认证数据。
|
|
20
|
+
request 为 None 时从当前 RequestContext 解析(FiuaiContextMiddleware + AuthMiddleware 或 init_context 内可用),无上下文时返回 None。
|
|
21
|
+
传入 request 时从 request 取,不存在时抛 HTTPException/ValueError。
|
|
22
|
+
"""
|
|
23
|
+
if request is None:
|
|
24
|
+
return get_auth_data_from_context()
|
|
31
25
|
if engine == "fastapi":
|
|
32
26
|
if not isinstance(request, Request):
|
|
33
|
-
raise TypeError(
|
|
34
|
-
|
|
27
|
+
raise TypeError(
|
|
28
|
+
"request must be a FastAPI Request object when engine='fastapi'"
|
|
29
|
+
)
|
|
30
|
+
auth_data = getattr(request.state, "auth_data", None)
|
|
35
31
|
if not auth_data:
|
|
36
32
|
raise HTTPException(
|
|
37
33
|
status_code=401,
|
|
38
34
|
detail={
|
|
39
35
|
"error": "Unauthorized",
|
|
40
36
|
"message": "Authentication data not found",
|
|
41
|
-
"code": "AUTH_NOT_FOUND"
|
|
42
|
-
}
|
|
37
|
+
"code": "AUTH_NOT_FOUND",
|
|
38
|
+
},
|
|
43
39
|
)
|
|
44
40
|
return auth_data
|
|
45
|
-
|
|
41
|
+
if engine == "dict":
|
|
46
42
|
if not isinstance(request, dict):
|
|
47
43
|
raise TypeError("request must be a dict when engine='dict'")
|
|
48
|
-
auth_data = request.get(
|
|
44
|
+
auth_data = request.get("auth_data")
|
|
49
45
|
if not auth_data:
|
|
50
46
|
raise ValueError("Authentication data not found in request dict")
|
|
51
47
|
return auth_data
|
|
52
|
-
|
|
53
|
-
raise ValueError("engine must be either 'fastapi' or 'dict'")
|
|
48
|
+
raise ValueError("engine must be either 'fastapi' or 'dict'")
|
|
54
49
|
|
|
55
50
|
|
|
56
51
|
def get_current_user_id(
|
|
57
|
-
request: Union[Request, Dict[str, str]],
|
|
58
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
59
|
-
) -> str:
|
|
60
|
-
"""
|
|
61
|
-
获取当前用户ID
|
|
62
|
-
|
|
63
|
-
Args:
|
|
64
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
65
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
66
|
-
|
|
67
|
-
Returns:
|
|
68
|
-
str: 用户ID
|
|
52
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
53
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
54
|
+
) -> Optional[str]:
|
|
55
|
+
"""
|
|
56
|
+
获取当前用户ID。request 为 None 时从当前上下文取;无上下文或未认证时返回 None。
|
|
69
57
|
"""
|
|
70
58
|
auth_data = get_auth_data(request, engine)
|
|
71
|
-
return auth_data.user_id
|
|
59
|
+
return auth_data.user_id if auth_data else None
|
|
72
60
|
|
|
73
61
|
|
|
74
62
|
def get_current_tenant_id(
|
|
75
|
-
request: Union[Request, Dict[str, str]],
|
|
76
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
77
|
-
) -> str:
|
|
78
|
-
"""
|
|
79
|
-
获取当前租户ID
|
|
80
|
-
|
|
81
|
-
Args:
|
|
82
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
83
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
84
|
-
|
|
85
|
-
Returns:
|
|
86
|
-
str: 租户ID
|
|
63
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
64
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
65
|
+
) -> Optional[str]:
|
|
66
|
+
"""
|
|
67
|
+
获取当前租户ID。request 为 None 时从当前上下文取;无上下文或未认证时返回 None。
|
|
87
68
|
"""
|
|
88
69
|
auth_data = get_auth_data(request, engine)
|
|
89
|
-
return auth_data.auth_tenant_id
|
|
70
|
+
return auth_data.auth_tenant_id if auth_data else None
|
|
90
71
|
|
|
91
72
|
|
|
92
73
|
def get_current_company(
|
|
93
|
-
request: Union[Request, Dict[str, str]],
|
|
94
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
95
|
-
) -> str:
|
|
96
|
-
"""
|
|
97
|
-
获取当前公司ID
|
|
98
|
-
|
|
99
|
-
Args:
|
|
100
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
101
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
102
|
-
|
|
103
|
-
Returns:
|
|
104
|
-
str: 公司ID
|
|
74
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
75
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
76
|
+
) -> Optional[str]:
|
|
77
|
+
"""
|
|
78
|
+
获取当前公司ID。request 为 None 时从当前上下文取;无上下文或未认证时返回 None。
|
|
105
79
|
"""
|
|
106
80
|
auth_data = get_auth_data(request, engine)
|
|
107
|
-
return auth_data.current_company
|
|
81
|
+
return auth_data.current_company if auth_data else None
|
|
108
82
|
|
|
109
83
|
|
|
110
84
|
def get_company_unique_no(
|
|
111
|
-
request: Union[Request, Dict[str, str]],
|
|
112
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
113
|
-
) -> str:
|
|
114
|
-
"""
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
Args:
|
|
118
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
119
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
120
|
-
|
|
121
|
-
Returns:
|
|
122
|
-
str: 公司唯一编号
|
|
85
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
86
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
87
|
+
) -> Optional[str]:
|
|
88
|
+
"""
|
|
89
|
+
获取当前公司唯一编号。request 为 None 时从当前上下文取;无上下文或未认证时返回 None。
|
|
123
90
|
"""
|
|
124
91
|
auth_data = get_auth_data(request, engine)
|
|
125
|
-
return auth_data.company_unique_no
|
|
92
|
+
return auth_data.company_unique_no if auth_data else None
|
|
126
93
|
|
|
127
94
|
|
|
128
95
|
def get_impersonation(
|
|
129
|
-
request: Union[Request, Dict[str, str]],
|
|
130
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
131
|
-
) -> str:
|
|
132
|
-
"""
|
|
133
|
-
获取当前代表的租户ID
|
|
134
|
-
|
|
135
|
-
Args:
|
|
136
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
137
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
138
|
-
|
|
139
|
-
Returns:
|
|
140
|
-
str: 代表的租户ID
|
|
96
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
97
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
98
|
+
) -> Optional[str]:
|
|
99
|
+
"""
|
|
100
|
+
获取当前代表的租户ID。request 为 None 时从当前上下文取;无上下文或未认证时返回 None。
|
|
141
101
|
"""
|
|
142
102
|
auth_data = get_auth_data(request, engine)
|
|
143
|
-
return auth_data.impersonation
|
|
103
|
+
return auth_data.impersonation if auth_data else None
|
|
144
104
|
|
|
145
105
|
|
|
146
106
|
def get_current_client(
|
|
147
|
-
request: Union[Request, Dict[str, str]],
|
|
148
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
149
|
-
) -> str:
|
|
150
|
-
"""
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
Args:
|
|
154
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
155
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
156
|
-
|
|
157
|
-
Returns:
|
|
158
|
-
str: 客户端标识
|
|
107
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
108
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
109
|
+
) -> Optional[str]:
|
|
110
|
+
"""
|
|
111
|
+
获取当前客户端标识。request 为 None 时从当前上下文取;无上下文或未认证时返回 None。
|
|
159
112
|
"""
|
|
160
113
|
auth_data = get_auth_data(request, engine)
|
|
161
|
-
return auth_data.client
|
|
114
|
+
return auth_data.client if auth_data else None
|
|
162
115
|
|
|
163
116
|
|
|
164
117
|
def is_impersonating(
|
|
165
|
-
request: Union[Request, Dict[str, str]],
|
|
166
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
118
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
119
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
167
120
|
) -> bool:
|
|
168
121
|
"""
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
Args:
|
|
172
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
173
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
174
|
-
|
|
175
|
-
Returns:
|
|
176
|
-
bool: 是否正在代表其他租户
|
|
122
|
+
检查是否正在代表其他租户。request 为 None 时从当前上下文取;无上下文或未认证时返回 False。
|
|
177
123
|
"""
|
|
178
124
|
auth_data = get_auth_data(request, engine)
|
|
179
|
-
|
|
125
|
+
if not auth_data:
|
|
126
|
+
return False
|
|
127
|
+
return bool(
|
|
128
|
+
auth_data.impersonation and auth_data.impersonation != auth_data.auth_tenant_id
|
|
129
|
+
)
|
|
@@ -619,7 +619,7 @@ class ContextAwareQdrantManager:
|
|
|
619
619
|
Dict[str, Optional[str]]: 包含 auth_tenant_id, auth_company_id, user_id 的字典
|
|
620
620
|
"""
|
|
621
621
|
try:
|
|
622
|
-
from
|
|
622
|
+
from ...auth import get_auth_data
|
|
623
623
|
auth_data = get_auth_data()
|
|
624
624
|
if auth_data:
|
|
625
625
|
return {
|
fiuai_sdk_python/utils/logger.py
CHANGED
|
@@ -8,49 +8,78 @@
|
|
|
8
8
|
import logging
|
|
9
9
|
import os
|
|
10
10
|
import sys
|
|
11
|
+
from typing import Any, Callable, Dict, Optional
|
|
11
12
|
|
|
12
13
|
|
|
14
|
+
def _make_context_filter(
|
|
15
|
+
context_injector: Optional[Callable[[], Optional[Dict[str, Any]]]],
|
|
16
|
+
) -> logging.Filter:
|
|
17
|
+
"""根据 context_injector 构建过滤器:非 None 时注入返回值到 record,否则仅设置默认 trace_id。"""
|
|
18
|
+
|
|
19
|
+
class _InjectorFilter(logging.Filter):
|
|
20
|
+
def __init__(self, injector: Optional[Callable[[], Optional[Dict[str, Any]]]]) -> None:
|
|
21
|
+
super().__init__()
|
|
22
|
+
self._injector = injector
|
|
23
|
+
|
|
24
|
+
def filter(self, record: logging.LogRecord) -> bool:
|
|
25
|
+
if self._injector is not None:
|
|
26
|
+
try:
|
|
27
|
+
ctx = self._injector()
|
|
28
|
+
if ctx:
|
|
29
|
+
for k, v in ctx.items():
|
|
30
|
+
setattr(record, k, v)
|
|
31
|
+
except Exception:
|
|
32
|
+
pass
|
|
33
|
+
if not getattr(record, "trace_id", None):
|
|
34
|
+
record.trace_id = "-"
|
|
35
|
+
return True
|
|
36
|
+
|
|
37
|
+
return _InjectorFilter(context_injector)
|
|
13
38
|
|
|
14
39
|
|
|
15
40
|
def init_logger(
|
|
16
41
|
log_path: str = "logs/",
|
|
17
42
|
log_level: str = "INFO",
|
|
18
43
|
json_log: bool = False,
|
|
19
|
-
caller: bool = True
|
|
44
|
+
caller: bool = True,
|
|
45
|
+
context_injector: Optional[Callable[[], Optional[Dict[str, Any]]]] = None,
|
|
20
46
|
):
|
|
21
47
|
"""初始化日志配置
|
|
22
|
-
|
|
48
|
+
|
|
23
49
|
Args:
|
|
24
50
|
log_path: 日志文件路径
|
|
25
51
|
log_level: 日志级别
|
|
26
52
|
json_log: 是否使用JSON格式日志
|
|
27
53
|
caller: 是否显示调用者信息
|
|
54
|
+
context_injector: 可选,无参可调用对象,返回 dict(如 {"trace_id": "xxx"}),
|
|
55
|
+
非 None 时会将返回的键值注入到每条日志记录中。
|
|
28
56
|
"""
|
|
29
57
|
# 创建日志目录
|
|
30
58
|
if log_path and not os.path.exists(log_path):
|
|
31
59
|
os.makedirs(log_path)
|
|
32
|
-
|
|
60
|
+
|
|
33
61
|
# 设置日志级别
|
|
34
62
|
level = getattr(logging, log_level.upper(), logging.INFO)
|
|
35
|
-
|
|
63
|
+
|
|
36
64
|
# 获取根日志记录器
|
|
37
65
|
root_logger = logging.getLogger()
|
|
38
|
-
|
|
66
|
+
|
|
39
67
|
# 设置根日志记录器的级别
|
|
40
68
|
root_logger.setLevel(level)
|
|
41
|
-
|
|
69
|
+
|
|
42
70
|
# 清除现有的处理器(避免重复添加)
|
|
43
71
|
root_logger.handlers.clear()
|
|
44
|
-
|
|
72
|
+
|
|
73
|
+
context_filter = _make_context_filter(context_injector)
|
|
74
|
+
log_format = '%(asctime)s - %(name)s - %(levelname)s - [trace_id:%(trace_id)s] - %(message)s'
|
|
75
|
+
|
|
45
76
|
# 配置控制台处理器
|
|
46
77
|
console_handler = logging.StreamHandler(sys.stdout)
|
|
47
78
|
console_handler.setLevel(level)
|
|
48
|
-
# 添加 event_id 和 task_id 到日志格式中
|
|
49
|
-
log_format = '%(asctime)s - %(name)s - %(levelname)s - [trace_id:%(trace_id)s] - %(message)s'
|
|
50
79
|
console_handler.setFormatter(logging.Formatter(log_format))
|
|
51
|
-
|
|
80
|
+
console_handler.addFilter(context_filter)
|
|
52
81
|
root_logger.addHandler(console_handler)
|
|
53
|
-
|
|
82
|
+
|
|
54
83
|
# 如果指定了日志文件路径,添加文件处理器
|
|
55
84
|
if log_path:
|
|
56
85
|
file_handler = logging.FileHandler(
|
|
@@ -58,13 +87,11 @@ def init_logger(
|
|
|
58
87
|
encoding='utf-8'
|
|
59
88
|
)
|
|
60
89
|
file_handler.setLevel(level)
|
|
61
|
-
# 添加 event_id 和 task_id 到日志格式中
|
|
62
90
|
file_handler.setFormatter(logging.Formatter(log_format))
|
|
63
|
-
|
|
91
|
+
file_handler.addFilter(context_filter)
|
|
64
92
|
root_logger.addHandler(file_handler)
|
|
65
|
-
|
|
93
|
+
|
|
66
94
|
# 过滤第三方库的日志,只显示 ERROR 及以上级别
|
|
67
|
-
# 这样可以减少不必要的 INFO、DEBUG 和 WARNING 日志输出
|
|
68
95
|
third_party_loggers = [
|
|
69
96
|
'nebula3.logger',
|
|
70
97
|
'nebula3',
|
|
@@ -77,21 +104,13 @@ def init_logger(
|
|
|
77
104
|
third_party_logger.setLevel(logging.ERROR)
|
|
78
105
|
|
|
79
106
|
|
|
80
|
-
# 全局过滤器实例
|
|
81
|
-
|
|
82
|
-
|
|
83
107
|
def get_logger(name: str) -> logging.Logger:
|
|
84
108
|
"""获取日志记录器
|
|
85
|
-
|
|
86
|
-
自动添加 ContextFilter,从上下文中获取 event_id 和 task_id 并记录到日志中
|
|
87
|
-
|
|
109
|
+
|
|
88
110
|
Args:
|
|
89
111
|
name: 日志记录器名称
|
|
90
|
-
|
|
112
|
+
|
|
91
113
|
Returns:
|
|
92
114
|
logging.Logger: 日志记录器实例
|
|
93
115
|
"""
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return logger
|
|
116
|
+
return logging.getLogger(name)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fiuai_sdk_python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: FiuAI Python SDK - 企业级AI服务集成开发工具包
|
|
5
5
|
Project-URL: Homepage, https://github.com/fiuai/fiuai-sdk-python
|
|
6
6
|
Project-URL: Documentation, https://github.com/fiuai/fiuai-sdk-python#readme
|
|
@@ -15,10 +15,10 @@ fiuai_sdk_python/resp.py,sha256=4twCxmwqe2e1vlhfFnu-5_FR8PwQiveB9njY3exaQ88,1018
|
|
|
15
15
|
fiuai_sdk_python/setup.py,sha256=ER0IPAouHhrVSzG0Iu87Ky0R5c4kCgOF77kRAOO-1MI,8025
|
|
16
16
|
fiuai_sdk_python/type.py,sha256=vinZKflNvmQNhqO5mDARAE6O133k0LiR1s1ZvexN_q4,28940
|
|
17
17
|
fiuai_sdk_python/util.py,sha256=x3TkNsC8_nzA-8x6ndIGrIpE9sRKpn3vlxnj2Hqpxwo,2326
|
|
18
|
-
fiuai_sdk_python/auth/__init__.py,sha256=
|
|
19
|
-
fiuai_sdk_python/auth/context_mgr.py,sha256=
|
|
18
|
+
fiuai_sdk_python/auth/__init__.py,sha256=bPLrLT2wDPURVXJ6a0Hi-AhwCCCj1PISY2Gn_Jv427o,1225
|
|
19
|
+
fiuai_sdk_python/auth/context_mgr.py,sha256=cw7A9xfrJMPdRIwOWMr11HI8XEwTNTUYa9AzCObytB0,11296
|
|
20
20
|
fiuai_sdk_python/auth/header.py,sha256=JoMT6OJQUU7laGP6235kolfG-Qy_AP6ZQQQ9Ca8U88c,3606
|
|
21
|
-
fiuai_sdk_python/auth/helper.py,sha256=
|
|
21
|
+
fiuai_sdk_python/auth/helper.py,sha256=DUKYe-Y0O-uRVeBqbmsayzF2EfogLNyXf05o4a8iAJc,4726
|
|
22
22
|
fiuai_sdk_python/auth/type.py,sha256=lPUgbSOW-mQfOZpxPGhwDmpbKr5UfjznEuSKGwDosxY,2233
|
|
23
23
|
fiuai_sdk_python/examples/fastapi_integration.py,sha256=6VonD8xkpwUFh3qwQh6mdHGbITscX-MMJF2k3Gj2bJc,1701
|
|
24
24
|
fiuai_sdk_python/http/__init__.py,sha256=RMtrf0O-iuAGMIqfpQg6sQHj_O9Lo4Lhn7KejcapZzo,692
|
|
@@ -31,12 +31,12 @@ fiuai_sdk_python/pkg/db/errors.py,sha256=JJwfM_sHXYAOfP5peg9rg8n2BsCMnPXIKVLrOFM
|
|
|
31
31
|
fiuai_sdk_python/pkg/db/manager.py,sha256=HapTkFOfCzQLCXWBAOlGHsjGCWVBNBLEMCDH7Kty7tI,14855
|
|
32
32
|
fiuai_sdk_python/pkg/db/utils.py,sha256=qqZ14eV7fy9x_mwcEDKJDz1W54xPndpJ1QfM_D0E3FI,2419
|
|
33
33
|
fiuai_sdk_python/pkg/vector/__init__.py,sha256=fvbetFxbHiFeojnTfKT3roA1hOcoNHF_eCRuG6HwMpI,404
|
|
34
|
-
fiuai_sdk_python/pkg/vector/vector.py,sha256=
|
|
34
|
+
fiuai_sdk_python/pkg/vector/vector.py,sha256=hdwhDSiKp4a7s6dVwFNTRk1BPqhZppywD8LnOudoMdo,28990
|
|
35
35
|
fiuai_sdk_python/utils/__init__.py,sha256=UwwsvqBsaRCHbWdx-wvM48szT3j50h95k9MZdbfawRQ,72
|
|
36
36
|
fiuai_sdk_python/utils/ids.py,sha256=ZDtEqt_Woth8ytPB2tdnnTIv7noWr8XYhSsUvkZ7Hc0,6448
|
|
37
|
-
fiuai_sdk_python/utils/logger.py,sha256=
|
|
37
|
+
fiuai_sdk_python/utils/logger.py,sha256=RuKn9TFmV1IfsRTV3ZdtXLZkM44GkHs32ehbJdrdu-8,3657
|
|
38
38
|
fiuai_sdk_python/utils/text.py,sha256=bnob_W0nj_Vj8Hp93B0cYmFOY8IhUWF0C8UedOYCNvs,1667
|
|
39
|
-
fiuai_sdk_python-0.
|
|
40
|
-
fiuai_sdk_python-0.
|
|
41
|
-
fiuai_sdk_python-0.
|
|
42
|
-
fiuai_sdk_python-0.
|
|
39
|
+
fiuai_sdk_python-0.7.0.dist-info/METADATA,sha256=VvQZG__GFesGKAStADnKtBE96LTN2jGaa_vZjZXOCrs,1523
|
|
40
|
+
fiuai_sdk_python-0.7.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
41
|
+
fiuai_sdk_python-0.7.0.dist-info/licenses/LICENSE,sha256=PFMF0dFErrBFqU-rryEby0yW8GBagYqrdbyZQHMUCJg,1062
|
|
42
|
+
fiuai_sdk_python-0.7.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|