- 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>
137 lines
3.6 KiB
TypeScript
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();
|