| |
| const isNode = typeof process !== "undefined" && process.versions?.node && typeof window === "undefined"; |
|
|
| |
| const LOGGING_ENABLED = typeof process !== "undefined" && process.env?.ENABLE_REQUEST_LOGS === 'true'; |
|
|
| let fs = null; |
| let path = null; |
| let LOGS_DIR = null; |
|
|
| |
| async function ensureNodeModules() { |
| if (!isNode || !LOGGING_ENABLED || fs) return; |
| try { |
| fs = await import("fs"); |
| path = await import("path"); |
| LOGS_DIR = path.join(typeof process !== "undefined" && process.cwd ? process.cwd() : ".", "logs"); |
| } catch { |
| |
| } |
| } |
|
|
| |
| function formatTimestamp(date = new Date()) { |
| const pad = (n) => String(n).padStart(2, "0"); |
| const y = date.getFullYear(); |
| const m = pad(date.getMonth() + 1); |
| const d = pad(date.getDate()); |
| const h = pad(date.getHours()); |
| const min = pad(date.getMinutes()); |
| const s = pad(date.getSeconds()); |
| const ms = String(date.getMilliseconds()).padStart(3, "0"); |
| return `${y}${m}${d}_${h}${min}${s}_${ms}`; |
| } |
|
|
| |
| async function createLogSession(sourceFormat, targetFormat, model) { |
| await ensureNodeModules(); |
| if (!fs || !LOGS_DIR) return null; |
| |
| try { |
| if (!fs.existsSync(LOGS_DIR)) { |
| fs.mkdirSync(LOGS_DIR, { recursive: true }); |
| } |
| |
| const timestamp = formatTimestamp(); |
| const safeModel = (model || "unknown").replace(/[/:]/g, "-"); |
| const folderName = `${sourceFormat}_${targetFormat}_${safeModel}_${timestamp}`; |
| const sessionPath = path.join(LOGS_DIR, folderName); |
| |
| fs.mkdirSync(sessionPath, { recursive: true }); |
| |
| return sessionPath; |
| } catch (err) { |
| console.log("[LOG] Failed to create log session:", err.message); |
| return null; |
| } |
| } |
|
|
| |
| function writeJsonFile(sessionPath, filename, data) { |
| if (!fs || !sessionPath) return; |
| |
| try { |
| const filePath = path.join(sessionPath, filename); |
| fs.writeFileSync(filePath, JSON.stringify(data, null, 2)); |
| } catch (err) { |
| console.log(`[LOG] Failed to write ${filename}:`, err.message); |
| } |
| } |
|
|
| |
| function maskSensitiveHeaders(headers) { |
| if (!headers) return {}; |
| return { ...headers }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| } |
|
|
| |
| function createNoOpLogger() { |
| return { |
| sessionPath: null, |
| logClientRawRequest() {}, |
| logRawRequest() {}, |
| logOpenAIRequest() {}, |
| logTargetRequest() {}, |
| logProviderResponse() {}, |
| appendProviderChunk() {}, |
| appendOpenAIChunk() {}, |
| logConvertedResponse() {}, |
| appendConvertedChunk() {}, |
| logError() {} |
| }; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export async function createRequestLogger(sourceFormat, targetFormat, model) { |
| |
| if (!LOGGING_ENABLED) { |
| return createNoOpLogger(); |
| } |
| |
| |
| const sessionPath = await createLogSession(sourceFormat, targetFormat, model); |
| |
| return { |
| get sessionPath() { return sessionPath; }, |
| |
| |
| logClientRawRequest(endpoint, body, headers = {}) { |
| writeJsonFile(sessionPath, "1_req_client.json", { |
| timestamp: new Date().toISOString(), |
| endpoint, |
| headers: maskSensitiveHeaders(headers), |
| body |
| }); |
| }, |
| |
| |
| logRawRequest(body, headers = {}) { |
| writeJsonFile(sessionPath, "2_req_source.json", { |
| timestamp: new Date().toISOString(), |
| headers: maskSensitiveHeaders(headers), |
| body |
| }); |
| }, |
| |
| |
| logOpenAIRequest(body) { |
| writeJsonFile(sessionPath, "3_req_openai.json", { |
| timestamp: new Date().toISOString(), |
| body |
| }); |
| }, |
| |
| |
| logTargetRequest(url, headers, body) { |
| writeJsonFile(sessionPath, "4_req_target.json", { |
| timestamp: new Date().toISOString(), |
| url, |
| headers: maskSensitiveHeaders(headers), |
| body |
| }); |
| }, |
| |
| |
| logProviderResponse(status, statusText, headers, body) { |
| const filename = "5_res_provider.json"; |
| writeJsonFile(sessionPath, filename, { |
| timestamp: new Date().toISOString(), |
| status, |
| statusText, |
| headers: headers ? (typeof headers.entries === "function" ? Object.fromEntries(headers.entries()) : headers) : {}, |
| body |
| }); |
| }, |
| |
| |
| appendProviderChunk(chunk) { |
| if (!fs || !sessionPath) return; |
| try { |
| const filePath = path.join(sessionPath, "5_res_provider.txt"); |
| fs.appendFileSync(filePath, chunk); |
| } catch (err) { |
| |
| } |
| }, |
| |
| |
| appendOpenAIChunk(chunk) { |
| if (!fs || !sessionPath) return; |
| try { |
| const filePath = path.join(sessionPath, "6_res_openai.txt"); |
| fs.appendFileSync(filePath, chunk); |
| } catch (err) { |
| |
| } |
| }, |
| |
| |
| logConvertedResponse(body) { |
| writeJsonFile(sessionPath, "7_res_client.json", { |
| timestamp: new Date().toISOString(), |
| body |
| }); |
| }, |
| |
| |
| appendConvertedChunk(chunk) { |
| if (!fs || !sessionPath) return; |
| try { |
| const filePath = path.join(sessionPath, "7_res_client.txt"); |
| fs.appendFileSync(filePath, chunk); |
| } catch (err) { |
| |
| } |
| }, |
| |
| |
| logError(error, requestBody = null) { |
| writeJsonFile(sessionPath, "6_error.json", { |
| timestamp: new Date().toISOString(), |
| error: error?.message || String(error), |
| stack: error?.stack, |
| requestBody |
| }); |
| } |
| }; |
| } |
|
|
| |
| export function logRequest() {} |
| export function logResponse() {} |
| export function logError(provider, { error, url, model, requestBody }) { |
| if (!fs || !LOGS_DIR) return; |
| |
| try { |
| if (!fs.existsSync(LOGS_DIR)) { |
| fs.mkdirSync(LOGS_DIR, { recursive: true }); |
| } |
| |
| const date = new Date().toISOString().split("T")[0]; |
| const logPath = path.join(LOGS_DIR, `${provider}-${date}.log`); |
| |
| const logEntry = { |
| timestamp: new Date().toISOString(), |
| type: "error", |
| provider, |
| model, |
| url, |
| error: error?.message || String(error), |
| stack: error?.stack, |
| requestBody |
| }; |
| |
| fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n"); |
| } catch (err) { |
| console.log("[LOG] Failed to write error log:", err.message); |
| } |
| } |
|
|