快手发码通知采集到独立日志文件,修复 integration 日志阈值问题
This commit is contained in:
@@ -8,7 +8,7 @@ import { handleDestroyCode } from '../services/platforms/kuaishou-industry/destr
|
||||
import { handleQueryCode } from '../services/platforms/kuaishou-industry/query-code-service.js'
|
||||
import { handleConsumeCode } from '../services/platforms/kuaishou-industry/consume-code-service.js'
|
||||
import { buildIndustryErrorResponse } from '../services/platforms/kuaishou-industry/response.js'
|
||||
import { createRequestId, logIntegration } from '../utils/logger.js'
|
||||
import { createRequestId, logCapture, logIntegration } from '../utils/logger.js'
|
||||
|
||||
const router = Router()
|
||||
|
||||
@@ -24,6 +24,7 @@ const industryRateLimit = createRateLimitMiddleware({
|
||||
router.post('/send-code', industryRateLimit, async (req, res) => {
|
||||
const requestId = createRequestId('ksind')
|
||||
const startedAt = Date.now()
|
||||
const mergedParams = mergeRequestParams(req)
|
||||
|
||||
logIntegration('[kuaishou-industry/send-code]', '收到快手行业电子凭证发码请求', {
|
||||
requestId,
|
||||
@@ -34,9 +35,23 @@ router.post('/send-code', industryRateLimit, async (req, res) => {
|
||||
body: req.body,
|
||||
})
|
||||
|
||||
logCapture('[kuaishou-industry/send-code]', '快手通知商家发码消息', {
|
||||
requestId,
|
||||
receivedAt: new Date().toISOString(),
|
||||
method: req.method,
|
||||
originalUrl: req.originalUrl,
|
||||
ip: req.ip,
|
||||
params: mergedParams,
|
||||
}, { channel: 'send-code', sanitize: false })
|
||||
|
||||
try {
|
||||
const params = mergeRequestParams(req)
|
||||
const result = await handleSendCode(params)
|
||||
logCapture('[kuaishou-industry/send-code]', '快手通知商家发码处理完成', {
|
||||
requestId,
|
||||
durationMs: Date.now() - startedAt,
|
||||
result,
|
||||
}, { channel: 'send-code', sanitize: false })
|
||||
logIntegration('[kuaishou-industry/send-code]', '发码处理完成', {
|
||||
requestId,
|
||||
durationMs: Date.now() - startedAt,
|
||||
@@ -45,6 +60,14 @@ router.post('/send-code', industryRateLimit, async (req, res) => {
|
||||
res.status(200).json(result)
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : '系统异常'
|
||||
logCapture('[kuaishou-industry/send-code]', '快手通知商家发码处理失败', {
|
||||
requestId,
|
||||
durationMs: Date.now() - startedAt,
|
||||
error: {
|
||||
name: error instanceof Error ? error.name : 'Error',
|
||||
message,
|
||||
},
|
||||
}, { channel: 'send-code', sanitize: false })
|
||||
logIntegration('[kuaishou-industry/send-code]', '发码处理失败', {
|
||||
requestId,
|
||||
durationMs: Date.now() - startedAt,
|
||||
|
||||
@@ -123,6 +123,25 @@ export function logExternalHttpPacket(
|
||||
return logIntegration(scope, message, normalizeExternalHttpPacketDetail(detail), { level })
|
||||
}
|
||||
|
||||
export function logCapture(
|
||||
scope: unknown,
|
||||
message: unknown,
|
||||
detail: LogDetail = undefined,
|
||||
{ channel = 'capture', sanitize = false }: { channel?: string; sanitize?: boolean } = {},
|
||||
): LogEntry | null {
|
||||
const entry = {
|
||||
time: new Date().toISOString(),
|
||||
level: 'info' as LogLevel,
|
||||
scope: String(scope || 'capture').trim() || 'capture',
|
||||
message: String(message || '').trim() || '-',
|
||||
pid: process.pid,
|
||||
detail: normalizeLogValue(detail, sanitize !== false),
|
||||
}
|
||||
|
||||
enqueueFileWrite(entry, resolveLogFilePath(channel, entry.time), sanitize !== false, true)
|
||||
return entry
|
||||
}
|
||||
|
||||
function writeLog(
|
||||
level: LogLevel,
|
||||
scope: unknown,
|
||||
@@ -146,12 +165,19 @@ function writeLog(
|
||||
}
|
||||
|
||||
writeConsole(entry)
|
||||
enqueueFileWrite(entry, resolveLogFilePath(channel, entry.time))
|
||||
enqueueFileWrite(entry, resolveLogFilePath(channel, entry.time), true)
|
||||
return entry
|
||||
}
|
||||
|
||||
function enqueueFileWrite(entry: LogEntry, filePath: string): void {
|
||||
const line = formatLogEntry(entry, { color: false })
|
||||
function enqueueFileWrite(
|
||||
entry: LogEntry,
|
||||
filePath: string,
|
||||
sanitize: boolean,
|
||||
jsonLine = false,
|
||||
): void {
|
||||
const line = jsonLine
|
||||
? JSON.stringify(entry)
|
||||
: formatLogEntry(entry, { color: false, sanitize })
|
||||
const dateKey = extractLogDateKey(entry.time)
|
||||
|
||||
writeQueue = writeQueue
|
||||
@@ -204,7 +230,7 @@ export function shouldWriteLog(
|
||||
|
||||
export function formatLogEntry(
|
||||
entry: Partial<LogEntry>,
|
||||
{ color = false }: { color?: boolean } = {},
|
||||
{ color = false, sanitize = true }: { color?: boolean; sanitize?: boolean } = {},
|
||||
): string {
|
||||
const normalizedEntry = {
|
||||
time: String(entry?.time || new Date().toISOString()),
|
||||
@@ -212,7 +238,7 @@ export function formatLogEntry(
|
||||
scope: String(entry?.scope || 'app').trim() || 'app',
|
||||
message: String(entry?.message || '').trim() || '-',
|
||||
pid: Number(entry?.pid || process.pid),
|
||||
detail: sanitizeLogValue(entry?.detail),
|
||||
detail: sanitize !== false ? sanitizeLogValue(entry?.detail) : entry?.detail,
|
||||
}
|
||||
const timestamp = colorize(formatLogTimestamp(normalizedEntry.time), ANSI.gray, color)
|
||||
const level = colorize(
|
||||
@@ -248,10 +274,21 @@ export function formatLogEntry(
|
||||
}
|
||||
|
||||
export function resolveLogFilePath(channel = 'app', time = new Date().toISOString()): string {
|
||||
const normalizedChannel = String(channel || '').trim() === 'integration' ? 'integration' : 'app'
|
||||
const normalizedChannel = normalizeLogChannelName(channel)
|
||||
return path.join(LOG_DIR, `${normalizedChannel}-${extractLogDateKey(time)}.log`)
|
||||
}
|
||||
|
||||
function normalizeLogChannelName(value: unknown): string {
|
||||
const normalized = String(value || '').trim().toLowerCase()
|
||||
if (!normalized) {
|
||||
return 'app'
|
||||
}
|
||||
if (normalized === 'integration') {
|
||||
return 'integration'
|
||||
}
|
||||
return /^[a-z0-9-]{1,40}$/.test(normalized) ? normalized : 'app'
|
||||
}
|
||||
|
||||
export function resolveExpiredLogFilenames(
|
||||
fileNames: string[] = [],
|
||||
referenceTime = new Date().toISOString(),
|
||||
@@ -280,37 +317,37 @@ function resolveDataRoot(): string {
|
||||
return configured ? path.resolve(configured) : path.resolve(PROJECT_ROOT, 'data')
|
||||
}
|
||||
|
||||
function normalizeLogValue(value: unknown): unknown {
|
||||
function normalizeLogValue(value: unknown, sanitize = true): unknown {
|
||||
if (typeof value === 'undefined') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const normalizeCurrent = (current: unknown): unknown => {
|
||||
if (current instanceof Error) {
|
||||
const currentError = current as Error & HttpErrorLike
|
||||
return {
|
||||
name: currentError.name,
|
||||
message: sanitize ? sanitizeLogString(currentError.message) : currentError.message,
|
||||
stack: sanitize ? sanitizeLogString(currentError.stack) : currentError.stack,
|
||||
statusCode: currentError.statusCode,
|
||||
errorCode: currentError.errorCode,
|
||||
context: sanitize ? sanitizeLogValue(currentError.context) : currentError.context,
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof current === 'bigint') {
|
||||
return String(current)
|
||||
}
|
||||
|
||||
return current
|
||||
}
|
||||
|
||||
try {
|
||||
return sanitizeLogValue(
|
||||
JSON.parse(
|
||||
JSON.stringify(value, (_key, current) => {
|
||||
if (current instanceof Error) {
|
||||
const currentError = current as Error & HttpErrorLike
|
||||
return {
|
||||
name: current.name,
|
||||
message: sanitizeLogString(current.message),
|
||||
stack: sanitizeLogString(current.stack),
|
||||
statusCode: currentError.statusCode,
|
||||
errorCode: currentError.errorCode,
|
||||
context: sanitizeLogValue(currentError.context),
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof current === 'bigint') {
|
||||
return String(current)
|
||||
}
|
||||
|
||||
return current
|
||||
}),
|
||||
),
|
||||
)
|
||||
return sanitize
|
||||
? sanitizeLogValue(JSON.parse(JSON.stringify(value, (_key, current) => normalizeCurrent(current))))
|
||||
: JSON.parse(JSON.stringify(value, (_key, current) => normalizeCurrent(current)))
|
||||
} catch {
|
||||
return sanitizeLogString(String(value))
|
||||
return sanitize ? sanitizeLogString(String(value)) : String(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,7 +669,7 @@ function shouldDeleteLogFileByDate(fileName: unknown, cutoffDateKey: string): bo
|
||||
return true
|
||||
}
|
||||
|
||||
const matched = /^(app|integration)-(\d{4}-\d{2}-\d{2})\.log$/.exec(String(fileName || '').trim())
|
||||
const matched = /^([a-z0-9-]{1,40})-(\d{4}-\d{2}-\d{2})\.log$/.exec(String(fileName || '').trim())
|
||||
|
||||
if (!matched) {
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user