Adding further console logging but also fixed lines with JSON.stringify(error)

This commit is contained in:
Chuck Skelton
2026-05-26 16:21:32 -07:00
parent 41ae13ea3a
commit 10cda7ba3f
7 changed files with 81 additions and 35 deletions
+10 -1
View File
@@ -14,12 +14,21 @@ export interface HandleErrorOptions {
redactedError?: string | ARMError | Error; redactedError?: string | ARMError | Error;
} }
export const stringifyError = function (err: any) {
var plainObject: { [key: string]: any } = {};
Object.getOwnPropertyNames(err).forEach(function (key) {
plainObject[key] = err[key];
});
return JSON.stringify(plainObject, null, '\r\n');
};
export const handleError = ( export const handleError = (
error: string | ARMError | Error, error: string | ARMError | Error,
area: string, area: string,
consoleErrorPrefix?: string, consoleErrorPrefix?: string,
options?: HandleErrorOptions, options?: HandleErrorOptions,
): void => { ): void => {
console.log("{{cdbp}} in handleError(): raw error: " + stringifyError(error)); //CTODO in case a stray error happens
const errorMessage = getErrorMessage(error); const errorMessage = getErrorMessage(error);
const errorCode = error instanceof ARMError ? error.code : undefined; const errorCode = error instanceof ARMError ? error.code : undefined;
@@ -44,7 +53,7 @@ export const handleError = (
export const getErrorMessage = (error: string | Error = ""): string => { export const getErrorMessage = (error: string | Error = ""): string => {
let errorMessage = typeof error === "string" ? error : error.message; let errorMessage = typeof error === "string" ? error : error.message;
if (!errorMessage) { if (!errorMessage) {
errorMessage = JSON.stringify(error); errorMessage = stringifyError(error);
} }
return replaceKnownError(errorMessage); return replaceKnownError(errorMessage);
}; };
+34 -18
View File
@@ -11,7 +11,7 @@ import { listGremlinDatabases } from "../../Utils/arm/generatedClients/cosmos/gr
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/cosmos/mongoDBResources"; import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/cosmos/mongoDBResources";
import { listSqlDatabases } from "../../Utils/arm/generatedClients/cosmos/sqlResources"; import { listSqlDatabases } from "../../Utils/arm/generatedClients/cosmos/sqlResources";
import { client } from "../CosmosClient"; import { client } from "../CosmosClient";
import { handleError } from "../ErrorHandlingUtils"; import { handleError, stringifyError } from "../ErrorHandlingUtils";
export async function readDatabases(): Promise<DataModels.Database[]> { export async function readDatabases(): Promise<DataModels.Database[]> {
let databases: DataModels.Database[]; let databases: DataModels.Database[];
@@ -26,6 +26,7 @@ export async function readDatabases(): Promise<DataModels.Database[]> {
(userContext.fabricContext?.artifactInfo as FabricArtifactInfo[CosmosDbArtifactType.MIRRORED_KEY]).resourceTokenInfo (userContext.fabricContext?.artifactInfo as FabricArtifactInfo[CosmosDbArtifactType.MIRRORED_KEY]).resourceTokenInfo
.resourceTokens .resourceTokens
) { ) {
console.log("{{cdbp}} in readDatabases(): isFabricMirroredKey && has resourceTokens"); //CTODO should not get here
const tokensData = (userContext.fabricContext.artifactInfo as FabricArtifactInfo[CosmosDbArtifactType.MIRRORED_KEY]) const tokensData = (userContext.fabricContext.artifactInfo as FabricArtifactInfo[CosmosDbArtifactType.MIRRORED_KEY])
.resourceTokenInfo; .resourceTokenInfo;
@@ -59,6 +60,7 @@ export async function readDatabases(): Promise<DataModels.Database[]> {
clearMessage(); clearMessage();
return databases; return databases;
} else if (isFabricNative() && userContext.fabricContext?.databaseName) { } else if (isFabricNative() && userContext.fabricContext?.databaseName) {
console.log("{{cdbp}} in readDatabases(): isFabricNative"); //CTODO should not get here
const databaseId = userContext.fabricContext.databaseName; const databaseId = userContext.fabricContext.databaseName;
databases = [ databases = [
{ {
@@ -81,9 +83,15 @@ export async function readDatabases(): Promise<DataModels.Database[]> {
userContext.apiType !== "Tables" && userContext.apiType !== "Tables" &&
!isFabric() !isFabric()
) { ) {
console.log("{{cdbp}} in readDatabases(): authType == AAD, enableSDKOperations, apiType != Tables, !isFabric");
console.log("{{cdbp}} in readDatabases(): databaseaccount: " + userContext.databaseAccount);
console.log("{{cdbp}} in readDatabases(): calling readDatabasesWithARM");
databases = await readDatabasesWithARM(); databases = await readDatabasesWithARM();
console.log("{{cdbp}} in readDatabases(): done readDatabasesWithARM");
} else { } else {
console.log("{{cdbp}} in readDatabases(): calling SDK");
const sdkResponse = await client().databases.readAll().fetchAll(); const sdkResponse = await client().databases.readAll().fetchAll();
console.log("{{cdbp}} in readDatabases(): done SDK");
databases = sdkResponse.resources as DataModels.Database[]; databases = sdkResponse.resources as DataModels.Database[];
} }
} catch (error) { } catch (error) {
@@ -108,22 +116,30 @@ export async function readDatabasesWithARM(accountOverride?: {
const accountName = accountOverride?.accountName ?? userContext?.databaseAccount?.name ?? ""; const accountName = accountOverride?.accountName ?? userContext?.databaseAccount?.name ?? "";
const apiType = accountOverride?.apiType ?? userContext.apiType; const apiType = accountOverride?.apiType ?? userContext.apiType;
switch (apiType) { try {
case "SQL": switch (apiType) {
rpResponse = await listSqlDatabases(subscriptionId, resourceGroup, accountName); case "SQL":
break; console.log("{{cdbp}} in readDatabasesWithARM(): calling listSqlDatabases");
case "Mongo": rpResponse = await listSqlDatabases(subscriptionId, resourceGroup, accountName);
rpResponse = await listMongoDBDatabases(subscriptionId, resourceGroup, accountName); console.log("{{cdbp}} in readDatabasesWithARM(): done listSqlDatabases");
break; break;
case "Cassandra": case "Mongo":
rpResponse = await listCassandraKeyspaces(subscriptionId, resourceGroup, accountName); rpResponse = await listMongoDBDatabases(subscriptionId, resourceGroup, accountName);
break; break;
case "Gremlin": case "Cassandra":
rpResponse = await listGremlinDatabases(subscriptionId, resourceGroup, accountName); rpResponse = await listCassandraKeyspaces(subscriptionId, resourceGroup, accountName);
break; break;
default: case "Gremlin":
throw new Error(`Unsupported default experience type: ${apiType}`); rpResponse = await listGremlinDatabases(subscriptionId, resourceGroup, accountName);
} break;
default:
throw new Error(`Unsupported default experience type: ${apiType}`);
}
return rpResponse?.value?.map((database) => database.properties?.resource as DataModels.Database) ?? []; console.log("{{cdbp}} in readDatabasesWithARM(): response: " + JSON.stringify(rpResponse));
return rpResponse?.value?.map((database) => database.properties?.resource as DataModels.Database) ?? [];
} catch (error) {
console.log("{{cdbp}} in readDatabasesWithARM(): ERROR: " + stringifyError(error));
throw error;
}
} }
+13 -2
View File
@@ -23,7 +23,7 @@ import { AuthType } from "../AuthType";
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer"; import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
import * as Constants from "../Common/Constants"; import * as Constants from "../Common/Constants";
import { Areas, ConnectionStatusType, HttpStatusCodes, Notebook } from "../Common/Constants"; import { Areas, ConnectionStatusType, HttpStatusCodes, Notebook } from "../Common/Constants";
import { getErrorMessage, getErrorStack, handleError } from "../Common/ErrorHandlingUtils"; import { getErrorMessage, getErrorStack, handleError, stringifyError } from "../Common/ErrorHandlingUtils";
import * as Logger from "../Common/Logger"; import * as Logger from "../Common/Logger";
import { QueriesClient } from "../Common/QueriesClient"; import { QueriesClient } from "../Common/QueriesClient";
import { readCollection } from "../Common/dataAccess/readCollection"; import { readCollection } from "../Common/dataAccess/readCollection";
@@ -287,7 +287,7 @@ export default class Explorer {
"We were unable to establish authorization for this account, due to pop-ups being disabled in the browser.\nPlease enable pop-ups for this site and try again", "We were unable to establish authorization for this account, due to pop-ups being disabled in the browser.\nPlease enable pop-ups for this site and try again",
); );
} else { } else {
const errorJson = JSON.stringify(error); const errorJson = stringifyError(error);
logConsoleError( logConsoleError(
`Failed to perform authorization for this account, due to the following error: \n${errorJson}`, `Failed to perform authorization for this account, due to the following error: \n${errorJson}`,
); );
@@ -401,19 +401,27 @@ export default class Explorer {
}, },
startKey, startKey,
); );
console.log("{{cdbp}} in refreshAllDatabases(): done readDatabases");
const currentDatabases = useDatabases.getState().databases; const currentDatabases = useDatabases.getState().databases;
console.log("{{cdbp}} in refreshAllDatabases(): currentDatabases: " + currentDatabases);
const deltaDatabases = this.getDeltaDatabases(databases, currentDatabases); const deltaDatabases = this.getDeltaDatabases(databases, currentDatabases);
console.log("{{cdbp}} in refreshAllDatabases(): deltaDatabases: " + deltaDatabases);
let updatedDatabases = currentDatabases.filter( let updatedDatabases = currentDatabases.filter(
(database) => !deltaDatabases.toDelete.some((deletedDatabase) => deletedDatabase.id() === database.id()), (database) => !deltaDatabases.toDelete.some((deletedDatabase) => deletedDatabase.id() === database.id()),
); );
console.log("{{cdbp}} in refreshAllDatabases(): updatedDatabases after filter: " + updatedDatabases);
updatedDatabases = [...updatedDatabases, ...deltaDatabases.toAdd].sort((db1, db2) => updatedDatabases = [...updatedDatabases, ...deltaDatabases.toAdd].sort((db1, db2) =>
db1.id().localeCompare(db2.id()), db1.id().localeCompare(db2.id()),
); );
console.log("{{cdbp}} in refreshAllDatabases(): updatedDatabases after sort: " + updatedDatabases);
useDatabases.setState({ databases: updatedDatabases, databasesFetchedSuccessfully: true }); useDatabases.setState({ databases: updatedDatabases, databasesFetchedSuccessfully: true });
scenarioMonitor.completePhase(MetricScenario.DatabaseLoad, ApplicationMetricPhase.DatabasesFetched); scenarioMonitor.completePhase(MetricScenario.DatabaseLoad, ApplicationMetricPhase.DatabasesFetched);
console.log("{{cdbp}} in refreshAllDatabases(): calling refreshAndExpandNewDatabases");
await this.refreshAndExpandNewDatabases(deltaDatabases.toAdd, updatedDatabases); await this.refreshAndExpandNewDatabases(deltaDatabases.toAdd, updatedDatabases);
console.log("{{cdbp}} in refreshAllDatabases(): done refreshAndExpandNewDatabases");
} catch (error) { } catch (error) {
console.log("{{cdbp}} in refreshAllDatabases(): ERROR: " + stringifyError(error)); //CTODO this should be logged already but just in case
const errorMessage = getErrorMessage(error); const errorMessage = getErrorMessage(error);
TelemetryProcessor.traceFailure( TelemetryProcessor.traceFailure(
Action.LoadDatabases, Action.LoadDatabases,
@@ -603,6 +611,7 @@ export default class Explorer {
? databases ? databases
: databases.filter((db) => db.isDatabaseExpanded() || db.id() === Constants.SavedQueries.DatabaseName); : databases.filter((db) => db.isDatabaseExpanded() || db.id() === Constants.SavedQueries.DatabaseName);
console.log("{{cdbp}} in refreshAndExpandNewDatabases(): databasesToLoad: " + databasesToLoad);
const startKey: number = TelemetryProcessor.traceStart(Action.LoadCollections, { const startKey: number = TelemetryProcessor.traceStart(Action.LoadCollections, {
dataExplorerArea: Constants.Areas.ResourceTree, dataExplorerArea: Constants.Areas.ResourceTree,
}); });
@@ -611,6 +620,7 @@ export default class Explorer {
try { try {
await Promise.all( await Promise.all(
databasesToLoad.map(async (database: ViewModels.Database) => { databasesToLoad.map(async (database: ViewModels.Database) => {
console.log("{{cdbp}} in refreshAndExpandNewDatabases(): loadCollections for database: " + database.id);
await database.loadCollections(true); await database.loadCollections(true);
const isNewDatabase: boolean = _.some(newDatabases, (db: ViewModels.Database) => db.id() === database.id()); const isNewDatabase: boolean = _.some(newDatabases, (db: ViewModels.Database) => db.id() === database.id());
if (isNewDatabase) { if (isNewDatabase) {
@@ -630,6 +640,7 @@ export default class Explorer {
// Start DatabaseTreeRendered — React render cycle will complete it in ResourceTree // Start DatabaseTreeRendered — React render cycle will complete it in ResourceTree
scenarioMonitor.startPhase(MetricScenario.DatabaseLoad, ApplicationMetricPhase.DatabaseTreeRendered); scenarioMonitor.startPhase(MetricScenario.DatabaseLoad, ApplicationMetricPhase.DatabaseTreeRendered);
} catch (error) { } catch (error) {
console.log("{{cdbp}} in refreshAndExpandNewDatabases(): ERROR: " + stringifyError(error)); //CTODO this should be logged already but just in case
TelemetryProcessor.traceFailure( TelemetryProcessor.traceFailure(
Action.LoadCollections, Action.LoadCollections,
{ {
+7 -7
View File
@@ -4,7 +4,7 @@ import Q from "q";
import { AuthType } from "../../AuthType"; import { AuthType } from "../../AuthType";
import * as Constants from "../../Common/Constants"; import * as Constants from "../../Common/Constants";
import { CassandraProxyAPIs } from "../../Common/Constants"; import { CassandraProxyAPIs } from "../../Common/Constants";
import { handleError } from "../../Common/ErrorHandlingUtils"; import { handleError, stringifyError } from "../../Common/ErrorHandlingUtils";
import * as HeadersUtility from "../../Common/HeadersUtility"; import * as HeadersUtility from "../../Common/HeadersUtility";
import { createDocument } from "../../Common/dataAccess/createDocument"; import { createDocument } from "../../Common/dataAccess/createDocument";
import { deleteDocument } from "../../Common/dataAccess/deleteDocument"; import { deleteDocument } from "../../Common/dataAccess/deleteDocument";
@@ -32,7 +32,7 @@ export interface CassandraTableKey {
} }
export abstract class TableDataClient { export abstract class TableDataClient {
constructor() {} constructor() { }
public abstract createDocument( public abstract createDocument(
collection: ViewModels.Collection, collection: ViewModels.Collection,
@@ -172,7 +172,7 @@ export class CassandraAPIDataClient extends TableDataClient {
deferred.resolve(entity); deferred.resolve(entity);
}, },
(error) => { (error) => {
const errorText = error.responseJSON?.message ?? JSON.stringify(error); const errorText = error.responseJSON?.message ?? stringifyError(error);
handleError(errorText, "AddRowCassandra", `Error while adding new row to table ${collection.id()}`); handleError(errorText, "AddRowCassandra", `Error while adding new row to table ${collection.id()}`);
deferred.reject(errorText); deferred.reject(errorText);
}, },
@@ -361,7 +361,7 @@ export class CassandraAPIDataClient extends TableDataClient {
deferred.resolve(); deferred.resolve();
}, },
(error) => { (error) => {
const errorText = error.responseJSON?.message ?? JSON.stringify(error); const errorText = error.responseJSON?.message ?? stringifyError(error);
handleError( handleError(
errorText, errorText,
"CreateKeyspaceCassandra", "CreateKeyspaceCassandra",
@@ -400,7 +400,7 @@ export class CassandraAPIDataClient extends TableDataClient {
deferred.resolve(); deferred.resolve();
}, },
(error) => { (error) => {
const errorText = error.responseJSON?.message ?? JSON.stringify(error); const errorText = error.responseJSON?.message ?? stringifyError(error);
handleError( handleError(
errorText, errorText,
"CreateTableCassandra", "CreateTableCassandra",
@@ -450,7 +450,7 @@ export class CassandraAPIDataClient extends TableDataClient {
deferred.resolve(data); deferred.resolve(data);
}, },
(error: any) => { (error: any) => {
const errorText = error.responseJSON?.message ?? JSON.stringify(error); const errorText = error.responseJSON?.message ?? stringifyError(error);
handleError(errorText, "FetchKeysCassandra", `Error fetching keys for table ${collection.id()}`); handleError(errorText, "FetchKeysCassandra", `Error fetching keys for table ${collection.id()}`);
deferred.reject(errorText); deferred.reject(errorText);
}, },
@@ -492,7 +492,7 @@ export class CassandraAPIDataClient extends TableDataClient {
deferred.resolve(data.columns); deferred.resolve(data.columns);
}, },
(error: any) => { (error: any) => {
const errorText = error.responseJSON?.message ?? JSON.stringify(error); const errorText = error.responseJSON?.message ?? stringifyError(error);
handleError(errorText, "FetchSchemaCassandra", `Error fetching schema for table ${collection.id()}`); handleError(errorText, "FetchSchemaCassandra", `Error fetching schema for table ${collection.id()}`);
deferred.reject(errorText); deferred.reject(errorText);
}, },
+3 -2
View File
@@ -1,5 +1,6 @@
import * as msal from "@azure/msal-browser"; import * as msal from "@azure/msal-browser";
import { getEnvironmentScopeEndpoint } from "Common/EnvironmentUtility"; import { getEnvironmentScopeEndpoint } from "Common/EnvironmentUtility";
import { stringifyError } from "Common/ErrorHandlingUtils";
import { Action, ActionModifiers } from "Shared/Telemetry/TelemetryConstants"; import { Action, ActionModifiers } from "Shared/Telemetry/TelemetryConstants";
import { hasProxyServer, isDataplaneRbacSupported } from "Utils/APITypeUtils"; import { hasProxyServer, isDataplaneRbacSupported } from "Utils/APITypeUtils";
import { AuthType } from "../AuthType"; import { AuthType } from "../AuthType";
@@ -154,9 +155,9 @@ export async function acquireMsalTokenForAccount(
traceFailure(Action.SignInAad, { traceFailure(Action.SignInAad, {
request: JSON.stringify(loginRequest), request: JSON.stringify(loginRequest),
acquireTokenType: silent ? "silent" : "interactive", acquireTokenType: silent ? "silent" : "interactive",
errorMessage: JSON.stringify(error), errorMessage: stringifyError(error),
}); });
traceFailure(Action.AcquireMsalToken, { error: JSON.stringify(error) }, msalStartKey); traceFailure(Action.AcquireMsalToken, { error: stringifyError(error) }, msalStartKey);
// Mark expected failure for health metrics so timeout emits healthy // Mark expected failure for health metrics so timeout emits healthy
if (isExpectedError(error)) { if (isExpectedError(error)) {
scenarioMonitor.markExpectedFailure(); scenarioMonitor.markExpectedFailure();
@@ -6,9 +6,10 @@
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/DocumentDB/preview/2025-11-01-preview/cosmos-db.json Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/DocumentDB/preview/2025-11-01-preview/cosmos-db.json
*/ */
import { stringifyError } from "Common/ErrorHandlingUtils";
import { configContext } from "../../../../ConfigContext";
import { armRequest } from "../../request"; import { armRequest } from "../../request";
import * as Types from "./types"; import * as Types from "./types";
import { configContext } from "../../../../ConfigContext";
const apiVersion = "2025-11-01-preview"; const apiVersion = "2025-11-01-preview";
/* Lists the SQL databases under an existing Azure Cosmos DB database account. */ /* Lists the SQL databases under an existing Azure Cosmos DB database account. */
@@ -18,7 +19,14 @@ export async function listSqlDatabases(
accountName: string, accountName: string,
): Promise<Types.SqlDatabaseListResult> { ): Promise<Types.SqlDatabaseListResult> {
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases`; const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases`;
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion }); console.log("{{cdbp}} in listSqlDatabases(): path: " + path);
try {
console.log("{{cdbp}} in listSqlDatabases(): calling armRequest");
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
} catch (error) {
console.log("{{cdbp}} in listSqlDatabases(): ERROR: " + stringifyError(error));
throw error;
}
} }
/* Gets the SQL database under an existing Azure Cosmos DB database account with the provided name. */ /* Gets the SQL database under an existing Azure Cosmos DB database account with the provided name. */
+4 -3
View File
@@ -1,5 +1,6 @@
import * as msal from "@azure/msal-browser"; import * as msal from "@azure/msal-browser";
import { useBoolean } from "@fluentui/react-hooks"; import { useBoolean } from "@fluentui/react-hooks";
import { stringifyError } from "Common/ErrorHandlingUtils";
import * as React from "react"; import * as React from "react";
import { ConfigContext } from "../ConfigContext"; import { ConfigContext } from "../ConfigContext";
import { import {
@@ -77,7 +78,7 @@ export function useAADAuth(config?: ConfigContext): ReturnType {
localStorage.setItem("cachedTenantId", response.tenantId); localStorage.setItem("cachedTenantId", response.tenantId);
} catch (error) { } catch (error) {
setAuthFailure({ setAuthFailure({
failureMessage: `Login failed: ${JSON.stringify(error)}`, failureMessage: `Login failed: ${stringifyError(error)}`,
}); });
} }
}, [msalInstance, config]); }, [msalInstance, config]);
@@ -111,7 +112,7 @@ export function useAADAuth(config?: ConfigContext): ReturnType {
localStorage.setItem("cachedTenantId", response.tenantId); localStorage.setItem("cachedTenantId", response.tenantId);
} catch (error) { } catch (error) {
setAuthFailure({ setAuthFailure({
failureMessage: `Tenant switch failed: ${JSON.stringify(error)}`, failureMessage: `Tenant switch failed: ${stringifyError(error)}`,
}); });
} }
}, },
@@ -144,7 +145,7 @@ export function useAADAuth(config?: ConfigContext): ReturnType {
failureLinkAction: acquireTokens, failureLinkAction: acquireTokens,
}); });
} else { } else {
const errorJson = JSON.stringify(error); const errorJson = stringifyError(error);
setAuthFailure({ setAuthFailure({
failureMessage: `We were unable to establish authorization for this account, due to the following error: \n${errorJson}`, failureMessage: `We were unable to establish authorization for this account, due to the following error: \n${errorJson}`,
}); });