-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
Guardrail Monitor - measure guardrail reliability in prod #21944
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
21a0d9f
fafa97a
a693fb0
7d845cc
00b3d21
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,12 +1,16 @@ | ||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||
| CheckCircleOutlined, | ||||||||||||||||||||||||||
| CloseOutlined, | ||||||||||||||||||||||||||
| CopyOutlined, | ||||||||||||||||||||||||||
| DownOutlined, | ||||||||||||||||||||||||||
| WarningOutlined, | ||||||||||||||||||||||||||
| } from "@ant-design/icons"; | ||||||||||||||||||||||||||
| import { useQuery } from "@tanstack/react-query"; | ||||||||||||||||||||||||||
| import moment from "moment"; | ||||||||||||||||||||||||||
| import { Button, Spin } from "antd"; | ||||||||||||||||||||||||||
| import React, { useState } from "react"; | ||||||||||||||||||||||||||
| import { uiSpendLogsCall } from "@/components/networking"; | ||||||||||||||||||||||||||
| import { LogDetailsDrawer } from "@/components/view_logs/LogDetailsDrawer"; | ||||||||||||||||||||||||||
| import type { LogEntry as ViewLogsLogEntry } from "@/components/view_logs/columns"; | ||||||||||||||||||||||||||
| import type { LogEntry } from "./mockData"; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const actionConfig: Record< | ||||||||||||||||||||||||||
|
|
@@ -42,6 +46,9 @@ interface LogViewerProps { | |||||||||||||||||||||||||
| logs?: LogEntry[]; | ||||||||||||||||||||||||||
| logsLoading?: boolean; | ||||||||||||||||||||||||||
| totalLogs?: number; | ||||||||||||||||||||||||||
| accessToken?: string | null; | ||||||||||||||||||||||||||
| startDate?: string; | ||||||||||||||||||||||||||
| endDate?: string; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export function LogViewer({ | ||||||||||||||||||||||||||
|
|
@@ -50,10 +57,14 @@ export function LogViewer({ | |||||||||||||||||||||||||
| logs = [], | ||||||||||||||||||||||||||
| logsLoading = false, | ||||||||||||||||||||||||||
| totalLogs, | ||||||||||||||||||||||||||
| accessToken = null, | ||||||||||||||||||||||||||
| startDate = "", | ||||||||||||||||||||||||||
| endDate = "", | ||||||||||||||||||||||||||
| }: LogViewerProps) { | ||||||||||||||||||||||||||
| const [sampleSize, setSampleSize] = useState(10); | ||||||||||||||||||||||||||
| const [expandedLog, setExpandedLog] = useState<string | null>(null); | ||||||||||||||||||||||||||
| const [activeFilter, setActiveFilter] = useState<string>(filterAction); | ||||||||||||||||||||||||||
| const [selectedRequestId, setSelectedRequestId] = useState<string | null>(null); | ||||||||||||||||||||||||||
| const [drawerOpen, setDrawerOpen] = useState(false); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const filteredLogs = logs.filter( | ||||||||||||||||||||||||||
| (log) => activeFilter === "all" || log.action === activeFilter | ||||||||||||||||||||||||||
|
|
@@ -68,6 +79,43 @@ export function LogViewer({ | |||||||||||||||||||||||||
| "passed", | ||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const startTime = startDate | ||||||||||||||||||||||||||
| ? moment(startDate).utc().format("YYYY-MM-DD HH:mm:ss") | ||||||||||||||||||||||||||
| : moment().subtract(24, "hours").utc().format("YYYY-MM-DD HH:mm:ss"); | ||||||||||||||||||||||||||
| const endTime = endDate | ||||||||||||||||||||||||||
| ? moment(endDate).utc().endOf("day").format("YYYY-MM-DD HH:mm:ss") | ||||||||||||||||||||||||||
| : moment().utc().format("YYYY-MM-DD HH:mm:ss"); | ||||||||||||||||||||||||||
|
Comment on lines
+82
to
+87
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unstable query key causes unnecessary refetches When Consider wrapping these in
Suggested change
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const { data: fullLogResponse } = useQuery({ | ||||||||||||||||||||||||||
| queryKey: ["spend-log-by-request", selectedRequestId, startTime, endTime], | ||||||||||||||||||||||||||
| queryFn: async () => { | ||||||||||||||||||||||||||
| if (!accessToken || !selectedRequestId) return null; | ||||||||||||||||||||||||||
| const res = await uiSpendLogsCall({ | ||||||||||||||||||||||||||
| accessToken, | ||||||||||||||||||||||||||
| start_date: startTime, | ||||||||||||||||||||||||||
| end_date: endTime, | ||||||||||||||||||||||||||
| page: 1, | ||||||||||||||||||||||||||
| page_size: 10, | ||||||||||||||||||||||||||
| params: { request_id: selectedRequestId }, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| return res as { data: ViewLogsLogEntry[]; total: number }; | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| enabled: Boolean(accessToken && selectedRequestId && drawerOpen), | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const selectedLog: ViewLogsLogEntry | null = | ||||||||||||||||||||||||||
| fullLogResponse?.data?.[0] ?? null; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const handleLogClick = (log: LogEntry) => { | ||||||||||||||||||||||||||
| setSelectedRequestId(log.id); | ||||||||||||||||||||||||||
| setDrawerOpen(true); | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const handleCloseDrawer = () => { | ||||||||||||||||||||||||||
| setDrawerOpen(false); | ||||||||||||||||||||||||||
| setSelectedRequestId(null); | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||
| <div className="bg-white border border-gray-200 rounded-lg"> | ||||||||||||||||||||||||||
| <div className="p-4 border-b border-gray-200"> | ||||||||||||||||||||||||||
|
|
@@ -128,16 +176,15 @@ export function LogViewer({ | |||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||
| {!logsLoading && displayLogs.length > 0 && ( | ||||||||||||||||||||||||||
| <div className="divide-y divide-gray-100"> | ||||||||||||||||||||||||||
| {displayLogs.map((log) => { | ||||||||||||||||||||||||||
| const config = actionConfig[log.action]; | ||||||||||||||||||||||||||
| const ActionIcon = config.icon; | ||||||||||||||||||||||||||
| const isExpanded = expandedLog === log.id; | ||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||
| <div key={log.id}> | ||||||||||||||||||||||||||
| <div className="divide-y divide-gray-100"> | ||||||||||||||||||||||||||
| {displayLogs.map((log) => { | ||||||||||||||||||||||||||
| const config = actionConfig[log.action]; | ||||||||||||||||||||||||||
| const ActionIcon = config.icon; | ||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||
| key={log.id} | ||||||||||||||||||||||||||
| type="button" | ||||||||||||||||||||||||||
| onClick={() => setExpandedLog(isExpanded ? null : log.id)} | ||||||||||||||||||||||||||
| onClick={() => handleLogClick(log)} | ||||||||||||||||||||||||||
| className="w-full text-left px-4 py-3 hover:bg-gray-50 transition-colors flex items-start gap-3" | ||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||
| <ActionIcon | ||||||||||||||||||||||||||
|
|
@@ -160,60 +207,21 @@ export function LogViewer({ | |||||||||||||||||||||||||
| {log.input_snippet ?? log.input ?? "β"} | ||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| <span | ||||||||||||||||||||||||||
| className={`flex-shrink-0 mt-1 transition-transform ${ | ||||||||||||||||||||||||||
| isExpanded ? "rotate-180" : "" | ||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||
| <DownOutlined className="w-4 h-4 text-gray-400" /> | ||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||
| <DownOutlined className="w-4 h-4 text-gray-400 flex-shrink-0 mt-1" /> | ||||||||||||||||||||||||||
| </button> | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| {isExpanded && ( | ||||||||||||||||||||||||||
| <div className="px-4 pb-4 pl-11"> | ||||||||||||||||||||||||||
| <div className="bg-gray-50 rounded-lg p-4 space-y-3 text-sm"> | ||||||||||||||||||||||||||
| <div> | ||||||||||||||||||||||||||
| <div className="flex items-center justify-between mb-1"> | ||||||||||||||||||||||||||
| <span className="text-xs font-medium text-gray-500 uppercase tracking-wide"> | ||||||||||||||||||||||||||
| Input | ||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||
| type="text" | ||||||||||||||||||||||||||
| size="small" | ||||||||||||||||||||||||||
| icon={<CopyOutlined />} | ||||||||||||||||||||||||||
| aria-label="Copy input" | ||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| <p className="text-gray-800 font-mono text-xs bg-white rounded border border-gray-200 p-3"> | ||||||||||||||||||||||||||
| {log.input_snippet ?? log.input ?? "β"} | ||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| <div> | ||||||||||||||||||||||||||
| <span className="text-xs font-medium text-gray-500 uppercase tracking-wide"> | ||||||||||||||||||||||||||
| Output | ||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||
| <p className="text-gray-800 font-mono text-xs bg-white rounded border border-gray-200 p-3 mt-1"> | ||||||||||||||||||||||||||
| {log.output_snippet ?? log.output ?? "β"} | ||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| {(log.reason ?? log.score != null) && ( | ||||||||||||||||||||||||||
| <div> | ||||||||||||||||||||||||||
| <span className="text-xs font-medium text-gray-500 uppercase tracking-wide"> | ||||||||||||||||||||||||||
| Reason | ||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||
| <p className="text-gray-700 text-xs mt-1"> | ||||||||||||||||||||||||||
| {log.reason ?? (log.score != null ? `Score: ${log.score}` : "β")} | ||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
| })} | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
| })} | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| <LogDetailsDrawer | ||||||||||||||||||||||||||
| open={drawerOpen} | ||||||||||||||||||||||||||
| onClose={handleCloseDrawer} | ||||||||||||||||||||||||||
| logEntry={selectedLog} | ||||||||||||||||||||||||||
| accessToken={accessToken} | ||||||||||||||||||||||||||
| allLogs={selectedLog ? [selectedLog] : []} | ||||||||||||||||||||||||||
| startTime={startTime} | ||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate IDs in
metric_idswhen names matchWhen
logical_idequalsguardrail_id(e.g. for guardrails where the name was set to match the UUID),metric_idswill contain the same value twice. While Prisma's{"in": [...]}handles duplicates gracefully, it's wasteful. Consider deduplicating:Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!