From 4fc1e1cb564f2608cf37ea85677f8ea8c1935a1b Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Thu, 15 Jan 2026 12:44:08 -0800 Subject: [PATCH 1/2] Add output logging channel for debug logs --- src/core/analyzer.ts | 5 ++++- src/core/routerResolver.ts | 13 +++++++++++++ src/extension.ts | 13 ++++++++++++- src/utils/logger.ts | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 src/utils/logger.ts diff --git a/src/core/analyzer.ts b/src/core/analyzer.ts index ebd7b83..9f53fac 100644 --- a/src/core/analyzer.ts +++ b/src/core/analyzer.ts @@ -4,6 +4,7 @@ import { readFileSync } from "node:fs" import type { Tree } from "web-tree-sitter" +import { logError } from "../utils/logger" import { decoratorExtractor, findNodesByType, @@ -55,10 +56,12 @@ export function analyzeFile( const code = readFileSync(filePath, "utf-8") const tree = parser.parse(code) if (!tree) { + logError(`Failed to parse file: "${filePath}"`) return null } return analyzeTree(tree, filePath) - } catch { + } catch (error) { + logError(`Error reading file: "${filePath}"`, error) return null } } diff --git a/src/core/routerResolver.ts b/src/core/routerResolver.ts index 9946cb8..e92ca9a 100644 --- a/src/core/routerResolver.ts +++ b/src/core/routerResolver.ts @@ -1,5 +1,6 @@ import { existsSync } from "node:fs" import { isAbsolute, join } from "node:path" +import { log } from "../utils/logger" import { analyzeFile } from "./analyzer" import { resolveNamedImport, resolveRouterFromInit } from "./importResolver" import type { FileAnalysis, RouterInfo, RouterNode } from "./internal" @@ -62,10 +63,12 @@ function buildRouterGraphInternal( } if (!existsSync(resolvedEntryFile)) { + log(`File not found: "${entryFile}"`) return null } // Prevent infinite recursion on circular imports if (visited.has(resolvedEntryFile)) { + log(`Skipping already visited file: "${resolvedEntryFile}"`) return null } @@ -74,9 +77,14 @@ function buildRouterGraphInternal( // Analyze the entry file let analysis = analyzeFile(resolvedEntryFile, parser) if (!analysis) { + log(`Failed to analyze file: "${resolvedEntryFile}"`) return null } + log( + `Analyzed "${resolvedEntryFile}": ${analysis.routes.length} routes, ${analysis.routers.length} routers, ${analysis.includeRouters.length} include_router calls`, + ) + // Find FastAPI instantiation (filter by targetVariable if specified) let appRouter = findAppRouter(analysis.routers, targetVariable) @@ -130,6 +138,9 @@ function buildRouterGraphInternal( // Process include_router calls to find child routers for (const include of analysis.includeRouters) { + log( + `Resolving include_router: ${include.router} (prefix: ${include.prefix || "none"})`, + ) const childRouter = resolveRouterReference( include.router, analysis, @@ -220,6 +231,7 @@ function resolveRouterReference( ) if (!matchingImport) { + log(`No import found for router reference: ${reference}`) return null } @@ -236,6 +248,7 @@ function resolveRouterReference( ) if (!importedFilePath) { + log(`Could not resolve import: ${matchingImport.modulePath}`) return null } diff --git a/src/extension.ts b/src/extension.ts index 281ef59..9d43433 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,6 +2,8 @@ * VSCode extension entry point for FastAPI endpoint discovery. */ +import { existsSync } from "node:fs" +import { basename, sep } from "node:path" import * as vscode from "vscode" import { discoverFastAPIApps } from "./appDiscovery" import { clearImportCache } from "./core/importResolver" @@ -13,6 +15,7 @@ import { EndpointTreeProvider, } from "./providers/EndpointTreeProvider" import { TestCodeLensProvider } from "./providers/TestCodeLensProvider" +import { disposeLogger, log } from "./utils/logger" let parserService: Parser | null = null @@ -25,7 +28,13 @@ function navigateToLocation(location: SourceLocation): void { } export async function activate(context: vscode.ExtensionContext) { - // Initialize parser + const extensionVersion = + vscode.extensions.getExtension("FastAPILabs.fastapi-vscode")?.packageJSON + ?.version ?? "unknown" + log( + `FastAPI extension ${extensionVersion} activated (VS Code ${vscode.version})`, + ) + parserService = new Parser() await parserService.init({ core: vscode.Uri.joinPath( @@ -166,7 +175,9 @@ function registerCommands( } export function deactivate() { + log("Extension deactivated") parserService?.dispose() parserService = null clearImportCache() + disposeLogger() } diff --git a/src/utils/logger.ts b/src/utils/logger.ts new file mode 100644 index 0000000..ca29328 --- /dev/null +++ b/src/utils/logger.ts @@ -0,0 +1,36 @@ +/** + * Output channel logger for the FastAPI extension. + * Provides visibility into extension activity for troubleshooting. + * + * Uses LogOutputChannel for colored log levels and automatic timestamps. + */ + +import * as vscode from "vscode" + +let outputChannel: vscode.LogOutputChannel | null = null + +function getOutputChannel(): vscode.LogOutputChannel { + if (!outputChannel) { + outputChannel = vscode.window.createOutputChannel("FastAPI", { log: true }) + } + return outputChannel +} + +export function log(message: string): void { + getOutputChannel().info(message) +} + +export function logError(message: string, error?: unknown): void { + if (error instanceof Error) { + getOutputChannel().error(`${message}: ${error.message}`) + } else if (error !== undefined) { + getOutputChannel().error(`${message}: ${String(error)}`) + } else { + getOutputChannel().error(message) + } +} + +export function disposeLogger(): void { + outputChannel?.dispose() + outputChannel = null +} From 9a632b608b2a78af605e7ec1f661778750c52244 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 20 Jan 2026 13:44:03 -0800 Subject: [PATCH 2/2] Rebase --- src/extension.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 9d43433..2e14d32 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,8 +2,6 @@ * VSCode extension entry point for FastAPI endpoint discovery. */ -import { existsSync } from "node:fs" -import { basename, sep } from "node:path" import * as vscode from "vscode" import { discoverFastAPIApps } from "./appDiscovery" import { clearImportCache } from "./core/importResolver"