mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-05 14:52:09 +03:00
fix: add four-stage request log payloads
This commit is contained in:
@@ -80,8 +80,42 @@ export default function RequestLoggerDetail({ log, detail, loading, onClose, onC
|
||||
}
|
||||
};
|
||||
|
||||
const requestJson = detail?.requestBody ? JSON.stringify(detail.requestBody, null, 2) : null;
|
||||
const responseJson = detail?.responseBody ? JSON.stringify(detail.responseBody, null, 2) : null;
|
||||
const toPrettyJson = (payload) => {
|
||||
if (payload === null || payload === undefined) return null;
|
||||
try {
|
||||
return JSON.stringify(payload, null, 2);
|
||||
} catch {
|
||||
return String(payload);
|
||||
}
|
||||
};
|
||||
|
||||
const pipelinePayloads = detail?.pipelinePayloads || null;
|
||||
const payloadSections = pipelinePayloads
|
||||
? [
|
||||
{
|
||||
key: "client-request",
|
||||
title: "Client Request",
|
||||
json: toPrettyJson(pipelinePayloads.clientRequest),
|
||||
},
|
||||
{
|
||||
key: "provider-request",
|
||||
title: "Provider Request",
|
||||
json: toPrettyJson(pipelinePayloads.providerRequest),
|
||||
},
|
||||
{
|
||||
key: "provider-response",
|
||||
title: "Provider Response",
|
||||
json: toPrettyJson(pipelinePayloads.providerResponse),
|
||||
},
|
||||
{
|
||||
key: "client-response",
|
||||
title: "Client Response",
|
||||
json: toPrettyJson(pipelinePayloads.clientResponse),
|
||||
},
|
||||
].filter((section) => section.json)
|
||||
: [];
|
||||
const requestJson = detail?.requestBody ? toPrettyJson(detail.requestBody) : null;
|
||||
const responseJson = detail?.responseBody ? toPrettyJson(detail.responseBody) : null;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -240,33 +274,41 @@ export default function RequestLoggerDetail({ log, detail, loading, onClose, onC
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{/* Response Payload (返回) — show first */}
|
||||
{responseJson && (
|
||||
{payloadSections.length > 0 &&
|
||||
payloadSections.map((section) => (
|
||||
<PayloadSection
|
||||
key={section.key}
|
||||
title={section.title}
|
||||
json={section.json}
|
||||
onCopy={() => onCopy(section.json)}
|
||||
/>
|
||||
))}
|
||||
|
||||
{payloadSections.length === 0 && responseJson && (
|
||||
<PayloadSection
|
||||
title="Response Payload (返回)"
|
||||
title="Response Payload (Legacy)"
|
||||
json={responseJson}
|
||||
onCopy={() => onCopy(responseJson)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Request Payload (请求) */}
|
||||
{requestJson && (
|
||||
{payloadSections.length === 0 && requestJson && (
|
||||
<PayloadSection
|
||||
title="Request Payload (请求)"
|
||||
title="Request Payload (Legacy)"
|
||||
json={requestJson}
|
||||
onCopy={() => onCopy(requestJson)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!requestJson && !responseJson && !loading && (
|
||||
{payloadSections.length === 0 && !requestJson && !responseJson && !loading && (
|
||||
<div className="p-6 text-center text-text-muted">
|
||||
<span className="material-symbols-outlined text-[32px] mb-2 block opacity-40">
|
||||
info
|
||||
</span>
|
||||
<p className="text-sm">No payload data available for this log entry.</p>
|
||||
<p className="text-xs mt-1">
|
||||
Request/response bodies are only captured for non-streaming calls or when
|
||||
streaming completes normally.
|
||||
Enable detailed logging first if you want the four-stage client/provider payload
|
||||
view for new requests.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -93,6 +93,9 @@ export default function RequestLoggerV2() {
|
||||
const [selectedLog, setSelectedLog] = useState(null);
|
||||
const [detailLoading, setDetailLoading] = useState(false);
|
||||
const [detailData, setDetailData] = useState(null);
|
||||
const [detailLoggingEnabled, setDetailLoggingEnabled] = useState(false);
|
||||
const [detailLoggingLoading, setDetailLoggingLoading] = useState(false);
|
||||
const [detailLoggingReady, setDetailLoggingReady] = useState(false);
|
||||
const intervalRef = useRef(null);
|
||||
const hasLoadedRef = useRef(false);
|
||||
const [providerNodes, setProviderNodes] = useState([]);
|
||||
@@ -161,6 +164,20 @@ export default function RequestLoggerV2() {
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/api/logs/detail?limit=1")
|
||||
.then(async (res) => {
|
||||
if (!res.ok) return null;
|
||||
return await res.json();
|
||||
})
|
||||
.then((data) => {
|
||||
if (!data) return;
|
||||
setDetailLoggingEnabled(data.enabled === true);
|
||||
setDetailLoggingReady(true);
|
||||
})
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
// Auto-refresh
|
||||
useEffect(() => {
|
||||
if (intervalRef.current) clearInterval(intervalRef.current);
|
||||
@@ -232,6 +249,25 @@ export default function RequestLoggerV2() {
|
||||
setDetailData(null);
|
||||
};
|
||||
|
||||
const toggleDetailLogging = async () => {
|
||||
setDetailLoggingLoading(true);
|
||||
try {
|
||||
const nextEnabled = !detailLoggingEnabled;
|
||||
const res = await fetch("/api/logs/detail", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ enabled: nextEnabled }),
|
||||
});
|
||||
if (!res.ok) throw new Error("Failed to update detailed logging");
|
||||
setDetailLoggingEnabled(nextEnabled);
|
||||
setDetailLoggingReady(true);
|
||||
} catch (error) {
|
||||
console.error("Failed to toggle detailed logging:", error);
|
||||
} finally {
|
||||
setDetailLoggingLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Unique accounts and providers for dropdowns
|
||||
|
||||
const uniqueAccounts = [...new Set(logs.map((l) => l.account).filter((a) => a && a !== "-"))];
|
||||
@@ -271,6 +307,33 @@ export default function RequestLoggerV2() {
|
||||
{recording ? "Recording" : "Paused"}
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={toggleDetailLogging}
|
||||
disabled={detailLoggingLoading}
|
||||
className={`flex items-center gap-2 px-3 py-1.5 rounded-full text-sm font-medium border transition-colors disabled:opacity-60 ${
|
||||
detailLoggingEnabled
|
||||
? "bg-amber-500/10 border-amber-500/30 text-amber-700 dark:text-amber-300"
|
||||
: "bg-bg-subtle border-border text-text-muted"
|
||||
}`}
|
||||
title="Capture four-stage pipeline payloads for new requests"
|
||||
>
|
||||
<span
|
||||
className={`w-2 h-2 rounded-full ${detailLoggingEnabled ? "bg-amber-500" : "bg-text-muted"}`}
|
||||
/>
|
||||
{detailLoggingLoading
|
||||
? "Updating detailed logs..."
|
||||
: detailLoggingEnabled
|
||||
? "Detailed Logs On"
|
||||
: "Detailed Logs Off"}
|
||||
</button>
|
||||
|
||||
{detailLoggingReady && (
|
||||
<span className="text-[11px] text-text-muted">
|
||||
New requests will {detailLoggingEnabled ? "" : "not "}capture client/provider pipeline
|
||||
payloads.
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* Search */}
|
||||
<div className="flex-1 min-w-[200px] relative">
|
||||
<span className="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-text-muted text-[18px]">
|
||||
|
||||
Reference in New Issue
Block a user