Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
7a783c7
Initial plan
Copilot Jan 16, 2026
8abac89
Add ENABLE_COMPILE_CONFIG_LOGGING environment variable to control deb…
Copilot Jan 16, 2026
9750838
Fix JavaScript hoisting issue with logCompileConfig function
Copilot Jan 16, 2026
94bf93f
Refactor to use Node.js DEBUG pattern instead of individual env vars
Copilot Jan 17, 2026
b4bcd2d
Keep original naming convention for debug areas
Copilot Jan 17, 2026
451c4e0
Refactor to use debug npm package and update launch.json comments
Copilot Jan 17, 2026
ca30a74
Add documentation comment for ENABLE_LM_LOGGING in launch.json
Copilot Jan 19, 2026
42c1d4f
Refactor typespec-vscode to use debug package for LM logging
Copilot Jan 19, 2026
3b2668f
Remove unnecessary debug variable in language-model.ts
Copilot Jan 21, 2026
fa37194
Revert tspconfig completion to use regular log function
Copilot Jan 21, 2026
58fb695
Remove unused logCompileConfig function
Copilot Jan 21, 2026
21ba492
Fix code formatting issues
Copilot Jan 23, 2026
856eeb0
Move debug package to devDependencies in typespec-vscode
Copilot Jan 23, 2026
9757eaf
Replace debug npm package with custom implementation using TYPESPEC_D…
Copilot Feb 5, 2026
bb835bb
Move debug code to dedicated debug.ts files
Copilot Feb 6, 2026
e0515c1
Merge remote-tracking branch 'origin/main' into copilot/fix-lsp-debug…
Copilot Feb 6, 2026
bae6a68
Merge branch 'main' and update ThirdPartyNotices.txt
Copilot Feb 6, 2026
f0f7b6e
Add changelog and document why TYPESPEC_DEBUG is used instead of DEBUG
Copilot Feb 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
changeKind: internal
packages:
- "@typespec/compiler"
- typespec-vscode
---

Gate debug logs behind TYPESPEC_DEBUG environment variable to suppress spam messages during compilation
10 changes: 7 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,13 @@
// Set the telemetry key environment variable to use if you dont want to set it in package.json
//"TYPESPEC_VSCODE_TELEMETRY_KEY": "{The instrumentation key of your Application Insights}",

//"ENABLE_SERVER_COMPILE_LOGGING": "true",
//"ENABLE_UPDATE_MANAGER_LOGGING": "true",
//"ENABLE_LM_LOGGING": "true",
// Enable debug logging for specific areas using TYPESPEC_DEBUG environment variable
// Examples:
// "TYPESPEC_DEBUG": "typespec:server_compile" - Enable server compilation debug logs
// "TYPESPEC_DEBUG": "typespec:lm" - Enable Language Model debug logs
// "TYPESPEC_DEBUG": "typespec:*" - Enable all typespec debug logs
// "TYPESPEC_DEBUG": "typespec:server_compile,typespec:compile_config" - Enable multiple areas
//"TYPESPEC_DEBUG": "typespec:server_compile,typespec:update_manager,typespec:compile_config,typespec:lm",

