import { parseArgs } from "@std/cli/parse-args"; import { red, yellow, cyan, gray } from "@std/fmt/colors"; import { createAuthenticatedClient } from "../utils/client.ts"; import { logger } from "../utils/logger.ts"; import { SlicesConfigLoader, mergeConfig } from "../utils/config.ts"; function showLogsHelp() { console.log(` slices logs - View Jetstream logs for a slice USAGE: slices logs [OPTIONS] OPTIONS: --slice Target slice URI (optional, or from slices.json) --limit Maximum number of log entries to return (default: 100, max: 1000) --api-url Slices API base URL (default: https://api.slices.network or from slices.json) -h, --help Show this help message EXAMPLES: slices logs --slice at://did:plc:example/slice slices logs --limit 50 slices logs # Uses config from slices.json `); } export async function logsCommand(commandArgs: unknown[], _globalArgs: Record): Promise { const args = parseArgs(commandArgs as string[], { boolean: ["help"], string: ["slice", "api-url", "limit"], alias: { h: "help", }, }); if (args.help) { showLogsHelp(); return; } const configLoader = new SlicesConfigLoader(); const slicesConfig = await configLoader.load(); const mergedConfig = mergeConfig(slicesConfig, args); const sliceUri = mergedConfig.slice; const apiUrl = mergedConfig.apiUrl || "https://api.slices.network"; const limit = args.limit ? parseInt(args.limit as string, 10) : 100; if (isNaN(limit) || limit < 1 || limit > 1000) { logger.error("--limit must be a number between 1 and 1000"); Deno.exit(1); } try { const client = await createAuthenticatedClient(sliceUri || "", apiUrl); const response = await client.network.slices.slice.getJetstreamLogs({ slice: sliceUri, limit, }); if (response.logs.length === 0) { logger.info("No logs found"); return; } logger.section(`Jetstream Logs (${response.logs.length} entries)`); for (const log of response.logs) { const timestamp = new Date(log.createdAt).toLocaleString(); const level = log.level.toUpperCase().padEnd(5); const coloredLevel = colorizeLevel(level, log.level); console.log(`${timestamp} ${coloredLevel} ${log.message}`); if (log.metadata && Object.keys(log.metadata).length > 0) { console.log(` ${gray(JSON.stringify(log.metadata))}`); } } } catch (error) { const err = error as Error; logger.error(`Failed to fetch logs: ${err.message}`); Deno.exit(1); } } function colorizeLevel(levelText: string, level: string): string { switch (level.toLowerCase()) { case "error": return red(levelText); case "warn": return yellow(levelText); case "info": return cyan(levelText); case "debug": return gray(levelText); default: return levelText; } }