feat(usage-logs): 新增缓存成本字段并更新相关逻辑

This commit is contained in:
Jeff Gu committed 2026-04-14 20:16:32 +08:00
1 parent 9b2ac4e45f
commit 3b7f39a171
4 files changed
+35 -15

No files matched your search

+3 -2
View File
@@ -469,8 +469,8 @@ export function UsageLogs() {
<td className="px-2 py-3">
{/* <div className="font-medium">{formatCompactNumber(item.totalTokens)} tokens</div> */}
<div className="text-xs text-muted-foreground">
输入 {formatCompactNumber(item.promptTokens)} / 输出{" "}
{formatCompactNumber(item.completionTokens)}
{formatCompactNumber(item.promptTokens)} / {formatCompactNumber(item.completionTokens)} /{" "}
{formatCompactNumber(item.cachedTokens)}
</div>
<div className="mt-1 text-xs text-muted-foreground">
{formatCurrency(item.totalCost, displayDecimals)}
@@ -631,6 +631,7 @@ export function UsageLogs() {
<div className="grid gap-x-8 border-t border-border/60 pt-2 md:grid-cols-2">
<div className="divide-y divide-border/60">
<DetailRow label="总成本" value={formatCurrency(selectedItem.totalCost, displayDecimals)} />
<DetailRow label="缓存成本" value={formatCurrency(selectedItem.cacheCost, displayDecimals)} />
<DetailRow label="延迟" value={formatDuration(selectedItem.latencyMs)} />
<DetailRow label="总 Tokens" value={formatCompactNumber(selectedItem.totalTokens)} />
</div>
+1
View File
@@ -177,6 +177,7 @@ export interface AnalyticsEventItem {
cachedTokens: number
totalTokens: number
totalCost: number
cacheCost: number
latencyMs: number
retryCount: number
upstreamStatus: number
+22 -9
View File
@@ -131,6 +131,7 @@ const DOUBLE_FIELDS = {
upstreamStatus: "double8",
successFlag: "double9",
billingScale: "double10",
cacheCost: "double11",
} as const;
const BREAKDOWN_FIELDS: Record<AnalyticsBreakdownDimension, string> = {
@@ -197,6 +198,7 @@ const USAGE_LOG_NUMERIC_COLUMNS = [
DOUBLE_FIELDS.upstreamStatus,
DOUBLE_FIELDS.successFlag,
DOUBLE_FIELDS.billingScale,
DOUBLE_FIELDS.cacheCost,
];
const ALL_PROBED_COLUMNS = [
@@ -538,16 +540,19 @@ const buildDoubleSelect = (
: `0 AS ${alias}`;
};
const buildNormalizedTotalCostExpression = (support: DatasetColumnSupport): string => {
if (!isColumnAvailable(support, DOUBLE_FIELDS.totalCost)) {
const buildNormalizedCostExpression = (
support: DatasetColumnSupport,
costField: string
): string => {
if (!isColumnAvailable(support, costField)) {
return "0";
}
if (!isColumnAvailable(support, DOUBLE_FIELDS.billingScale)) {
return `${DOUBLE_FIELDS.totalCost} * ${LEGACY_TO_RAW_FACTOR}`;
return `${costField} * ${LEGACY_TO_RAW_FACTOR}`;
}
return `if(${DOUBLE_FIELDS.billingScale} > 0, ${DOUBLE_FIELDS.totalCost} * (${BILLING_RAW_SCALE} / ${DOUBLE_FIELDS.billingScale}), ${DOUBLE_FIELDS.totalCost} * ${LEGACY_TO_RAW_FACTOR})`;
return `if(${DOUBLE_FIELDS.billingScale} > 0, ${costField} * (${BILLING_RAW_SCALE} / ${DOUBLE_FIELDS.billingScale}), ${costField} * ${LEGACY_TO_RAW_FACTOR})`;
};
const hasAnyLegacyLogSchema = (support: DatasetColumnSupport): boolean => {
@@ -624,7 +629,7 @@ export const queryUsageOverview = async (
const { range, config } = getRangeConfig(requestedRange);
const dataset = getDatasetName(c);
const columnSupport = await getDatasetColumnSupport(c, dataset, buildRangeWhereClause(config));
const normalizedTotalCostExpression = buildNormalizedTotalCostExpression(columnSupport);
const normalizedTotalCostExpression = buildNormalizedCostExpression(columnSupport, DOUBLE_FIELDS.totalCost);
const rows = await runAnalyticsQuery<Record<string, unknown>>(c, `
SELECT
sum(_sample_interval) AS requests,
@@ -666,7 +671,7 @@ export const queryUsageTrend = async (
const dataset = getDatasetName(c);
const trendWindow = buildTrendWindow(range, config);
const columnSupport = await getDatasetColumnSupport(c, dataset, trendWindow.whereClause);
const normalizedTotalCostExpression = buildNormalizedTotalCostExpression(columnSupport);
const normalizedTotalCostExpression = buildNormalizedCostExpression(columnSupport, DOUBLE_FIELDS.totalCost);
const rows = await runAnalyticsQuery<Record<string, unknown>>(c, `
SELECT
toUnixTimestamp(${buildBucketClause(config)}) AS bucket_ts,
@@ -716,7 +721,7 @@ export const queryUsageBreakdown = async (
const dataset = getDatasetName(c);
const dimensionField = BREAKDOWN_FIELDS[dimension];
const columnSupport = await getDatasetColumnSupport(c, dataset, buildRangeWhereClause(config));
const normalizedTotalCostExpression = buildNormalizedTotalCostExpression(columnSupport);
const normalizedTotalCostExpression = buildNormalizedCostExpression(columnSupport, DOUBLE_FIELDS.totalCost);
const rows = await runAnalyticsQuery<Record<string, unknown>>(c, `
SELECT
${dimensionField} AS label,
@@ -785,6 +790,8 @@ WHERE ${buildRangeWhereClause(config)}
const columnSupport = await getDatasetColumnSupport(c, dataset, buildRangeWhereClause(config));
const compatibilityWarning = getUsageLogCompatibilityWarning(columnSupport);
const normalizedTotalCostExpression = buildNormalizedCostExpression(columnSupport, DOUBLE_FIELDS.totalCost);
const normalizedCacheCostExpression = buildNormalizedCostExpression(columnSupport, DOUBLE_FIELDS.cacheCost);
const rows = await runAnalyticsQuery<Record<string, unknown>>(c, `
SELECT
timestamp,
@@ -812,7 +819,8 @@ SELECT
${buildDoubleSelect(columnSupport, DOUBLE_FIELDS.completionTokens, "completion_tokens")},
${buildDoubleSelect(columnSupport, DOUBLE_FIELDS.cachedTokens, "cached_tokens")},
${buildDoubleSelect(columnSupport, DOUBLE_FIELDS.totalTokens, "total_tokens")},
${buildNormalizedTotalCostExpression(columnSupport)} AS total_cost,
${normalizedTotalCostExpression} AS total_cost,
${normalizedCacheCostExpression} AS cache_cost,
${buildDoubleSelect(columnSupport, DOUBLE_FIELDS.latencyMs, "latency_ms")},
${buildDoubleSelect(columnSupport, DOUBLE_FIELDS.retryCount, "retry_count")},
${buildDoubleSelect(columnSupport, DOUBLE_FIELDS.upstreamStatus, "upstream_status")}
@@ -853,6 +861,7 @@ LIMIT ${limit}
cachedTokens: toNumber(row.cached_tokens),
totalTokens: toNumber(row.total_tokens),
totalCost: toNumber(row.total_cost),
cacheCost: toNumber(row.cache_cost),
latencyMs: toNumber(row.latency_ms),
retryCount: toNumber(row.retry_count),
upstreamStatus: toNumber(row.upstream_status),
@@ -958,6 +967,8 @@ WHERE ${whereClause}
};
}
const normalizedTotalCostExpression = buildNormalizedCostExpression(columnSupport, DOUBLE_FIELDS.totalCost);
const normalizedCacheCostExpression = buildNormalizedCostExpression(columnSupport, DOUBLE_FIELDS.cacheCost);
const rows = await runAnalyticsQuery<Record<string, unknown>>(c, `
SELECT
timestamp,
@@ -985,7 +996,8 @@ SELECT
${buildDoubleSelect(columnSupport, DOUBLE_FIELDS.completionTokens, "completion_tokens")},
${buildDoubleSelect(columnSupport, DOUBLE_FIELDS.cachedTokens, "cached_tokens")},
${buildDoubleSelect(columnSupport, DOUBLE_FIELDS.totalTokens, "total_tokens")},
${buildNormalizedTotalCostExpression(columnSupport)} AS total_cost,
${normalizedTotalCostExpression} AS total_cost,
${normalizedCacheCostExpression} AS cache_cost,
${buildDoubleSelect(columnSupport, DOUBLE_FIELDS.latencyMs, "latency_ms")},
${buildDoubleSelect(columnSupport, DOUBLE_FIELDS.retryCount, "retry_count")},
${buildDoubleSelect(columnSupport, DOUBLE_FIELDS.upstreamStatus, "upstream_status")}
@@ -1038,6 +1050,7 @@ OFFSET ${offset}
cachedTokens: toNumber(row.cached_tokens),
totalTokens: toNumber(row.total_tokens),
totalCost: toNumber(row.total_cost),
cacheCost: toNumber(row.cache_cost),
latencyMs: toNumber(row.latency_ms),
retryCount: toNumber(row.retry_count),
upstreamStatus: toNumber(row.upstream_status),
+9 -4
View File
@@ -27,6 +27,7 @@ export type UsageLogContext = {
type UsageCostResult = {
totalCost: number;
cacheCost: number;
}
type FailureLogParams = {
@@ -188,7 +189,7 @@ export const buildUsageRequestMetadata = (c: Context<HonoCustomType>) => {
const buildCommonPoint = (
context: UsageLogContext,
usage: Usage,
totalCost: number,
costResult: UsageCostResult,
result: "success" | "failure",
errorCode: string,
errorSummary: string
@@ -230,12 +231,13 @@ const buildCommonPoint = (
completionTokens,
cachedTokens,
totalTokens,
safeNumber(totalCost),
safeNumber(costResult.totalCost),
Math.max(0, Date.now() - context.startedAt),
safeNumber(context.trackingState.retryCount),
upstreamStatus,
result === "success" ? 1 : 0,
BILLING_RAW_SCALE,
safeNumber(costResult.cacheCost),
],
};
};
@@ -246,7 +248,7 @@ export const writeUsageSuccessEvent = (
usage: Usage,
costResult: UsageCostResult
) => {
writeDataPoint(c, buildCommonPoint(context, usage, costResult.totalCost, "success", "", ""));
writeDataPoint(c, buildCommonPoint(context, usage, costResult, "success", "", ""));
};
export const writeUsageFailureEvent = (
@@ -259,7 +261,10 @@ export const writeUsageFailureEvent = (
buildCommonPoint(
context,
{},
0,
{
totalCost: 0,
cacheCost: 0,
},
"failure",
params.errorCode,
params.errorSummary || context.trackingState.errorSummary || ""