feat: add proxy log client detection filters
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import { TextDecoder } from 'node:util';
|
||||
import type { FastifyRequest, FastifyReply } from 'fastify';
|
||||
import { tokenRouter } from '../../services/tokenRouter.js';
|
||||
import { db, hasProxyLogDownstreamApiKeyIdColumn, schema } from '../../db/index.js';
|
||||
import { refreshModelsAndRebuildRoutes } from '../../services/modelService.js';
|
||||
import { reportProxyAllFailed, reportTokenExpired } from '../../services/alertService.js';
|
||||
import { isTokenExpiredError } from '../../services/alertRules.js';
|
||||
@@ -49,9 +48,9 @@ import {
|
||||
unwrapGeminiCliPayload,
|
||||
} from '../../routes/proxy/geminiCliCompat.js';
|
||||
import { dispatchRuntimeRequest } from '../../routes/proxy/runtimeExecutor.js';
|
||||
import { detectCliProfile } from '../cliProfiles/registry.js';
|
||||
import type { CliProfileId } from '../cliProfiles/types.js';
|
||||
import { summarizeConversationFileInputsInOpenAiBody } from '../capabilities/conversationFileCapabilities.js';
|
||||
import { detectDownstreamClientContext, type DownstreamClientContext } from '../../routes/proxy/downstreamClientContext.js';
|
||||
import { insertProxyLog } from '../../services/proxyLogStore.js';
|
||||
|
||||
const MAX_RETRIES = 2;
|
||||
|
||||
@@ -63,25 +62,6 @@ function asTrimmedString(value: unknown): string {
|
||||
return typeof value === 'string' ? value.trim() : '';
|
||||
}
|
||||
|
||||
type DownstreamClientContext = {
|
||||
clientKind: CliProfileId;
|
||||
sessionId?: string;
|
||||
traceHint?: string;
|
||||
};
|
||||
|
||||
function detectDownstreamClientContext(input: {
|
||||
downstreamPath: string;
|
||||
headers?: Record<string, unknown>;
|
||||
body?: unknown;
|
||||
}): DownstreamClientContext {
|
||||
const detected = detectCliProfile(input);
|
||||
return {
|
||||
clientKind: detected.id,
|
||||
...(detected.sessionId ? { sessionId: detected.sessionId } : {}),
|
||||
...(detected.traceHint ? { traceHint: detected.traceHint } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
export async function handleChatSurfaceRequest(
|
||||
request: FastifyRequest,
|
||||
reply: FastifyReply,
|
||||
@@ -131,8 +111,6 @@ export async function handleChatSurfaceRequest(
|
||||
proxyToken: getProxyAuthContext(request)?.token || null,
|
||||
});
|
||||
const downstreamApiKeyId = getProxyAuthContext(request)?.keyId ?? null;
|
||||
const logDownstreamApiKeyId = downstreamApiKeyId !== null
|
||||
&& await hasProxyLogDownstreamApiKeyIdColumn();
|
||||
|
||||
const excludeChannelIds: number[] = [];
|
||||
let retryCount = 0;
|
||||
@@ -297,7 +275,7 @@ export async function handleChatSurfaceRequest(
|
||||
null,
|
||||
null,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -323,7 +301,7 @@ export async function handleChatSurfaceRequest(
|
||||
null,
|
||||
null,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
await recordOauthQuotaResetHint({
|
||||
accountId: selected.account.id,
|
||||
@@ -426,7 +404,7 @@ export async function handleChatSurfaceRequest(
|
||||
null,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -462,7 +440,7 @@ export async function handleChatSurfaceRequest(
|
||||
null,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
|
||||
if (shouldRetryProxyRequest(failure.status, failure.reason) && retryCount < MAX_RETRIES) {
|
||||
@@ -500,7 +478,7 @@ export async function handleChatSurfaceRequest(
|
||||
null,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -550,7 +528,7 @@ export async function handleChatSurfaceRequest(
|
||||
null,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -604,7 +582,7 @@ export async function handleChatSurfaceRequest(
|
||||
billingDetails,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -654,7 +632,7 @@ export async function handleChatSurfaceRequest(
|
||||
null,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
|
||||
if (shouldRetryProxyRequest(failure.status, failure.reason) && retryCount < MAX_RETRIES) {
|
||||
@@ -716,7 +694,7 @@ export async function handleChatSurfaceRequest(
|
||||
billingDetails,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
|
||||
return reply.send(downstreamResponse);
|
||||
@@ -738,7 +716,7 @@ export async function handleChatSurfaceRequest(
|
||||
null,
|
||||
null,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
|
||||
if (retryCount < MAX_RETRIES) {
|
||||
@@ -817,8 +795,6 @@ export async function handleClaudeCountTokensSurfaceRequest(
|
||||
});
|
||||
const downstreamPolicy = getDownstreamRoutingPolicy(request);
|
||||
const downstreamApiKeyId = getProxyAuthContext(request)?.keyId ?? null;
|
||||
const logDownstreamApiKeyId = downstreamApiKeyId !== null
|
||||
&& await hasProxyLogDownstreamApiKeyIdColumn();
|
||||
const excludeChannelIds: number[] = [];
|
||||
let retryCount = 0;
|
||||
|
||||
@@ -942,7 +918,7 @@ export async function handleClaudeCountTokensSurfaceRequest(
|
||||
null,
|
||||
upstreamRequest.path,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
if (shouldRetryProxyRequest(upstream.status, typeof payload === 'string' ? payload : text) && retryCount < MAX_RETRIES) {
|
||||
retryCount += 1;
|
||||
@@ -969,7 +945,7 @@ export async function handleClaudeCountTokensSurfaceRequest(
|
||||
null,
|
||||
upstreamRequest.path,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
return reply.code(upstream.status).type(contentType).send(payload);
|
||||
} catch (error: any) {
|
||||
@@ -990,7 +966,7 @@ export async function handleClaudeCountTokensSurfaceRequest(
|
||||
null,
|
||||
null,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
if (retryCount < MAX_RETRIES) {
|
||||
retryCount += 1;
|
||||
@@ -1036,11 +1012,11 @@ async function logProxy(
|
||||
upstreamPath,
|
||||
errorMessage,
|
||||
});
|
||||
await db.insert(schema.proxyLogs).values({
|
||||
await insertProxyLog({
|
||||
routeId: selected.channel.routeId,
|
||||
channelId: selected.channel.id,
|
||||
accountId: selected.account.id,
|
||||
...(downstreamApiKeyId !== null ? { downstreamApiKeyId } : {}),
|
||||
downstreamApiKeyId,
|
||||
modelRequested,
|
||||
modelActual: selected.actualModel,
|
||||
status,
|
||||
@@ -1050,11 +1026,15 @@ async function logProxy(
|
||||
completionTokens,
|
||||
totalTokens,
|
||||
estimatedCost,
|
||||
billingDetails: billingDetails ? JSON.stringify(billingDetails) : null,
|
||||
billingDetails,
|
||||
clientFamily: clientContext?.clientKind || null,
|
||||
clientAppId: clientContext?.clientAppId || null,
|
||||
clientAppName: clientContext?.clientAppName || null,
|
||||
clientConfidence: clientContext?.clientConfidence || null,
|
||||
errorMessage: normalizedErrorMessage,
|
||||
retryCount,
|
||||
createdAt,
|
||||
}).run();
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn('[proxy/chat] failed to write proxy log', error);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ import {
|
||||
wrapGeminiCliRequest,
|
||||
} from '../../routes/proxy/geminiCliCompat.js';
|
||||
import { dispatchRuntimeRequest } from '../../routes/proxy/runtimeExecutor.js';
|
||||
import { detectDownstreamClientContext, type DownstreamClientContext } from '../../routes/proxy/downstreamClientContext.js';
|
||||
import { insertProxyLog } from '../../services/proxyLogStore.js';
|
||||
|
||||
const MAX_RETRIES = 2;
|
||||
const GEMINI_MODEL_PROBES = [
|
||||
@@ -203,6 +205,7 @@ async function logProxy(
|
||||
retryCount: number,
|
||||
downstreamPath: string,
|
||||
upstreamPath: string | null,
|
||||
clientContext: DownstreamClientContext | null = null,
|
||||
promptTokens = 0,
|
||||
completionTokens = 0,
|
||||
totalTokens = 0,
|
||||
@@ -210,11 +213,16 @@ async function logProxy(
|
||||
try {
|
||||
const createdAt = formatUtcSqlDateTime(new Date());
|
||||
const normalizedErrorMessage = composeProxyLogMessage({
|
||||
clientKind: clientContext?.clientKind && clientContext.clientKind !== 'generic'
|
||||
? clientContext.clientKind
|
||||
: null,
|
||||
sessionId: clientContext?.sessionId || null,
|
||||
traceHint: clientContext?.traceHint || null,
|
||||
downstreamPath,
|
||||
upstreamPath,
|
||||
errorMessage,
|
||||
});
|
||||
await db.insert(schema.proxyLogs).values({
|
||||
await insertProxyLog({
|
||||
routeId: selected.channel.routeId,
|
||||
channelId: selected.channel.id,
|
||||
accountId: selected.account.id,
|
||||
@@ -227,11 +235,14 @@ async function logProxy(
|
||||
completionTokens,
|
||||
totalTokens,
|
||||
estimatedCost: 0,
|
||||
billingDetails: null,
|
||||
clientFamily: clientContext?.clientKind || null,
|
||||
clientAppId: clientContext?.clientAppId || null,
|
||||
clientAppName: clientContext?.clientAppName || null,
|
||||
clientConfidence: clientContext?.clientConfidence || null,
|
||||
errorMessage: normalizedErrorMessage,
|
||||
retryCount,
|
||||
createdAt,
|
||||
}).run();
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn('[proxy/gemini] failed to write proxy log', error);
|
||||
}
|
||||
@@ -355,6 +366,11 @@ export async function geminiProxyRoute(app: FastifyInstance) {
|
||||
|
||||
const policy = getDownstreamRoutingPolicy(request);
|
||||
const downstreamPath = resolveDownstreamPath(request);
|
||||
const clientContext = detectDownstreamClientContext({
|
||||
downstreamPath,
|
||||
headers: request.headers as Record<string, unknown>,
|
||||
body: request.body,
|
||||
});
|
||||
const excludeChannelIds: number[] = [];
|
||||
let retryCount = 0;
|
||||
let lastStatus = 503;
|
||||
@@ -489,6 +505,7 @@ export async function geminiProxyRoute(app: FastifyInstance) {
|
||||
retryCount,
|
||||
downstreamPath,
|
||||
upstreamPath,
|
||||
clientContext,
|
||||
);
|
||||
if (retryCount < MAX_RETRIES) {
|
||||
retryCount += 1;
|
||||
@@ -523,6 +540,7 @@ export async function geminiProxyRoute(app: FastifyInstance) {
|
||||
retryCount,
|
||||
downstreamPath,
|
||||
upstreamPath,
|
||||
clientContext,
|
||||
);
|
||||
reply.raw.end();
|
||||
return;
|
||||
@@ -572,6 +590,7 @@ export async function geminiProxyRoute(app: FastifyInstance) {
|
||||
retryCount,
|
||||
downstreamPath,
|
||||
upstreamPath,
|
||||
clientContext,
|
||||
parsedUsage.promptTokens,
|
||||
parsedUsage.completionTokens,
|
||||
parsedUsage.totalTokens,
|
||||
@@ -607,6 +626,7 @@ export async function geminiProxyRoute(app: FastifyInstance) {
|
||||
retryCount,
|
||||
downstreamPath,
|
||||
upstreamPath,
|
||||
clientContext,
|
||||
parsedUsage.promptTokens,
|
||||
parsedUsage.completionTokens,
|
||||
parsedUsage.totalTokens,
|
||||
@@ -629,6 +649,7 @@ export async function geminiProxyRoute(app: FastifyInstance) {
|
||||
retryCount,
|
||||
downstreamPath,
|
||||
upstreamPath,
|
||||
clientContext,
|
||||
);
|
||||
return reply.code(upstream.status).type(contentType || 'application/json').send(text);
|
||||
}
|
||||
@@ -743,6 +764,7 @@ export async function geminiProxyRoute(app: FastifyInstance) {
|
||||
retryCount,
|
||||
downstreamPath,
|
||||
null,
|
||||
clientContext,
|
||||
);
|
||||
if (retryCount < MAX_RETRIES) {
|
||||
retryCount += 1;
|
||||
@@ -780,6 +802,7 @@ export async function geminiProxyRoute(app: FastifyInstance) {
|
||||
retryCount,
|
||||
downstreamPath,
|
||||
upstreamPath,
|
||||
clientContext,
|
||||
parsedUsage.promptTokens,
|
||||
parsedUsage.completionTokens,
|
||||
parsedUsage.totalTokens,
|
||||
@@ -809,6 +832,7 @@ export async function geminiProxyRoute(app: FastifyInstance) {
|
||||
retryCount,
|
||||
downstreamPath,
|
||||
upstreamPath || null,
|
||||
clientContext,
|
||||
);
|
||||
if (retryCount < MAX_RETRIES) {
|
||||
retryCount += 1;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { TextDecoder } from 'node:util';
|
||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||
import { db, hasProxyLogDownstreamApiKeyIdColumn, schema } from '../../db/index.js';
|
||||
import { tokenRouter } from '../../services/tokenRouter.js';
|
||||
import { refreshModelsAndRebuildRoutes } from '../../services/modelService.js';
|
||||
import { reportProxyAllFailed, reportTokenExpired } from '../../services/alertService.js';
|
||||
@@ -44,12 +43,12 @@ import {
|
||||
unwrapGeminiCliPayload,
|
||||
} from '../../routes/proxy/geminiCliCompat.js';
|
||||
import { isCodexResponsesSurface } from '../cliProfiles/codexProfile.js';
|
||||
import { detectCliProfile } from '../cliProfiles/registry.js';
|
||||
import type { CliProfileId } from '../cliProfiles/types.js';
|
||||
import {
|
||||
summarizeConversationFileInputsInOpenAiBody,
|
||||
summarizeConversationFileInputsInResponsesBody,
|
||||
} from '../capabilities/conversationFileCapabilities.js';
|
||||
import { detectDownstreamClientContext, type DownstreamClientContext } from '../../routes/proxy/downstreamClientContext.js';
|
||||
import { insertProxyLog } from '../../services/proxyLogStore.js';
|
||||
|
||||
const MAX_RETRIES = 2;
|
||||
|
||||
@@ -135,25 +134,6 @@ function carriesResponsesFileUrlInput(value: unknown): boolean {
|
||||
|
||||
type UsageSummary = ReturnType<typeof parseProxyUsage>;
|
||||
|
||||
type DownstreamClientContext = {
|
||||
clientKind: CliProfileId;
|
||||
sessionId?: string;
|
||||
traceHint?: string;
|
||||
};
|
||||
|
||||
function detectDownstreamClientContext(input: {
|
||||
downstreamPath: string;
|
||||
headers?: Record<string, unknown>;
|
||||
body?: unknown;
|
||||
}): DownstreamClientContext {
|
||||
const detected = detectCliProfile(input);
|
||||
return {
|
||||
clientKind: detected.id,
|
||||
...(detected.sessionId ? { sessionId: detected.sessionId } : {}),
|
||||
...(detected.traceHint ? { traceHint: detected.traceHint } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function deriveCodexExplicitSessionId(body: Record<string, unknown>): string | null {
|
||||
const promptCacheKey = typeof body.prompt_cache_key === 'string'
|
||||
? body.prompt_cache_key.trim()
|
||||
@@ -196,8 +176,6 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
if (!await ensureModelAllowedForDownstreamKey(request, reply, requestedModel)) return;
|
||||
const downstreamPolicy = getDownstreamRoutingPolicy(request);
|
||||
const downstreamApiKeyId = getProxyAuthContext(request)?.keyId ?? null;
|
||||
const logDownstreamApiKeyId = downstreamApiKeyId !== null
|
||||
&& await hasProxyLogDownstreamApiKeyIdColumn();
|
||||
const excludeChannelIds: number[] = [];
|
||||
let retryCount = 0;
|
||||
|
||||
@@ -397,7 +375,7 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
null,
|
||||
null,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -423,7 +401,7 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
null,
|
||||
null,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
await recordOauthQuotaResetHint({
|
||||
accountId: selected.account.id,
|
||||
@@ -505,7 +483,7 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
usageForLog.promptTokens, usageForLog.completionTokens, usageForLog.totalTokens, estimatedCost, billingDetails,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('[responses] post-stream success logging failed:', error);
|
||||
@@ -578,7 +556,7 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
null,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -617,7 +595,7 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
null,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
|
||||
if (shouldRetryProxyRequest(failure.status, failure.reason) && retryCount < MAX_RETRIES) {
|
||||
@@ -652,7 +630,7 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
null,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -708,7 +686,7 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
null,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -772,7 +750,7 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
null,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
if (shouldRetryProxyRequest(failure.status, failure.reason) && retryCount < MAX_RETRIES) {
|
||||
retryCount += 1;
|
||||
@@ -826,7 +804,7 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
resolvedUsage.promptTokens, resolvedUsage.completionTokens, resolvedUsage.totalTokens, estimatedCost, billingDetails,
|
||||
successfulUpstreamPath,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
return reply.send(downstreamData);
|
||||
} catch (err: any) {
|
||||
@@ -847,7 +825,7 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
null,
|
||||
null,
|
||||
clientContext,
|
||||
logDownstreamApiKeyId ? downstreamApiKeyId : null,
|
||||
downstreamApiKeyId,
|
||||
);
|
||||
if (retryCount < MAX_RETRIES) {
|
||||
retryCount += 1;
|
||||
@@ -894,11 +872,11 @@ async function logProxy(
|
||||
upstreamPath,
|
||||
errorMessage,
|
||||
});
|
||||
await db.insert(schema.proxyLogs).values({
|
||||
await insertProxyLog({
|
||||
routeId: selected.channel.routeId,
|
||||
channelId: selected.channel.id,
|
||||
accountId: selected.account.id,
|
||||
...(downstreamApiKeyId !== null ? { downstreamApiKeyId } : {}),
|
||||
downstreamApiKeyId,
|
||||
modelRequested,
|
||||
modelActual: selected.actualModel,
|
||||
status,
|
||||
@@ -908,11 +886,15 @@ async function logProxy(
|
||||
completionTokens,
|
||||
totalTokens,
|
||||
estimatedCost,
|
||||
billingDetails: billingDetails ? JSON.stringify(billingDetails) : null,
|
||||
billingDetails,
|
||||
clientFamily: clientContext?.clientKind || null,
|
||||
clientAppId: clientContext?.clientAppId || null,
|
||||
clientAppName: clientContext?.clientAppName || null,
|
||||
clientConfidence: clientContext?.clientConfidence || null,
|
||||
errorMessage: normalizedErrorMessage,
|
||||
retryCount,
|
||||
createdAt,
|
||||
}).run();
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn('[proxy/responses] failed to write proxy log', error);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user