Merge pull request #2513 from github/koesie10/show-telemetry-without-vscode

Make the `showAndLogExceptionWithTelemetry` function work without the `vscode` module
This commit is contained in:
Koen Vlaswinkel
2023-06-16 09:39:12 +02:00
committed by GitHub
34 changed files with 237 additions and 115 deletions

View File

@@ -4,11 +4,13 @@ import { AppEventEmitter } from "./events";
import { NotificationLogger } from "./logging"; import { NotificationLogger } from "./logging";
import { Memento } from "./memento"; import { Memento } from "./memento";
import { AppCommandManager } from "./commands"; import { AppCommandManager } from "./commands";
import { AppTelemetry } from "./telemetry";
export interface App { export interface App {
createEventEmitter<T>(): AppEventEmitter<T>; createEventEmitter<T>(): AppEventEmitter<T>;
readonly mode: AppMode; readonly mode: AppMode;
readonly logger: NotificationLogger; readonly logger: NotificationLogger;
readonly telemetry?: AppTelemetry;
readonly subscriptions: Disposable[]; readonly subscriptions: Disposable[];
readonly extensionPath: string; readonly extensionPath: string;
readonly globalStoragePath: string; readonly globalStoragePath: string;

View File

@@ -1,4 +1,6 @@
import { NotificationLogger } from "./notification-logger"; import { NotificationLogger } from "./notification-logger";
import { AppTelemetry } from "../telemetry";
import { RedactableError } from "../../pure/errors";
export interface ShowAndLogOptions { export interface ShowAndLogOptions {
/** /**
@@ -87,3 +89,28 @@ async function internalShowAndLog(
void logger.log(fullMessage || message); void logger.log(fullMessage || message);
await fn.bind(logger)(message); await fn.bind(logger)(message);
} }
interface ShowAndLogExceptionOptions extends ShowAndLogOptions {
/** Custom properties to include in the telemetry report. */
extraTelemetryProperties?: { [key: string]: string };
}
/**
* Show an error message, log it to the console, and emit redacted information as telemetry
*
* @param logger The logger that will receive the message.
* @param telemetry The telemetry instance to use for reporting.
* @param error The error to show. Only redacted information will be included in the telemetry.
* @param options See individual fields on `ShowAndLogExceptionOptions` type.
*
* @return A promise that resolves to the selected item or undefined when being dismissed.
*/
export async function showAndLogExceptionWithTelemetry(
logger: NotificationLogger,
telemetry: AppTelemetry | undefined,
error: RedactableError,
options: ShowAndLogExceptionOptions = {},
): Promise<void> {
telemetry?.sendError(error, options.extraTelemetryProperties);
return showAndLogErrorMessage(logger, error.fullMessage, options);
}

View File

@@ -0,0 +1,10 @@
import { RedactableError } from "../pure/errors";
export interface AppTelemetry {
sendCommandUsage(name: string, executionTime: number, error?: Error): void;
sendUIInteraction(name: string): void;
sendError(
error: RedactableError,
extraProperties?: { [key: string]: string },
): void;
}

View File

@@ -4,6 +4,7 @@ import {
extLogger, extLogger,
NotificationLogger, NotificationLogger,
showAndLogWarningMessage, showAndLogWarningMessage,
showAndLogExceptionWithTelemetry,
} from "../logging"; } from "../logging";
import { import {
asError, asError,
@@ -12,8 +13,8 @@ import {
} from "../../pure/helpers-pure"; } from "../../pure/helpers-pure";
import { redactableError } from "../../pure/errors"; import { redactableError } from "../../pure/errors";
import { UserCancellationException } from "./progress"; import { UserCancellationException } from "./progress";
import { telemetryListener } from "../../telemetry"; import { telemetryListener } from "./telemetry";
import { showAndLogExceptionWithTelemetry } from "./logging"; import { AppTelemetry } from "../telemetry";
/** /**
* Create a command manager for VSCode, wrapping registerCommandWithErrorHandling * Create a command manager for VSCode, wrapping registerCommandWithErrorHandling
@@ -21,9 +22,12 @@ import { showAndLogExceptionWithTelemetry } from "./logging";
*/ */
export function createVSCodeCommandManager< export function createVSCodeCommandManager<
Commands extends Record<string, CommandFunction>, Commands extends Record<string, CommandFunction>,
>(logger?: NotificationLogger): CommandManager<Commands> { >(
logger?: NotificationLogger,
telemetry?: AppTelemetry,
): CommandManager<Commands> {
return new CommandManager((commandId, task) => { return new CommandManager((commandId, task) => {
return registerCommandWithErrorHandling(commandId, task, logger); return registerCommandWithErrorHandling(commandId, task, logger, telemetry);
}, wrapExecuteCommand); }, wrapExecuteCommand);
} }
@@ -34,11 +38,13 @@ export function createVSCodeCommandManager<
* @param task The task to run. It is passed directly to `commands.registerCommand`. Any * @param task The task to run. It is passed directly to `commands.registerCommand`. Any
* arguments to the command handler are passed on to the task. * arguments to the command handler are passed on to the task.
* @param logger The logger to use for error reporting. * @param logger The logger to use for error reporting.
* @param telemetry The telemetry listener to use for error reporting.
*/ */
export function registerCommandWithErrorHandling( export function registerCommandWithErrorHandling(
commandId: string, commandId: string,
task: (...args: any[]) => Promise<any>, task: (...args: any[]) => Promise<any>,
logger: NotificationLogger = extLogger, logger: NotificationLogger = extLogger,
telemetry: AppTelemetry | undefined = telemetryListener,
): Disposable { ): Disposable {
return commands.registerCommand(commandId, async (...args: any[]) => { return commands.registerCommand(commandId, async (...args: any[]) => {
const startTime = Date.now(); const startTime = Date.now();
@@ -64,7 +70,7 @@ export function registerCommandWithErrorHandling(
const fullMessage = errorStack const fullMessage = errorStack
? `${errorMessage.fullMessage}\n${errorStack}` ? `${errorMessage.fullMessage}\n${errorStack}`
: errorMessage.fullMessage; : errorMessage.fullMessage;
void showAndLogExceptionWithTelemetry(logger, errorMessage, { void showAndLogExceptionWithTelemetry(logger, telemetry, errorMessage, {
fullMessage, fullMessage,
extraTelemetryProperties: { extraTelemetryProperties: {
command: commandId, command: commandId,

View File

@@ -7,8 +7,8 @@ import {
getErrorMessage, getErrorMessage,
getErrorStack, getErrorStack,
} from "../../pure/helpers-pure"; } from "../../pure/helpers-pure";
import { extLogger } from "../logging"; import { extLogger, showAndLogExceptionWithTelemetry } from "../logging";
import { showAndLogExceptionWithTelemetry } from "./logging"; import { telemetryListener } from "./telemetry";
export async function tryOpenExternalFile( export async function tryOpenExternalFile(
commandManager: AppCommandManager, commandManager: AppCommandManager,
@@ -36,6 +36,7 @@ the file in the file explorer and dragging it into the workspace.`,
} catch (e) { } catch (e) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
asError(e), asError(e),
)`Failed to reveal file in OS: ${getErrorMessage(e)}`, )`Failed to reveal file in OS: ${getErrorMessage(e)}`,
@@ -45,6 +46,7 @@ the file in the file explorer and dragging it into the workspace.`,
} else { } else {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError(asError(e))`Could not open file ${fileLocation}`, redactableError(asError(e))`Could not open file ${fileLocation}`,
{ {
fullMessage: `${getErrorMessage(e)}\n${getErrorStack(e)}`, fullMessage: `${getErrorMessage(e)}\n${getErrorStack(e)}`,

View File

@@ -1,30 +0,0 @@
import {
NotificationLogger,
showAndLogErrorMessage,
ShowAndLogOptions,
} from "../logging";
import { RedactableError } from "../../pure/errors";
import { telemetryListener } from "../../telemetry";
interface ShowAndLogExceptionOptions extends ShowAndLogOptions {
/** Custom properties to include in the telemetry report. */
extraTelemetryProperties?: { [key: string]: string };
}
/**
* Show an error message, log it to the console, and emit redacted information as telemetry
*
* @param logger The logger that will receive the message.
* @param error The error to show. Only redacted information will be included in the telemetry.
* @param options See individual fields on `ShowAndLogExceptionOptions` type.
*
* @return A promise that resolves to the selected item or undefined when being dismissed.
*/
export async function showAndLogExceptionWithTelemetry(
logger: NotificationLogger,
error: RedactableError,
options: ShowAndLogExceptionOptions = {},
): Promise<void> {
telemetryListener?.sendError(error, options.extraTelemetryProperties);
return showAndLogErrorMessage(logger, error.fullMessage, options);
}

View File

@@ -13,13 +13,14 @@ import {
LOG_TELEMETRY, LOG_TELEMETRY,
isIntegrationTestMode, isIntegrationTestMode,
isCanary, isCanary,
} from "./config"; } from "../../config";
import * as appInsights from "applicationinsights"; import * as appInsights from "applicationinsights";
import { extLogger } from "./common"; import { extLogger } from "../index";
import { UserCancellationException } from "./common/vscode/progress"; import { UserCancellationException } from "./progress";
import { showBinaryChoiceWithUrlDialog } from "./common/vscode/dialog"; import { showBinaryChoiceWithUrlDialog } from "./dialog";
import { RedactableError } from "./pure/errors"; import { RedactableError } from "../../pure/errors";
import { SemVer } from "semver"; import { SemVer } from "semver";
import { AppTelemetry } from "../telemetry";
// Key is injected at build time through the APP_INSIGHTS_KEY environment variable. // Key is injected at build time through the APP_INSIGHTS_KEY environment variable.
const key = "REPLACE-APP-INSIGHTS-KEY"; const key = "REPLACE-APP-INSIGHTS-KEY";
@@ -54,7 +55,10 @@ const baseDataPropertiesToRemove = [
const NOT_SET_CLI_VERSION = "not-set"; const NOT_SET_CLI_VERSION = "not-set";
export class TelemetryListener extends ConfigListener { export class ExtensionTelemetryListener
extends ConfigListener
implements AppTelemetry
{
static relevantSettings = [ENABLE_TELEMETRY, CANARY_FEATURES]; static relevantSettings = [ENABLE_TELEMETRY, CANARY_FEATURES];
private reporter?: TelemetryReporter; private reporter?: TelemetryReporter;
@@ -152,7 +156,7 @@ export class TelemetryListener extends ConfigListener {
void this.reporter?.dispose(); void this.reporter?.dispose();
} }
sendCommandUsage(name: string, executionTime: number, error?: Error) { sendCommandUsage(name: string, executionTime: number, error?: Error): void {
if (!this.reporter) { if (!this.reporter) {
return; return;
} }
@@ -174,7 +178,7 @@ export class TelemetryListener extends ConfigListener {
); );
} }
sendUIInteraction(name: string) { sendUIInteraction(name: string): void {
if (!this.reporter) { if (!this.reporter) {
return; return;
} }
@@ -193,7 +197,7 @@ export class TelemetryListener extends ConfigListener {
sendError( sendError(
error: RedactableError, error: RedactableError,
extraProperties?: { [key: string]: string }, extraProperties?: { [key: string]: string },
) { ): void {
if (!this.reporter) { if (!this.reporter) {
return; return;
} }
@@ -272,16 +276,16 @@ export class TelemetryListener extends ConfigListener {
/** /**
* The global Telemetry instance * The global Telemetry instance
*/ */
export let telemetryListener: TelemetryListener | undefined; export let telemetryListener: ExtensionTelemetryListener | undefined;
export async function initializeTelemetry( export async function initializeTelemetry(
extension: Extension<any>, extension: Extension<any>,
ctx: ExtensionContext, ctx: ExtensionContext,
): Promise<TelemetryListener> { ): Promise<ExtensionTelemetryListener> {
if (telemetryListener !== undefined) { if (telemetryListener !== undefined) {
throw new Error("Telemetry is already initialized"); throw new Error("Telemetry is already initialized");
} }
telemetryListener = new TelemetryListener( telemetryListener = new ExtensionTelemetryListener(
extension.id, extension.id,
extension.packageJSON.version, extension.packageJSON.version,
key, key,

View File

@@ -9,6 +9,8 @@ import { VSCodeAppEventEmitter } from "./events";
import { AppCommandManager, QueryServerCommandManager } from "../commands"; import { AppCommandManager, QueryServerCommandManager } from "../commands";
import { createVSCodeCommandManager } from "./commands"; import { createVSCodeCommandManager } from "./commands";
import { AppEnvironmentContext } from "./environment-context"; import { AppEnvironmentContext } from "./environment-context";
import { AppTelemetry } from "../telemetry";
import { telemetryListener } from "./telemetry";
export class ExtensionApp implements App { export class ExtensionApp implements App {
public readonly credentials: VSCodeCredentials; public readonly credentials: VSCodeCredentials;
@@ -59,6 +61,10 @@ export class ExtensionApp implements App {
return extLogger; return extLogger;
} }
public get telemetry(): AppTelemetry | undefined {
return telemetryListener;
}
public createEventEmitter<T>(): AppEventEmitter<T> { public createEventEmitter<T>(): AppEventEmitter<T> {
return new VSCodeAppEventEmitter<T>(); return new VSCodeAppEventEmitter<T>();
} }

View File

@@ -6,7 +6,7 @@ import {
QueryCompareResult, QueryCompareResult,
} from "../pure/interface-types"; } from "../pure/interface-types";
import { extLogger, Logger } from "../common"; import { extLogger, Logger } from "../common";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../common/logging";
import { CodeQLCliServer } from "../codeql-cli/cli"; import { CodeQLCliServer } from "../codeql-cli/cli";
import { DatabaseManager } from "../databases/local-databases"; import { DatabaseManager } from "../databases/local-databases";
import { jumpToLocation } from "../databases/local-databases/locations"; import { jumpToLocation } from "../databases/local-databases/locations";
@@ -23,7 +23,7 @@ import {
AbstractWebview, AbstractWebview,
WebviewPanelConfig, WebviewPanelConfig,
} from "../common/vscode/abstract-webview"; } from "../common/vscode/abstract-webview";
import { telemetryListener } from "../telemetry"; import { telemetryListener } from "../common/vscode/telemetry";
import { redactableError } from "../pure/errors"; import { redactableError } from "../pure/errors";
interface ComparePair { interface ComparePair {
@@ -152,6 +152,7 @@ export class CompareView extends AbstractWebview<
case "unhandledError": case "unhandledError":
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
msg.error, msg.error,
)`Unhandled error in result comparison view: ${msg.error.message}`, )`Unhandled error in result comparison view: ${msg.error.message}`,

View File

@@ -17,7 +17,10 @@ import {
} from "../pure/interface-types"; } from "../pure/interface-types";
import { ProgressUpdate } from "../common/vscode/progress"; import { ProgressUpdate } from "../common/vscode/progress";
import { QueryRunner } from "../query-server"; import { QueryRunner } from "../query-server";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import {
showAndLogExceptionWithTelemetry,
showAndLogErrorMessage,
} from "../common/logging";
import { outputFile, pathExists, readFile } from "fs-extra"; import { outputFile, pathExists, readFile } from "fs-extra";
import { load as loadYaml } from "js-yaml"; import { load as loadYaml } from "js-yaml";
import { DatabaseItem, DatabaseManager } from "../databases/local-databases"; import { DatabaseItem, DatabaseManager } from "../databases/local-databases";
@@ -42,7 +45,6 @@ import {
} from "./auto-model"; } from "./auto-model";
import { showLlmGeneration } from "../config"; import { showLlmGeneration } from "../config";
import { getAutoModelUsages } from "./auto-model-usages-query"; import { getAutoModelUsages } from "./auto-model-usages-query";
import { showAndLogErrorMessage } from "../common/logging";
export class DataExtensionsEditorView extends AbstractWebview< export class DataExtensionsEditorView extends AbstractWebview<
ToDataExtensionsEditorMessage, ToDataExtensionsEditorMessage,
@@ -276,6 +278,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
} catch (err) { } catch (err) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
this.app.logger, this.app.logger,
this.app.telemetry,
redactableError( redactableError(
asError(err), asError(err),
)`Failed to load external API usages: ${getErrorMessage(err)}`, )`Failed to load external API usages: ${getErrorMessage(err)}`,
@@ -342,6 +345,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
} catch (e: unknown) { } catch (e: unknown) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
this.app.logger, this.app.logger,
this.app.telemetry,
redactableError( redactableError(
asError(e), asError(e),
)`Failed to generate flow model: ${getErrorMessage(e)}`, )`Failed to generate flow model: ${getErrorMessage(e)}`,
@@ -476,6 +480,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
if (e instanceof RequestError && e.status === 429) { if (e instanceof RequestError && e.status === 429) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
this.app.logger, this.app.logger,
this.app.telemetry,
redactableError(e)`Rate limit hit, please try again soon.`, redactableError(e)`Rate limit hit, please try again soon.`,
); );
return null; return null;

View File

@@ -4,7 +4,7 @@ import { writeFile } from "fs-extra";
import { dump as dumpYaml } from "js-yaml"; import { dump as dumpYaml } from "js-yaml";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders"; import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { extLogger, TeeLogger } from "../common"; import { extLogger, TeeLogger } from "../common";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../common/logging";
import { isQueryLanguage } from "../common/query-language"; import { isQueryLanguage } from "../common/query-language";
import { CancellationToken } from "vscode"; import { CancellationToken } from "vscode";
import { CodeQLCliServer } from "../codeql-cli/cli"; import { CodeQLCliServer } from "../codeql-cli/cli";
@@ -14,6 +14,7 @@ import { fetchExternalApiQueries } from "./queries";
import { QueryResultType } from "../pure/new-messages"; import { QueryResultType } from "../pure/new-messages";
import { join } from "path"; import { join } from "path";
import { redactableError } from "../pure/errors"; import { redactableError } from "../pure/errors";
import { telemetryListener } from "../common/vscode/telemetry";
export type RunQueryOptions = { export type RunQueryOptions = {
cliServer: Pick<CodeQLCliServer, "resolveQlpacks">; cliServer: Pick<CodeQLCliServer, "resolveQlpacks">;
@@ -42,6 +43,7 @@ export async function runQuery({
if (!isQueryLanguage(databaseItem.language)) { if (!isQueryLanguage(databaseItem.language)) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError`Unsupported database language ${databaseItem.language}`, redactableError`Unsupported database language ${databaseItem.language}`,
); );
return; return;
@@ -51,6 +53,7 @@ export async function runQuery({
if (!query) { if (!query) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError`No external API usage query found for language ${databaseItem.language}`, redactableError`No external API usage query found for language ${databaseItem.language}`,
); );
return; return;
@@ -107,6 +110,7 @@ export async function runQuery({
if (completedQuery.resultType !== QueryResultType.SUCCESS) { if (completedQuery.resultType !== QueryResultType.SUCCESS) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError`External API usage query failed: ${ redactableError`External API usage query failed: ${
completedQuery.message ?? "No message" completedQuery.message ?? "No message"
}`, }`,
@@ -130,6 +134,7 @@ export async function readQueryResults({
if (bqrsInfo["result-sets"].length !== 1) { if (bqrsInfo["result-sets"].length !== 1) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError`Expected exactly one result set, got ${bqrsInfo["result-sets"].length}`, redactableError`Expected exactly one result set, got ${bqrsInfo["result-sets"].length}`,
); );
return undefined; return undefined;

View File

@@ -4,7 +4,7 @@ import { basename } from "path";
import { QueryRunner } from "../query-server"; import { QueryRunner } from "../query-server";
import { CodeQLCliServer } from "../codeql-cli/cli"; import { CodeQLCliServer } from "../codeql-cli/cli";
import { extLogger, TeeLogger } from "../common"; import { extLogger, TeeLogger } from "../common";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../common/logging";
import { extensiblePredicateDefinitions } from "./predicates"; import { extensiblePredicateDefinitions } from "./predicates";
import { ProgressCallback } from "../common/vscode/progress"; import { ProgressCallback } from "../common/vscode/progress";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders"; import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
@@ -18,6 +18,7 @@ import { file } from "tmp-promise";
import { writeFile } from "fs-extra"; import { writeFile } from "fs-extra";
import { dump } from "js-yaml"; import { dump } from "js-yaml";
import { qlpackOfDatabase } from "../language-support"; import { qlpackOfDatabase } from "../language-support";
import { telemetryListener } from "../common/vscode/telemetry";
type FlowModelOptions = { type FlowModelOptions = {
cliServer: CodeQLCliServer; cliServer: CodeQLCliServer;
@@ -82,6 +83,7 @@ async function getModeledMethodsFromFlow(
if (queryPath === undefined) { if (queryPath === undefined) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError`Failed to find ${type} query`, redactableError`Failed to find ${type} query`,
); );
return []; return [];
@@ -117,6 +119,7 @@ async function getModeledMethodsFromFlow(
if (queryResult.resultType !== QueryResultType.SUCCESS) { if (queryResult.resultType !== QueryResultType.SUCCESS) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError`Failed to run ${basename(queryPath)} query: ${ redactableError`Failed to run ${basename(queryPath)} query: ${
queryResult.message ?? "No message" queryResult.message ?? "No message"
}`, }`,
@@ -130,6 +133,7 @@ async function getModeledMethodsFromFlow(
if (bqrsInfo["result-sets"].length !== 1) { if (bqrsInfo["result-sets"].length !== 1) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError`Expected exactly one result set, got ${ redactableError`Expected exactly one result set, got ${
bqrsInfo["result-sets"].length bqrsInfo["result-sets"].length
} for ${basename(queryPath)}`, } for ${basename(queryPath)}`,

View File

@@ -32,7 +32,10 @@ import {
isLikelyDatabaseRoot, isLikelyDatabaseRoot,
isLikelyDbLanguageFolder, isLikelyDbLanguageFolder,
} from "./local-databases/db-contents-heuristics"; } from "./local-databases/db-contents-heuristics";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import {
showAndLogExceptionWithTelemetry,
showAndLogErrorMessage,
} from "../common/logging";
import { import {
importArchiveDatabase, importArchiveDatabase,
promptImportGithubDatabase, promptImportGithubDatabase,
@@ -48,7 +51,6 @@ import {
createMultiSelectionCommand, createMultiSelectionCommand,
createSingleSelectionCommand, createSingleSelectionCommand,
} from "../common/vscode/selection-commands"; } from "../common/vscode/selection-commands";
import { showAndLogErrorMessage } from "../common/logging";
enum SortOrder { enum SortOrder {
NameAsc = "NameAsc", NameAsc = "NameAsc",
@@ -280,6 +282,7 @@ export class DatabaseUI extends DisposableObject {
} catch (e) { } catch (e) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
this.app.logger, this.app.logger,
this.app.telemetry,
redactableError( redactableError(
asError(e), asError(e),
)`Failed to choose and set database: ${getErrorMessage(e)}`, )`Failed to choose and set database: ${getErrorMessage(e)}`,
@@ -420,6 +423,7 @@ export class DatabaseUI extends DisposableObject {
} catch (e) { } catch (e) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
this.app.logger, this.app.logger,
this.app.telemetry,
redactableError( redactableError(
asError(e), asError(e),
)`Failed to delete orphaned database: ${getErrorMessage(e)}`, )`Failed to delete orphaned database: ${getErrorMessage(e)}`,
@@ -449,6 +453,7 @@ export class DatabaseUI extends DisposableObject {
} catch (e: unknown) { } catch (e: unknown) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
this.app.logger, this.app.logger,
this.app.telemetry,
redactableError( redactableError(
asError(e), asError(e),
)`Failed to choose and set database: ${getErrorMessage(e)}`, )`Failed to choose and set database: ${getErrorMessage(e)}`,

View File

@@ -1,6 +1,6 @@
import vscode, { ExtensionContext } from "vscode"; import vscode, { ExtensionContext } from "vscode";
import { extLogger, Logger } from "../../common"; import { extLogger, Logger } from "../../common";
import { showAndLogExceptionWithTelemetry } from "../../common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../../common/logging";
import { DisposableObject } from "../../pure/disposable-object"; import { DisposableObject } from "../../pure/disposable-object";
import { App } from "../../common/app"; import { App } from "../../common/app";
import { QueryRunner } from "../../query-server"; import { QueryRunner } from "../../query-server";
@@ -29,6 +29,7 @@ import { remove } from "fs-extra";
import { containsPath } from "../../pure/files"; import { containsPath } from "../../pure/files";
import { DatabaseChangedEvent, DatabaseEventKind } from "./database-events"; import { DatabaseChangedEvent, DatabaseEventKind } from "./database-events";
import { DatabaseResolver } from "./database-resolver"; import { DatabaseResolver } from "./database-resolver";
import { telemetryListener } from "../../common/vscode/telemetry";
/** /**
* The name of the key in the workspaceState dictionary in which we * The name of the key in the workspaceState dictionary in which we
@@ -413,6 +414,7 @@ export class DatabaseManager extends DisposableObject {
// database list had an unexpected type - nothing to be done? // database list had an unexpected type - nothing to be done?
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
asError(e), asError(e),
)`Database list loading failed: ${getErrorMessage(e)}`, )`Database list loading failed: ${getErrorMessage(e)}`,

View File

@@ -80,7 +80,12 @@ import {
ProgressReporter, ProgressReporter,
queryServerLogger, queryServerLogger,
} from "./common"; } from "./common";
import { showAndLogExceptionWithTelemetry } from "./common/vscode/logging"; import {
showAndLogExceptionWithTelemetry,
showAndLogErrorMessage,
showAndLogInformationMessage,
showAndLogWarningMessage,
} from "./common/logging";
import { QueryHistoryManager } from "./query-history/query-history-manager"; import { QueryHistoryManager } from "./query-history/query-history-manager";
import { CompletedLocalQueryInfo } from "./query-results"; import { CompletedLocalQueryInfo } from "./query-results";
import { import {
@@ -90,7 +95,10 @@ import {
import { QLTestAdapterFactory } from "./query-testing/test-adapter"; import { QLTestAdapterFactory } from "./query-testing/test-adapter";
import { TestUIService } from "./query-testing/test-ui"; import { TestUIService } from "./query-testing/test-ui";
import { CompareView } from "./compare/compare-view"; import { CompareView } from "./compare/compare-view";
import { initializeTelemetry } from "./telemetry"; import {
initializeTelemetry,
telemetryListener,
} from "./common/vscode/telemetry";
import { ProgressCallback, withProgress } from "./common/vscode/progress"; import { ProgressCallback, withProgress } from "./common/vscode/progress";
import { CodeQlStatusBarHandler } from "./status-bar"; import { CodeQlStatusBarHandler } from "./status-bar";
import { getPackagingCommands } from "./packaging"; import { getPackagingCommands } from "./packaging";
@@ -126,11 +134,6 @@ import { TestRunner } from "./query-testing/test-runner";
import { TestManagerBase } from "./query-testing/test-manager-base"; import { TestManagerBase } from "./query-testing/test-manager-base";
import { NewQueryRunner, QueryRunner, QueryServerClient } from "./query-server"; import { NewQueryRunner, QueryRunner, QueryServerClient } from "./query-server";
import { QueriesModule } from "./queries-panel/queries-module"; import { QueriesModule } from "./queries-panel/queries-module";
import {
showAndLogErrorMessage,
showAndLogInformationMessage,
showAndLogWarningMessage,
} from "./common/logging";
/** /**
* extension.ts * extension.ts
@@ -1134,6 +1137,7 @@ async function showResultsForComparison(
} catch (e) { } catch (e) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError(asError(e))`Failed to show results: ${getErrorMessage( redactableError(asError(e))`Failed to show results: ${getErrorMessage(
e, e,
)}`, )}`,
@@ -1159,16 +1163,16 @@ function addUnhandledRejectionListener() {
)`Unhandled error: ${getErrorMessage(error)}`; )`Unhandled error: ${getErrorMessage(error)}`;
// Add a catch so that showAndLogExceptionWithTelemetry fails, we avoid // Add a catch so that showAndLogExceptionWithTelemetry fails, we avoid
// triggering "unhandledRejection" and avoid an infinite loop // triggering "unhandledRejection" and avoid an infinite loop
showAndLogExceptionWithTelemetry(extLogger, message).catch( showAndLogExceptionWithTelemetry(
(telemetryError: unknown) => { extLogger,
void extLogger.log( telemetryListener,
`Failed to send error telemetry: ${getErrorMessage( message,
telemetryError, ).catch((telemetryError: unknown) => {
)}`, void extLogger.log(
); `Failed to send error telemetry: ${getErrorMessage(telemetryError)}`,
void extLogger.log(message.fullMessage); );
}, void extLogger.log(message.fullMessage);
); });
} }
}; };

View File

@@ -28,7 +28,8 @@ import { asError, getErrorMessage } from "../../pure/helpers-pure";
import { redactableError } from "../../pure/errors"; import { redactableError } from "../../pure/errors";
import { AstViewerCommands } from "../../common/commands"; import { AstViewerCommands } from "../../common/commands";
import { extLogger } from "../../common"; import { extLogger } from "../../common";
import { showAndLogExceptionWithTelemetry } from "../../common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../../common/logging";
import { telemetryListener } from "../../common/vscode/telemetry";
export interface AstItem { export interface AstItem {
id: BqrsId; id: BqrsId;
@@ -147,6 +148,7 @@ export class AstViewer extends DisposableObject {
(error: unknown) => (error: unknown) =>
showAndLogExceptionWithTelemetry( showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
asError(error), asError(error),
)`Failed to reveal AST: ${getErrorMessage(error)}`, )`Failed to reveal AST: ${getErrorMessage(error)}`,
@@ -211,6 +213,7 @@ export class AstViewer extends DisposableObject {
(error: unknown) => (error: unknown) =>
showAndLogExceptionWithTelemetry( showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
asError(error), asError(error),
)`Failed to reveal AST: ${getErrorMessage(error)}`, )`Failed to reveal AST: ${getErrorMessage(error)}`,

View File

@@ -18,12 +18,13 @@ import {
import { CodeQLCliServer } from "../../codeql-cli/cli"; import { CodeQLCliServer } from "../../codeql-cli/cli";
import { DatabaseItem } from "../../databases/local-databases"; import { DatabaseItem } from "../../databases/local-databases";
import { extLogger, TeeLogger } from "../../common"; import { extLogger, TeeLogger } from "../../common";
import { showAndLogExceptionWithTelemetry } from "../../common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../../common/logging";
import { CancellationToken } from "vscode"; import { CancellationToken } from "vscode";
import { ProgressCallback } from "../../common/vscode/progress"; import { ProgressCallback } from "../../common/vscode/progress";
import { CoreCompletedQuery, QueryRunner } from "../../query-server"; import { CoreCompletedQuery, QueryRunner } from "../../query-server";
import { redactableError } from "../../pure/errors"; import { redactableError } from "../../pure/errors";
import { QLPACK_FILENAMES } from "../../pure/ql"; import { QLPACK_FILENAMES } from "../../pure/ql";
import { telemetryListener } from "../../common/vscode/telemetry";
export async function qlpackOfDatabase( export async function qlpackOfDatabase(
cli: Pick<CodeQLCliServer, "resolveQlpacks">, cli: Pick<CodeQLCliServer, "resolveQlpacks">,
@@ -102,7 +103,7 @@ current library path (tried searching the following packs: ${joinedPacksToSearch
Try upgrading the CodeQL libraries. If that doesn't work, then ${keyTypeName} queries are not yet available \ Try upgrading the CodeQL libraries. If that doesn't work, then ${keyTypeName} queries are not yet available \
for this language.`; for this language.`;
void showAndLogExceptionWithTelemetry(extLogger, error); void showAndLogExceptionWithTelemetry(extLogger, telemetryListener, error);
throw error; throw error;
} }

View File

@@ -6,7 +6,8 @@ import { getErrorMessage } from "../pure/helpers-pure";
import { redactableError } from "../pure/errors"; import { redactableError } from "../pure/errors";
import { AppCommandManager, QueryEditorCommands } from "../common/commands"; import { AppCommandManager, QueryEditorCommands } from "../common/commands";
import { extLogger } from "../common"; import { extLogger } from "../common";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../common/logging";
import { telemetryListener } from "../common/vscode/telemetry";
type QueryEditorOptions = { type QueryEditorOptions = {
commandManager: AppCommandManager; commandManager: AppCommandManager;
@@ -80,9 +81,14 @@ async function previewQueryHelp(
) )
? redactableError`Could not generate markdown from ${pathToQhelp}: Bad formatting in .qhelp file.` ? redactableError`Could not generate markdown from ${pathToQhelp}: Bad formatting in .qhelp file.`
: redactableError`Could not open a preview of the generated file (${absolutePathToMd}).`; : redactableError`Could not open a preview of the generated file (${absolutePathToMd}).`;
void showAndLogExceptionWithTelemetry(extLogger, errorMessage, { void showAndLogExceptionWithTelemetry(
fullMessage: `${errorMessage}\n${getErrorMessage(e)}`, extLogger,
}); telemetryListener,
errorMessage,
{
fullMessage: `${errorMessage}\n${getErrorMessage(e)}`,
},
);
} }
} }
} }

View File

@@ -1,5 +1,8 @@
import { BaseLogger, extLogger, Logger } from "../common"; import { BaseLogger, extLogger, Logger } from "../common";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import {
showAndLogExceptionWithTelemetry,
showAndLogWarningMessage,
} from "../common/logging";
import { CoreQueryResults } from "../query-server"; import { CoreQueryResults } from "../query-server";
import { QueryHistoryManager } from "../query-history/query-history-manager"; import { QueryHistoryManager } from "../query-history/query-history-manager";
import { DatabaseItem } from "../databases/local-databases"; import { DatabaseItem } from "../databases/local-databases";
@@ -17,8 +20,8 @@ import { CodeQLCliServer } from "../codeql-cli/cli";
import { QueryResultType } from "../pure/new-messages"; import { QueryResultType } from "../pure/new-messages";
import { redactableError } from "../pure/errors"; import { redactableError } from "../pure/errors";
import { LocalQueries } from "./local-queries"; import { LocalQueries } from "./local-queries";
import { showAndLogWarningMessage } from "../common/logging";
import { tryGetQueryMetadata } from "../codeql-cli/query-metadata"; import { tryGetQueryMetadata } from "../codeql-cli/query-metadata";
import { telemetryListener } from "../common/vscode/telemetry";
function formatResultMessage(result: CoreQueryResults): string { function formatResultMessage(result: CoreQueryResults): string {
switch (result.resultType) { switch (result.resultType) {
@@ -154,7 +157,11 @@ export class LocalQueryRun {
const message = results.message const message = results.message
? redactableError`Failed to run query: ${results.message}` ? redactableError`Failed to run query: ${results.message}`
: redactableError`Failed to run query`; : redactableError`Failed to run query`;
void showAndLogExceptionWithTelemetry(extLogger, message); void showAndLogExceptionWithTelemetry(
extLogger,
telemetryListener,
message,
);
} }
const message = formatResultMessage(results); const message = formatResultMessage(results);
const successful = results.resultType === QueryResultType.SUCCESS; const successful = results.resultType === QueryResultType.SUCCESS;

View File

@@ -41,7 +41,7 @@ import {
ParsedResultSets, ParsedResultSets,
} from "../pure/interface-types"; } from "../pure/interface-types";
import { extLogger, Logger } from "../common"; import { extLogger, Logger } from "../common";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../common/logging";
import { import {
CompletedQueryInfo, CompletedQueryInfo,
interpretResultsSarif, interpretResultsSarif,
@@ -71,7 +71,7 @@ import {
} from "../common/vscode/abstract-webview"; } from "../common/vscode/abstract-webview";
import { isCanary, PAGE_SIZE } from "../config"; import { isCanary, PAGE_SIZE } from "../config";
import { HistoryItemLabelProvider } from "../query-history/history-item-label-provider"; import { HistoryItemLabelProvider } from "../query-history/history-item-label-provider";
import { telemetryListener } from "../telemetry"; import { telemetryListener } from "../common/vscode/telemetry";
import { redactableError } from "../pure/errors"; import { redactableError } from "../pure/errors";
import { ResultsViewCommands } from "../common/commands"; import { ResultsViewCommands } from "../common/commands";
@@ -320,6 +320,7 @@ export class ResultsView extends AbstractWebview<
case "unhandledError": case "unhandledError":
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
msg.error, msg.error,
)`Unhandled error in results view: ${msg.error.message}`, )`Unhandled error in results view: ${msg.error.message}`,
@@ -331,6 +332,7 @@ export class ResultsView extends AbstractWebview<
} catch (e) { } catch (e) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
asError(e), asError(e),
)`Error handling message from results view: ${getErrorMessage(e)}`, )`Error handling message from results view: ${getErrorMessage(e)}`,
@@ -381,6 +383,7 @@ export class ResultsView extends AbstractWebview<
if (this._displayedQuery === undefined) { if (this._displayedQuery === undefined) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError`Failed to sort results since evaluation info was unknown.`, redactableError`Failed to sort results since evaluation info was unknown.`,
); );
return; return;
@@ -400,6 +403,7 @@ export class ResultsView extends AbstractWebview<
if (this._displayedQuery === undefined) { if (this._displayedQuery === undefined) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError`Failed to sort results since evaluation info was unknown.`, redactableError`Failed to sort results since evaluation info was unknown.`,
); );
return; return;
@@ -811,6 +815,7 @@ export class ResultsView extends AbstractWebview<
// trying to render uninterpreted results anyway. // trying to render uninterpreted results anyway.
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
asError(e), asError(e),
)`Showing raw results instead of interpreted ones due to an error. ${getErrorMessage( )`Showing raw results instead of interpreted ones due to an error. ${getErrorMessage(

View File

@@ -7,12 +7,15 @@ import {
withProgress, withProgress,
} from "../common/vscode/progress"; } from "../common/vscode/progress";
import { extLogger } from "../common"; import { extLogger } from "../common";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import {
showAndLogExceptionWithTelemetry,
showAndLogInformationMessage,
} from "../common/logging";
import { asError, getErrorStack } from "../pure/helpers-pure"; import { asError, getErrorStack } from "../pure/helpers-pure";
import { redactableError } from "../pure/errors"; import { redactableError } from "../pure/errors";
import { PACKS_BY_QUERY_LANGUAGE } from "../common/query-language"; import { PACKS_BY_QUERY_LANGUAGE } from "../common/query-language";
import { PackagingCommands } from "../common/commands"; import { PackagingCommands } from "../common/commands";
import { showAndLogInformationMessage } from "../common/logging"; import { telemetryListener } from "../common/vscode/telemetry";
type PackagingOptions = { type PackagingOptions = {
cliServer: CodeQLCliServer; cliServer: CodeQLCliServer;
@@ -92,6 +95,7 @@ export async function handleDownloadPacks(
} catch (error) { } catch (error) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
asError(error), asError(error),
)`Unable to download all packs. See log for more details.`, )`Unable to download all packs. See log for more details.`,

View File

@@ -13,7 +13,8 @@ import { asError, getErrorMessage } from "../pure/helpers-pure";
import { redactableError } from "../pure/errors"; import { redactableError } from "../pure/errors";
import { EvalLogViewerCommands } from "../common/commands"; import { EvalLogViewerCommands } from "../common/commands";
import { extLogger } from "../common"; import { extLogger } from "../common";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../common/logging";
import { telemetryListener } from "../common/vscode/telemetry";
export interface EvalLogTreeItem { export interface EvalLogTreeItem {
label?: string; label?: string;
@@ -111,6 +112,7 @@ export class EvalLogViewer extends DisposableObject {
(err: unknown) => (err: unknown) =>
showAndLogExceptionWithTelemetry( showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
asError(err), asError(err),
)`Failed to reveal tree view: ${getErrorMessage(err)}`, )`Failed to reveal tree view: ${getErrorMessage(err)}`,

View File

@@ -13,7 +13,8 @@ import { QueryHistoryDto, QueryHistoryItemDto } from "./query-history-dto";
import { mapQueryHistoryToDomainModel } from "./query-history-dto-mapper"; import { mapQueryHistoryToDomainModel } from "./query-history-dto-mapper";
import { mapQueryHistoryToDto } from "./query-history-domain-mapper"; import { mapQueryHistoryToDto } from "./query-history-domain-mapper";
import { extLogger } from "../../common"; import { extLogger } from "../../common";
import { showAndLogExceptionWithTelemetry } from "../../common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../../common/logging";
import { telemetryListener } from "../../common/vscode/telemetry";
const ALLOWED_QUERY_HISTORY_VERSIONS = [1, 2]; const ALLOWED_QUERY_HISTORY_VERSIONS = [1, 2];
@@ -32,6 +33,7 @@ export async function readQueryHistoryFromFile(
if (!ALLOWED_QUERY_HISTORY_VERSIONS.includes(obj.version)) { if (!ALLOWED_QUERY_HISTORY_VERSIONS.includes(obj.version)) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError`Can't parse query history. Unsupported query history format: v${obj.version}.`, redactableError`Can't parse query history. Unsupported query history format: v${obj.version}.`,
); );
return []; return [];
@@ -68,6 +70,7 @@ export async function readQueryHistoryFromFile(
} catch (e) { } catch (e) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError(asError(e))`Error loading query history.`, redactableError(asError(e))`Error loading query history.`,
{ {
fullMessage: `Error loading query history.\n${getErrorStack(e)}`, fullMessage: `Error loading query history.\n${getErrorStack(e)}`,

View File

@@ -13,7 +13,10 @@ import { tmpDir } from "../../tmp-dir";
import { ProgressCallback } from "../../common/vscode/progress"; import { ProgressCallback } from "../../common/vscode/progress";
import { QueryMetadata } from "../../pure/interface-types"; import { QueryMetadata } from "../../pure/interface-types";
import { extLogger, Logger } from "../../common"; import { extLogger, Logger } from "../../common";
import { showAndLogExceptionWithTelemetry } from "../../common/vscode/logging"; import {
showAndLogExceptionWithTelemetry,
showAndLogWarningMessage,
} from "../../common/logging";
import * as messages from "../../pure/legacy-messages"; import * as messages from "../../pure/legacy-messages";
import * as newMessages from "../../pure/new-messages"; import * as newMessages from "../../pure/new-messages";
import * as qsClient from "./query-server-client"; import * as qsClient from "./query-server-client";
@@ -23,8 +26,8 @@ import { QueryEvaluationInfo, QueryOutputDir } from "../../run-queries-shared";
import { redactableError } from "../../pure/errors"; import { redactableError } from "../../pure/errors";
import { CoreQueryResults, CoreQueryTarget } from "../query-runner"; import { CoreQueryResults, CoreQueryTarget } from "../query-runner";
import { Position } from "../../pure/messages-shared"; import { Position } from "../../pure/messages-shared";
import { showAndLogWarningMessage } from "../../common/logging";
import { ensureDirSync } from "fs-extra"; import { ensureDirSync } from "fs-extra";
import { telemetryListener } from "../../common/vscode/telemetry";
const upgradesTmpDir = join(tmpDir.name, "upgrades"); const upgradesTmpDir = join(tmpDir.name, "upgrades");
ensureDirSync(upgradesTmpDir); ensureDirSync(upgradesTmpDir);
@@ -386,6 +389,7 @@ export async function compileAndRunQueryAgainstDatabaseCore(
} catch (e) { } catch (e) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
asError(e), asError(e),
)`Couldn't resolve available ML models for ${qlProgram.queryPath}. Running the query without any ML models: ${e}.`, )`Couldn't resolve available ML models for ${qlProgram.queryPath}. Running the query without any ML models: ${e}.`,
@@ -444,7 +448,11 @@ export async function compileAndRunQueryAgainstDatabaseCore(
? redactableError`${result.message}` ? redactableError`${result.message}`
: redactableError`Failed to run query`; : redactableError`Failed to run query`;
void extLogger.log(error.fullMessage); void extLogger.log(error.fullMessage);
void showAndLogExceptionWithTelemetry(extLogger, error); void showAndLogExceptionWithTelemetry(
extLogger,
telemetryListener,
error,
);
} }
return translateLegacyResult(result); return translateLegacyResult(result);

View File

@@ -6,7 +6,7 @@ import {
UserCancellationException, UserCancellationException,
} from "../../common/vscode/progress"; } from "../../common/vscode/progress";
import { extLogger } from "../../common"; import { extLogger } from "../../common";
import { showAndLogExceptionWithTelemetry } from "../../common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../../common/logging";
import * as messages from "../../pure/legacy-messages"; import * as messages from "../../pure/legacy-messages";
import * as qsClient from "./query-server-client"; import * as qsClient from "./query-server-client";
import * as tmp from "tmp-promise"; import * as tmp from "tmp-promise";
@@ -14,6 +14,7 @@ import { dirname } from "path";
import { DatabaseItem } from "../../databases/local-databases"; import { DatabaseItem } from "../../databases/local-databases";
import { asError, getErrorMessage } from "../../pure/helpers-pure"; import { asError, getErrorMessage } from "../../pure/helpers-pure";
import { redactableError } from "../../pure/errors"; import { redactableError } from "../../pure/errors";
import { telemetryListener } from "../../common/vscode/telemetry";
/** /**
* Maximum number of lines to include from database upgrade message, * Maximum number of lines to include from database upgrade message,
@@ -207,6 +208,7 @@ export async function upgradeDatabaseExplicit(
} catch (e) { } catch (e) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
asError(e), asError(e),
)`Compilation of database upgrades failed: ${getErrorMessage(e)}`, )`Compilation of database upgrades failed: ${getErrorMessage(e)}`,
@@ -222,6 +224,7 @@ export async function upgradeDatabaseExplicit(
: redactableError`[no error message available]`; : redactableError`[no error message available]`;
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError`Compilation of database upgrades failed: ${error}`, redactableError`Compilation of database upgrades failed: ${error}`,
); );
return; return;
@@ -256,6 +259,7 @@ export async function upgradeDatabaseExplicit(
} catch (e) { } catch (e) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError(asError(e))`Database upgrade failed: ${getErrorMessage( redactableError(asError(e))`Database upgrade failed: ${getErrorMessage(
e, e,
)}`, )}`,

View File

@@ -6,9 +6,12 @@ import { asError, getErrorMessage } from "../pure/helpers-pure";
import { redactableError } from "../pure/errors"; import { redactableError } from "../pure/errors";
import { access } from "fs-extra"; import { access } from "fs-extra";
import { BaseLogger, extLogger } from "../common"; import { BaseLogger, extLogger } from "../common";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import {
showAndLogExceptionWithTelemetry,
showAndLogWarningMessage,
} from "../common/logging";
import { DisposableObject } from "../pure/disposable-object"; import { DisposableObject } from "../pure/disposable-object";
import { showAndLogWarningMessage } from "../common/logging"; import { telemetryListener } from "../common/vscode/telemetry";
async function isFileAccessible(uri: Uri): Promise<boolean> { async function isFileAccessible(uri: Uri): Promise<boolean> {
try { try {
@@ -87,6 +90,7 @@ export class TestRunner extends DisposableObject {
// So we need to display the error message ourselves and then rethrow. // So we need to display the error message ourselves and then rethrow.
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError(asError(e))`Cannot remove database ${ redactableError(asError(e))`Cannot remove database ${
database.name database.name
}: ${getErrorMessage(e)}`, }: ${getErrorMessage(e)}`,

View File

@@ -4,7 +4,7 @@ import {
WebviewPanelConfig, WebviewPanelConfig,
} from "../common/vscode/abstract-webview"; } from "../common/vscode/abstract-webview";
import { assertNever } from "../pure/helpers-pure"; import { assertNever } from "../pure/helpers-pure";
import { telemetryListener } from "../telemetry"; import { telemetryListener } from "../common/vscode/telemetry";
import { import {
FromDataFlowPathsMessage, FromDataFlowPathsMessage,
ToDataFlowPathsMessage, ToDataFlowPathsMessage,
@@ -12,7 +12,7 @@ import {
import { DataFlowPaths } from "./shared/data-flow-paths"; import { DataFlowPaths } from "./shared/data-flow-paths";
import { redactableError } from "../pure/errors"; import { redactableError } from "../pure/errors";
import { extLogger } from "../common"; import { extLogger } from "../common";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../common/logging";
export class DataFlowPathsView extends AbstractWebview< export class DataFlowPathsView extends AbstractWebview<
ToDataFlowPathsMessage, ToDataFlowPathsMessage,
@@ -61,6 +61,7 @@ export class DataFlowPathsView extends AbstractWebview<
case "unhandledError": case "unhandledError":
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
extLogger, extLogger,
telemetryListener,
redactableError( redactableError(
msg.error, msg.error,
)`Unhandled error in data flow paths view: ${msg.error.message}`, )`Unhandled error in data flow paths view: ${msg.error.message}`,

View File

@@ -71,8 +71,8 @@ import {
} from "./repo-states-store"; } from "./repo-states-store";
import { GITHUB_AUTH_PROVIDER_ID } from "../common/vscode/authentication"; import { GITHUB_AUTH_PROVIDER_ID } from "../common/vscode/authentication";
import { FetchError } from "node-fetch"; import { FetchError } from "node-fetch";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging";
import { import {
showAndLogExceptionWithTelemetry,
showAndLogInformationMessage, showAndLogInformationMessage,
showAndLogWarningMessage, showAndLogWarningMessage,
} from "../common/logging"; } from "../common/logging";
@@ -329,6 +329,7 @@ export class VariantAnalysisManager
if (!this.variantAnalyses.get(variantAnalysisId)) { if (!this.variantAnalyses.get(variantAnalysisId)) {
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
this.app.logger, this.app.logger,
this.app.telemetry,
redactableError`No variant analysis found with id: ${variantAnalysisId}.`, redactableError`No variant analysis found with id: ${variantAnalysisId}.`,
); );
} }

View File

@@ -3,7 +3,10 @@ import {
AbstractWebview, AbstractWebview,
WebviewPanelConfig, WebviewPanelConfig,
} from "../common/vscode/abstract-webview"; } from "../common/vscode/abstract-webview";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/logging"; import {
showAndLogExceptionWithTelemetry,
showAndLogWarningMessage,
} from "../common/logging";
import { import {
FromVariantAnalysisMessage, FromVariantAnalysisMessage,
ToVariantAnalysisMessage, ToVariantAnalysisMessage,
@@ -18,7 +21,7 @@ import {
VariantAnalysisViewInterface, VariantAnalysisViewInterface,
VariantAnalysisViewManager, VariantAnalysisViewManager,
} from "./variant-analysis-view-manager"; } from "./variant-analysis-view-manager";
import { telemetryListener } from "../telemetry"; import { telemetryListener } from "../common/vscode/telemetry";
import { redactableError } from "../pure/errors"; import { redactableError } from "../pure/errors";
import { DataFlowPathsView } from "./data-flow-paths-view"; import { DataFlowPathsView } from "./data-flow-paths-view";
import { DataFlowPaths } from "./shared/data-flow-paths"; import { DataFlowPaths } from "./shared/data-flow-paths";
@@ -27,7 +30,6 @@ import {
getVariantAnalysisDefaultResultsFilter, getVariantAnalysisDefaultResultsFilter,
getVariantAnalysisDefaultResultsSort, getVariantAnalysisDefaultResultsSort,
} from "../config"; } from "../config";
import { showAndLogWarningMessage } from "../common/logging";
export class VariantAnalysisView export class VariantAnalysisView
extends AbstractWebview<ToVariantAnalysisMessage, FromVariantAnalysisMessage> extends AbstractWebview<ToVariantAnalysisMessage, FromVariantAnalysisMessage>
@@ -164,6 +166,7 @@ export class VariantAnalysisView
case "unhandledError": case "unhandledError":
void showAndLogExceptionWithTelemetry( void showAndLogExceptionWithTelemetry(
this.app.logger, this.app.logger,
this.app.telemetry,
redactableError( redactableError(
msg.error, msg.error,
)`Unhandled error in variant analysis results view: ${msg.error.message}`, )`Unhandled error in variant analysis results view: ${msg.error.message}`,

View File

@@ -9,6 +9,8 @@ import { Credentials } from "../../src/common/authentication";
import { AppCommandManager } from "../../src/common/commands"; import { AppCommandManager } from "../../src/common/commands";
import { createMockCommandManager } from "./commandsMock"; import { createMockCommandManager } from "./commandsMock";
import { NotificationLogger } from "../../src/common"; import { NotificationLogger } from "../../src/common";
import { AppTelemetry } from "../../src/common/telemetry";
import { createMockTelemetryReporter } from "./telemetryMock";
export function createMockApp({ export function createMockApp({
extensionPath = "/mock/extension/path", extensionPath = "/mock/extension/path",
@@ -20,6 +22,7 @@ export function createMockApp({
commands = createMockCommandManager(), commands = createMockCommandManager(),
environment = createMockEnvironmentContext(), environment = createMockEnvironmentContext(),
logger = createMockLogger(), logger = createMockLogger(),
telemetry = createMockTelemetryReporter(),
}: { }: {
extensionPath?: string; extensionPath?: string;
workspaceStoragePath?: string; workspaceStoragePath?: string;
@@ -30,10 +33,12 @@ export function createMockApp({
commands?: AppCommandManager; commands?: AppCommandManager;
environment?: EnvironmentContext; environment?: EnvironmentContext;
logger?: NotificationLogger; logger?: NotificationLogger;
telemetry?: AppTelemetry;
}): App { }): App {
return { return {
mode: AppMode.Test, mode: AppMode.Test,
logger, logger,
telemetry,
subscriptions: [], subscriptions: [],
extensionPath, extensionPath,
workspaceStoragePath, workspaceStoragePath,

View File

@@ -0,0 +1,9 @@
import { AppTelemetry } from "../../src/common/telemetry";
export function createMockTelemetryReporter(): AppTelemetry {
return {
sendCommandUsage: jest.fn(),
sendUIInteraction: jest.fn(),
sendError: jest.fn(),
};
}

View File

@@ -5,15 +5,16 @@ import { CodeQLCliServer } from "../../../../src/codeql-cli/cli";
import { getErrorMessage } from "../../../../src/pure/helpers-pure"; import { getErrorMessage } from "../../../../src/pure/helpers-pure";
import * as log from "../../../../src/common/logging/notifications"; import * as log from "../../../../src/common/logging/notifications";
import * as vscodeLog from "../../../../src/common/vscode/logging";
import { import {
handleDownloadPacks, handleDownloadPacks,
handleInstallPackDependencies, handleInstallPackDependencies,
} from "../../../../src/packaging"; } from "../../../../src/packaging";
import { mockedQuickPickItem } from "../../utils/mocking.helpers"; import { mockedQuickPickItem } from "../../utils/mocking.helpers";
import { getActivatedExtension } from "../../global.helper"; import { getActivatedExtension } from "../../global.helper";
import { showAndLogInformationMessage } from "../../../../src/common/logging"; import {
import { showAndLogExceptionWithTelemetry } from "../../../../src/common/vscode/logging"; showAndLogInformationMessage,
showAndLogExceptionWithTelemetry,
} from "../../../../src/common/logging";
describe("Packaging commands", () => { describe("Packaging commands", () => {
let cli: CodeQLCliServer; let cli: CodeQLCliServer;
@@ -35,7 +36,7 @@ describe("Packaging commands", () => {
.spyOn(window, "showInputBox") .spyOn(window, "showInputBox")
.mockResolvedValue(undefined); .mockResolvedValue(undefined);
showAndLogExceptionWithTelemetrySpy = jest showAndLogExceptionWithTelemetrySpy = jest
.spyOn(vscodeLog, "showAndLogExceptionWithTelemetry") .spyOn(log, "showAndLogExceptionWithTelemetry")
.mockResolvedValue(undefined); .mockResolvedValue(undefined);
showAndLogInformationMessageSpy = jest showAndLogInformationMessageSpy = jest
.spyOn(log, "showAndLogInformationMessage") .spyOn(log, "showAndLogInformationMessage")
@@ -82,7 +83,7 @@ describe("Packaging commands", () => {
expect(showAndLogExceptionWithTelemetrySpy).toHaveBeenCalled(); expect(showAndLogExceptionWithTelemetrySpy).toHaveBeenCalled();
expect( expect(
showAndLogExceptionWithTelemetrySpy.mock.calls[0][1].fullMessage, showAndLogExceptionWithTelemetrySpy.mock.calls[0][2].fullMessage,
).toEqual("Unable to download all packs. See log for more details."); ).toEqual("Unable to download all packs. See log for more details.");
}); });

View File

@@ -11,9 +11,9 @@ import { readdir, readFile } from "fs-extra";
import { load } from "js-yaml"; import { load } from "js-yaml";
import { dirname, join } from "path"; import { dirname, join } from "path";
import { fetchExternalApiQueries } from "../../../../src/data-extensions-editor/queries"; import { fetchExternalApiQueries } from "../../../../src/data-extensions-editor/queries";
import * as vscodeLog from "../../../../src/common/vscode/logging"; import * as log from "../../../../src/common/logging/notifications";
import { RedactableError } from "../../../../src/pure/errors"; import { RedactableError } from "../../../../src/pure/errors";
import { showAndLogExceptionWithTelemetry } from "../../../../src/common/vscode/logging"; import { showAndLogExceptionWithTelemetry } from "../../../../src/common/logging";
function createMockUri(path = "/a/b/c/foo"): Uri { function createMockUri(path = "/a/b/c/foo"): Uri {
return { return {
@@ -140,7 +140,7 @@ describe("readQueryResults", () => {
beforeEach(() => { beforeEach(() => {
showAndLogExceptionWithTelemetrySpy = jest.spyOn( showAndLogExceptionWithTelemetrySpy = jest.spyOn(
vscodeLog, log,
"showAndLogExceptionWithTelemetry", "showAndLogExceptionWithTelemetry",
); );
}); });
@@ -153,6 +153,7 @@ describe("readQueryResults", () => {
expect(await readQueryResults(options)).toBeUndefined(); expect(await readQueryResults(options)).toBeUndefined();
expect(showAndLogExceptionWithTelemetrySpy).toHaveBeenCalledWith( expect(showAndLogExceptionWithTelemetrySpy).toHaveBeenCalledWith(
expect.anything(), expect.anything(),
undefined,
expect.any(RedactableError), expect.any(RedactableError),
); );
}); });
@@ -186,6 +187,7 @@ describe("readQueryResults", () => {
expect(await readQueryResults(options)).toBeUndefined(); expect(await readQueryResults(options)).toBeUndefined();
expect(showAndLogExceptionWithTelemetrySpy).toHaveBeenCalledWith( expect(showAndLogExceptionWithTelemetrySpy).toHaveBeenCalledWith(
expect.anything(), expect.anything(),
undefined,
expect.any(RedactableError), expect.any(RedactableError),
); );
}); });

View File

@@ -6,9 +6,9 @@ import {
window, window,
} from "vscode"; } from "vscode";
import { import {
TelemetryListener, ExtensionTelemetryListener,
telemetryListener as globalTelemetryListener, telemetryListener as globalTelemetryListener,
} from "../../../src/telemetry"; } from "../../../src/common/vscode/telemetry";
import { UserCancellationException } from "../../../src/common/vscode/progress"; import { UserCancellationException } from "../../../src/common/vscode/progress";
import { ENABLE_TELEMETRY } from "../../../src/config"; import { ENABLE_TELEMETRY } from "../../../src/config";
import { createMockExtensionContext } from "./index"; import { createMockExtensionContext } from "./index";
@@ -25,7 +25,7 @@ describe("telemetry reporting", () => {
let originalTelemetryGlobal: boolean | undefined; let originalTelemetryGlobal: boolean | undefined;
let isCanary: string; let isCanary: string;
let ctx: ExtensionContext; let ctx: ExtensionContext;
let telemetryListener: TelemetryListener; let telemetryListener: ExtensionTelemetryListener;
let sendTelemetryEventSpy: jest.SpiedFunction< let sendTelemetryEventSpy: jest.SpiedFunction<
typeof TelemetryReporter.prototype.sendTelemetryEvent typeof TelemetryReporter.prototype.sendTelemetryEvent
@@ -81,7 +81,7 @@ describe("telemetry reporting", () => {
await enableTelemetry("telemetry", true); await enableTelemetry("telemetry", true);
await enableTelemetry("codeQL.telemetry", true); await enableTelemetry("codeQL.telemetry", true);
telemetryListener = new TelemetryListener( telemetryListener = new ExtensionTelemetryListener(
"my-id", "my-id",
"1.2.3", "1.2.3",
"fake-key", "fake-key",