mirror of
https://github.com/Routstr/routstrd.git
synced 2026-07-22 12:22:20 +00:00
feat(daemon): wire SdkLogger through daemon with per-request reqId prefixing
- daemon/index.ts: add makeSdkLogger() factory, wire daemonSdkLogger into
createBunSqliteDriver, createProviderRegistryFromStore, ModelManager, ProviderManager
- daemon/http/index.ts: add makeSdkLogger() factory, generate per-request
reqId via randomBytes(4), pass reqLogger = sdkLogger.child("req:${reqId}")
to routeRequests so every log line from a request is prefixed [req:XXXXXXXX]
- start-daemon.ts: remove >> logfile 2>&1 redirect and getTodayLogFile();
all file logging now goes through the daemon's writeLog() with daily rotation
Result: Every log line from a request is prefixed [req:XXXXXXXX], all entries
have [ISO] [INFO/ERROR/DEBUG] timestamps, no duplicates, and the log file
rotates correctly at midnight.
This commit is contained in:
@@ -6,7 +6,7 @@ import {
|
||||
InsufficientBalanceError,
|
||||
ProviderManager,
|
||||
} from "@routstr/sdk";
|
||||
import type { UsageTrackingDriver } from "@routstr/sdk";
|
||||
import type { UsageTrackingDriver, SdkLogger } from "@routstr/sdk";
|
||||
import { logger } from "../../utils/logger";
|
||||
import {
|
||||
CocodHttpError,
|
||||
@@ -264,6 +264,19 @@ async function buildWalletDetails(deps: DaemonDeps): Promise<{
|
||||
};
|
||||
}
|
||||
|
||||
function makeSdkLogger(prefix?: string): SdkLogger {
|
||||
const tag = prefix ? `[${prefix}]` : undefined;
|
||||
const fmt = (...args: unknown[]) => (tag ? [tag, ...args] : args);
|
||||
return {
|
||||
log: (...args: unknown[]) => logger.log(...fmt(...args)),
|
||||
warn: (...args: unknown[]) => logger.log(...fmt(...args)),
|
||||
error: (...args: unknown[]) => logger.error(...fmt(...args)),
|
||||
debug: (...args: unknown[]) => logger.debug(...fmt(...args)),
|
||||
child: (p: string) => makeSdkLogger(prefix ? `${prefix}:${p}` : p),
|
||||
};
|
||||
}
|
||||
const sdkLogger: SdkLogger = makeSdkLogger();
|
||||
|
||||
export function createDaemonRequestHandler(deps: {
|
||||
provider: string | null;
|
||||
server: { close(cb?: () => void): void };
|
||||
@@ -1030,7 +1043,9 @@ export function createDaemonRequestHandler(deps: {
|
||||
|
||||
try {
|
||||
await deps.ensureProvidersBootstrapped();
|
||||
logger.log("Routing request with path: ", url.pathname);
|
||||
const reqId = randomBytes(4).toString("hex");
|
||||
const reqLogger = sdkLogger.child(`req:${reqId}`);
|
||||
logger.log(`[req:${reqId}] Routing request with path: `, url.pathname);
|
||||
|
||||
const response = await routeRequests({
|
||||
modelId,
|
||||
@@ -1048,6 +1063,7 @@ export function createDaemonRequestHandler(deps: {
|
||||
usageTrackingDriver: deps.usageTrackingDriver,
|
||||
sdkStore: deps.store,
|
||||
providerManager: deps.providerManager,
|
||||
logger: reqLogger,
|
||||
});
|
||||
|
||||
// Bridge the Web `Response` to the Node `ServerResponse` with no
|
||||
|
||||
@@ -8,8 +8,22 @@ import {
|
||||
createStorageAdapterFromStore,
|
||||
createSdkStore,
|
||||
} from "@routstr/sdk";
|
||||
import type { SdkLogger } from "@routstr/sdk";
|
||||
import { DB_PATH, SOCKET_PATH, PID_FILE } from "../utils/config";
|
||||
import { logger } from "../utils/logger";
|
||||
|
||||
function makeSdkLogger(prefix?: string): SdkLogger {
|
||||
const tag = prefix ? `[${prefix}]` : undefined;
|
||||
const fmt = (...args: unknown[]) => (tag ? [tag, ...args] : args);
|
||||
return {
|
||||
log: (...args: unknown[]) => logger.log(...fmt(...args)),
|
||||
warn: (...args: unknown[]) => logger.log(...fmt(...args)),
|
||||
error: (...args: unknown[]) => logger.error(...fmt(...args)),
|
||||
debug: (...args: unknown[]) => logger.debug(...fmt(...args)),
|
||||
child: (p: string) => makeSdkLogger(prefix ? `${prefix}:${p}` : p),
|
||||
};
|
||||
}
|
||||
const daemonSdkLogger: SdkLogger = makeSdkLogger();
|
||||
import { parseArgs } from "./args";
|
||||
import { ensureDirs, loadDaemonConfig, saveDaemonConfig } from "./config-store";
|
||||
import {
|
||||
@@ -35,7 +49,7 @@ async function main(): Promise<void> {
|
||||
const updatedConfig = { ...config, port, provider };
|
||||
saveDaemonConfig(updatedConfig);
|
||||
|
||||
const sqliteDriver = await createBunSqliteDriver(DB_PATH);
|
||||
const sqliteDriver = await createBunSqliteDriver(DB_PATH, { logger: daemonSdkLogger });
|
||||
const { store, hydrate } = createSdkStore({ driver: sqliteDriver });
|
||||
await hydrate;
|
||||
const { Database } = await import("bun:sqlite");
|
||||
@@ -46,11 +60,11 @@ async function main(): Promise<void> {
|
||||
});
|
||||
|
||||
const discoveryAdapter = createDiscoveryAdapterFromStore(store);
|
||||
const providerRegistry = createProviderRegistryFromStore(store);
|
||||
const providerRegistry = createProviderRegistryFromStore(store, daemonSdkLogger);
|
||||
const storageAdapter = createStorageAdapterFromStore(store);
|
||||
const modelManager = new ModelManager(discoveryAdapter);
|
||||
const modelManager = new ModelManager(discoveryAdapter, { logger: daemonSdkLogger });
|
||||
// Create shared ProviderManager for consistent failure tracking across all requests
|
||||
const providerManager = new ProviderManager(providerRegistry, store);
|
||||
const providerManager = new ProviderManager(providerRegistry, store, daemonSdkLogger);
|
||||
const { ensureProvidersBootstrapped, getRoutstr21Models, getModelProviders } =
|
||||
createModelService(modelManager, store);
|
||||
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
import { logger } from "./utils/logger";
|
||||
import { existsSync } from "fs";
|
||||
import { CONFIG_DIR, LOGS_DIR } from "./utils/config";
|
||||
import { withCrossProcessLock } from "./utils/process-lock";
|
||||
|
||||
const DAEMON_STARTUP_LOCK_PATH = `${CONFIG_DIR}/routstrd-startup.lock`;
|
||||
|
||||
function getTodayLogFile(): string {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = String(now.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(now.getDate()).padStart(2, "0");
|
||||
return `${LOGS_DIR}/${year}-${month}-${day}.log`;
|
||||
}
|
||||
|
||||
async function isDaemonHealthy(port: string): Promise<boolean> {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 2000);
|
||||
@@ -48,14 +39,8 @@ async function startDaemonUnlocked(
|
||||
args.push("--provider", options.provider);
|
||||
}
|
||||
|
||||
// Ensure logs directory exists (logger handles date-based files)
|
||||
if (!existsSync(LOGS_DIR)) {
|
||||
await Bun.$`mkdir -p ${LOGS_DIR}`;
|
||||
}
|
||||
|
||||
const daemonScript = new URL("./daemon/index.js", import.meta.url).pathname;
|
||||
const todayLogFile = getTodayLogFile();
|
||||
const shellCmd = `bun run "${daemonScript}" ${args.map((a) => `'${a}'`).join(" ")} >> "${todayLogFile}" 2>&1`;
|
||||
const shellCmd = `bun run "${daemonScript}" ${args.map((a) => `'${a}'`).join(" ")}`;
|
||||
|
||||
const proc = Bun.spawn(["sh", "-c", shellCmd], {
|
||||
stdout: "inherit",
|
||||
|
||||
Reference in New Issue
Block a user