Files
9router/src/sse/utils/logger.js
T
decoluaandCursor a625ea9fd8 refactor(log): unify request lifecycle logging with session-colored tags
Collapse scattered per-request console lines (request/routing/auth/pending/
usage/stream-usage/stream) into 3 correlated lines: request, transform,
done. Add stable per-session color tag so concurrent request lines are
easy to follow, surface thinking intent, always-on full error logging
for debug, re-enable warn level, and uppercase keyword labels. Also fix
usage overview cards wrapping (5 cards -> grid-cols-5).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-10 18:01:20 +07:00

118 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Logger utility for cloud
const LOG_LEVELS = {
DEBUG: 0,
INFO: 1,
WARN: 2,
ERROR: 3
};
const LEVEL = LOG_LEVELS[process.env.LOG_LEVEL?.toUpperCase?.()] ?? LOG_LEVELS.INFO;
function formatTime() {
return new Date().toLocaleTimeString("en-US", { hour12: false });
}
// Colored-dot tags to correlate request lines by session (same session → same color)
const REQ_TAGS = ["🟢", "🔵", "🟣", "🟡", "🟠", "🔴", "⚪", "🟤"];
let tagCursor = 0;
// Allocate next rotating tag (fallback when no session seed available)
export function nextTag() {
const tag = REQ_TAGS[tagCursor % REQ_TAGS.length];
tagCursor++;
return tag;
}
// Stable tag derived from a session/connection seed: same seed always maps to the same color
export function tagForSession(seed) {
if (!seed) return nextTag();
let h = 0;
for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) | 0;
return REQ_TAGS[Math.abs(h) % REQ_TAGS.length];
}
// Print one correlated line: [time] tag symbol message
export function line(tag, symbol, message) {
if (LEVEL > LOG_LEVELS.INFO) return;
console.log(`[${formatTime()}] ${tag} ${symbol} ${message}`);
}
// Like line() but always printed regardless of LOG_LEVEL (errors must never be hidden)
export function errorLine(tag, symbol, message) {
console.log(`[${formatTime()}] ${tag} ${symbol} ${message}`);
}
// Format thinking intent for the request line ("high(10k)" / "off" / "auto")
export function fmtThink(intent) {
if (!intent || !intent.mode) return null;
if (intent.mode === "none") return "off";
if (intent.mode === "auto") return "auto";
if (intent.mode === "budget") {
const k = intent.budget >= 1000 ? `${Math.round(intent.budget / 1000)}k` : `${intent.budget}`;
return k;
}
if (intent.mode === "level") return intent.level;
return null;
}
function formatData(data) {
if (!data) return "";
if (typeof data === "string") return data;
try {
return JSON.stringify(data);
} catch {
return String(data);
}
}
export function debug(tag, message, data) {
if (LEVEL <= LOG_LEVELS.DEBUG) {
const dataStr = data ? ` ${formatData(data)}` : "";
console.log(`[${formatTime()}] 🔍 [${tag}] ${message}${dataStr}`);
}
}
export function info(tag, message, data) {
if (LEVEL <= LOG_LEVELS.INFO) {
const dataStr = data ? ` ${formatData(data)}` : "";
console.log(`[${formatTime()}] ℹ️ [${tag}] ${message}${dataStr}`);
}
}
export function warn(tag, message, data) {
if (LEVEL <= LOG_LEVELS.WARN) {
const dataStr = data ? ` ${formatData(data)}` : "";
console.warn(`[${formatTime()}] ⚠️ [${tag}] ${message}${dataStr}`);
}
}
export function error(tag, message, data) {
if (LEVEL <= LOG_LEVELS.ERROR) {
const dataStr = data ? ` ${formatData(data)}` : "";
console.log(`[${formatTime()}] ❌ [${tag}] ${message}${dataStr}`);
}
}
export function request(method, path, extra) {
const dataStr = extra ? ` ${formatData(extra)}` : "";
console.log(`\x1b[36m[${formatTime()}] 📥 ${method} ${path}${dataStr}\x1b[0m`);
}
export function response(status, duration, extra) {
const icon = status < 400 ? "📤" : "💥";
const dataStr = extra ? ` ${formatData(extra)}` : "";
console.log(`[${formatTime()}] ${icon} ${status} (${duration}ms)${dataStr}`);
}
export function stream(event, data) {
const dataStr = data ? ` ${formatData(data)}` : "";
console.log(`[${formatTime()}] 🌊 [STREAM] ${event}${dataStr}`);
}
// Mask sensitive data
export function maskKey(key) {
if (!key || key.length < 8) return "***";
return `${key.slice(0, 4)}...${key.slice(-4)}`;
}