"TYPESPEC_SERVER_NODE_OPTIONS": "--nolazy --inspect-brk=4242",
"TYPESPEC_DEVELOPMENT_MODE": "true"
Expand Down
18 changes: 12 additions & 6 deletions packages/compiler/src/server/compile-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { getLocationInYamlScript } from "../yaml/diagnostics.js";
import { parseYaml } from "../yaml/parser.js";
import { ClientConfigProvider } from "./client-config-provider.js";
import { serverOptions } from "./constants.js";
import { debugLoggers } from "./debug.js";
import { resolveEntrypointFile } from "./entrypoint-resolver.js";
import { FileService } from "./file-service.js";
import { FileSystemCache } from "./file-system-cache.js";
Expand Down Expand Up @@ -90,6 +91,8 @@ export function createCompileService({
const eventListeners = new Map<string, (...args: unknown[]) => void | Promise<void>>();
const compileManager = new ServerCompileManager(updateManager, compilerHost, log);
let configFilePath: string | undefined;
const debug = debugLoggers.compileConfig;
const logDebug = debug.enabled ? log : () => {};

return { compile, getScript, on, notifyChange, getMainFileForDocument };

Expand Down Expand Up @@ -129,15 +132,15 @@ export function createCompileService({
}
const mainFile = await getMainFileForDocument(path);
if (mainFile === undefined) {
log({ level: "debug", message: `failed to resolve main file for ${path}` });
logDebug({ level: "debug", message: `failed to resolve main file for ${path}` });
return undefined;
}
if (!mainFile.endsWith(".tsp")) {
return undefined;
}
const config = await getConfig(mainFile);
configFilePath = config.filename;
log({ level: "debug", message: `config resolved`, detail: config });
logDebug({ level: "debug", message: `config resolved`, detail: config });
const [optionsFromConfig, _] = resolveOptionsFromConfig(config, {
cwd: getDirectoryPath(path),
});
Expand Down Expand Up @@ -217,7 +220,7 @@ export function createCompileService({
) {
// If the file that changed wasn't imported by anything from the main
// file, retry using the file itself as the main file.
log({
logDebug({
level: "debug",
message: `target file was not included in compiling, try to compile ${path} as main file directly`,
});
Expand Down Expand Up @@ -246,7 +249,7 @@ export function createCompileService({
const [yamlScript] = parseYaml(await serverHost.compilerHost.readFile(configFilePath));
const target = getLocationInYamlScript(yamlScript, ["emit", emitterName], "key");
if (target.pos === 0) {
log({
logDebug({
level: "debug",
message: `Unexpected situation, can't find emitter '${emitterName}' in config file '${configFilePath}'`,
});
Expand Down Expand Up @@ -286,7 +289,7 @@ export function createCompileService({
const lookupDir = entrypointStat.isDirectory() ? mainFile : getDirectoryPath(mainFile);
const configPath = await findTypeSpecConfigPath(compilerHost, lookupDir, true);
if (!configPath) {
log({
logDebug({
level: "debug",
message: `can't find path with config file, try to use default config`,
});
Expand Down Expand Up @@ -337,7 +340,10 @@ export function createCompileService({
*/
async function getMainFileForDocument(path: string) {
if (path.startsWith("untitled:")) {
log({ level: "debug", message: `untitled document treated as its own main file: ${path}` });
logDebug({
level: "debug",
message: `untitled document treated as its own main file: ${path}`,
});
return path;
}

Expand Down
6 changes: 0 additions & 6 deletions packages/compiler/src/server/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,3 @@ export const serverOptions: CompilerOptions = {
export const Commands = {
APPLY_CODE_FIX: "typespec.applyCodeFix",
};

/**
* Environment variables to enable some logging when needed
*/
export const ENABLE_SERVER_COMPILE_LOGGING = "ENABLE_SERVER_COMPILE_LOGGING";
export const ENABLE_UPDATE_MANAGER_LOGGING = "ENABLE_UPDATE_MANAGER_LOGGING";
55 changes: 55 additions & 0 deletions packages/compiler/src/server/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { getEnvironmentVariable } from "../utils/misc.js";

/**
* Debug areas that can be enabled via TYPESPEC_DEBUG environment variable.
*
* Note: We use TYPESPEC_DEBUG instead of DEBUG because the DEBUG environment variable
* is not supported in VSCode extensions. See: https://github.com/microsoft/vscode/issues/290140
*
* Usage: TYPESPEC_DEBUG=typespec:server_compile,typespec:compile_config
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it looks like DEBUG will never work with vscode from the issue coment, do you think we still need the typespec: prefix?

Could the area also try to follow the pattern we have for tracing for consitency(Use . instead of _) service.compile service.config

*
* Examples:
* TYPESPEC_DEBUG=typespec:server_compile - Enable server compilation debug logs
* TYPESPEC_DEBUG=typespec:* - Enable all typespec debug logs
* TYPESPEC_DEBUG=typespec:server_compile,typespec:compile_config - Enable multiple areas
*/
const debugAreas = {
serverCompile: "typespec:server_compile",
updateManager: "typespec:update_manager",
compileConfig: "typespec:compile_config",
} as const;

/**
* Check if a debug area is enabled via the TYPESPEC_DEBUG environment variable.
* Supports comma-separated values and wildcards.
*/
function isDebugEnabled(area: string): boolean {
const debug = getEnvironmentVariable("TYPESPEC_DEBUG");
if (!debug) {
return false;
}

const areas = debug.split(",").map((a) => a.trim());

return areas.some((pattern) => {
// Exact match
if (pattern === area) {
return true;
}

// Wildcard pattern matching
if (pattern.includes("*")) {
const regexPattern = pattern.replace(/\*/g, ".*");
const regex = new RegExp(`^${regexPattern}$`);
return regex.test(area);
}

return false;
});
}

export const debugLoggers = {
serverCompile: { enabled: isDebugEnabled(debugAreas.serverCompile) },
updateManager: { enabled: isDebugEnabled(debugAreas.updateManager) },
compileConfig: { enabled: isDebugEnabled(debugAreas.compileConfig) },
} as const;
11 changes: 7 additions & 4 deletions packages/compiler/src/server/entrypoint-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { getDirectoryPath, joinPaths } from "../core/path-utils.js";
import { SystemHost, Diagnostic as TypeSpecDiagnostic } from "../core/types.js";
import { doIO, loadFile } from "../utils/io.js";
import { resolveTspMain } from "../utils/misc.js";
import { debugLoggers } from "./debug.js";
import { FileSystemCache } from "./file-system-cache.js";
import { ServerLog } from "./types.js";

Expand All @@ -14,6 +15,8 @@ export async function resolveEntrypointFile(
log: (log: ServerLog) => void,
): Promise<string | undefined> {
const options = { allowFileNotFound: true };
const debug = debugLoggers.compileConfig;
const logDebug = debug.enabled ? log : () => {};

const pathStat = await doIO(() => host.stat(path), path, logMainFileSearchDiagnostic, options);
const isFilePath = pathStat?.isFile() ?? false;
Expand All @@ -36,22 +39,22 @@ export async function resolveEntrypointFile(

const tspMain = resolveTspMain(pkg);
if (typeof tspMain === "string") {
log({
logDebug({
level: "debug",
message: `tspMain resolved from package.json (${pkgPath}) as ${tspMain}`,
});

const packageJsonEntrypoint = await existingFile(dir, tspMain);
if (packageJsonEntrypoint) {
log({ level: "debug", message: `entrypoint file found as ${packageJsonEntrypoint}` });
logDebug({ level: "debug", message: `entrypoint file found as ${packageJsonEntrypoint}` });
return packageJsonEntrypoint;
}
}

for (const entrypoint of entrypoints) {
const candidate = await existingFile(dir, entrypoint);
if (candidate) {
log({
logDebug({
level: "debug",
message: `main file found using client provided entrypoint: ${candidate}`,
});
Expand All @@ -67,7 +70,7 @@ export async function resolveEntrypointFile(
dir = parentDir;
}

log({ level: "debug", message: `reached directory root, using '${path}' as main file` });
logDebug({ level: "debug", message: `reached directory root, using '${path}' as main file` });
return isFilePath ? path : undefined;

function logMainFileSearchDiagnostic(diagnostic: TypeSpecDiagnostic) {
Expand Down
9 changes: 3 additions & 6 deletions packages/compiler/src/server/server-compile-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import {
Program,
ServerLog,
} from "../index.js";
import { getEnvironmentVariable } from "../utils/misc.js";
import { ENABLE_SERVER_COMPILE_LOGGING } from "./constants.js";
import { debugLoggers } from "./debug.js";
import { trackActionFunc } from "./server-track-action-task.js";
import { UpdateManager } from "./update-manager.js";

Expand Down Expand Up @@ -45,10 +44,8 @@ export class ServerCompileManager {
private compilerHost: CompilerHost,
private log: (log: ServerLog) => void,
) {
this.logDebug =
getEnvironmentVariable(ENABLE_SERVER_COMPILE_LOGGING)?.toLowerCase() === "true"
? (msg) => this.log({ level: "debug", message: msg })
: () => {};
const debug = debugLoggers.serverCompile;
this.logDebug = debug.enabled ? (msg) => this.log({ level: "debug", message: msg }) : () => {};
}

async compile(
Expand Down
15 changes: 7 additions & 8 deletions packages/compiler/src/server/update-manager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { TextDocumentIdentifier } from "vscode-languageserver";
import { TextDocument } from "vscode-languageserver-textdocument";
import { getEnvironmentVariable } from "../utils/misc.js";
import { ENABLE_UPDATE_MANAGER_LOGGING } from "./constants.js";
import { debugLoggers } from "./debug.js";
import { ServerLog } from "./types.js";

interface PendingUpdate {
Expand Down Expand Up @@ -43,12 +42,12 @@ export class UpdateManager<T = void> {
log: (sl: ServerLog) => void,
getDebounceDelay?: () => number,
) {
this._log =
getEnvironmentVariable(ENABLE_UPDATE_MANAGER_LOGGING)?.toLowerCase() === "true"
? (sl: ServerLog) => {
log({ ...sl, message: `#FromUpdateManager(${this.name}): ${sl.message}` });
}
: () => {};
const debug = debugLoggers.updateManager;
this._log = debug.enabled
? (sl: ServerLog) => {
log({ ...sl, message: `#FromUpdateManager(${this.name}): ${sl.message}` });
}
: () => {};

// Set the debounce delay function once during construction
this.getDebounceDelay = getDebounceDelay ?? this.getAdaptiveDebounceDelay;
Expand Down
2 changes: 0 additions & 2 deletions packages/typespec-vscode/src/const.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export const StartFileName = "main.tsp";
export const TspConfigFileName = "tspconfig.yaml";
export const EmptyGuid = "00000000-0000-0000-0000-000000000000";

export const ENABLE_LM_LOGGING = "ENABLE_LM_LOGGING";
41 changes: 41 additions & 0 deletions packages/typespec-vscode/src/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Debug logger for Language Model operations.
* Can be enabled via TYPESPEC_DEBUG environment variable.
*
* Note: We use TYPESPEC_DEBUG instead of DEBUG because the DEBUG environment variable
* is not supported in VSCode extensions. See: https://github.com/microsoft/vscode/issues/290140
*
* Usage: TYPESPEC_DEBUG=typespec:lm
*
* Examples:
* TYPESPEC_DEBUG=typespec:lm - Enable Language Model debug logs
* TYPESPEC_DEBUG=typespec:* - Enable all typespec debug logs
*/
function isDebugEnabled(area: string): boolean {
const debug = process.env.TYPESPEC_DEBUG;
if (!debug) {
return false;
}

const areas = debug.split(",").map((a) => a.trim());

return areas.some((pattern) => {
// Exact match
if (pattern === area) {
return true;
}

// Wildcard pattern matching
if (pattern.includes("*")) {
const regexPattern = pattern.replace(/\*/g, ".*");
const regex = new RegExp(`^${regexPattern}$`);
return regex.test(area);
}

return false;
});
}

export const debugLoggers = {
lm: { enabled: isDebugEnabled("typespec:lm") },
} as const;
4 changes: 2 additions & 2 deletions packages/typespec-vscode/src/lm/language-model.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { inspect } from "util";
import { LanguageModelChat, LanguageModelChatMessage, lm } from "vscode";
import { ENABLE_LM_LOGGING } from "../const";
import { debugLoggers } from "../debug";
import logger, { LogItem } from "../log/logger";
import { RetryResult, runWithRetry, runWithTimingLog } from "../utils";

Expand All @@ -23,7 +23,7 @@ export async function sendLmChatRequest(
/** Only for logging purpose */
id?: string,
): Promise<string | undefined> {
const logEnabled = process.env[ENABLE_LM_LOGGING] === "true";
const logEnabled = debugLoggers.lm.enabled;
const lmLog = (item: LogItem) => {
if (logEnabled || item.level === "error" || item.level === "warning") {
logger.log(
Expand Down
Loading