coze-coding-utils 0.2.7a1__tar.gz → 0.2.8a2__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.
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/PKG-INFO +1 -1
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/pyproject.toml +1 -1
- coze_coding_utils-0.2.8a2/src/coze_coding_utils/log/config.py +28 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/log/loop_trace.py +0 -2
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/log/node_log.py +36 -7
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/log/write_log.py +28 -18
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/runtime_ctx/context.py +18 -0
- coze_coding_utils-0.2.7a1/src/coze_coding_utils/log/config.py +0 -10
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/.gitignore +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/LICENSE +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/README.md +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/__init__.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/error/__init__.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/error/classifier.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/error/codes.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/error/exceptions.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/error/patterns.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/file/__init__.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/file/file.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/helper/__init__.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/helper/agent_helper.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/helper/graph_helper.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/helper/stream_runner.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/log/__init__.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/log/common.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/log/err_trace.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/log/parser.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/messages/__init__.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/messages/client.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/messages/server.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/openai/__init__.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/openai/converter/__init__.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/openai/converter/request_converter.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/openai/converter/response_converter.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/openai/handler.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/openai/types/__init__.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/openai/types/request.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/openai/types/response.py +0 -0
- {coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/runtime_ctx/__init__.py +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Application configuration
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from coze_coding_utils.runtime_ctx.context import ENV_WORKTREE_NAME
|
|
8
|
+
|
|
9
|
+
# Logging
|
|
10
|
+
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
|
|
11
|
+
|
|
12
|
+
LOG_DIR = Path(os.getenv("COZE_LOG_DIR", "/tmp/app/work/logs/bypass"))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def resolve_log_dir() -> Path:
|
|
16
|
+
"""Resolve the per-process log directory based on COZE_WORKTREE_NAME.
|
|
17
|
+
|
|
18
|
+
沙箱拉起产物子进程时通过环境变量 COZE_WORKTREE_NAME 注入当前 worktree 名(主仓为空)。
|
|
19
|
+
LogWatcherManager 在 services/devbox/app/services/log_watcher.py 里按 worktree 隔离监听目录:
|
|
20
|
+
- 主仓 → LOG_DIR/
|
|
21
|
+
- 具名 worktree → LOG_DIR/worktrees/<name>/
|
|
22
|
+
SDK 这里用同样规则解析写入目录,watcher 才能拾起对应日志,按正确 worktree group 推 IDE。
|
|
23
|
+
"""
|
|
24
|
+
worktree_name = os.getenv(ENV_WORKTREE_NAME, "")
|
|
25
|
+
if worktree_name:
|
|
26
|
+
return LOG_DIR / "worktrees" / worktree_name
|
|
27
|
+
return LOG_DIR
|
|
28
|
+
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/log/loop_trace.py
RENAMED
|
@@ -33,7 +33,6 @@ def init_run_config(graph, ctx):
|
|
|
33
33
|
"commit_hash": commit_hash,
|
|
34
34
|
"coze_entity_type": ctx.rpc_persist_res_rec_root_entity_type,
|
|
35
35
|
"coze_entity_id": ctx.rpc_persist_res_rec_root_entity_id,
|
|
36
|
-
"coze_tt_env": ctx.x_tt_env,
|
|
37
36
|
"coze_run_id" : ctx.run_id,
|
|
38
37
|
}
|
|
39
38
|
)
|
|
@@ -58,7 +57,6 @@ def init_agent_config(graph, ctx):
|
|
|
58
57
|
"commit_hash": commit_hash,
|
|
59
58
|
"coze_entity_type": ctx.rpc_persist_res_rec_root_entity_type,
|
|
60
59
|
"coze_entity_id": ctx.rpc_persist_res_rec_root_entity_id,
|
|
61
|
-
"coze_tt_env": ctx.x_tt_env,
|
|
62
60
|
"coze_run_id" : ctx.run_id,
|
|
63
61
|
}
|
|
64
62
|
)
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/log/node_log.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import time
|
|
2
2
|
import logging
|
|
3
3
|
from uuid import UUID
|
|
4
|
-
from coze_coding_utils.log.config import LOG_DIR
|
|
4
|
+
from coze_coding_utils.log.config import LOG_DIR, resolve_log_dir
|
|
5
5
|
from coze_coding_utils.log.common import get_execute_mode, is_prod
|
|
6
6
|
import uuid
|
|
7
7
|
from langchain_core.callbacks import BaseCallbackHandler
|
|
@@ -26,8 +26,11 @@ class ParamInfo:
|
|
|
26
26
|
|
|
27
27
|
# 2. 确保日志目录存在
|
|
28
28
|
# 尝试使用可写目录,先尝试/app目录,如果失败则使用/tmp目录
|
|
29
|
+
|
|
29
30
|
try:
|
|
30
|
-
|
|
31
|
+
_resolved_log_dir = resolve_log_dir()
|
|
32
|
+
os.makedirs(_resolved_log_dir, exist_ok=True)
|
|
33
|
+
LOG_FILE = os.path.join(_resolved_log_dir, 'app.log')
|
|
31
34
|
# 测试写入权限
|
|
32
35
|
with open(LOG_FILE, 'a') as f:
|
|
33
36
|
pass
|
|
@@ -99,7 +102,7 @@ def create_log_entry(level="info", message="", timestamp=None, log_id=None, late
|
|
|
99
102
|
input_data="", output_data="", node_id="", project_id="", commit_id="",
|
|
100
103
|
execute_mode="run", caller="", node_type="", node_title="",
|
|
101
104
|
token="", cost="", error_code="", error_message="", event_type="", execution_id="", node_name="",
|
|
102
|
-
method=""):
|
|
105
|
+
method="", worktree_name="", user_id=""):
|
|
103
106
|
"""
|
|
104
107
|
创建符合要求的日志条目
|
|
105
108
|
:param level: 日志级别
|
|
@@ -124,6 +127,8 @@ def create_log_entry(level="info", message="", timestamp=None, log_id=None, late
|
|
|
124
127
|
:param execution_id: 执行唯一ID(可选)
|
|
125
128
|
:param node_name: 节点名称
|
|
126
129
|
:param method: 方法名称
|
|
130
|
+
:param worktree_name: 当前 worktree 名(主仓为空字符串),便于多 worktree 并发排查
|
|
131
|
+
:param user_id: 当前用户 ID(沙箱 owner / 调用方),便于多用户并发排查
|
|
127
132
|
:return: 格式化的日志字典
|
|
128
133
|
"""
|
|
129
134
|
if timestamp is None:
|
|
@@ -156,10 +161,12 @@ def create_log_entry(level="info", message="", timestamp=None, log_id=None, late
|
|
|
156
161
|
"execute_id": execution_id,
|
|
157
162
|
"node_name": node_name,
|
|
158
163
|
"method": method,
|
|
164
|
+
"worktree_name": worktree_name,
|
|
165
|
+
"user_id": user_id,
|
|
159
166
|
}
|
|
160
167
|
|
|
161
168
|
|
|
162
|
-
def log_workflow_start(project_id, commit_id, log_id=None, execute_id="", input_data="", method=""):
|
|
169
|
+
def log_workflow_start(project_id, commit_id, log_id=None, execute_id="", input_data="", method="", worktree_name="", user_id=""):
|
|
163
170
|
"""
|
|
164
171
|
记录流程开始日志
|
|
165
172
|
:param project_id: 项目ID
|
|
@@ -167,6 +174,8 @@ def log_workflow_start(project_id, commit_id, log_id=None, execute_id="", input_
|
|
|
167
174
|
:param is_test_run: 是否试运行
|
|
168
175
|
:param log_id: 日志ID(可选)
|
|
169
176
|
:param execute_id: 执行唯一ID(可选)
|
|
177
|
+
:param worktree_name: 当前 worktree 名
|
|
178
|
+
:param user_id: 当前用户 ID
|
|
170
179
|
"""
|
|
171
180
|
event_type = "test_run_start" if not is_prod() else "run_start"
|
|
172
181
|
execute_mode = "test_run" if not is_prod() else "run"
|
|
@@ -184,13 +193,15 @@ def log_workflow_start(project_id, commit_id, log_id=None, execute_id="", input_
|
|
|
184
193
|
execution_id=execute_id,
|
|
185
194
|
input_data=input_data,
|
|
186
195
|
method=method,
|
|
196
|
+
worktree_name=worktree_name,
|
|
197
|
+
user_id=user_id,
|
|
187
198
|
)
|
|
188
199
|
|
|
189
200
|
write_log(log_entry)
|
|
190
201
|
|
|
191
202
|
|
|
192
203
|
def log_workflow_end(execution_id, output=None, total_time=None, status="success", token_consumed=None,
|
|
193
|
-
error_reason=None, error_code=None, is_test_run=False, log_id="", method=""):
|
|
204
|
+
error_reason=None, error_code=None, is_test_run=False, log_id="", method="", worktree_name="", user_id=""):
|
|
194
205
|
"""
|
|
195
206
|
记录流程结束日志
|
|
196
207
|
:param execution_id: 执行唯一ID
|
|
@@ -201,6 +212,8 @@ def log_workflow_end(execution_id, output=None, total_time=None, status="success
|
|
|
201
212
|
:param error_reason: 错误原因
|
|
202
213
|
:param error_code: 错误码
|
|
203
214
|
:param is_test_run: 是否试运行
|
|
215
|
+
:param worktree_name: 当前 worktree 名
|
|
216
|
+
:param user_id: 当前用户 ID
|
|
204
217
|
"""
|
|
205
218
|
level = "error" if status == "error" else "info"
|
|
206
219
|
execute_mode = "test_run" if is_test_run else "run"
|
|
@@ -222,6 +235,8 @@ def log_workflow_end(execution_id, output=None, total_time=None, status="success
|
|
|
222
235
|
execution_id=execution_id,
|
|
223
236
|
log_id=log_id,
|
|
224
237
|
method=method,
|
|
238
|
+
worktree_name=worktree_name,
|
|
239
|
+
user_id=user_id,
|
|
225
240
|
)
|
|
226
241
|
|
|
227
242
|
write_log(log_entry)
|
|
@@ -271,7 +286,9 @@ class Logger(BaseCallbackHandler):
|
|
|
271
286
|
event_type="node_start",
|
|
272
287
|
log_id=self.runtime_ctx.logid,
|
|
273
288
|
method=self.runtime_ctx.method,
|
|
274
|
-
node_type="condition"
|
|
289
|
+
node_type="condition",
|
|
290
|
+
worktree_name=self.runtime_ctx.worktree_name,
|
|
291
|
+
user_id=self.runtime_ctx.user_id,
|
|
275
292
|
)
|
|
276
293
|
write_log(log_entry)
|
|
277
294
|
return
|
|
@@ -290,6 +307,8 @@ class Logger(BaseCallbackHandler):
|
|
|
290
307
|
log_id=self.runtime_ctx.logid,
|
|
291
308
|
node_name=node_info.name,
|
|
292
309
|
method=self.runtime_ctx.method,
|
|
310
|
+
worktree_name=self.runtime_ctx.worktree_name,
|
|
311
|
+
user_id=self.runtime_ctx.user_id,
|
|
293
312
|
)
|
|
294
313
|
write_log(log_entry)
|
|
295
314
|
|
|
@@ -321,7 +340,9 @@ class Logger(BaseCallbackHandler):
|
|
|
321
340
|
event_type="node_end",
|
|
322
341
|
log_id=self.runtime_ctx.logid,
|
|
323
342
|
method=self.runtime_ctx.method,
|
|
324
|
-
node_type="condition"
|
|
343
|
+
node_type="condition",
|
|
344
|
+
worktree_name=self.runtime_ctx.worktree_name,
|
|
345
|
+
user_id=self.runtime_ctx.user_id,
|
|
325
346
|
)
|
|
326
347
|
write_log(log_entry)
|
|
327
348
|
return
|
|
@@ -340,6 +361,8 @@ class Logger(BaseCallbackHandler):
|
|
|
340
361
|
log_id=self.runtime_ctx.logid,
|
|
341
362
|
node_name=node_info.name,
|
|
342
363
|
method=self.runtime_ctx.method,
|
|
364
|
+
worktree_name=self.runtime_ctx.worktree_name,
|
|
365
|
+
user_id=self.runtime_ctx.user_id,
|
|
343
366
|
)
|
|
344
367
|
write_log(log_entry)
|
|
345
368
|
|
|
@@ -354,6 +377,8 @@ class Logger(BaseCallbackHandler):
|
|
|
354
377
|
execute_id=self.runtime_ctx.run_id,
|
|
355
378
|
input_data=_serialize_data(inputs),
|
|
356
379
|
method=self.runtime_ctx.method,
|
|
380
|
+
worktree_name=self.runtime_ctx.worktree_name,
|
|
381
|
+
user_id=self.runtime_ctx.user_id,
|
|
357
382
|
)
|
|
358
383
|
|
|
359
384
|
def _on_graph_end(self, outputs: Dict[str, Any]):
|
|
@@ -367,6 +392,8 @@ class Logger(BaseCallbackHandler):
|
|
|
367
392
|
log_id=self.runtime_ctx.logid,
|
|
368
393
|
is_test_run=not is_prod(),
|
|
369
394
|
method=self.runtime_ctx.method,
|
|
395
|
+
worktree_name=self.runtime_ctx.worktree_name,
|
|
396
|
+
user_id=self.runtime_ctx.user_id,
|
|
370
397
|
)
|
|
371
398
|
|
|
372
399
|
def on_chain_error(
|
|
@@ -409,6 +436,8 @@ class Logger(BaseCallbackHandler):
|
|
|
409
436
|
error_message=str(error),
|
|
410
437
|
node_name=node_name,
|
|
411
438
|
method=self.runtime_ctx.method,
|
|
439
|
+
worktree_name=self.runtime_ctx.worktree_name,
|
|
440
|
+
user_id=self.runtime_ctx.user_id,
|
|
412
441
|
)
|
|
413
442
|
write_log(error_log_entry)
|
|
414
443
|
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/log/write_log.py
RENAMED
|
@@ -5,16 +5,16 @@ from contextvars import ContextVar
|
|
|
5
5
|
from typing import Optional
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from coze_coding_utils.runtime_ctx.context import Context
|
|
8
|
-
from coze_coding_utils.log.config import LOG_DIR
|
|
8
|
+
from coze_coding_utils.log.config import LOG_DIR, resolve_log_dir
|
|
9
9
|
|
|
10
10
|
request_context: ContextVar[Optional[Context]] = ContextVar('request_context', default=None)
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class ContextFilter(logging.Filter):
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
def filter(self, record: logging.LogRecord) -> bool:
|
|
16
16
|
ctx = request_context.get()
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
if ctx:
|
|
19
19
|
record.log_id = ctx.logid or ''
|
|
20
20
|
record.run_id = ctx.run_id or ''
|
|
@@ -22,6 +22,8 @@ class ContextFilter(logging.Filter):
|
|
|
22
22
|
record.project_id = ctx.project_id or ''
|
|
23
23
|
record.method = ctx.method or ''
|
|
24
24
|
record.x_tt_env = ctx.x_tt_env or ''
|
|
25
|
+
record.worktree_name = ctx.worktree_name or ''
|
|
26
|
+
record.user_id = ctx.user_id or ''
|
|
25
27
|
else:
|
|
26
28
|
record.log_id = ''
|
|
27
29
|
record.run_id = ''
|
|
@@ -29,7 +31,9 @@ class ContextFilter(logging.Filter):
|
|
|
29
31
|
record.project_id = ''
|
|
30
32
|
record.method = ''
|
|
31
33
|
record.x_tt_env = ''
|
|
32
|
-
|
|
34
|
+
record.worktree_name = ''
|
|
35
|
+
record.user_id = ''
|
|
36
|
+
|
|
33
37
|
return True
|
|
34
38
|
|
|
35
39
|
|
|
@@ -44,7 +48,7 @@ class APSchedulerFilter(logging.Filter):
|
|
|
44
48
|
|
|
45
49
|
|
|
46
50
|
class JsonFormatter(logging.Formatter):
|
|
47
|
-
|
|
51
|
+
|
|
48
52
|
def format(self, record: logging.LogRecord) -> str:
|
|
49
53
|
log_data = {
|
|
50
54
|
'message': record.getMessage(),
|
|
@@ -57,29 +61,32 @@ class JsonFormatter(logging.Formatter):
|
|
|
57
61
|
'project_id': getattr(record, 'project_id', ''),
|
|
58
62
|
'method': getattr(record, 'method', ''),
|
|
59
63
|
'x_tt_env': getattr(record, 'x_tt_env', ''),
|
|
64
|
+
'worktree_name': getattr(record, 'worktree_name', ''),
|
|
65
|
+
'user_id': getattr(record, 'user_id', ''),
|
|
60
66
|
'lineno': record.lineno,
|
|
61
67
|
'funcName': record.funcName,
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
if record.exc_info:
|
|
65
71
|
log_data['exc_info'] = self.formatException(record.exc_info)
|
|
66
|
-
|
|
72
|
+
|
|
67
73
|
for key, value in record.__dict__.items():
|
|
68
|
-
if key not in ['name', 'msg', 'args', 'created', 'filename', 'funcName',
|
|
69
|
-
'levelname', 'levelno', 'lineno', 'module', 'msecs',
|
|
74
|
+
if key not in ['name', 'msg', 'args', 'created', 'filename', 'funcName',
|
|
75
|
+
'levelname', 'levelno', 'lineno', 'module', 'msecs',
|
|
70
76
|
'message', 'pathname', 'process', 'processName', 'relativeCreated',
|
|
71
77
|
'thread', 'threadName', 'exc_info', 'exc_text', 'stack_info',
|
|
72
78
|
'log_id', 'run_id', 'space_id', 'project_id', 'method',
|
|
73
|
-
'x_tt_env', '
|
|
79
|
+
'x_tt_env', 'worktree_name', 'user_id',
|
|
80
|
+
'rpc_persist_rec_rec_biz_scene',
|
|
74
81
|
'rpc_persist_coze_record_root_id', 'rpc_persist_rec_root_entity_type',
|
|
75
82
|
'rpc_persist_rec_root_entity_id']:
|
|
76
83
|
log_data[key] = value
|
|
77
|
-
|
|
84
|
+
|
|
78
85
|
return json.dumps(log_data, ensure_ascii=False)
|
|
79
86
|
|
|
80
87
|
|
|
81
88
|
class PlainTextFormatter(logging.Formatter):
|
|
82
|
-
|
|
89
|
+
|
|
83
90
|
def format(self, record: logging.LogRecord) -> str:
|
|
84
91
|
log_data = {
|
|
85
92
|
'message': record.getMessage(),
|
|
@@ -92,24 +99,27 @@ class PlainTextFormatter(logging.Formatter):
|
|
|
92
99
|
'project_id': getattr(record, 'project_id', ''),
|
|
93
100
|
'method': getattr(record, 'method', ''),
|
|
94
101
|
'x_tt_env': getattr(record, 'x_tt_env', ''),
|
|
102
|
+
'worktree_name': getattr(record, 'worktree_name', ''),
|
|
103
|
+
'user_id': getattr(record, 'user_id', ''),
|
|
95
104
|
'lineno': record.lineno,
|
|
96
105
|
'funcName': record.funcName,
|
|
97
106
|
}
|
|
98
|
-
|
|
107
|
+
|
|
99
108
|
if record.exc_info:
|
|
100
109
|
log_data['exc_info'] = self.formatException(record.exc_info)
|
|
101
|
-
|
|
110
|
+
|
|
102
111
|
for key, value in record.__dict__.items():
|
|
103
|
-
if key not in ['name', 'msg', 'args', 'created', 'filename', 'funcName',
|
|
104
|
-
'levelname', 'levelno', 'lineno', 'module', 'msecs',
|
|
112
|
+
if key not in ['name', 'msg', 'args', 'created', 'filename', 'funcName',
|
|
113
|
+
'levelname', 'levelno', 'lineno', 'module', 'msecs',
|
|
105
114
|
'message', 'pathname', 'process', 'processName', 'relativeCreated',
|
|
106
115
|
'thread', 'threadName', 'exc_info', 'exc_text', 'stack_info',
|
|
107
116
|
'log_id', 'run_id', 'space_id', 'project_id', 'method',
|
|
108
|
-
'x_tt_env', '
|
|
117
|
+
'x_tt_env', 'worktree_name', 'user_id',
|
|
118
|
+
'rpc_persist_rec_rec_biz_scene',
|
|
109
119
|
'rpc_persist_coze_record_root_id', 'rpc_persist_rec_root_entity_type',
|
|
110
120
|
'rpc_persist_rec_root_entity_id']:
|
|
111
121
|
log_data[key] = value
|
|
112
|
-
|
|
122
|
+
|
|
113
123
|
return json.dumps(log_data, ensure_ascii=False)
|
|
114
124
|
|
|
115
125
|
|
|
@@ -124,7 +134,7 @@ def setup_logging(
|
|
|
124
134
|
|
|
125
135
|
if log_file is None:
|
|
126
136
|
try:
|
|
127
|
-
log_dir = Path(
|
|
137
|
+
log_dir = Path(resolve_log_dir())
|
|
128
138
|
log_dir.mkdir(parents=True, exist_ok=True)
|
|
129
139
|
log_file = str(log_dir / 'app.log')
|
|
130
140
|
except Exception as e:
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/runtime_ctx/context.py
RENAMED
|
@@ -20,10 +20,17 @@ HEADER_RPC_PERSIST_RES_REC_ROOT_ENTITY_ID = (
|
|
|
20
20
|
HEADER_RPC_PERSIST_RES_REC_EXT_INFO = (
|
|
21
21
|
"rpc-persist-res-rec-ext-info" # 扩展信息,json字符串格式
|
|
22
22
|
)
|
|
23
|
+
# 多 worktree / 多用户排查诊断用:上游可通过 header 透传这两个字段,让本次 ctx 持有它们,
|
|
24
|
+
# 下游的 LangGraph callback / 业务日志直接 record 出来,多会话并发时按字段过滤排查。
|
|
25
|
+
HEADER_X_COZE_WORKTREE_NAME = "x-coze-worktree-name"
|
|
26
|
+
HEADER_X_COZE_USER_ID = "x-coze-user-id"
|
|
23
27
|
|
|
24
28
|
# Environment variable keys
|
|
25
29
|
ENV_SPACE_ID = "COZE_PROJECT_SPACE_ID"
|
|
26
30
|
ENV_PROJECT_ID = "COZE_PROJECT_ID"
|
|
31
|
+
# 沙箱拉起产物子进程时注入。worktree_name 主仓为空字符串;user_id 为创建沙箱的用户 ID。
|
|
32
|
+
ENV_WORKTREE_NAME = "COZE_WORKTREE_NAME"
|
|
33
|
+
ENV_USER_ID = "COZE_USER_ID"
|
|
27
34
|
|
|
28
35
|
|
|
29
36
|
@dataclass(slots=True)
|
|
@@ -36,6 +43,11 @@ class Context:
|
|
|
36
43
|
logid: str = ""
|
|
37
44
|
method: str = ""
|
|
38
45
|
|
|
46
|
+
# 多 worktree / 多用户支持:默认读环境变量(沙箱拉起产物时注入),上游 HTTP 请求 header 可覆盖。
|
|
47
|
+
# 用 "" 表示主仓 / 未提供,避免 None 在 logging record 里出现 'None' 字面值。
|
|
48
|
+
worktree_name: str = ""
|
|
49
|
+
user_id: str = ""
|
|
50
|
+
|
|
39
51
|
x_run_mode: Optional[str] = None
|
|
40
52
|
x_tt_env: Optional[str] = None
|
|
41
53
|
x_use_ppe: Optional[str] = None
|
|
@@ -58,6 +70,8 @@ def new_context(
|
|
|
58
70
|
space_id=os.getenv(ENV_SPACE_ID, ""),
|
|
59
71
|
project_id=os.getenv(ENV_PROJECT_ID, ""),
|
|
60
72
|
method=method,
|
|
73
|
+
worktree_name=os.getenv(ENV_WORKTREE_NAME, ""),
|
|
74
|
+
user_id=os.getenv(ENV_USER_ID, ""),
|
|
61
75
|
)
|
|
62
76
|
if headers:
|
|
63
77
|
norm = {k.casefold(): v for k, v in headers.items()}
|
|
@@ -67,6 +81,8 @@ def new_context(
|
|
|
67
81
|
HEADER_X_USE_PPE: "x_use_ppe",
|
|
68
82
|
HEADER_X_TT_ENV_FE: "x_tt_env_fe",
|
|
69
83
|
HEADER_X_RUN_MODE: "x_run_mode",
|
|
84
|
+
HEADER_X_COZE_WORKTREE_NAME: "worktree_name",
|
|
85
|
+
HEADER_X_COZE_USER_ID: "user_id",
|
|
70
86
|
HEADER_RPC_PERSIST_RES_REC_BIZ_SCENE: "rpc_persist_res_rec_biz_scene",
|
|
71
87
|
HEADER_RPC_PERSIST_COZE_RECORD_ROOT_ID: "rpc_persist_coze_record_root_id",
|
|
72
88
|
HEADER_RPC_PERSIST_RES_REC_ROOT_ENTITY_TYPE: "rpc_persist_res_rec_root_entity_type",
|
|
@@ -91,6 +107,8 @@ def default_headers(ctx: Context | None) -> Dict[str, str]:
|
|
|
91
107
|
"x_use_ppe": HEADER_X_USE_PPE,
|
|
92
108
|
"x_tt_env_fe": HEADER_X_TT_ENV_FE,
|
|
93
109
|
"x_run_mode": HEADER_X_RUN_MODE,
|
|
110
|
+
"worktree_name": HEADER_X_COZE_WORKTREE_NAME,
|
|
111
|
+
"user_id": HEADER_X_COZE_USER_ID,
|
|
94
112
|
"rpc_persist_res_rec_biz_scene": HEADER_RPC_PERSIST_RES_REC_BIZ_SCENE,
|
|
95
113
|
"rpc_persist_coze_record_root_id": HEADER_RPC_PERSIST_COZE_RECORD_ROOT_ID,
|
|
96
114
|
"rpc_persist_res_rec_root_entity_type": HEADER_RPC_PERSIST_RES_REC_ROOT_ENTITY_TYPE,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/error/__init__.py
RENAMED
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/error/classifier.py
RENAMED
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/error/codes.py
RENAMED
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/error/exceptions.py
RENAMED
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/error/patterns.py
RENAMED
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/file/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/helper/__init__.py
RENAMED
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/helper/agent_helper.py
RENAMED
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/helper/graph_helper.py
RENAMED
|
File without changes
|
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/log/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/log/err_trace.py
RENAMED
|
File without changes
|
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/messages/__init__.py
RENAMED
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/messages/client.py
RENAMED
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/messages/server.py
RENAMED
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/openai/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coze_coding_utils-0.2.7a1 → coze_coding_utils-0.2.8a2}/src/coze_coding_utils/openai/handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|