Files
claude-code-router/src/index.ts
BigUncle b8f52ba538 feat logging: Implement LOG_LEVEL configuration option and improve logging consistency
- Add LOG_LEVEL configuration option to control logging verbosity
- Update UI to include LOG_LEVEL dropdown in settings
- Fix logging inconsistency between environment variables and config file
- Unify logging configuration to use config file settings
- Maintain separate logging systems for different purposes:
  * Server-level logs (HTTP requests, API calls) using pino in ~/.claude-code-router/logs/
  * Application-level logs (routing decisions, business logic) in ~/.claude-code-router/claude-code-router.log
- Update documentation with accurate logging system information
- Add detailed information about dual logging systems in README.md and README_zh.md
- Improve type safety and validation in ConfigProvider

Co-authored-by: qwen-cli <https://github.com/QwenLM/qwen-code>
2025-08-14 21:17:27 +08:00

137 lines
3.6 KiB
TypeScript

import { existsSync } from "fs";
import { writeFile } from "fs/promises";
import { homedir } from "os";
import path, { join } from "path";
import { initConfig, initDir, cleanupLogFiles } from "./utils";
import { createServer } from "./server";
import { router } from "./utils/router";
import { apiKeyAuth } from "./middleware/auth";
import {
cleanupPidFile,
isServiceRunning,
savePid,
} from "./utils/processCheck";
import { CONFIG_FILE } from "./constants";
import createWriteStream from "pino-rotating-file-stream";
import { HOME_DIR } from "./constants";
import { configureLogging } from "./utils/log";
async function initializeClaudeConfig() {
const homeDir = homedir();
const configPath = join(homeDir, ".claude.json");
if (!existsSync(configPath)) {
const userID = Array.from(
{ length: 64 },
() => Math.random().toString(16)[2]
).join("");
const configContent = {
numStartups: 184,
autoUpdaterStatus: "enabled",
userID,
hasCompletedOnboarding: true,
lastOnboardingVersion: "1.0.17",
projects: {},
};
await writeFile(configPath, JSON.stringify(configContent, null, 2));
}
}
interface RunOptions {
port?: number;
}
async function run(options: RunOptions = {}) {
// Check if service is already running
if (isServiceRunning()) {
console.log("✅ Service is already running in the background.");
return;
}
await initializeClaudeConfig();
await initDir();
// Clean up old log files, keeping only the 10 most recent ones
await cleanupLogFiles();
const config = await initConfig();
// Configure logging based on config
configureLogging(config);
let HOST = config.HOST;
if (config.HOST && !config.APIKEY) {
HOST = "127.0.0.1";
console.warn("⚠️ API key is not set. HOST is forced to 127.0.0.1.");
}
const port = config.PORT || 3456;
// Save the PID of the background process
savePid(process.pid);
// Handle SIGINT (Ctrl+C) to clean up PID file
process.on("SIGINT", () => {
console.log("Received SIGINT, cleaning up...");
cleanupPidFile();
process.exit(0);
});
// Handle SIGTERM to clean up PID file
process.on("SIGTERM", () => {
cleanupPidFile();
process.exit(0);
});
console.log(HOST);
// Use port from environment variable if set (for background process)
const servicePort = process.env.SERVICE_PORT
? parseInt(process.env.SERVICE_PORT)
: port;
// Configure logger based on config settings
const loggerConfig = config.LOG !== false ? {
level: config.LOG_LEVEL || "info",
stream: createWriteStream({
path: HOME_DIR,
filename: config.LOGNAME || `./logs/ccr-${+new Date()}.log`,
maxFiles: 3,
interval: "1d",
}),
} : false;
const server = createServer({
jsonPath: CONFIG_FILE,
initialConfig: {
// ...config,
providers: config.Providers || config.providers,
HOST: HOST,
PORT: servicePort,
LOG_FILE: join(
homedir(),
".claude-code-router",
"claude-code-router.log"
),
},
logger: loggerConfig,
});
// Add async preHandler hook for authentication
server.addHook("preHandler", async (req, reply) => {
return new Promise((resolve, reject) => {
const done = (err?: Error) => {
if (err) reject(err);
else resolve();
};
// Call the async auth function
apiKeyAuth(config)(req, reply, done).catch(reject);
});
});
server.addHook("preHandler", async (req, reply) => {
if (req.url.startsWith("/v1/messages")) {
router(req, reply, config);
}
});
server.start();
}
export { run };
// run();