请求明细支持查看原始请求/响应:OT_PROXY_LOG_RAW 开关控制,仅管理员记录与可见,流式全量捕获
- 配置: ProxyConfig.LogRaw (OT_PROXY_LOG_RAW, 默认 false) - 存储: usage_logs 新增 raw_request/raw_response 文本列 (AutoMigrate) - 网关: NewGateway 接收 logRaw 参数 - handlers: 三个协议入口按 开关+管理员 条件记录原始请求体 - passthrough: 非流式 copyAndCapture 捕获响应, 流式 streamCopy 累积全部原始 SSE 行, finishUsage 统一写入 - admin API: AdminUsage 返回 raw_request/raw_response (仅管理员) - 前端: 用量页新增查看入口, 弹窗 tab 切换请求/响应 - gitignore: 修正 server/web/ 忽略规则(尾随空格导致未生效)
This commit is contained in:
@@ -6,6 +6,7 @@ import { protocolShort } from '@/lib/protocol'
|
||||
import { fmtCost, fmtTime } from '@/lib/format'
|
||||
import Badge from '@/components/ui/Badge.vue'
|
||||
import Button from '@/components/ui/Button.vue'
|
||||
import Modal from '@/components/ui/Modal.vue'
|
||||
import type { UsageLog } from '@/types'
|
||||
|
||||
const toast = useToastStore()
|
||||
@@ -15,6 +16,14 @@ const page = ref(1)
|
||||
const modelFilter = ref('')
|
||||
const pageSize = 15
|
||||
|
||||
const viewing = ref<UsageLog | null>(null)
|
||||
const viewTab = ref<'request' | 'response'>('request')
|
||||
|
||||
function openRaw(l: UsageLog) {
|
||||
viewing.value = l
|
||||
viewTab.value = 'request'
|
||||
}
|
||||
|
||||
async function load() {
|
||||
try {
|
||||
const { data } = await http.get(
|
||||
@@ -77,6 +86,7 @@ onMounted(load)
|
||||
<span class="mono-num">{{ l.input_tokens }}/{{ l.output_tokens }} tok</span>
|
||||
<span class="mono-num">{{ l.latency_ms }}ms</span>
|
||||
<span class="mono-num w-full">{{ fmtTime(l.created_at) }}</span>
|
||||
<Button v-if="l.raw_request" size="sm" variant="ghost" class="ml-auto" @click="openRaw(l)">查看原始</Button>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="logs.length === 0" class="card px-4 py-8 text-center text-sm text-muted">暂无请求记录</p>
|
||||
@@ -95,6 +105,7 @@ onMounted(load)
|
||||
<th scope="col" class="px-4 py-2.5 font-medium">耗时</th>
|
||||
<th scope="col" class="px-4 py-2.5 font-medium">状态</th>
|
||||
<th scope="col" class="px-4 py-2.5 font-medium">时间</th>
|
||||
<th scope="col" class="px-4 py-2.5 font-medium">原始</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -109,9 +120,13 @@ onMounted(load)
|
||||
<Badge :variant="l.status === 'success' ? 'ok' : l.status === 'canceled' ? 'neutral' : 'err'">{{ l.status }}</Badge>
|
||||
</td>
|
||||
<td class="px-4 py-2.5 font-mono text-xs text-muted">{{ fmtTime(l.created_at) }}</td>
|
||||
<td class="px-4 py-2.5">
|
||||
<Button v-if="l.raw_request" size="sm" variant="ghost" @click="openRaw(l)">查看</Button>
|
||||
<span v-else class="text-xs text-muted">-</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="logs.length === 0">
|
||||
<td colspan="8" class="px-4 py-10 text-center text-sm text-muted">暂无请求记录</td>
|
||||
<td colspan="9" class="px-4 py-10 text-center text-sm text-muted">暂无请求记录</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -124,5 +139,42 @@ onMounted(load)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal :open="!!viewing" title="原始请求与响应" width="max-w-3xl" @close="viewing = null">
|
||||
<div v-if="viewing" class="space-y-3">
|
||||
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||
<div class="text-xs text-muted">
|
||||
<span class="font-mono text-ink">{{ viewing.model }}</span>
|
||||
<span class="mx-1.5">·</span>
|
||||
<span class="font-mono">{{ viewing.user || '-' }}</span>
|
||||
<span class="mx-1.5">·</span>
|
||||
<span class="mono-num">{{ fmtTime(viewing.created_at) }}</span>
|
||||
</div>
|
||||
<div class="flex gap-1 rounded-md border border-edge p-0.5">
|
||||
<button
|
||||
class="rounded px-2.5 py-1 text-xs transition"
|
||||
:class="viewTab === 'request' ? 'bg-surface2 text-ink' : 'text-muted'"
|
||||
@click="viewTab = 'request'"
|
||||
>
|
||||
请求
|
||||
</button>
|
||||
<button
|
||||
class="rounded px-2.5 py-1 text-xs transition"
|
||||
:class="viewTab === 'response' ? 'bg-surface2 text-ink' : 'text-muted'"
|
||||
@click="viewTab = 'response'"
|
||||
>
|
||||
响应
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<pre
|
||||
v-if="viewTab === 'request' ? viewing.raw_request : viewing.raw_response"
|
||||
class="max-h-[60vh] overflow-auto rounded-md border border-edge bg-surface p-3 font-mono text-xs leading-relaxed text-ink whitespace-pre-wrap break-all"
|
||||
>{{ viewTab === 'request' ? viewing.raw_request : viewing.raw_response }}</pre>
|
||||
<p v-else class="rounded-md border border-edge bg-surface p-4 text-center text-xs text-muted">
|
||||
该请求未记录{{ viewTab === 'request' ? '原始请求' : '原始响应' }}
|
||||
</p>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user