mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
feat(trace): 在请求链路追踪中记录并展示首字时间(TTFB)
将 first_byte_time_ms 添加到候选记录的 extra_data 中, 并在前端时间线组件中展示该指标。
This commit is contained in:
@@ -175,6 +175,13 @@
|
||||
{{ currentAttempt.finished_at ? formatTime(currentAttempt.finished_at) : '进行中' }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="currentAttempt.extra_data?.first_byte_time_ms != null"
|
||||
class="info-item"
|
||||
>
|
||||
<span class="info-label">首字 (TTFB)</span>
|
||||
<span class="info-value mono">{{ formatLatency(currentAttempt.extra_data.first_byte_time_ms) }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="currentAttempt.key_name || currentAttempt.key_id"
|
||||
class="info-item"
|
||||
|
||||
@@ -1438,6 +1438,13 @@ class CliMessageHandlerBase(BaseMessageHandler):
|
||||
if ctx.status_code and ctx.status_code >= 400:
|
||||
# 请求链路追踪使用 upstream_response(原始响应),回退到 error_message(友好消息)
|
||||
trace_error_message = ctx.upstream_response or ctx.error_message or f"HTTP {ctx.status_code}"
|
||||
extra_data = {
|
||||
"stream_completed": False,
|
||||
"chunk_count": ctx.chunk_count,
|
||||
"data_count": ctx.data_count,
|
||||
}
|
||||
if ctx.first_byte_time_ms is not None:
|
||||
extra_data["first_byte_time_ms"] = ctx.first_byte_time_ms
|
||||
RequestCandidateService.mark_candidate_failed(
|
||||
db=bg_db,
|
||||
candidate_id=ctx.attempt_id,
|
||||
@@ -1447,23 +1454,22 @@ class CliMessageHandlerBase(BaseMessageHandler):
|
||||
error_message=trace_error_message,
|
||||
status_code=ctx.status_code,
|
||||
latency_ms=response_time_ms,
|
||||
extra_data={
|
||||
"stream_completed": False,
|
||||
"chunk_count": ctx.chunk_count,
|
||||
"data_count": ctx.data_count,
|
||||
},
|
||||
extra_data=extra_data,
|
||||
)
|
||||
else:
|
||||
extra_data = {
|
||||
"stream_completed": True,
|
||||
"chunk_count": ctx.chunk_count,
|
||||
"data_count": ctx.data_count,
|
||||
}
|
||||
if ctx.first_byte_time_ms is not None:
|
||||
extra_data["first_byte_time_ms"] = ctx.first_byte_time_ms
|
||||
RequestCandidateService.mark_candidate_success(
|
||||
db=bg_db,
|
||||
candidate_id=ctx.attempt_id,
|
||||
status_code=ctx.status_code,
|
||||
latency_ms=response_time_ms,
|
||||
extra_data={
|
||||
"stream_completed": True,
|
||||
"chunk_count": ctx.chunk_count,
|
||||
"data_count": ctx.data_count,
|
||||
},
|
||||
extra_data=extra_data,
|
||||
)
|
||||
|
||||
finally:
|
||||
|
||||
@@ -241,16 +241,20 @@ class StreamTelemetryRecorder:
|
||||
|
||||
from src.services.request.candidate import RequestCandidateService
|
||||
|
||||
extra_data: Dict[str, Any] = {
|
||||
"stream_completed": ctx.is_success(),
|
||||
"data_count": ctx.data_count,
|
||||
}
|
||||
if ctx.first_byte_time_ms is not None:
|
||||
extra_data["first_byte_time_ms"] = ctx.first_byte_time_ms
|
||||
|
||||
if ctx.is_success():
|
||||
RequestCandidateService.mark_candidate_success(
|
||||
db=db,
|
||||
candidate_id=ctx.attempt_id,
|
||||
status_code=ctx.status_code,
|
||||
latency_ms=response_time_ms,
|
||||
extra_data={
|
||||
"stream_completed": True,
|
||||
"data_count": ctx.data_count,
|
||||
},
|
||||
extra_data=extra_data,
|
||||
)
|
||||
else:
|
||||
error_type = "client_disconnected" if ctx.status_code == 499 else "stream_error"
|
||||
@@ -263,10 +267,7 @@ class StreamTelemetryRecorder:
|
||||
error_message=trace_error_message,
|
||||
status_code=ctx.status_code,
|
||||
latency_ms=response_time_ms,
|
||||
extra_data={
|
||||
"stream_completed": False,
|
||||
"data_count": ctx.data_count,
|
||||
},
|
||||
extra_data=extra_data,
|
||||
)
|
||||
|
||||
async def _update_usage_status_on_error(
|
||||
|
||||
Reference in New Issue
Block a user